PHPackages                             marshmallow/seoable - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. marshmallow/seoable

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

marshmallow/seoable
===================

A Laravel Nova field which adds all SEO related meta fields to an Resource.

v5.2.0(3w ago)514.2k↓83.6%1[1 PRs](https://github.com/marshmallow-packages/seoable/pulls)3MITPHPPHP ^8.1CI passing

Since Apr 3Pushed 2w ago1 watchersCompare

[ Source](https://github.com/marshmallow-packages/seoable)[ Packagist](https://packagist.org/packages/marshmallow/seoable)[ Docs](https://marshmallow.dev)[ RSS](/packages/marshmallow-seoable/feed)WikiDiscussions main Synced 2d ago

READMEChangelog (10)Dependencies (16)Versions (112)Used By (3)

Seoable — SEO meta fields for Laravel Nova
==========================================

[](#seoable--seo-meta-fields-for-laravel-nova)

[![Latest Version on Packagist](https://camo.githubusercontent.com/f249eb0be5ee6cb76f8150118a31654714d36d44e9527f3ef9a6ef79d63bd79a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d617273686d616c6c6f772f73656f61626c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/marshmallow/seoable)[![Total Downloads](https://camo.githubusercontent.com/c3110e359fbb310b45d3885195a7ab87fc157721a033020f3d47a6251e789dae/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d617273686d616c6c6f772f73656f61626c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/marshmallow/seoable)[![License](https://camo.githubusercontent.com/253e1ca5bdbed0ba62d5a01830edc0a87d6ea9a5684c2a464eecab54729b25a0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6d617273686d616c6c6f772f73656f61626c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/marshmallow/seoable)

A Laravel Nova field that adds all SEO related meta fields to any Resource. SEO data is attached to any Eloquent model through a morph relationship using a single trait, and rendered into your layout with one facade call. The package also ships sitemap generation, a customisable `robots.txt`, structured data (JSON-LD) schemas, pretty URLs, and built-in support for Google Tag Manager, Google Analytics, Cookiebot, Hotjar, Microsoft Clarity and Facebook tags.

Requirements
------------

[](#requirements)

- PHP `^8.1`
- [Laravel Nova](https://nova.laravel.com/) `^5.0`

How to install
--------------

[](#how-to-install)

To install the package run the install below:

```
composer require marshmallow/seoable

```

And then run the migrations:

```
php artisan migrate

```

And then publish the configs:

```
php artisan vendor:publish --provider="Marshmallow\Seoable\ServiceProvider"

```

PLEASE NOTE
-----------

[](#please-note)

If you are using route caching you need to make sure you have a queue:work running. If you change a route we will recache your routes automaticly but this is done via a queue.

Manually
--------

[](#manually)

You can change the SEO data with the methods below.

```
use Marshmallow\Seoable\Facades\Seo;

Seo::setTitle(string $title);
Seo::setDescription(string $description);
Seo::setKeywords(array $keywords);
Seo::setImage(string $image);
Seo::setFollowType(string $follow_type);
Seo::setHrefs(array $hrefs);
Seo::setHideInSitemap(bool $hide_in_sitemap);
Seo::setLocale(string $locale);
Seo::setHtmlLanguage(string $html_language);
Seo::setSeoCanonicalUrl(string $canonical);
```

How to use the field
--------------------

[](#how-to-use-the-field)

Find the model you want to have the SEO fields on, example could be `App\Models\Page`, then add the `Seoable` trait:

```
...
use Marshmallow\Seoable\Traits\Seoable;

class Page extends Model
{
    use Seoable;
    ...
}

```

Then use the field in the nova resource `App\Nova\Page`:

```
...
use Marshmallow\Seoable\Seoable;

class Page extends Resource
{
  ...
  public function fields(Request $request)
  {
    return [
      ...,
      Seoable::make('Seo'),
    ];
  }
}

```

You can also render the field inside a Nova tab with `Seoable::makeAsTab('Seo')`.

Then go to the top of your layout blade as default it's `resources/views/welcome.blade.php`:

```
...

    {{ Seo::generate() }}
    ...

```

Last step! Tell the SEO Facade which model it can use to set the SEO data.

```
use Marshmallow\Seoable\Facades\Seo;

class ExampleController extends Controller
{
    public function show (Product $product)
    {
        $product->useForSeo();

        return view('product')->with([
            'product' => $product
        ])
    }
}

```

Publish the Nova Resources
--------------------------

[](#publish-the-nova-resources)

```
php artisan marshmallow:resource Route Seoable
php artisan marshmallow:resource PrettyUrl Seoable
```

Use sluggable (optional)
------------------------

[](#use-sluggable-optional)

SEO-driven websites usually need clean, slug-based URLs. This package does **not** depend on any slug package itself, so you are free to use whichever one you like. At Marshmallow we use [`marshmallow/sluggable`](https://github.com/marshmallow-packages/sluggable) so every SEO site shares the same slug-building logic — install it separately if you want the same setup:

```
composer require marshmallow/sluggable
```

```
class YourEloquentModel extends Model
{
    use HasSlug;

    /**
     * Get the options for generating the slug.
     */
    public function getSlugOptions() : SlugOptions
    {
        return SlugOptions::create()
            ->generateSlugsFrom('name')
            ->saveSlugsTo('slug');
    }
}
```

Use routes
----------

[](#use-routes)

```
php artisan marshmallow:resource Route Seoable
```

Add the following to your `routes/web.php`.

```
use Marshmallow\Seoable\Seoable;

Seoable::routes();
```

Use pretty URL's
----------------

[](#use-pretty-urls)

If you wish to use the pretty urls module, you need to activate this in your config. This is set to `false` by default. This module will register a middleware for you. Because this functionality is currently in beta it is disabled by default. If you find any issues, please let us know.

```
// config/seo.php

return [
    'use_pretty_urls' => true,
];
```

Setup default values for a model
--------------------------------

[](#setup-default-values-for-a-model)

You can overrule how the seo defaults per model are handled. You can use the methods below.

```
// Return the SEO title for the model
public function getSeoTitle(): ?string

// Return the SEO description for the model
public function setSeoDescription(): ?string

// Return the SEO keywords for the model
public function setSeoKeywords(): ?array

// Return the SEO image for the model
public function setSeoImage(): ?string

// Return the SEO follow type for the model
public function setSeoFollowType(): ?string

```

Setup Sitemap functionality
---------------------------

[](#setup-sitemap-functionality)

If you want the sitemap functionality then activate the sitemap by changing the `seo.sitemap_status` config to `true`. Then add the models which has the `SeoSitemapTrait` trait to the `seo.sitemap_models` array, like this:

```
    ...
    'sitemap_status' => env('SITEMAP_STATUS', true),

    ...
    'sitemap_models' => [
        App\Models\Page::class
    ],

```

### Add Sitemap trait to models

[](#add-sitemap-trait-to-models)

When you want the eloquent model to be shown in the sitemap then you need to add the `SeoSitemapTrait` trait to it:

```
...
use Marshmallow\Seoable\Traits\SeoSitemapTrait;

class Page extends Model
{
    use Seoable, SeoSitemapTrait;
    ...

    /**
     * Get the Page url by item
     *
     * @return string
     */
    public function getSitemapItemUrl()
    {
        return url($this->slug);
    }

    /**
     * Query all the Page items which should be
     * part of the sitemap (crawlable for google).
     *
     * @return Builder
     */
    public static function getSitemapItems()
    {
        return static::all();
    }
}

```

Know you should be able to go to the `seo.sitemap_path` which is `/sitemap` as default. Then you should get an xml in the correct sitemap structure for [Google Search Console](https://search.google.com/search-console/about).

Structured Data
---------------

[](#structured-data)

```
$faq = \Marshmallow\Seoable\Helpers\Schemas\SchemaFaqPage::make();
$faq->addQuestionAndAnswer('What is the name of this company?', 'Marshmallow');

\Marshmallow\Seoable\Facades\Seo::addSchema($faq);
```

Robots
------

[](#robots)

This package also allows you to use a customer Robots.txt. You should create a helper class where you will add your Robots.txt content. For instance, create a class in `app/Helpers/RobotTxt.php`. In this class you should implement a `handle` method. This package will call the method for you and output the result.

```
# app/Helpers/RobotTxt.php

namespace App\Helpers;

use Marshmallow\Seoable\Objects\Robots;
use Marshmallow\Seoable\Contracts\RobotTxtInterface;

class RobotTxt implements RobotTxtInterface
{
    public function handle(Robots $robots): Robots
    {
        return $robots->userAgent('*')
            ->allow('/')
            ->disallow('/login');
    }
}
```

### Implementation robots

[](#implementation-robots)

Once you've created the helper class you should let the seoable config know where to find this helper.

```
return [

    /*
    |--------------------------------------------------------------------------
    | Robots.txt
    |--------------------------------------------------------------------------
    |
    | Override the class which builds the robots.txt file. If you are using this,
    | do not forget to delete the original public/robots.txt file.
    |
    */
    'robots_resolver' => App\Helpers\DefaultRobotsTxt::class,
];
```

To complete the implementation, you only need the remove the default `public/robots.txt` file and you are good to go!

How does it look in Laravel Nova
--------------------------------

[](#how-does-it-look-in-laravel-nova)

If the field is shown **in the index view** of the Resource, then you should see a column with a dot: [![alt text](/assets/images/seo-field-index.jpg)](/assets/images/seo-field-index.jpg)

**In detail view** you will see a text saying `You need some SEO data` if no SEO is setup yet. But if you have any then, you will get the toggle button, which will show you an example how it will look like on Google and on Facebook: [![alt text](/assets/images/seo-field-detail-hidden.jpg)](/assets/images/seo-field-detail-hidden.jpg)[![alt text](/assets/images/seo-field-detail-show.jpg)](/assets/images/seo-field-detail-show.jpg)

**In form view** you should see all the SEO input fields: [![alt text](/assets/images/seo-field-form.jpg)](/assets/images/seo-field-form.jpg)

Credits
-------

[](#credits)

- [Stef van Esch](https://github.com/marshmallow-packages)
- [All Contributors](https://github.com/marshmallow-packages/seoable/contributors)

Security
--------

[](#security)

If you discover any security related issues, please email  instead of using the issue tracker.

License
-------

[](#license)

The MIT License (MIT). Please see the [License File](https://packagist.org/packages/marshmallow/seoable) for more information.

###  Health Score

60

—

FairBetter than 98% of packages

Maintenance96

Actively maintained with recent releases

Popularity30

Limited adoption so far

Community17

Small or concentrated contributor base

Maturity82

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 76.8% 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

Every ~21 days

Recently: every ~73 days

Total

106

Last Release

25d ago

Major Versions

v2.24.4 → v3.0.62023-06-27

v3.4.0 → v5.0.02025-01-05

v3.4.1 → v5.0.12025-01-07

v3.5.1 → v5.0.22025-04-24

v3.x-dev → v5.0.32025-08-01

PHP version history (4 changes)v1.0.0PHP &gt;=7.1.0

v2.8.2PHP ^7.1|^8.0

v3.0.0PHP ^8.0

v5.0.1PHP ^8.1

### Community

Maintainers

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

---

Top Contributors

[![stefvanesch](https://avatars.githubusercontent.com/u/46725619?v=4)](https://github.com/stefvanesch "stefvanesch (222 commits)")[![LTKort](https://avatars.githubusercontent.com/u/2412670?v=4)](https://github.com/LTKort "LTKort (50 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (16 commits)")[![milan607](https://avatars.githubusercontent.com/u/258212842?v=4)](https://github.com/milan607 "milan607 (1 commits)")

---

Tags

laravelnovaseoable

### Embed Badge

![Health badge](/badges/marshmallow-seoable/health.svg)

```
[![Health](https://phpackages.com/badges/marshmallow-seoable/health.svg)](https://phpackages.com/packages/marshmallow-seoable)
```

###  Alternatives

[ebess/advanced-nova-media-library

Laravel Nova tools for managing the Spatie media library.

6163.5M22](/packages/ebess-advanced-nova-media-library)[optimistdigital/nova-sortable

This Laravel Nova package allows you to reorder models in a Nova resource's index view using drag &amp; drop.

2852.1M6](/packages/optimistdigital-nova-sortable)[outl1ne/nova-sortable

This Laravel Nova package allows you to reorder models in a Nova resource's index view using drag &amp; drop.

2862.1M9](/packages/outl1ne-nova-sortable)[markwalet/nova-modal-response

A Laravel Nova asset for Modal responses on an action.

17878.9k](/packages/markwalet-nova-modal-response)[advoor/nova-editor-js

A Laravel Nova field bringing EditorJs magic to Nova.

92219.3k3](/packages/advoor-nova-editor-js)[outl1ne/nova-page-manager

Page(s) and region(s) manager for Laravel Nova.

17947.0k](/packages/outl1ne-nova-page-manager)

PHPackages © 2026

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