PHPackages                             jasanya/seo-library-laravel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. jasanya/seo-library-laravel

ActiveLibrary

jasanya/seo-library-laravel
===========================

Production-grade SEO support package for Laravel 13 Blade applications.

1.0.0(1mo ago)02↑2900%MITPHPPHP ^8.3

Since Mar 28Pushed 1mo agoCompare

[ Source](https://github.com/jasanya-tech/jasanyatech-seo-library-laravel)[ Packagist](https://packagist.org/packages/jasanya/seo-library-laravel)[ RSS](/packages/jasanya-seo-library-laravel/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (7)Versions (3)Used By (0)

Perfect SEO
===========

[](#perfect-seo)

Reusable Laravel 13 SEO support package for Blade applications with a Blade-first API centered around:

```

```

The package is designed for real production usage: safe defaults, per-page overrides, JSON-LD schema support, automatic `sitemap.xml`, automatic `robots.txt`, and developer-friendly preset builders.

Architecture
------------

[](#architecture)

`Perfect SEO` is split into small responsibilities:

- `SeoManager` stores request-scoped SEO state and exposes the public API.
- `MetaRenderer` turns current SEO state into deduplicated Blade-safe tags.
- `Schema/*` contains JSON-LD schema builders with validation and omission of invalid fields.
- `Sitemap/*` handles source registration, chunking, and XML generation.
- `Robots/RobotsRenderer` generates plain text `robots.txt`.
- `Components/Meta` is the Blade entry point for ``.

Folder Structure
----------------

[](#folder-structure)

```
packages/seo-library-laravel/
├── composer.json
├── config/seo.php
├── resources/views/
│   ├── components/meta.blade.php
│   └── sitemap/
├── routes/seo.php
├── src/
│   ├── Components/
│   ├── Contracts/
│   ├── DTOs/
│   ├── Facades/
│   ├── Http/Controllers/
│   ├── Renderers/
│   ├── Robots/
│   ├── Schema/
│   ├── Sitemap/
│   ├── Support/
│   ├── SeoManager.php
│   └── SeoServiceProvider.php
└── tests/

```

Public API
----------

[](#public-api)

```
use JasanyaTech\SEO\Facades\SEO;

SEO::title('Home');
SEO::description('Welcome to our website');
SEO::canonical(url()->current());
SEO::robots('index,follow');
SEO::image(asset('images/og/default.jpg'), 'Default social image');
SEO::website();
SEO::organization();
SEO::breadcrumbs([
    ['name' => 'Home', 'url' => route('home')],
    ['name' => 'Blog', 'url' => route('blog.index')],
]);

SEO::article([
    'headline' => $post->title,
    'description' => $post->excerpt,
    'image' => $post->cover_url,
    'datePublished' => $post->published_at,
    'dateModified' => $post->updated_at,
    'author' => $post->author_name,
    'mainEntityOfPage' => route('blog.show', $post->slug),
]);

SEO::forBlogPost($post);
SEO::forProduct($product);
SEO::forService($service);

SEO::sitemap()->register('posts', fn () => Post::query()
    ->published()
    ->get(['slug', 'updated_at'])
    ->map(fn (Post $post) => [
        'url' => route('blog.show', $post->slug),
        'lastmod' => $post->updated_at,
    ]));
```

Installation
------------

[](#installation)

If you extract this into its own repository:

```
composer require jasanya/seo-library-laravel
```

For a local path package in another Laravel app:

```
{
    "repositories": [
        {
            "type": "path",
            "url": "packages/seo-library-laravel"
        }
    ]
}
```

Then publish the config:

```
php artisan vendor:publish --tag=seo-config
```

Configuration
-------------

[](#configuration)

Default config lives in `config/seo.php` and includes:

- site defaults
- canonical query ignore rules
- default robots
- default Open Graph image
- locale and alternate locales
- organization and website schema data
- sitemap settings
- robots settings
- environment-aware safety rules

Example:

```
return [
    'site' => [
        'name' => env('SEO_SITE_NAME', config('app.name')),
        'url' => env('APP_URL'),
        'title_separator' => '|',
        'default_title' => null,
        'default_description' => null,
        'default_locale' => 'id_ID',
        'alternate_locales' => [],
    ],
];
```

Blade Usage
-----------

[](#blade-usage)

Place the component inside ``:

```

```

You can also pass a DTO directly:

```

```

Controller Usage
----------------

[](#controller-usage)

```
use App\Models\Post;
use JasanyaTech\SEO\Facades\SEO;

public function show(Post $post)
{
    SEO::forBlogPost($post, [
        'breadcrumbs' => [
            ['name' => 'Home', 'url' => route('home')],
            ['name' => 'Blog', 'url' => route('blog.index')],
            ['name' => $post->title, 'url' => route('blog.show', $post->slug)],
        ],
    ]);

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

Presets
-------

[](#presets)

### Homepage

[](#homepage)

```
SEO::title('Home')
    ->description('Welcome to our website')
    ->canonical(route('home'))
    ->website()
    ->organization();
```

### Blog Index

[](#blog-index)

```
SEO::forBlogListing(
    title: 'Blog',
    description: 'Latest articles and updates',
    breadcrumbs: [
        ['name' => 'Home', 'url' => route('home')],
        ['name' => 'Blog', 'url' => route('blog.index')],
    ],
    canonical: route('blog.index'),
);
```

### Blog Detail with Article Schema

[](#blog-detail-with-article-schema)

```
SEO::forBlogPost($post, [
    'breadcrumbs' => [
        ['name' => 'Home', 'url' => route('home')],
        ['name' => 'Blog', 'url' => route('blog.index')],
        ['name' => $post->title, 'url' => route('blog.show', $post->slug)],
    ],
]);
```

### Product Index

[](#product-index)

```
SEO::forProductListing(
    title: 'Products',
    description: 'Browse our product catalog',
    canonical: route('products.index'),
);
```

### Product Detail

[](#product-detail)

```
SEO::forProduct($product, [
    'breadcrumbs' => [
        ['name' => 'Home', 'url' => route('home')],
        ['name' => 'Products', 'url' => route('products.index')],
        ['name' => $product->name, 'url' => route('products.show', $product->slug)],
    ],
]);
```

### Service Index

[](#service-index)

```
SEO::forServiceListing(
    title: 'Services',
    description: 'Professional service catalog',
    canonical: route('services.index'),
);
```

### Service Detail

[](#service-detail)

```
SEO::forService($service, [
    'breadcrumbs' => [
        ['name' => 'Home', 'url' => route('home')],
        ['name' => 'Services', 'url' => route('services.index')],
        ['name' => $service->name, 'url' => route('services.show', $service->slug)],
    ],
]);
```

Breadcrumb Integration
----------------------

[](#breadcrumb-integration)

```
SEO::breadcrumbs([
    ['name' => 'Home', 'url' => route('home')],
    ['name' => 'Blog', 'url' => route('blog.index')],
    ['name' => $post->title, 'url' => route('blog.show', $post->slug)],
]);
```

This automatically prepares `BreadcrumbList` JSON-LD and stores the cleaned breadcrumb data for the current request.

Schema Usage
------------

[](#schema-usage)

Supported out of the box:

- `WebSite`
- `Organization`
- `BreadcrumbList`
- `Article`
- `Product`
- `Service`

Only valid schema fields are emitted. Missing or misleading fields are omitted instead of guessed.

Sitemap Registration
--------------------

[](#sitemap-registration)

Built-in routes:

- `/sitemap.xml`
- `/sitemaps/{source}.xml`
- `/sitemaps/{source}-{page}.xml`

Register sitemap sources anywhere during bootstrapping, for example in `AppServiceProvider`:

```
use App\Models\Post;
use JasanyaTech\SEO\Facades\SEO;

public function boot(): void
{
    SEO::sitemap()->register('posts', fn () => Post::query()
        ->whereNotNull('published_at')
        ->get()
        ->map(fn (Post $post) => [
            'url' => route('blog.show', $post->slug),
            'lastmod' => $post->updated_at,
            'changefreq' => 'weekly',
            'priority' => 0.7,
        ]));
}
```

The package:

- normalizes URLs
- skips non-indexable entries
- chunks large sources
- adds the homepage automatically if configured

robots.txt
----------

[](#robotstxt)

Built-in route:

- `/robots.txt`

Default output example:

```
User-agent: *
Allow: /

Sitemap: https://example.com/sitemap.xml

```

On non-production environments, the package can disallow all crawling automatically if `robots.disallow_non_production` is enabled.

Troubleshooting
---------------

[](#troubleshooting)

- If your Blade output does not change, clear cached views and config.
- If Vite assets are missing in the UI, run `npm run dev` or `npm run build`.
- If your sitemap is empty, verify that your registered source returns absolute public URLs.
- If JSON-LD is missing, check that the required source fields actually exist.

Testing
-------

[](#testing)

Package tests cover:

- title rendering
- description rendering
- canonical normalization
- robots meta rendering
- Open Graph and Twitter tags
- JSON-LD schema output
- blog/product/service presets
- sitemap index and child sitemap responses
- robots.txt output

Run the Laravel test suite:

```
php artisan test --compact
```

###  Health Score

39

—

LowBetter than 86% of packages

Maintenance90

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

46d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/d48e21f657ce48fd691514353d43013a18c77381f3e84be1ba5cbaee6f728c67?d=identicon)[sahrulprograming](/maintainers/sahrulprograming)

---

Top Contributors

[![sahrulprograming](https://avatars.githubusercontent.com/u/79908759?v=4)](https://github.com/sahrulprograming "sahrulprograming (5 commits)")

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/jasanya-seo-library-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/jasanya-seo-library-laravel/health.svg)](https://phpackages.com/packages/jasanya-seo-library-laravel)
```

###  Alternatives

[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.5k25.9M107](/packages/laravel-cashier)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k12.1M99](/packages/laravel-pulse)[laravel-doctrine/orm

An integration library for Laravel and Doctrine ORM

8425.3M87](/packages/laravel-doctrine-orm)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9682.1M97](/packages/roots-acorn)[psalm/plugin-laravel

Psalm plugin for Laravel

3274.9M308](/packages/psalm-plugin-laravel)[laravel/folio

Page based routing for Laravel.

608453.9k27](/packages/laravel-folio)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
