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

Seo Helper Laravel Package

arcanedev/seo-helper

Laravel package for managing SEO metadata with a clean API. Set page titles, meta descriptions, keywords, canonical URLs, robots directives, Open Graph, and Twitter Card tags, with Blade helpers for easy integration.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer; Laravel's package discovery registers the service provider and the SEO facade automatically:

composer require arcanedev/seo-helper

Publish and review the config first — it is the source of truth for defaults, Open Graph/Twitter data, analytics, and webmaster verification tags:

php artisan vendor:publish --provider="Arcanedev\SeoHelper\SeoHelperServiceProvider"

If you want model-backed metadata (per-post titles/descriptions), also publish and run the migration that creates the polymorphic seo_meta table:

php artisan vendor:publish --tag=seo-helper:migrations
php artisan migrate

First use case: in your base layout's <head>, render everything in one call:

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

Then set values per page from the controller (or a view composer) before the layout renders:

public function show(Post $post)
{
    SEO::setTitle($post->title);
    SEO::setDescription(Str::limit(strip_tags($post->excerpt), 155));
    SEO::setCanonical($post->url);
    SEO::setImage($post->featured_image_url); // absolute URL
    SEO::setKeywords($post->tags->pluck('name')->all());

    return view('posts.show', compact('post'));
}

Implementation Patterns

Centralize defaults, override per page. Put site-wide defaults in config/seo-helper.php (site title suffix, default description, robots, Open Graph image) and let controllers set only what's page-specific. This keeps {!! SEO::render() !!} in one layout file and avoids duplicating tags in every view.

Use a middleware or view composer for the common case. A small middleware that sets title/description from the route, or a View::composer('*', ...) that applies the site name, prevents every controller from repeating boilerplate:

View::composer('*', function ($view) {
    SEO::setTitle(config('app.name'), ' | ');
});

Model-backed SEO via the SeoMeta trait. For CMS-style apps, add the trait to models that need editable metadata and manage it in an admin form with updateOrCreate:

use Arcanedev\SeoHelper\Traits\SeoMeta;

class Post extends Model
{
    use SeoMeta;
}

// Controller
SEO::setModel($post); // pulls title/description/keywords from the relation

// Admin save
$post->seoMeta()->updateOrCreate([], [
    'title'       => $request->seo_title,
    'description' => $request->seo_description,
    'keywords'    => $request->seo_keywords,
]);

Open Graph / Twitter integration. Configure site-level OG type, Twitter handle, and fallback image once in config, then override per page (setImage, setTitle, setUrl) so shared links preview correctly. Always use absolute URLs for images and canonicals.

Webmaster and analytics tags. Rather than pasting verification/analytics snippets into Blade, register them through the helper (or config) so they render consistently and only when configured:

SEO::addWebmaster('google', config('services.google.verification'));
SEO::addAnalytics('google', config('services.google.analytics_id'));

Keep the render call last. Anything set after SEO::render() in the layout is silently ignored, so treat setting SEO metadata as a controller/middleware responsibility and rendering as a pure output concern.

Gotchas and Tips

  • Escape the output correctly. Use {!! SEO::render() !!} — using {{ }} will HTML-escape the tags and dump them as text.
  • Order matters. The helper accumulates state on a singleton; anything set after the layout renders won't appear. Set metadata in controllers, middleware, or a view composer, never in a partial included after <head>.
  • Singleton state leaks into tests. Because the helper is a container singleton, titles/descriptions set in one test can bleed into the next. Reset it in setUp()/tearDown() (inspect the SeoHelper class for the reset/clear method) or refresh the application between tests.
  • Config caching traps. After editing config/seo-helper.php, run php artisan config:clear (and re-cache in production). Stale cached config is the usual cause of "my default description didn't change."
  • Check length limits in config. Title/description trimming behavior is configurable; verify the max-length keys rather than assuming the package truncates at 60/155 characters. Strip HTML from model descriptions before passing them in.
  • setKeywords accepts arrays or strings — pass an array for tagged content, a comma-separated string for static pages; both render as a single keywords meta tag.
  • Canonical and OG images must be absolute. Relative paths will render but break in social previews and search indexing. Generate them with url()/asset().
  • Version compatibility. The 2024 release targets modern Laravel, but confirm the illuminate/* constraints in composer.json against your Laravel version before upgrading majors; older Laravel installs may need a pinned older release and manual provider/facade registration (pre-auto-discovery).
  • Extension points. The underlying Meta/Open Graph/Twitter objects are resolvable from the container if you need to add custom tags (SEO::addMeta('name', 'content')) or build a Blade component wrapping common patterns. For anything the package doesn't cover (JSON-LD structured data, sitemaps), generate it separately and include it alongside SEO::render() — don't try to force it through the meta builder.
  • Localization. The helper stores a single set of metadata; for multilingual sites, set values per request locale in middleware rather than expecting per-language variants.
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