PHPackages                             oliwol/laravel-slugify - 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. [Database &amp; ORM](/categories/database)
4. /
5. oliwol/laravel-slugify

ActiveLibrary[Database &amp; ORM](/categories/database)

oliwol/laravel-slugify
======================

A trait to easily add slug generation to your Laravel models.

v1.2.0(1mo ago)2630↓50%[7 issues](https://github.com/oliwol/laravel-slugify/issues)MITPHPPHP ^8.4|^8.5CI passing

Since Oct 27Pushed 1mo agoCompare

[ Source](https://github.com/oliwol/laravel-slugify)[ Packagist](https://packagist.org/packages/oliwol/laravel-slugify)[ RSS](/packages/oliwol-laravel-slugify/feed)WikiDiscussions 1.x Synced 1mo ago

READMEChangelog (10)Dependencies (14)Versions (18)Used By (0)

🌀 Laravel Slugify
=================

[](#-laravel-slugify)

[![Latest Version on Packagist](https://camo.githubusercontent.com/cac28ce995e1bbf18af2332b0a3be09544bb8ffbfe25fe7bd54c5f8cec06230c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6f6c69776f6c2f6c61726176656c2d736c75676966792e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/oliwol/laravel-slugify)[![GitHub Tests Action Status](https://camo.githubusercontent.com/f4f22bff1c411086434696075e87b20530a090e2d5fa976915ded9b6009bd2c0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6f6c69776f6c2f6c61726176656c2d736c75676966792f2e6769746875622f776f726b666c6f77732f74657374732e796d6c3f6272616e63683d312e78266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/oliwol/laravel-slugify/actions)[![License](https://camo.githubusercontent.com/641343bc793a7f0327afe21ccc1dd15cceeee437f9a83d529c0c48d31a5d379b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6f6c69776f6c2f6c61726176656c2d736c75676966792e7376673f7374796c653d666c61742d737175617265)](https://github.com/oliwol/laravel-slugify/blob/1.x/LICENSE)

A tiny trait that gives your Eloquent models clean, automatic slugs — without setup, ceremony, or extra weight.

Attach it to a model, define the source attribute, and the trait quietly handles generation, updates and uniqueness.

---

🚀 Installation
--------------

[](#-installation)

Install the package via Composer:

```
composer require oliwol/laravel-slugify
```

⚡️ Quick Start
--------------

[](#️-quick-start)

### Using the PHP Attribute (recommended)

[](#using-the-php-attribute-recommended)

```
use Oliwol\Slugify\HasSlug;
use Oliwol\Slugify\Slugify;

#[Slugify(from: 'title', to: 'slug')]
class Post extends Model
{
    use HasSlug;
}
```

### Using method overrides

[](#using-method-overrides)

```
use Oliwol\Slugify\HasSlug;

class Post extends Model
{
    use HasSlug;

    public function getAttributeToCreateSlugFrom(): string|array
    {
        return 'title';
    }

    public function getRouteKeyName(): string
    {
        return 'slug';
    }
}
```

> **Priority**: Method overrides always take precedence over the `#[Slugify]` attribute.

🛠️ Usage
--------

[](#️-usage)

Add the `HasSlug` trait to any Eloquent model where a slug should be automatically generated.

### Configuration via `#[Slugify]` Attribute

[](#configuration-via-slugify-attribute)

The `#[Slugify]` attribute accepts the following parameters:

- `from` (required) — the attribute(s) used to generate the slug. Accepts a single string (e.g. `'name'`) or an array of strings (e.g. `['first_name', 'last_name']`).
- `to` (optional) — the column to save the slug to. Falls back to `getRouteKeyName()` if omitted.
- `separator` (optional) — the character used to separate words in the slug. Defaults to `'-'`.
- `maxLength` (optional) — maximum number of characters for the slug. Truncates at word boundaries. Defaults to `null` (no limit).
- `regenerateOnUpdate` (optional) — whether to regenerate the slug when the source attribute changes on update. Defaults to `true`. Set to `false` to only generate slugs on creation (useful for SEO).

```
use Oliwol\Slugify\HasSlug;
use Oliwol\Slugify\Slugify;

// Full configuration via attribute
#[Slugify(from: 'name', to: 'slug')]
class Post extends Model
{
    use HasSlug;
}

// Only 'from' — slug column is determined by getRouteKeyName()
#[Slugify(from: 'name')]
class Post extends Model
{
    use HasSlug;

    public function getRouteKeyName(): string
    {
        return 'slug';
    }
}

// Multiple source attributes — generates slug from combined values
#[Slugify(from: ['first_name', 'last_name'], to: 'slug')]
class Author extends Model
{
    use HasSlug;
}
// first_name: "John", last_name: "Doe" → "john-doe"

// Custom separator — uses underscores instead of hyphens
#[Slugify(from: 'title', to: 'slug', separator: '_')]
class Post extends Model
{
    use HasSlug;
}
// "Hello World" → "hello_world"

// SEO-safe — slug is only generated on creation, never updated
#[Slugify(from: 'title', to: 'slug', regenerateOnUpdate: false)]
class Post extends Model
{
    use HasSlug;
}
```

> **Note**: The `to` parameter only controls where the slug is saved. For route model binding, you still need to override `getRouteKeyName()` separately on your model.

### Configuration via methods

[](#configuration-via-methods)

Alternatively, you can configure slug generation by overriding methods:

- `getAttributeToCreateSlugFrom()` — the attribute(s) used to generate the slug. Return a `string` or `array`.
- `getRouteKeyName()` — the slug column for route model binding (e.g. slug).
- Optionally `getAttributeToSaveSlugTo()` — a different column to save the slug.
- Optionally `getSlugSeparator()` — the separator character (default `'-'`).
- Optionally `getMaxSlugLength()` — maximum slug length, truncated at word boundaries (default `null`).
- Optionally `shouldRegenerateSlugOnUpdate()` — return `false` to only generate slugs on creation (default `true`).
- Optionally override `scopeSlugQuery()` — scoping for uniqueness (e.g. per team).

```
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Oliwol\Slugify\HasSlug;

class Post extends Model
{
    use HasSlug;

    /**
     * Attribute(s) used for generating the slug.
     * Return a string or an array of strings.
     */
    public function getAttributeToCreateSlugFrom(): string|array
    {
        return 'name';
    }

    /**
     * Use slug for route binding.
     */
    public function getRouteKeyName(): string
    {
        return 'slug';
    }

    /**
     * This package uses Laravel's getRouteKeyName to store the slug.
     * If you are using a different column for your routes,
     * use getAttributeToSaveSlugTo to store the slug.
     */
    public function getAttributeToSaveSlugTo(): string
    {
        return 'slug';
    }

    /**
     * Scope applied when checking for uniqueness.
     */
    public function scopeSlugQuery($query)
    {
        return $query->where('tenant_id', 1);
    }
}
```

Make sure your table contains the slug column:

```
$table->string('slug')->unique();
```

If you use scoping, you probably don’t want a global unique index. Example: slugs must be unique per tenant:

```
$table->unique(['tenant_id', 'slug']);
```

⚙️ How it works
---------------

[](#️-how-it-works)

The `HasSlug` trait hooks into the Eloquent saving event:

```
protected static function bootHasSlug(): void
 {
     static::saving(function (Model $model): void {
         if ($model->isSluggable()) {
             $model->createSlug();
         }
     });
 }
```

When triggered, it will:

1. Resolve the source attribute(s) — from the `#[Slugify]` attribute or a `getAttributeToCreateSlugFrom()` override. Supports a single attribute or multiple attributes.
2. Generate a slug by combining filled source values (null/empty values are skipped).
3. Skip regeneration if:
    1. None of the source attributes are dirty (unchanged), or
    2. The slug has been manually set and differs from the original.
4. Ensure uniqueness by incrementing existing slugs (my-post, my-post-2, my-post-3, …).

🔎 Finding Models by Slug
------------------------

[](#-finding-models-by-slug)

The trait provides two static methods to look up models by their slug:

```
// Returns the model or null
$post = Post::findBySlug('hello-world');

// Returns the model or throws ModelNotFoundException
$post = Post::findBySlugOrFail('hello-world');
```

Both methods respect the configured slug column (`to` / `getAttributeToSaveSlugTo()`) and apply `scopeSlugQuery()` for scoped lookups.

✅ Best practices &amp; caveats
------------------------------

[](#-best-practices--caveats)

- Ensure the route key column (`getRouteKeyName()`) is present in your table and is not the primary key (unless intentionally designed).
- If you manually set a slug, the trait will not override it. Use this to allow user-edited slugs.

🔍 Custom Scoping Example
------------------------

[](#-custom-scoping-example)

To ensure slugs are unique per tenant, override the `scopeSlugQuery()` method:

```
public function scopeSlugQuery($query)
{
    return $query->where('tenant_id', 1);
}
```

This will append a `WHERE tenant_id = ?` clause when checking for existing slugs.

📄 License
---------

[](#-license)

This package is open-sourced software licensed under the [MIT license](LICENSE).

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance69

Regular maintenance activity

Popularity21

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity61

Established project with proven stability

 Bus Factor1

Top contributor holds 82.6% 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 ~10 days

Recently: every ~1 days

Total

15

Last Release

57d ago

Major Versions

0.x-dev → v1.0.02026-01-10

PHP version history (2 changes)v0.0.1PHP ^8.4

v1.1.1PHP ^8.4|^8.5

### Community

Maintainers

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

---

Top Contributors

[![oliverwolschke](https://avatars.githubusercontent.com/u/226452870?v=4)](https://github.com/oliverwolschke "oliverwolschke (19 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (4 commits)")

---

Tags

eloquenteloquent-modelslaravellaravel-packageslugslug-generatorslugifyslugslugifylaravel

###  Code Quality

TestsPest

Static AnalysisPHPStan, Rector

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/oliwol-laravel-slugify/health.svg)

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

###  Alternatives

[cviebrock/eloquent-sluggable

Easy creation of slugs for your Eloquent models in Laravel

4.0k13.6M253](/packages/cviebrock-eloquent-sluggable)[tucker-eric/eloquentfilter

An Eloquent way to filter Eloquent Models

1.8k4.8M26](/packages/tucker-eric-eloquentfilter)[watson/validating

Eloquent model validating trait.

9723.3M47](/packages/watson-validating)[cybercog/laravel-love

Make Laravel Eloquent models reactable with any type of emotions in a minutes!

1.2k302.7k1](/packages/cybercog-laravel-love)[cviebrock/eloquent-taggable

Easy ability to tag your Eloquent models in Laravel.

567694.8k3](/packages/cviebrock-eloquent-taggable)[clickbar/laravel-magellan

This package provides functionality for working with the postgis extension in Laravel.

423715.4k1](/packages/clickbar-laravel-magellan)

PHPackages © 2026

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