jegex/laravel-seo

This is my package laravel-seo

Maintainers

Package info

github.com/jegex/laravel-seo

pkg:composer/jegex/laravel-seo

Fund package maintenance!

jegex

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 1

v0.1.0-alpha 2026-04-29 07:53 UTC

This package is auto-updated.

Last update: 2026-04-30 15:47:10 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

A comprehensive SEO package for Laravel inspired by Rank Math SEO (WordPress). Features include meta tags, Open Graph, Twitter Cards, template variables, sitemap generation, redirect management, and 404 tracking.

Note: This is a core SEO package - no admin dashboard included. For a Filament admin dashboard, check out the separate filament-seo package.

Support us

We invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.

Installation

You can install the package via composer:

composer require jegex/laravel-seo

You can publish and run the migrations with:

php artisan vendor:publish --tag="laravel-seo-migrations"
php artisan migrate

You can publish the config file with:

php artisan vendor:publish --tag="laravel-seo-config"

Optionally, you can publish the views using

php artisan vendor:publish --tag="laravel-seo-views"

Quick Start

1. Add Trait to Your Model

use Jegex\LaravelSeo\Traits\HasSeo;

class Post extends Model
{
    use HasSeo;
}

2. Use in Your Blade Layout

<!DOCTYPE html>
<html>
<head>
    {{ seo()->render() }}
</head>
<body>
    @yield('content')
</body>
</html>

3. Configure Templates (config/seo.php)

return [
    'site_name' => 'My Blog',
    'site_description' => 'A blog about Laravel',
    'separator' => ' - ',
    
    'templates' => [
        'post' => [
            'title' => '%title% %sep% %sitename%',
            'description' => '%excerpt%',
        ],
    ],
    
    'webmaster_verification' => [
        'google' => 'your-google-verification-code',
        'bing' => 'your-bing-verification-code',
    ],
];

Features

Template Variables (Rank Math Style)

Use these variables in your templates:

Variable Description
%title% Model title
%sitename% Website name
%sitedesc% Website description
%sep% Separator (default: -)
%currentdate% Current date
%currentyear% Current year
%author% Author name
%excerpt% Content excerpt (160 chars)
%categories% Categories list
%tags% Tags list

Helper Functions

// Set SEO data
seo('title', 'My Page Title');
seo('description', 'Page description');
seo('og:image', '/path/to/image.jpg');

// Or use methods
seo()->setTitle('My Title')->setDescription('My Description');

// Parse templates manually
parse_seo_template('%title% %sep% %sitename%', ['title' => 'Hello']);

Blade Components

<x-seo::meta-tags />
<x-seo::json-ld :schema="['@type' => 'Article', 'headline' => $title]" />
<x-seo::breadcrumbs :items="[['name' => 'Home', 'url' => '/'], ['name' => $category]]" />

Webmaster Verification

Add verification codes in config/seo.php:

'webmaster_verification' => [
    'google' => 'abc123...',
    'bing' => 'xyz789...',
    'pinterest' => 'pinterest-code',
    'yandex' => 'yandex-code',
],

Redirect Management

use Jegex\LaravelSeo\Models\Redirect;

// Create a 301 redirect
Redirect::create([
    'from_url' => '/old-page',
    'to_url' => '/new-page',
    'type' => 301,
]);

// Create a regex redirect
Redirect::create([
    'from_url' => '#/blog/(.*)#',
    'to_url' => '/articles/$1',
    'type' => 301,
    'is_regex' => true,
]);

// 410 Gone
Redirect::create([
    'from_url' => '/deleted-page',
    'type' => 410,
]);

Middleware

Add to your app/Http/Kernel.php:

protected $middleware = [
    // ...
    \Jegex\LaravelSeo\Http\Middleware\RedirectMiddleware::class,
    \Jegex\LaravelSeo\Http\Middleware\NotFoundTrackerMiddleware::class,
];

SEO Analysis

CLI Command

# Analyze all SEO entries
php artisan seo:analyze

# Analyze specific model
php artisan seo:analyze --model="App\Models\Post"

# Calculate and save scores
php artisan seo:analyze --calculate-scores

Model Analysis

$entry = $post->seoEntry;

// Get full analysis
$analysis = $entry->analyze();
// [
//     'score' => 85,
//     'alerts' => ['Title is slightly long...'],
//     'checks' => [...],
//     'details' => [...]
// ]

// Get score only
$entry->calculateScore();
echo $entry->seo_score; // 85

// Get score label
echo $entry->getScoreLabel(); // 'Good', 'Needs Improvement', or 'Poor'

Programmatic Analysis

use Jegex\LaravelSeo\Services\AnalyzerService;

$analyzer = app(AnalyzerService::class);
$analysis = $analyzer->analyze($content, [
    'title' => 'My Title',
    'description' => 'My Description',
    'focus_keyword' => 'laravel seo',
]);

echo $analysis['score']; // 0-100
echo $analysis['alerts'][0]; // First alert message

Breadcrumbs

Via Service

// Manual breadcrumbs
seo()->breadcrumbs()
    ->add('Home', '/')
    ->add('Blog', '/blog')
    ->add($post->title, $post->url());

// Auto from route
seo()->breadcrumbs()->fromRoute();

// Render
{{ seo()->breadcrumbs()->renderHtml() }}
{{ seo()->breadcrumbs()->renderSchema() }}

Via Blade Component

<x-seo::breadcrumbs :items="[
    ['name' => 'Home', 'url' => '/'],
    ['name' => 'Blog', 'url' => '/blog'],
    ['name' => $post->title]
]" />

JSON-LD Structured Data

Available Schema Types

  • article - Article/BlogPosting
  • website - WebSite with SearchAction
  • organization - Organization with contact info
  • breadcrumbs - BreadcrumbList

Creating Schema

// Via SEO service (auto-rendered)
seo()->addSchema('article')
    ->headline('My Article')
    ->author('John Doe')
    ->datePublished(now()->toIso8601String())
    ->image('https://example.com/image.jpg');

// Via Schema service
seo()->schema()
    ->website()
    ->name('My Site')
    ->url('/')
    ->potentialActionSearch('/search?q={search_term_string}');

// Organization schema
seo()->schema()
    ->organization()
    ->name('My Company')
    ->url('https://example.com')
    ->contactPoint('+1-234-567-8900', 'customer service');

Rendering

{{-- In your layout, schemas auto-render with meta tags --}}
{{ seo()->render() }}

{{-- Or render schemas only --}}
{{ seo()->schema()->render() }}

{{-- Manual schema --}}
<x-seo::json-ld :schema="['@type' => 'Article', 'headline' => $title]" />

Complete Example

Controller

class PostController extends Controller
{
    public function show(Post $post)
    {
        // Automatically uses HasSeo trait for defaults
        seo()->for($post);
        
        // Or manually override
        seo()->setTitle($post->title . ' | Custom Suffix');
        
        return view('posts.show', compact('post'));
    }
}

View (posts/show.blade.php)

@extends('layouts.app')

@section('content')
    <article>
        <h1>{{ $post->title }}</h1>
        <div>{{ $post->content }}</div>
    </article>
@endsection

Layout (layouts/app.blade.php)

<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    {{-- Render all SEO meta tags --}}
    {{ seo()->render() }}
    
    @stack('styles')
</head>
<body>
    @yield('content')
    
    @stack('scripts')
</body>
</html>

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.