magutti/seo-tools

SEO Tools for Laravel

Maintainers

Package info

github.com/marcoax/maguttiSeoTools

pkg:composer/magutti/seo-tools

Fund package maintenance!

standard

feross

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

V1.0 2026-03-21 21:09 UTC

This package is auto-updated.

Last update: 2026-03-21 21:10:02 UTC


README

A comprehensive SEO package for Laravel 12/13 that manages meta tags, Open Graph, Twitter Cards, and JSON-LD structured data from a single unified interface.

Features

  • Meta Tags — title, description, keywords, canonical, robots, hreflang, pagination, webmaster verification
  • Open Graph — full OG support including articles, videos, music, books, products, and profiles
  • Twitter Cards — summary, large image, app, and player card types
  • JSON-LD — Schema.org structured data, single or multiple blocks per page
  • Inertia.js integration — reactive meta tags for Vue/React frontends
  • Synchronized updates — setting a title once propagates across all formats

Requirements

  • PHP ^8.2
  • Laravel 12 or 13

Installation

composer require magutti/seo-tools

The service provider and facades are auto-discovered by Laravel.

Publish the configuration file:

php artisan vendor:publish --provider="Magutti\SeoTools\Providers\SeoToolsServiceProvider"

Configuration

config/seotools.php controls defaults for all managers:

return [
    'inertia' => false,  // set to true to enable Inertia.js support
    'meta' => [
        'defaults' => [
            'title'       => false,
            'titleBefore' => false,
            'description' => false,
            'separator'   => ' - ',
            'keywords'    => [],
            'canonical'   => false,
            'robots'      => false,
        ],
        'webmaster_tags' => [
            // 'google'    => 'your-code',
            // 'bing'      => 'your-code',
            // 'alexa'     => 'your-code',
            // 'pinterest' => 'your-code',
            // 'yandex'    => 'your-code',
            // 'norton'    => 'your-code',
        ],
    ],
    'opengraph' => [
        'defaults' => [
            'title'       => false,
            'description' => false,
            'url'         => false,
            'type'        => false,
            'site_name'   => false,
            'images'      => [],
        ],
    ],
    'twitter'  => ['defaults' => []],
    'json-ld'  => [
        'defaults' => [
            'title'       => false,
            'description' => false,
            'url'         => false,
            'type'        => 'WebPage',
            'images'      => [],
        ],
    ],
];

Basic Usage

In a controller

use Magutti\SeoTools\Facades\SEOTools as SEO;

class ArticleController extends Controller
{
    public function show(Article $article)
    {
        SEO::setTitle($article->title)
           ->setDescription($article->excerpt)
           ->setCanonical(route('articles.show', $article))
           ->addImages([$article->cover_url]);

        return view('articles.show', compact('article'));
    }
}

In a Blade view

<head>
    {!! SEO::generate() !!}
</head>

Pass true to minify the output:

{!! SEO::generate(true) !!}

Using the trait

use Magutti\SeoTools\Traits\SEOTools;

class PostController extends Controller
{
    use SEOTools;

    public function show(Post $post)
    {
        $this->seo()->setTitle($post->title);
    }
}

Facades

Facade Alias Class
SEOTools SEO Magutti\SeoTools\Facades\SEOTools
SEOMeta SEOMeta Magutti\SeoTools\Facades\SEOMeta
OpenGraph OpenGraph Magutti\SeoTools\Facades\OpenGraph
TwitterCard Twitter Magutti\SeoTools\Facades\TwitterCard
JsonLd JsonLd Magutti\SeoTools\Facades\JsonLd
JsonLdMulti Magutti\SeoTools\Facades\JsonLdMulti

SEOMeta

use Magutti\SeoTools\Facades\SEOMeta;

SEOMeta::setTitle('Page Title')
       ->setDescription('Page description')
       ->setKeywords(['laravel', 'seo'])
       ->setCanonical('https://example.com/page')
       ->setRobots('index,follow')
       ->addAlternateLanguage('it', 'https://example.com/it/page')
       ->setPrev('https://example.com/page/1')
       ->setNext('https://example.com/page/3');

Open Graph

use Magutti\SeoTools\Facades\OpenGraph;

OpenGraph::setTitle('Page Title')
         ->setDescription('Page description')
         ->setUrl('https://example.com/page')
         ->setType('article')
         ->setSiteName('My Site')
         ->addImage('https://example.com/image.jpg');

// Article-specific properties
OpenGraph::setArticle([
    'published_time' => '2024-01-01',
    'author'         => 'Marco Asperti',
    'section'        => 'Technology',
    'tags'           => ['laravel', 'seo'],
]);

Supported OG types with dedicated setters: article, profile, book, music.song, music.album, video.movie, video.episode, video.tv_show, product.

Twitter Cards

use Magutti\SeoTools\Facades\TwitterCard;

TwitterCard::setType('summary_large_image')
           ->setSite('@mysitehandle')
           ->setTitle('Page Title')
           ->setDescription('Page description')
           ->setImage('https://example.com/image.jpg');

JSON-LD

Single block

use Magutti\SeoTools\Facades\JsonLd;

JsonLd::setType('Article')
      ->setTitle('Article Title')
      ->setDescription('Article description')
      ->setUrl('https://example.com/article')
      ->addImage('https://example.com/image.jpg')
      ->addValue('author', ['@type' => 'Person', 'name' => 'Marco Asperti'])
      ->addValue('datePublished', '2024-01-01');

Multiple blocks

use Magutti\SeoTools\Facades\JsonLdMulti;

// First block (index 0 is created automatically)
JsonLdMulti::setType('Article')->setTitle('Article Title');

// Add a second block
JsonLdMulti::newJsonLd()
           ->setType('BreadcrumbList')
           ->addValue('itemListElement', [/* breadcrumb items */]);

// Switch between blocks
JsonLdMulti::select(0)->setDescription('Updated description');

SEOFriendly Interface

Implement Magutti\SeoTools\Contracts\SEOFriendly on your models to allow controllers to load SEO data in a standardized way:

use Magutti\SeoTools\Contracts\SEOFriendly;
use Magutti\SeoTools\Contracts\MetaTags;
use Magutti\SeoTools\Contracts\OpenGraph;
use Magutti\SeoTools\Contracts\TwitterCards;
use Magutti\SeoTools\Contracts\JsonLd;

class Article extends Model implements SEOFriendly
{
    public function loadSEO(MetaTags $meta, OpenGraph $og, TwitterCards $twitter, JsonLd $jsonLd): void
    {
        $meta->setTitle($this->title)->setDescription($this->excerpt);
        $og->setTitle($this->title)->addImage($this->cover_url);
        $twitter->setTitle($this->title)->setImage($this->cover_url);
        $jsonLd->setType('Article')->setTitle($this->title);
    }
}

Then in your controller:

use Magutti\SeoTools\Traits\SEOTools;

class ArticleController extends Controller
{
    use SEOTools;

    public function show(Article $article)
    {
        $this->loadSEO($article);
        return view('articles.show', compact('article'));
    }
}

Inertia.js Support

Set 'inertia' => true in config/seotools.php (or SEO_TOOLS_INERTIA=true in .env). Generated tags will include the inertia attribute, making them reactive in Vue/React components via @inertiajs/vue3 or @inertiajs/react.

License

MIT — see LICENSE.md.