actengage / sluggable
A simple trait to ensure Laravel models have slugs.
Requires
- php: ^8.2
- laravel/framework: ^11.0|^12.0|^13.0
Requires (Dev)
- larastan/larastan: ^3.9
- laravel/boost: ^2.3
- laravel/pint: ^1.29
- mockery/mockery: ^1.1
- orchestra/testbench: ^9.0
- pestphp/pest: *
- pestphp/pest-plugin-laravel: *
- phpunit/phpunit: ^10.0
- rector/rector: ^2.3
- dev-master
- v7.0.1
- v7.0.0
- v6.1.1
- v6.1.0
- v6.0.0
- v5.0.0
- v4.1.0
- v4.0.0
- v3.0.2
- v3.0.1
- v3.0.0
- v2.0.0
- v1.2.0
- v1.1.0
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- v0.2.2
- v0.2.1
- v0.2.0
- 0.1.1
- 0.1.0
- dev-changeset-release/master
- dev-fix/laravel-13-method-conflict
- dev-fix/release-workflow-v2
- dev-fix/release-depends-on-ci
- dev-feat/ci-cd-changesets
- dev-dependabot/composer/guzzlehttp/psr7-2.5.0
- dev-dependabot/composer/symfony/http-kernel-6.2.6
This package is auto-updated.
Last update: 2026-03-17 19:28:12 UTC
README
A simple package for managing "slugs" on Eloquent models. Sluggable is a trait for Eloquent models to ensure a slug exists for the model and is saved in a column.
Installation
composer require actengage/sluggable
Implementation
Add the Sluggable trait to your model.
namespace App\Models; use Actengage\Sluggable\Sluggable; use Illuminate\Database\Eloquent\Model; class Page extends Model { use Sluggable; protected $fillable = [ 'title', 'slug', ]; }
Basic Example
$page = Page::create([ 'title' => 'This is some title', ]); $page->slug; // 'this-is-some-title'
PHP Attributes
You can use PHP attributes to declaratively configure sluggable behavior instead of overriding methods.
#[Slug] — Set the qualifier
The qualifier is the model attribute used to generate the slug. Defaults to title.
use Actengage\Sluggable\Slug; #[Slug('name')] class Product extends Model { use Sluggable; }
#[SlugAttribute] — Set the slug column
The column where the slug is stored. Defaults to slug.
use Actengage\Sluggable\SlugAttribute; #[SlugAttribute('url_slug')] class Product extends Model { use Sluggable; }
#[SlugDelimiter] — Set the delimiter
The character used to separate words in the slug. Defaults to -.
use Actengage\Sluggable\SlugDelimiter; #[SlugDelimiter('_')] class Product extends Model { use Sluggable; }
#[PreventDuplicateSlugs] — Control duplicate prevention
By default, duplicate slugs are prevented by appending an incrementing number. Use this attribute to disable that behavior.
use Actengage\Sluggable\PreventDuplicateSlugs; #[PreventDuplicateSlugs(false)] class Product extends Model { use Sluggable; }
Combining attributes
use Actengage\Sluggable\PreventDuplicateSlugs; use Actengage\Sluggable\Slug; use Actengage\Sluggable\SlugAttribute; use Actengage\Sluggable\SlugDelimiter; #[Slug('name')] #[SlugAttribute('url_slug')] #[SlugDelimiter('_')] #[PreventDuplicateSlugs(false)] class Product extends Model { use Sluggable; }
Finding by Slug
$page = Page::findBySlug('this-is-some-title');
Slug Scope
$page = Page::slug('this-is-some-title')->first();
Duplicate Slug Prevention
By default, Sluggable prevents duplicate slugs by appending an incrementing number.
Page::create(['title' => 'test']); // slug: 'test' Page::create(['title' => 'test']); // slug: 'test-1' Page::create(['title' => 'test']); // slug: 'test-2'
This can be disabled with the #[PreventDuplicateSlugs] attribute or by setting the property on the model:
class Page extends Model { use Sluggable; protected $preventDuplicateSlugs = false; }
Publishing a New Release
This package uses changesets for automated versioning and releases.
- Create a branch and make your changes
- Add a changeset describing the change:
Select the bump level (patch, minor, or major) and write a summary. See the changeset skill for semver rules specific to this package.pnpm changeset - Open a PR — CI runs Pint, PHPStan, Rector, and Pest
- Merge the PR — the release workflow creates a "Version Packages" PR that bumps the version in
package.jsonand updatesCHANGELOG.md - Review and merge the "Version Packages" PR — a git tag and GitHub Release are created automatically