arcanedev/laravel-seo
Laravel SEO package for managing page metadata such as titles, meta tags, and Open Graph data. Provides a fluent API to define SEO fields in your app and render them in Blade views, keeping optimization logic centralized.
Before anything else, run a compatibility gate. This package targets Laravel 5 and its last tagged release is from September 2017, so its illuminate/support constraint will almost certainly block installation on Laravel 6+. On a modern app, composer require arcanedev/laravel-seo will either fail resolution or drag in an ancient framework tree — try it in a throwaway branch and read the conflict output before designing around it. If you are genuinely on Laravel 5.4/5.5, the flow below applies.
composer require arcanedev/laravel-seo (confirm the exact Packagist name in the repo's composer.json; ARCANEDEV has shipped these under both arcanedev/laravel-* and shorter names).Arcanedev\Seo\SeoServiceProvider in config/app.php and alias the facade.php artisan vendor:publish and pick the package's provider/tags interactively — don't guess tag names, the interactive menu lists them.<title> tags, so tune them before touching controllers.Your first useful use case is the 10-minute win: a controller sets a page title and description, and your single layouts/app.blade.php renders them once near </head>.
// Controller
Seo::setTitle('Pricing — Acme');
Seo::setDescription('Simple plans for teams of every size.');
Seo::setCanonical(route('pricing'));
// layouts/app.blade.php, inside <head>
@include('seo::meta') {{-- confirm the view namespace in the README --}}
Look at three files in this order: the published config, the published Blade view that renders the tags (this is what you'll actually customize), and the facade class docblock, which is the only reliable API reference given how thin the README is.
Controller-level setters plus a default layer. The cleanest pattern is: a base controller (or a View::composer('layouts.*') / middleware) sets site-wide defaults from config, then each action overrides title/description/canonical. This avoids repeating the site name in forty controllers and gives you one place to append "— Acme".
Model-driven pages. For blog posts, products, or any route-model-bound page, the idiomatic shape is a small helper — a trait on the model, an accessor, or a dedicated SeoPresenter — that maps model fields onto the facade. Keep it outside the model itself if you can; models get noisy fast.
// app/Http/Controllers/PostController.php
public function show(Post $post)
{
Seo::setTitle($post->seo_title ?: $post->title)
->setDescription($post->excerpt)
->setCanonical($post->url)
->setImage($post->cover_url); // for OG/Twitter if supported
return view('posts.show', compact('post'));
}
Ordering matters. Set tags in the controller (or a view composer that runs before render). Setting them from inside the Blade view after the @include('seo::meta') line does nothing — the partial has already emitted.
Wrap it, don't sprinkle it. Because the package is unmaintained, treat the facade as a third-party boundary: put Seo:: calls behind your own App\Support\Seo wrapper or a SeoManager binding. When you eventually migrate to artesaos/seotools, ralphjsmit/laravel-seo, or hand-rolled Blade components, you change one class instead of grepping 60 controllers.
Testing. Assert on rendered HTML, not on facade state: $response->assertSee('<title>Pricing — Acme</title>', false) and assertSee('name="description"', false). If you later swap implementations, these tests survive.
Sitemaps. Some ARCANEDEV SEO builds bundle a sitemap generator. Verify it exists in this version before promising it to anyone; in practice spatie/laravel-sitemap is a better-supported choice regardless.
artesaos/seotools (closest feature set, actively maintained) or simply a Blade component that renders meta tags, which is ~40 lines and removes the dependency entirely.illuminate/support version conflicts, and --ignore-platform-reqs-style workarounds are a trap: the code may call framework APIs that no longer exist.< will corrupt your meta tags if the package doesn't escape them. Test with a description like He said "hello" & left. Prefer e() at the point you set the value rather than trusting the renderer.<title> and description tags. Browsers tolerate it; crawlers pick unpredictably.php artisan config:clear after editing the published config; stale cached config is the classic reason default titles stop appearing.php artisan tinker then app('seo') (or the facade root) to inspect the current state and confirm the binding name. composer show arcanedev/laravel-seo to see what actually resolved.How can I help you explore Laravel packages today?