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

Laravel Seo Manager Laravel Package

michael-rubel/laravel-seo-manager

Laravel SEO Manager gives your app a clean, configurable way to handle SEO metadata—page titles, meta descriptions, canonical URLs, Open Graph and Twitter tags, robots directives, and sitemaps—so every page is search-ready without cluttering your controllers or Blade views.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is archived (last release May 2022, 20 stars), so treat it as a small, readable dependency rather than a long-term platform choice. Budget ~15 minutes to read the source before wiring it in.

composer require michael-rubel/laravel-seo-manager
php artisan vendor:publish --tag=seo-manager-config

The service provider is auto-discovered. If your app has discovery disabled, register MichaelRubel\SeoManager\SeoManagerServiceProvider manually in config/app.php.

Where to look first, in order:

  1. config/seo-manager.php — this is the whole feature. It maps URL patterns to a keyed array of tags (title, description, keywords, etc.) and defines fallback defaults.
  2. src/SeoManagerServiceProvider.php — confirms the container binding, facade alias, helper function, and whether a middleware is registered for URL resolution.
  3. src/SeoManager.php (or similarly named class) — the URL matcher and the getter/setter surface you will call from Blade and controllers.
  4. The facade/helper — the public accessor (seo(...) or SeoManager::...) is what you will use 95% of the time.

First use case — give the homepage real meta tags:

// config/seo-manager.php
'urls' => [
    '/' => [
        'title'       => 'Acme — Industrial Fasteners',
        'description' => 'Same-day shipping on metric and imperial fasteners.',
        'canonical'   => 'https://acme.test/',
    ],
    'about' => [
        'title'       => 'About Acme',
        'description' => 'Family-owned since 1974.',
    ],
],

Then in your layout head:

<title>{{ seo('title') }}</title>
<meta name="description" content="{{ seo('description') }}">
<link rel="canonical" href="{{ seo('canonical') }}">

Confirm the exact accessor name in the service provider before copying — the package is small enough that reading src/ is faster than guessing.

Implementation Patterns

  • One partial, one source of truth. Put every meta tag in resources/views/partials/seo.blade.php and @include it in the single layout. This makes it trivial to add Open Graph/Twitter tags the package does not cover.
  • Defaults plus per-URL overrides. Define a defaults block (site name, default description, fallback image) and treat anything in urls as an override. Merge logic in your own view composer if the package does not do it, so a missing key never renders an empty attribute.
  • Match specificity top-down. If wildcards are supported, order matters: list blog/how-to-ship before blog/*, and put the catch-all last. If ordering is config-array order, keep the file grouped by section (static pages, blog, product).
  • Dynamic pages need runtime setters, not config. For posts/{slug} or products/{sku} the right title lives in the database. Use the manager's runtime set(...)/setTitle(...) API in a controller, middleware, or View::composer('*', ...) after route model binding resolves the model. Do not try to enumerate thousands of URLs in config.
  • Locale prefixes. If you serve /en/... and /de/..., either add both variants to urls or normalize the path in a lightweight middleware before resolution. A single regex that strips ^/(en|de) is usually enough.
  • View composers for derived tags. Image tags, og:type, and product JSON-LD are easier to compute from the bound model than to store in config. Compose them alongside the manager's output in partials/seo.blade.php.
  • Feature-test the output. Add a Pest/PHPUnit test that hits /, /about, and one dynamic route and asserts assertSee('<title>', false) with the expected string. The package ships no test helpers, so this is your regression net.
  • Cache the config. php artisan config:cache in production; the config file is the entire data source, so this matters more than usual for a meta-tag package.

Gotchas and Tips

  • Archived and pinned. Check composer.json for illuminate/* and PHP constraints before installing on Laravel 10/11. On a newer framework you will likely need --ignore-platform-req or a fork. There are no security or compatibility patches coming.
  • Small community. 20 stars and zero dependents means almost no StackOverflow or blog coverage. Read src/ — it is a few hundred lines — and prefer extending/overriding over searching.
  • URL normalization is the main failure mode. Trailing slashes, www vs non-www, subdomains, query strings (?page=2), and locale segments all cause silent misses that fall back to defaults. Log the resolved key for a day during rollout.
  • config:cache vs runtime mutation. Never call config(['seo-manager.urls...' => ...]) at runtime in production — the config is already cached and the manager may have resolved earlier. Use the manager's setters or a view composer.
  • Escaping. Use {{ }} for values (title, description, canonical). Only use {!! !!} if the manager returns pre-rendered <meta> strings; otherwise you are opening an XSS hole from DB-driven titles.
  • Missing keys render empty attributes. Guard in the partial: @if(seo('description'))<meta name="description" content="{{ seo('description') }}">@endif, or normalize defaults in a composer.
  • Scope is narrow. This is meta management only — canonical, robots, OG/Twitter, JSON-LD, sitemap.xml, and robots.txt are your responsibility. Plan to layer spatie/laravel-sitemap or a hand-rolled route for those.
  • Extension points. Because the package is tiny, binding a subclass or $this->app->singleton(SeoManager::class, MySeoManager::class) is cheap, and vendoring the ~few files into app/Support/Seo is a legitimate exit strategy if the archived status becomes a problem.
  • Fallback plan. If the package blocks a framework upgrade, a 30-line view composer keyed off request()->path() replicates the core behavior. Evaluate that trade-off early rather than after you have hundreds of URL entries in config.
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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core
nodisrupt/laravel-agent
sierratecnologia/media-manager