Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Meta Laravel Package

ryannielson/meta

Meta is a Laravel package for managing page meta tags from PHP and Blade views. Set titles, descriptions, and arbitrary head metadata with a simple API, define defaults, override them per request, and render everything cleanly in your layouts. Lightweight and easy to integrate into existing applicat...

View on GitHub
Deep Wiki
Context7

Getting Started

ryannielson/meta is a small service + facade that accumulates meta tags during a request and renders them in one place — typically the <head> of your Blade layout. Think of it as a per-request "bag" of tags you fill from controllers and dump into a partial.

  1. Install. The only tagged release is from October 2015, so pin explicitly and verify what Composer resolves:

    composer require "ryannielson/meta"
    

    If resolution fails, fall back to the repo directly and confirm the constraint in composer.json. Because the package predates Laravel 5.5 auto-discovery, you must register it manually.

  2. Register the provider in config/app.php (or app/Providers/AppServiceProvider if you're on a modern skeleton with a custom registration path):

    'providers' => [
        // ...
        RyanNielson\Meta\MetaServiceProvider::class,
    ],
    
  3. Register the facade alias so Meta:: works:

    'aliases' => [
        // ...
        'Meta' => RyanNielson\Meta\Facades\Meta::class,
    ],
    

    Double-check the exact class names against the package README / vendor/ryannielson/meta/src — the namespace follows the vendor name (RyanNielson\Meta), but the facade class name is the one thing most likely to trip you up.

  4. Render in your layout. In resources/views/layouts/app.blade.php:

    <head>
        <meta charset="utf-8">
        {!! Meta::render() !!}
        <title>…</title>
    </head>
    

    Note the unescaped output — the point of render() is to emit pre-built <meta> HTML. See Gotchas.

  5. First use case. In a controller action, set the values the layout will pick up:

    public function show(Post $post)
    {
        Meta::title($post->title);
        Meta::description(Str::limit(strip_tags($post->body), 155));
    
        return view('posts.show', compact('post'));
    }
    

    Load the page and confirm the tags land in <head>. That's the entire happy path — after this you're just deciding where the calls live.

Implementation Patterns

Defaults in a base controller or middleware. Rather than repeating site-wide meta on every action, set defaults once and let individual actions override them:

// app/Http/Controllers/Controller.php (or a dedicated middleware)
protected function setDefaultMeta()
{
    Meta::title(config('app.name'));
    Meta::description('The best place to do the thing.');
}

Call it from a constructor or a HandleMetaDefaults middleware that runs before the controller. Middleware is cleaner because it survives controller refactors and applies to routes consistently.

View composers for default + override. If you'd rather keep controllers free of presentation concerns, register a composer:

View::composer('layouts.app', function ($view) {
    if (! Meta::has('title')) {      // confirm the exact method name in the README
        Meta::title(config('app.name'));
    }
});

The tricky part is ordering: the composer fires when the layout renders, which is after your controller/view ran, so controller-level overrides are safe. Defaults set inside the composer itself will be clobbered only if the controller explicitly re-set them afterward — which it can't, because it ran earlier. Keep defaults in middleware or AppServiceProvider::boot() if you want them strictly "lowest priority."

Per-page Open Graph / Twitter cards. The package's value is highest when a page needs more than a title — share images, og:type, canonical URLs. Set them alongside the normal tags:

Meta::title($post->title);
Meta::description($excerpt);
Meta::og('title', $post->title);            // verify method name in README
Meta::og('image', $post->featured_image_url);
Meta::canonical(route('posts.show', $post));

If the package doesn't ship an og() helper, use the generic tag method (something like Meta::tag('meta', ['property' => 'og:title', 'content' => $title])) — every version of this style of package exposes a raw tag/addTag escape hatch for exactly this.

Blade section fallback. A cheap and readable integration trick: let views declare meta via a section, and have the layout prefer it, falling back to the facade:

{{-- posts/show.blade.php --}}
@section('meta_title', $post->title)

{{-- layouts/app.blade.php --}}
<title>@yield('meta_title', config('app.name'))</title>

This is worth doing alongside the package rather than replacing it, because it makes the "static" cases trivial and reserves Meta:: for the dynamic cases (loops, OG images, computed descriptions).

A thin wrapper is the real pattern. Define App\Support\Seo that proxies to Meta and adds your own conventions (Seo::page($title, $description, $image)). When the package eventually breaks against a new Laravel version — and it will — you have exactly one class to rewrite instead of a grep across forty controllers. Bind it in the container and inject it rather than using the facade in new code.

Gotchas and Tips

  • {!! !!} is mandatory, and that's the primary risk. render() returns HTML, so you must not escape it. The flip side: if you ever feed user-controlled strings into Meta::description() or a tag's content, sanitise them before passing them in (strip_tags, Str::limit, e()) — the package may or may not escape attribute values on its own, and you shouldn't bet on it.

  • Singleton state lingers. The service is registered as a singleton in the container. Under FPM that's per-request and fine. Under Octane, Swoole, RoadRunner, or any long-running worker, that singleton persists across requests and you will leak the previous page's og:image into the next one. If you're on Octane, call a reset()/flush() (or rebind) at the start of each request, or don't use the package there.

  • Tests share the same trap. Multiple test methods in one process inherit the same meta bag. Reset in setUp() or assert on a fresh application instance per test.

  • No auto-discovery. On Laravel 5.5+ the package won't register itself. If Class 'Meta' not found appears, it's almost always the missing config/app.php alias or a stale php artisan config:clear. Run config:clear after editing providers/aliases.

  • It is abandoned (last release 2015). Expect friction on PHP 8 / Laravel 9+ around typed signatures or container contracts. Before committing, run the suite against your target Laravel version in a throwaway branch, or just budget for forking. For most greenfield work the honest recommendation is to skip it: a 20-line Blade component + a SeoService you own buys you the same thing with no dependency risk. Alternatives worth evaluating: butschster/meta-tags, artesaos/seotools, romanzipp/laravel-seo, or plain @yield/@stack.

  • Debugging ordering issues. When tags look wrong, ask: when did my call run? Middleware → controller → view composer → Blade @section. The last write wins, and "last" here means execution order, not conceptual priority. dd(app('meta')) inside the layout to see the actual accumulated state.

  • Config caching. If you publish a config file, remember php artisan config:cache — otherwise you'll edit values, see no change, and waste twenty minutes. config:clear after any provider or config change.

  • Extension points are limited, so use the seams you have. The realistic options are (a) the container: $this->app->bind('meta', MyMeta::class) in a service provider, and (b) a facade macro if the underlying class extends Macroable. Neither is guaranteed; verify. Practically, the wrapper class described above is the extension point you actually control.

  • Facade alias collisions. If another package already claims Meta in config/app.php, your alias assignment silently wins or loses depending on order. Rename the alias (SeoMeta) if you hit Call to undefined method.

  • Check the actual method signatures before writing 40 controllers' worth of calls. Different releases of this style of package expose title(), description(), keywords(), tag(), og(), canonical() inconsistently, and some support chaining while others return void. Five minutes in vendor/ryannielson/meta/src saves a painful refactor.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo