PHPackages                             tustin/laravel-sluggable - 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. tustin/laravel-sluggable

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

tustin/laravel-sluggable
========================

Generate slugs when saving Eloquent models

3.4.0(4y ago)05MITPHPPHP ^8.0

Since Dec 24Pushed 3y agoCompare

[ Source](https://github.com/Tustin/laravel-sluggable)[ Packagist](https://packagist.org/packages/tustin/laravel-sluggable)[ Docs](https://github.com/spatie/laravel-sluggable)[ GitHub Sponsors](https://github.com/spatie)[ RSS](/packages/tustin-laravel-sluggable/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (5)Versions (50)Used By (0)

[![](https://camo.githubusercontent.com/2bedf63f24cda7efab02da955dc11fb7ef8a060e2f26b73c33a7aac84529b8a3/68747470733a2f2f6769746875622d6164732e73332e65752d63656e7472616c2d312e616d617a6f6e6177732e636f6d2f737570706f72742d756b7261696e652e7376673f743d31)](https://supportukrainenow.org)

Generate slugs when saving Eloquent models
==========================================

[](#generate-slugs-when-saving-eloquent-models)

[![Latest Version on Packagist](https://camo.githubusercontent.com/04e459a472439650ccfa5aaee0b9a05ceaaa02140ce809f4cda60c1ca188d7f8/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7370617469652f6c61726176656c2d736c75676761626c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/spatie/laravel-sluggable)[![MIT Licensed](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE.md)[![GitHub Workflow Status](https://camo.githubusercontent.com/302831f7d0d791415d9de6cafde407fb3e4fabb6671e44d71fb30a4bc619f12c/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f776f726b666c6f772f7374617475732f7370617469652f6c61726176656c2d736c75676761626c652f72756e2d74657374733f6c6162656c3d7465737473)](https://github.com/spatie/laravel-sluggable/actions)[![Total Downloads](https://camo.githubusercontent.com/a6ebf5dcacdaed45b2a78019c976252e12f761adeb23d0ab8c2fccfe2d2673a5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7370617469652f6c61726176656c2d736c75676761626c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/spatie/laravel-sluggable)

This package provides a trait that will generate a unique slug when saving any Eloquent model.

```
$model = new EloquentModel();
$model->name = 'activerecord is awesome';
$model->save();

echo $model->slug; // outputs "activerecord-is-awesome"
```

The slugs are generated with Laravels `Str::slug` method, whereby spaces are converted to '-'.

Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects [on our website](https://spatie.be/opensource).

Support us
----------

[](#support-us)

[![](https://camo.githubusercontent.com/ba59ca0eae3b9a4517a003d1373e3b81707928de3640334ea57204039f0a1872/68747470733a2f2f6769746875622d6164732e73332e65752d63656e7472616c2d312e616d617a6f6e6177732e636f6d2f6c61726176656c2d736c75676761626c652e6a70673f743d31)](https://spatie.be/github-ad-click/laravel-sluggable)

We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us).

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](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards).

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

[](#installation)

You can install the package via composer:

```
composer require spatie/laravel-sluggable
```

Usage
-----

[](#usage)

Your Eloquent models should use the `Spatie\Sluggable\HasSlug` trait and the `Spatie\Sluggable\SlugOptions` class.

The trait contains an abstract method `getSlugOptions()` that you must implement yourself.

Your models' migrations should have a field to save the generated slug to.

Here's an example of how to implement the trait:

```
namespace App;

use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;
use Illuminate\Database\Eloquent\Model;

class YourEloquentModel extends Model
{
    use HasSlug;

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

With its migration:

```
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateYourEloquentModelTable extends Migration
{
    public function up()
    {
        Schema::create('your_eloquent_models', function (Blueprint $table) {
            $table->increments('id');
            $table->string('slug'); // Field name same as your `saveSlugsTo`
            $table->string('name');
            $table->timestamps();
        });
    }
}
```

### Using slugs in routes

[](#using-slugs-in-routes)

To use the generated slug in routes, remember to use Laravel's [implicit route model binding](https://laravel.com/docs/5.8/routing#implicit-binding):

```
namespace App;

use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;
use Illuminate\Database\Eloquent\Model;

class YourEloquentModel extends Model
{
    use HasSlug;

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

    /**
     * Get the route key for the model.
     *
     * @return string
     */
    public function getRouteKeyName()
    {
        return 'slug';
    }
}
```

### Using multiple fields to create the slug

[](#using-multiple-fields-to-create-the-slug)

Want to use multiple field as the basis for a slug? No problem!

```
public function getSlugOptions() : SlugOptions
{
    return SlugOptions::create()
        ->generateSlugsFrom(['first_name', 'last_name'])
        ->saveSlugsTo('slug');
}
```

### Customizing slug generation

[](#customizing-slug-generation)

You can also pass a `callable` to `generateSlugsFrom`.

By default the package will generate unique slugs by appending '-' and a number, to a slug that already exists.

You can disable this behaviour by calling `allowDuplicateSlugs`.

```
public function getSlugOptions() : SlugOptions
{
    return SlugOptions::create()
        ->generateSlugsFrom('name')
        ->saveSlugsTo('slug')
        ->allowDuplicateSlugs();
}
```

### Limiting the length of a slug

[](#limiting-the-length-of-a-slug)

You can also put a maximum size limit on the created slug:

```
public function getSlugOptions() : SlugOptions
{
    return SlugOptions::create()
        ->generateSlugsFrom('name')
        ->saveSlugsTo('slug')
        ->slugsShouldBeNoLongerThan(50);
}
```

The slug may be slightly longer than the value specified, due to the suffix which is added to make it unique.

You can also use a custom separator by calling `usingSeparator`

```
public function getSlugOptions() : SlugOptions
{
    return SlugOptions::create()
        ->generateSlugsFrom('name')
        ->saveSlugsTo('slug')
        ->usingSeparator('_');
}
```

### Setting the slug language

[](#setting-the-slug-language)

To set the language used by `Str::slug` you may call `usingLanguage`

```
public function getSlugOptions() : SlugOptions
{
    return SlugOptions::create()
        ->generateSlugsFrom('name')
        ->saveSlugsTo('slug')
        ->usingLanguage('nl');
}
```

### Overriding slugs

[](#overriding-slugs)

You can also override the generated slug just by setting it to another value than the generated slug.

```
$model = EloquentModel::create(['name' => 'my name']); //slug is now "my-name";
$model->slug = 'my-custom-url';
$model->save(); //slug is now "my-custom-url";
```

Prevents slugs from being generated on some conditions
------------------------------------------------------

[](#prevents-slugs-from-being-generated-on-some-conditions)

If you don't want to create the slug when the model has a state, you can use the `skipGenerateWhen` function.

```
public function getSlugOptions() : SlugOptions
{
    return SlugOptions::create()
        ->generateSlugsFrom('name')
        ->saveSlugsTo('slug')
        ->skipGenerateWhen(fn () => $this->state === 'draft');
}
```

### Prevent slugs from being generated on creation

[](#prevent-slugs-from-being-generated-on-creation)

If you don't want to create the slug when the model is initially created you can set use the `doNotGenerateSlugsOnCreate()` function.

```
public function getSlugOptions() : SlugOptions
{
    return SlugOptions::create()
        ->generateSlugsFrom('name')
        ->saveSlugsTo('slug')
        ->doNotGenerateSlugsOnCreate();
}
```

### Prevent slug updates

[](#prevent-slug-updates)

Similarly, if you want to prevent the slug from being updated on model updates, call `doNotGenerateSlugsOnUpdate()`.

```
public function getSlugOptions() : SlugOptions
{
    return SlugOptions::create()
        ->generateSlugsFrom('name')
        ->saveSlugsTo('slug')
        ->doNotGenerateSlugsOnUpdate();
}
```

This can be helpful for creating permalinks that don't change until you explicitly want it to.

```
$model = EloquentModel::create(['name' => 'my name']); //slug is now "my-name";
$model->save();

$model->name = 'changed name';
$model->save(); //slug stays "my-name"
```

### Regenerating slugs

[](#regenerating-slugs)

If you want to explicitly update the slug on the model you can call `generateSlug()` on your model at any time to make the slug according to your other options. Don't forget to `save()` the model to persist the update to your database.

### Preventing overwrites

[](#preventing-overwrites)

You can prevent slugs from being overwritten.

```
public function getSlugOptions() : SlugOptions
{
    return SlugOptions::create()
        ->generateSlugsFrom('name')
        ->saveSlugsTo('slug')
        ->preventOverwrite();
}
```

### Using scopes

[](#using-scopes)

If you have a global scope that should be taken into account, you can define this as well with `extraScope`. For example if you have a pages table containing pages of multiple websites and every website has it's own unique slugs.

```
public function getSlugOptions() : SlugOptions
{
    return SlugOptions::create()
        ->generateSlugsFrom('name')
        ->saveSlugsTo('slug')
        ->extraScope(fn ($builder) => $builder->where('scope_id', $this->scope_id));
}
```

### Integration with laravel-translatable

[](#integration-with-laravel-translatable)

You can use this package along with [laravel-translatable](https://github.com/spatie/laravel-translatable) to generate a slug for each locale. Instead of using the `HasSlug` trait, you must use the `HasTranslatableSlug` trait, and add the name of the slug field to the `$translatable` array. For slugs that are generated from a single field *or* multiple fields, you don't have to change anything else.

```
namespace App;

use Spatie\Sluggable\HasTranslatableSlug;
use Spatie\Sluggable\SlugOptions;
use Spatie\Translatable\HasTranslations;
use Illuminate\Database\Eloquent\Model;

class YourEloquentModel extends Model
{
    use HasTranslations, HasTranslatableSlug;

    public $translatable = ['name', 'slug'];

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

For slugs that are generated from a callable, you need to instantiate the `SlugOptions` with the `createWithLocales` method. The callable now takes two arguments instead of one. Both the `$model` and the `$locale` are available to generate a slug from.

```
namespace App;

use Spatie\Sluggable\HasTranslatableSlug;
use Spatie\Sluggable\SlugOptions;
use Spatie\Translatable\HasTranslations;
use Illuminate\Database\Eloquent\Model;

class YourEloquentModel extends Model
{
    use HasTranslations, HasTranslatableSlug;

    public $translatable = ['name', 'slug'];

    /**
     * Get the options for generating the slug.
     */
    public function getSlugOptions() : SlugOptions
    {
        return SlugOptions::createWithLocales(['en', 'nl'])
            ->generateSlugsFrom(function($model, $locale) {
                return "{$locale} {$model->id}";
            })
            ->saveSlugsTo('slug');
    }
}
```

#### Implicit route model binding

[](#implicit-route-model-binding)

You can also use Laravels [implicit route model binding](https://laravel.com/docs/8.x/routing#implicit-binding) inside your controller to automatically resolve the model. To use this feature, make sure that the slug column matches the `routeNameKey`.
Currently, only some database types support JSON opterations. Further information about which databases support JSON can be found in the [Laravel docs](https://laravel.com/docs/8.x/queries#json-where-clauses).

```
namespace App;

use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;
use Illuminate\Database\Eloquent\Model;

class YourEloquentModel extends Model
{
    use HasTranslations, HasTranslatableSlug;

    public $translatable = ['name', 'slug'];

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

    /**
     * Get the route key for the model.
     *
     * @return string
     */
    public function getRouteKeyName()
    {
        return 'slug';
    }
}
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.

Testing
-------

[](#testing)

```
composer test
```

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details.

Security
--------

[](#security)

If you've found a bug regarding security please mail  instead of using the issue tracker.

Credits
-------

[](#credits)

- [Freek Van der Herten](https://github.com/freekmurze)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

33

—

LowBetter than 75% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity4

Limited adoption so far

Community19

Small or concentrated contributor base

Maturity81

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 60.4% 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 ~51 days

Recently: every ~40 days

Total

47

Last Release

1419d ago

Major Versions

0.0.1 → 1.0.02015-12-24

1.5.1 → 2.0.02017-08-30

1.5.2 → 2.1.42018-08-28

2.6.2 → 3.0.02021-03-26

PHP version history (7 changes)0.0.1PHP &gt;=7.0.0

2.1.7PHP &gt;=7.1.3

2.2.0PHP ^7.2

2.3.0PHP ^7.4

2.6.0PHP ^7.4|^8.0

3.0.0PHP ^8.0

2.2.x-devPHP ^7.2|^8.0

### Community

Maintainers

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

---

Top Contributors

[![freekmurze](https://avatars.githubusercontent.com/u/483853?v=4)](https://github.com/freekmurze "freekmurze (183 commits)")[![marvin-wtt](https://avatars.githubusercontent.com/u/31454580?v=4)](https://github.com/marvin-wtt "marvin-wtt (26 commits)")[![pascalbaljet](https://avatars.githubusercontent.com/u/8403149?v=4)](https://github.com/pascalbaljet "pascalbaljet (11 commits)")[![joshuadegier](https://avatars.githubusercontent.com/u/2580917?v=4)](https://github.com/joshuadegier "joshuadegier (10 commits)")[![AdrianMrn](https://avatars.githubusercontent.com/u/12762044?v=4)](https://github.com/AdrianMrn "AdrianMrn (9 commits)")[![sebastiandedeyne](https://avatars.githubusercontent.com/u/1561079?v=4)](https://github.com/sebastiandedeyne "sebastiandedeyne (7 commits)")[![axelitus](https://avatars.githubusercontent.com/u/732441?v=4)](https://github.com/axelitus "axelitus (6 commits)")[![belzaaron](https://avatars.githubusercontent.com/u/21190036?v=4)](https://github.com/belzaaron "belzaaron (6 commits)")[![rubenvanassche](https://avatars.githubusercontent.com/u/619804?v=4)](https://github.com/rubenvanassche "rubenvanassche (5 commits)")[![crynobone](https://avatars.githubusercontent.com/u/172966?v=4)](https://github.com/crynobone "crynobone (4 commits)")[![brendt](https://avatars.githubusercontent.com/u/6905297?v=4)](https://github.com/brendt "brendt (3 commits)")[![akoepcke](https://avatars.githubusercontent.com/u/5311185?v=4)](https://github.com/akoepcke "akoepcke (3 commits)")[![SimonGenin](https://avatars.githubusercontent.com/u/5216993?v=4)](https://github.com/SimonGenin "SimonGenin (3 commits)")[![adamcopley](https://avatars.githubusercontent.com/u/15898134?v=4)](https://github.com/adamcopley "adamcopley (2 commits)")[![masterix21](https://avatars.githubusercontent.com/u/6555012?v=4)](https://github.com/masterix21 "masterix21 (2 commits)")[![spyric](https://avatars.githubusercontent.com/u/2044754?v=4)](https://github.com/spyric "spyric (2 commits)")[![shuvroroy](https://avatars.githubusercontent.com/u/21066418?v=4)](https://github.com/shuvroroy "shuvroroy (2 commits)")[![AlexVanderbist](https://avatars.githubusercontent.com/u/6287961?v=4)](https://github.com/AlexVanderbist "AlexVanderbist (2 commits)")[![Nielsvanpach](https://avatars.githubusercontent.com/u/10651054?v=4)](https://github.com/Nielsvanpach "Nielsvanpach (2 commits)")[![CSenshi](https://avatars.githubusercontent.com/u/27967284?v=4)](https://github.com/CSenshi "CSenshi (2 commits)")

---

Tags

spatielaravel-sluggable

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/tustin-laravel-sluggable/health.svg)

```
[![Health](https://phpackages.com/badges/tustin-laravel-sluggable/health.svg)](https://phpackages.com/packages/tustin-laravel-sluggable)
```

###  Alternatives

[spatie/laravel-sluggable

Generate slugs when saving Eloquent models

1.6k11.5M223](/packages/spatie-laravel-sluggable)[spatie/laravel-enum

Laravel Enum support

3655.4M31](/packages/spatie-laravel-enum)[spatie/laravel-settings

Store your application settings

1.5k5.9M72](/packages/spatie-laravel-settings)[spatie/laravel-event-sourcing

The easiest way to get started with event sourcing in Laravel

9003.7M26](/packages/spatie-laravel-event-sourcing)[spatie/laravel-livewire-wizard

Build wizards using Livewire

4061.0M4](/packages/spatie-laravel-livewire-wizard)[spatie/laravel-pjax

A pjax middleware for Laravel 5

513371.8k11](/packages/spatie-laravel-pjax)

PHPackages © 2026

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