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
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