[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-8447":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":15,"stars30d":16,"stars90d":15,"forks30d":15,"starsTrendScore":15,"compositeScore":17,"rankGlobal":10,"rankLanguage":10,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":21,"hasPages":19,"topics":22,"createdAt":10,"pushedAt":10,"updatedAt":26,"readmeContent":27,"aiSummary":28,"trendingCount":15,"starSnapshotCount":15,"syncStatus":29,"lastSyncTime":30,"discoverSource":31},8447,"eloquent-sluggable","cviebrock\u002Feloquent-sluggable","cviebrock","Easy creation of slugs for your Eloquent models in Laravel","",null,"PHP",3993,449,90,0,3,29.96,"MIT License",false,"master",true,[23,24,25],"eloquent-models","laravel","slug","2026-06-12 02:01:53","# Eloquent-Sluggable\n\nEasy creation of slugs for your Eloquent models in Laravel.\n\n> [!NOTE]\n> These instructions are for the latest version of Laravel.  \n> If you are using an older version, please install a version of the package\n> that [correlates to your Laravel version](#installation).\n\n[![Build Status](https:\u002F\u002Fgithub.com\u002Fcviebrock\u002Feloquent-sluggable\u002Fworkflows\u002Ftests\u002Fbadge.svg?branch=master)](https:\u002F\u002Fgithub.com\u002Fcviebrock\u002Feloquent-sluggable\u002Factions)\n[![Total Downloads](https:\u002F\u002Fposer.pugx.org\u002Fcviebrock\u002Feloquent-sluggable\u002Fdownloads?format=flat)](https:\u002F\u002Fpackagist.org\u002Fpackages\u002Fcviebrock\u002Feloquent-sluggable)\n[![Latest Stable Version](https:\u002F\u002Fposer.pugx.org\u002Fcviebrock\u002Feloquent-sluggable\u002Fv\u002Fstable?format=flat)](https:\u002F\u002Fpackagist.org\u002Fpackages\u002Fcviebrock\u002Feloquent-sluggable)\n[![Latest Unstable Version](https:\u002F\u002Fposer.pugx.org\u002Fcviebrock\u002Feloquent-sluggable\u002Fv\u002Funstable?format=flat)](https:\u002F\u002Fpackagist.org\u002Fpackages\u002Fcviebrock\u002Feloquent-sluggable)\n[![SensioLabsInsight](https:\u002F\u002Finsight.sensiolabs.com\u002Fprojects\u002F0b966e13-6a6a-4d17-bcea-61037f04cfe7\u002Fmini.png)](https:\u002F\u002Finsight.sensiolabs.com\u002Fprojects\u002F0b966e13-6a6a-4d17-bcea-61037f04cfe7)\n[![License](https:\u002F\u002Fimg.shields.io\u002Fpackagist\u002Fl\u002Fcviebrock\u002Feloquent-sluggable)](LICENSE.md)\n\n\n- [Eloquent-Sluggable](#eloquent-sluggable)\n  - [Background: What is a slug?](#background-what-is-a-slug)\n  - [Installation](#installation)\n  - [Updating your Eloquent Models](#updating-your-eloquent-models)\n  - [Usage](#usage)\n  - [The SlugService Class](#the-slugservice-class)\n  - [When Is A Model Slugged?](#when-is-a-model-slugged)\n  - [Events](#events)\n  - [Configuration](#configuration)\n    - [source](#source)\n    - [method](#method)\n    - [onUpdate](#onupdate)\n    - [separator](#separator)\n    - [unique](#unique)\n    - [uniqueSuffix](#uniquesuffix)\n    - [firstUniqueSuffix](#firstuniquesuffix)\n    - [includeTrashed](#includetrashed)\n    - [reserved](#reserved)\n    - [maxLength](#maxlength)\n    - [maxLengthKeepWords](#maxlengthkeepwords)\n    - [slugEngineOptions](#slugengineoptions)\n  - [Short Configuration](#short-configuration)\n  - [Extending Sluggable](#extending-sluggable)\n    - [customizeSlugEngine](#customizeslugengine)\n    - [scopeWithUniqueSlugConstraints](#scopewithuniqueslugconstraints)\n    - [scopeFindSimilarSlugs](#scopefindsimilarslugs)\n  - [SluggableScopeHelpers Trait](#sluggablescopehelpers-trait)\n  - [Route Model Binding](#route-model-binding)\n  - [Bugs, Suggestions, Contributions and Support](#bugs-suggestions-contributions-and-support)\n  - [Copyright and License](#copyright-and-license)\n\n\n## Background: What is a slug?\n\nA slug is a simplified version of a string, typically URL-friendly. The act of \"slugging\" \na string usually involves converting it to one case, and removing any non-URL-friendly \ncharacters (spaces, accented letters, ampersands, etc.). The resulting string can \nthen be used as an identifier for a particular resource.\n\nFor example, if you have a blog with posts, you could refer to each post via the ID:\n\n    http:\u002F\u002Fexample.com\u002Fpost\u002F1\n    http:\u002F\u002Fexample.com\u002Fpost\u002F2\n\n... but that's not particularly friendly (especially for \n[SEO](http:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSearch_engine_optimization)). You probably would \nprefer to use the post's title in the URL, but that becomes a problem if your post \nis titled \"My Dinner With André & François\", because this is pretty ugly too:\n\n    http:\u002F\u002Fexample.com\u002Fpost\u002FMy+Dinner+With+Andr%C3%A9+%26+Fran%C3%A7ois\n\nThe solution is to create a slug for the title and use that instead. You might want \nto use Laravel's built-in `Str::slug()` method to convert that title into something \nfriendlier:\n\n    http:\u002F\u002Fexample.com\u002Fpost\u002Fmy-dinner-with-andre-francois\n\nA URL like that will make users happier (it's readable, easier to type, etc.).\n\nFor more information, you might want to read \n[this](http:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSlug_(web_publishing)#Slug) description on Wikipedia.\n\nSlugs tend to be unique as well. So if you write another post with the same title, \nyou'd want to distinguish between them somehow, typically with an incremental counter \nadded to the end of the slug:\n\n    http:\u002F\u002Fexample.com\u002Fpost\u002Fmy-dinner-with-andre-francois\n    http:\u002F\u002Fexample.com\u002Fpost\u002Fmy-dinner-with-andre-francois-1\n    http:\u002F\u002Fexample.com\u002Fpost\u002Fmy-dinner-with-andre-francois-2\n\nThis keeps the URLs unique.\n\nThe **Eloquent-Sluggable** package for Laravel aims to handle all of this for you \nautomatically, with minimal configuration.\n\n\n## Installation\n\nDepending on your version of Laravel, you should install a different\nversion of the package.\n\n> [!NOTE]\n> As of version 6.0, the package's version should match the Laravel version.\n\n| Laravel Version | Package Version |\n|:---------------:|:---------------:|\n|      13.0       |      ^13.0      |\n|      12.0       |      ^12.0      |\n|      11.0       |      ^11.0      |\n|      10.0       |      ^10.0      |\n|       9.0       |      ^9.0       |\n|       8.0       |      ^8.0       |\n|       7.0       |      ^7.0       |\n|       6.0       |      ^6.0       |\n|       5.8       |      4.8.*      |\n|       5.7       |      4.7.*      |\n|       5.6       |      4.5.*      |\n|       5.5       |      4.4.*      |\n|       5.4       |      4.2.*      |\n\nOlder versions of Laravel can use older versions of the package, although they \nare no longer supported or maintained.  See [CHANGELOG.md](CHANGELOG.md) and\n[UPGRADING.md](UPGRADING.md) for specifics, and be sure that you are reading \nthe correct README.md for your version (GitHub displays the version in \nthe _master_ branch by default, which might not be what you want).\n\n> [!WARNING]\n> Support for Laravel [Lumen](https:\u002F\u002Flumen.laravel.com\u002F) has been dropped.\n\n\n1. Install the package via Composer:\n\n    ```sh\n    composer require cviebrock\u002Feloquent-sluggable\n    ```\n\n    The package will automatically register its service provider.\n\n2. Optionally, publish the configuration file if you want to change any defaults:\n\n    ```sh\n    php artisan vendor:publish --provider=\"Cviebrock\\EloquentSluggable\\ServiceProvider\"\n    ```\n\n\n## Updating your Eloquent Models\n\nYour models should use the Sluggable trait, which has an abstract method `sluggable()`\nthat you need to define.  This is where any model-specific configuration is set \n(see [Configuration](#configuration) below for details):\n\n```php\nuse Cviebrock\\EloquentSluggable\\Sluggable;\n\nclass Post extends Model\n{\n    use Sluggable;\n\n    \u002F**\n     * Return the sluggable configuration array for this model.\n     *\n     * @return array\n     *\u002F\n    public function sluggable(): array\n    {\n        return [\n            'slug' => [\n                'source' => 'title'\n            ]\n        ];\n    }\n}\n```\n\nOf course, your model and database will need a column in which to store the slug. \nYou can use `slug` or any other appropriate name you want; your configuration array\nwill determine to which field the data will be stored.  You will need to add the \ncolumn (which should be `NULLABLE`) manually via your own migration.\n\nThat's it ... your model is now \"sluggable\"!\n\n\n\n## Usage\n\nSaving a model is easy:\n\n```php\n$post = Post::create([\n    'title' => 'My Awesome Blog Post',\n]);\n```\n\nSo is retrieving the slug:\n\n```php\necho $post->slug;\n```\n\n> [!NOTE]\n> If you are replicating your models using Eloquent's `replicate()` method, \n> the package will automatically re-slug the model afterwards to ensure uniqueness.\n\n```php\n$post = Post::create([\n    'title' => 'My Awesome Blog Post',\n]);\n\u002F\u002F $post->slug is \"my-awesome-blog-post\"\n\n$newPost = $post->replicate();\n\u002F\u002F $newPost->slug is \"my-awesome-blog-post-1\"\n```\n\n> [!NOTE]\n> Empty strings, non-strings or other \"odd\" source values will result in different slugs:\n>\n> | Source Value | Resulting Slug        |\n> |--------------|-----------------------|\n> | string       | string                |\n> | empty string | _no slug will be set_ |\n> | `null`       | _no slug will be set_ |\n> | `0`          | `\"0\"`                 |\n> | `1`          | `\"1\"`                 |\n> | `false`      | `\"0\"`                 |\n> | `true`       | `\"1\"`                 |\n>\n> The above values would be subject to any unique or other checks as well.\n\n## The SlugService Class \n\nAll the logic to generate slugs is handled\nby the `\\Cviebrock\\EloquentSluggable\\Services\\SlugService` class.\n\nGenerally, you don't need to access this class directly, although there is one \nstatic method that can be used to generate a slug for a given string without actually\ncreating or saving an associated model.\n\n```php\nuse \\Cviebrock\\EloquentSluggable\\Services\\SlugService;\n\n$slug = SlugService::createSlug(Post::class, 'slug', 'My First Post');\n```\n\nThis would be useful for Ajax-y controllers or the like, where you want to show a \nuser what the unique slug _would_ be for a given test input, before actually creating\na model.  The first two arguments to the method are the model and slug field being\ntested, and the third argument is the source string to use for testing the slug.\n\nYou can also pass an optional array of configuration values as the fourth argument.\nThese will take precedence over the normal configuration values for the slug field\nbeing tested.  For example, if your model is configured to use unique slugs, but you \nwant to generate the \"base\" version of a slug for some reason, you could do:\n\n```php\n$slug = SlugService::createSlug(Post::class, 'slug', 'My First Post', ['unique' => false]);\n```\n\n\n\n## When Is A Model Slugged?\n\nCurrently, the model is slugged on Eloquent's `saving` event.\nThis means that the slug is generated before any new data is\nwritten to the database.\n  \nFor new models, this means that the primary key has not yet been set, \nso it could not be used as part of the slug source, e.g.:\n\n```php\npublic function sluggable(): array\n{\n    return [\n        'slug' => [\n            'source' => ['title', 'id']\n        ]\n    ];\n}\n```\n\n`$model->id` is `null` before the model is saved.  The benefit of hooking into\nthe `saving` event, however, is that we only needed to make one database\nquery to save all the model's data, including the slug.\n\nOptional, the model can be slugged on Eloquent's `saved` event.  \nThis means that all the other model attributes will have already been\npersisted to the database and _are_ available for use as slug sources.\nSo the above configuration would work.  The only drawback is that \nsaving the model to the database requires one extra query: the first one \nto save all the non-slug fields, and then a second one to update just \nthe slug field.\n  \nThis behaviour is a breaking change, and likely won't affect most users\n(unless you are doing some pre-saving validation on a model's slug field).\nWe feel the benefits outweigh the drawbacks, and so this will likely become\nthe new default behaviour in a future major release of the package.\nAlthough, to make the transition easier, you can configure this behaviour \nvia the `sluggableEvent` method the trait provides:\n\n```php\n    public function sluggableEvent(): string\n    {\n        \u002F**\n         * Default behaviour -- generate slug before model is saved.\n         *\u002F\n        return SluggableObserver::SAVING;\n\n        \u002F**\n         * Optional behaviour -- generate slug after model is saved.\n         * This will likely become the new default in the next major release.\n         *\u002F\n        return SluggableObserver::SAVED;\n    }\n```\n\nKeep in mind that you will need to use `SluggableObserver::SAVED` if you want\nto use your model's primary key as part of the source fields for your slugs.\n\n\n\n## Events\n\nSluggable models will fire two Eloquent model events: \"slugging\" and \"slugged\".\n  \nThe \"slugging\" event is fired just before the slug is generated.  If the callback\nfrom this event returns `false`, then the slugging is not performed. If anything\nelse is returned, including `null`, then the slugging will be performed.\n\nThe \"slugged\" event is fired just after a slug is generated.  It won't be called\nin the case where the model doesn't need slugging (as determined by the `needsSlugging()`\nmethod).\n\nYou can hook into either of these events just like any other Eloquent model event:\n\n```php\nPost::registerModelEvent('slugging', static function($post) {\n    if ($post->someCondition()) {\n        \u002F\u002F the model won't be slugged\n        return false;\n    }\n});\n\nPost::registerModelEvent('slugged', static function($post) {\n    Log::info('Post slugged: ' . $post->getSlug());\n});\n```\n\n\n\n## Configuration\n\nConfiguration was designed to be as flexible as possible. You can set up defaults \nfor all of your Eloquent models, and then override those settings for individual \nmodels.\n\nBy default, global configuration is set in the `config\u002Fsluggable.php` file. \nIf a configuration isn't set, then the package defaults are used. \nHere is an example configuration, with all the default settings shown:\n\n```php\nreturn [\n    'source'             => null,\n    'method'             => null,\n    'onUpdate'           => false,\n    'separator'          => '-',\n    'unique'             => true,\n    'uniqueSuffix'       => null,\n    'firstUniqueSuffix'  => 2,\n    'includeTrashed'     => false,\n    'reserved'           => null,\n    'maxLength'          => null,\n    'maxLengthKeepWords' => true,\n    'slugEngineOptions'  => [],\n];\n```\n\nFor individual models, configuration is handled in the `sluggable()` method that you\nneed to implement.  That method should return an indexed array where the keys represent\nthe fields where the slug value is stored and the values are the configuration for that\nfield.  This means you can create multiple slugs for the same model, based on different\nsource strings and with different configuration options.\n\n```php\npublic function sluggable(): array\n{\n    return [\n        'title-slug' => [\n            'source' => 'title'\n        ],\n        'author-slug' => [\n            'source' => ['author.lastname', 'author.firstname'],\n            'separator' => '_'\n        ],\n    ];\n}\n```\n  \n\n### source\n\nThis is the field or array of fields from which to build the slug. Each `$model->field` \nis concatenated (with space separation) to build the sluggable string. These can be \nmodel attributes (i.e. fields in the database), relationship attributes, or custom getters.\n \nTo reference fields from related models, use dot-notation. For example, the \nslug for the following book will be generated from its author's name and the book's title:\n\n```php\nclass Book extends Eloquent\n{\n    use Sluggable;\n\n    protected $fillable = ['title'];\n\n    public function sluggable(): array\n    {\n        return [\n            'slug' => [\n                'source' => ['author.name', 'title']\n            ]\n        ];\n    }\n    \n    public function author(): \\Illuminate\\Database\\Eloquent\\Relations\\BelongsTo\n    {\n        return $this->belongsTo(Author::class);\n    }\n}\n...\nclass Author extends Eloquent\n{\n    protected $fillable = ['name'];\n}\n```\n\nAn example using a custom getter:\n\n```php\nclass Person extends Eloquent\n{\n    use Sluggable;\n\n    public function sluggable(): array\n    {\n        return [\n            'slug' => [\n                'source' => 'fullname'\n            ]\n        ];\n    }\n\n    public function getFullnameAttribute(): string\n    {\n        return $this->firstname . ' ' . $this->lastname;\n    }\n}\n```\n\nIf `source` is empty, false or null, then the value of `$model->__toString()` is used\nas the source for slug generation.\n\n### method\n\nDefines the method used to turn the sluggable string into a slug. There are three \npossible options for this configuration:\n\n1. When `method` is null (the default setting), the package uses the default slugging\nengine -- [cocur\u002Fslugify](https:\u002F\u002Fgithub.com\u002Fcocur\u002Fslugify) -- to create the slug.\n\n2. When `method` is a callable, then that function or class method is used. The function\u002Fmethod \nshould expect two parameters: the string to process, and a separator string. \nFor example, to use Laravel's `Str::slug`, you could do:\n\n```php\n'method' => ['Illuminate\\\\Support\\\\Str', 'slug'],\n```\n\n3. You can also define `method` as a closure (again, expecting two parameters):\n\n```php\n'method' => static function(string $string, string $separator): string {\n    return strtolower(preg_replace('\u002F[^a-z]+\u002Fi', $separator, $string));\n},\n```\n\nAny other values for `method` will throw an exception.\n\nFor more complex slugging requirements, see [Extending Sluggable](#extending-sluggable) below.\n\n### onUpdate\n\nBy default, updating a model will not try and generate a new slug value.  It is assumed\nthat once your slug is generated, you won't want it to change (this may be especially\ntrue if you are using slugs for URLs and don't want to mess up your SEO mojo).\n\nIf you want to regenerate one or more of your model's slug fields, you can set those\nfields to null or an empty string before the update:\n\n```php\n$post->slug = null;\n$post->update(['title' => 'My New Title']);\n```\n\nIf this is the behaviour you want every time you update a model, then set the `onUpdate`\noption to true.\n\n### separator\n\nThis defines the separator used when building a slug, and is passed to the `method` \ndefined above. The default value is a hyphen.\n\n### unique\n\nThis is a boolean defining whether slugs should be unique among all models of the given type. \nFor example, if you have two blog posts and both are called \"My Blog Post\", then they \nwill both sluggify to \"my-blog-post\" if `unique` is false. This could be a problem, e.g. \nif you use the slug in URLs.\n\nBy setting `unique` to true, then the second Post model will sluggify to \"my-blog-post-1\". \nIf there is a third post with the same title, it will sluggify to \"my-blog-post-2\" \nand so on. Each subsequent model will get an incremental value appended to the end \nof the slug, ensuring uniqueness.\n\n### uniqueSuffix\n\nIf you want to use a different way of identifying uniqueness (other than auto-incrementing\nintegers), you can set the `uniqueSuffix` configuration to a function or callable that \ngenerates the \"unique\" values for you.\n \nThe function should take four parameters:\n1. the base slug (i.e. the non-unique slug)\n2. the separator string\n3. an `\\Illuminate\\Support\\Collection` of all the other slug strings that start with the same slug\n4. the first suffix to use (for the first slug that needs to be made unique)\nYou can then do whatever you want to create a new suffix that hasn't been used\nby any of the slugs in the collection.  For example, if you wanted\nto use letters instead of numbers as a suffix, this is one way to achieve that:\n\n```php\n'uniqueSuffix' => static function(string $slug, string $separator, Collection $list, $firstSuffix): string\n    {\n      $size = count($list);\n\n      return chr($size + 96);\n    }\n```\n\n### firstUniqueSuffix\n\nWhen adding a unique suffix, we start counting at \"2\", so that the list of\ngenerated slugs would look something like:\n- `my-unique-slug`\n- `my-unique-slug-2`\n- `my-unique-slug-3`\n- etc.\n\nIf you want to start counting at a different number (or pass a different value\ninto your custom `uniqueSuffix` function above), then you can define it here.\n\n> [!NOTE]\n> Prior versions of the package started with a unique suffix of `1`.  \n> This was switched to `2` in version 8.0.5, as it's a more\n> \"intuitive\" suffix value to attach to the second slug.\n\n### includeTrashed\n\nSetting this to `true` will also check deleted models when trying to enforce uniqueness. \nThis only affects Eloquent models that are using the \n[softDelete](http:\u002F\u002Flaravel.com\u002Fdocs\u002Feloquent#soft-deleting) feature. Default is `false`, \nso soft-deleted models don't count when checking for uniqueness.\n\n### reserved\n\nAn array of values that will never be allowed as slugs, e.g. to prevent collisions \nwith existing routes or controller methods, etc.. This can be an array, or a closure \nthat returns an array. Defaults to `null`: no reserved slug names.\n\n### maxLength\n\nSetting this to a positive integer will ensure that your generated slugs are restricted \nto a maximum length (e.g. to ensure that they fit within your database fields). By default, \nthis value is null and no limit is enforced.\n\n> [!NOTE]\n> If `unique` is enabled (which it is by default), and you anticipate having \n> several models with the same slug, then you should set this value to a few characters \n> less than the length of your database field. The reason why is that the class will \n> append \"-2\", \"-3\", \"-4\", etc., to subsequent models in order to maintain uniqueness. \n> These incremental extensions aren't included in part of the `maxLength` calculation.\n\n### maxLengthKeepWords\n\nIf you are truncating your slugs with the `maxLength` setting, than you probably\nwant to ensure that your slugs don't get truncated in the middle of a word.  For\nexample, if your source string is \"My First Post\", and your `maxLength` is 10,\nthe generated slug would end up being \"my-first-p\", which isn't ideal.\n\nBy default, the `maxLengthKeepWords` value is set to true which would trim the\npartial words off the end of the slug, resulting in \"my-first\" instead of \"my-first-p\".\n\nIf you want to keep partial words, then set this configuration to false.\n\n### slugEngineOptions\n\nWhen `method` is null (the default setting), the package uses the default slugging\nengine -- [cocur\u002Fslugify](https:\u002F\u002Fgithub.com\u002Fcocur\u002Fslugify) -- to create the slug.\nIf you want to pass a custom set of options to the Slugify constructor when the engine\nis instantiated, this is where you would define that. \nSee [the documentation](https:\u002F\u002Fgithub.com\u002Fcocur\u002Fslugify#more-options)\nfor Slugify for what those options are.  Also, look at \n[customizeSlugEngine](#customizeslugengine) for other ways to customize Slugify\nfor slugging.\n\nA common use for this is to turn on a different ruleset for a specific language.\nFor example the string `Jyväskylä` will slug to `jyvaeskylae` using the default settings.\nIn Finnish, it really should slug to `jyvaskyla`, so for that to work, you need to enable \nthe Finnish ruleset for the attribute you are slugging:\n\n```php\npublic function sluggable(): array\n{\n    return [\n        'slug' => [\n            'source' => 'title',\n            'slugEngineOptions' => [\n                'ruleset' => 'finnish'\n            ]\n        ]\n    ];\n}\n```\n\nThis can also be accomplished with the [customizeSlugEngine](#customizeslugengine) method\n(which, unless you add custom logic, will apply to _all_ attributes on the model):\n\n```php\npublic function customizeSlugEngine(Slugify $engine, string $attribute): \\Cocur\\Slugify\\Slugify\n{\n    $engine->activateRuleSet('finnish');\n\n    return $engine;\n}\n```\n\n## Short Configuration\n\nThe package supports a really short configuration syntax, if you are truly lazy:\n\n```php\npublic function sluggable(): array\n{\n    return ['slug'];\n}\n```\n\nThis will use all the default options from `config\u002Fsluggable.php`, use the model's\n`__toString()` method as the source, and store the slug in the `slug` field.\n\n\n\n## Extending Sluggable\n\nSometimes the configuration options aren't sufficient for complex needs (e.g. maybe \nthe uniqueness test needs to take other attributes into account).\n\nIn instances like these, the package offers hooks into the slugging workflow where you\ncan use your own functions, either on a per-model basis, or in your own trait that extends \nthe package's trait.\n\n> [!NOTE]\n> If you are putting these methods into your own trait, you will \n> need to indicate in your models that PHP should use _your_ trait methods \n> instead of the packages (since a class can't use two traits with the\n> same methods), e.g.\n>\n> ```php\n> \u002F**\n>  * Your trait where you collect your common Sluggable extension methods\n>  *\u002F\n> class MySluggableTrait {\n>     public function customizeSlugEngine(...) {}\n>     public function scopeWithUniqueSlugConstraints(...) {}\n>     \u002F\u002F etc.\n> }\n> \n> \u002F**\n>  * Your model\n>  *\u002F\n> class MyModel {\n>     \u002F\u002F Tell PHP to use your methods instead of the packages:\n>     use Sluggable,\n>         MySluggableTrait  {\n>             MySluggableTrait::customizeSlugEngine insteadof Sluggable;\n>             MySluggableTrait::scopeWithUniqueSlugConstraints insteadof Sluggable;\n>         }\n> \n>     \u002F\u002F ...\n> }\n> ```\n\n\n### customizeSlugEngine\n\n```php\n\u002F**\n * @param \\Cocur\\Slugify\\Slugify $engine\n * @param string $attribute\n * @return \\Cocur\\Slugify\\Slugify\n *\u002F\npublic function customizeSlugEngine(Slugify $engine, string $attribute): \\Cocur\\Slugify\\Slugify\n{\n    \u002F\u002F ...\n    return $engine;\n}\n```\n\nIf you extend this method, the Slugify engine can be customized before slugging occurs.\nThis might be where you change the character mappings that are used, or alter language files, etc..\n\nYou can customize the engine on a per-model and per-attribute basis (maybe your model has \ntwo slug fields, and one of them needs customization).\n\nTake a look at `tests\u002FModels\u002FPostWithCustomEngine.php` for an example.\n\nAlso, take a look at the [slugEngineOptions](#slugengineoptions)\nconfiguration for other ways to customize Slugify.\n\n### scopeWithUniqueSlugConstraints\n\n```php\n\u002F**\n * @param \\Illuminate\\Database\\Eloquent\\Builder $query\n * @param \\Illuminate\\Database\\Eloquent\\Model $model\n * @param string $attribute\n * @param array $config\n * @param string $slug\n * @return \\Illuminate\\Database\\Eloquent\\Builder\n *\u002F\npublic function scopeWithUniqueSlugConstraints(\n    Builder $query,\n    Model $model,\n    string $attribute,\n    array $config,\n    string $slug\n): Builder\n{\n    \u002F\u002F ...\n}\n```\n\nThis method is applied to the query that is used to determine \nif a given slug is unique.  The arguments passed to the scope are:\n\n* `$model` -- the object being slugged\n* `$attribute` -- the slug field being generated,\n* `$config` -- the configuration array for the given model and attribute\n* `$slug` -- the \"base\" slug (before any unique suffixes are applied)\n\nFeel free to use these values anyway you like in your query scope.  As an example, look at \n`tests\u002FModels\u002FPostWithUniqueSlugConstraints.php` where the slug is generated for a post from\nits title, but the slug is scoped to the author.  So Bob can have a post with the same title\nas Pam's post, but both will have the same slug.\n\n### scopeFindSimilarSlugs\n\n```php\n\u002F**\n * Query scope for finding \"similar\" slugs, used to determine uniqueness.\n *\n * @param \\Illuminate\\Database\\Eloquent\\Builder $query\n * @param string $attribute\n * @param array $config\n * @param string $slug\n * @return \\Illuminate\\Database\\Eloquent\\Builder\n *\u002F\npublic function scopeFindSimilarSlugs(Builder $query, string $attribute, array $config, string $slug): Builder\n{\n    \u002F\u002F ...\n}\n```\n\nThis is the default scope for finding \"similar\" slugs for a model.  Basically, the package looks for existing\nslugs that are the same as the `$slug` argument, or that start with `$slug` plus the separator string.\nThe resulting collection is what is passed to the `uniqueSuffix` handler.\n\nGenerally, this query scope (which is defined in the Sluggable trait) should be left alone.\nHowever, you are free to overload it in your models.\n\n\n\n## SluggableScopeHelpers Trait\n\nAdding the optional `SluggableScopeHelpers` trait to your model allows you to work with models\nand their slugs.  For example:\n\n```php\n$post = Post::whereSlug($slugString)->get();\n\n$post = Post::findBySlug($slugString);\n\n$post = Post::findBySlugOrFail($slugString);\n```\n\nBecause models can have more than one slug, this requires a bit more configuration.\nSee [SCOPE-HELPERS.md](SCOPE-HELPERS.md) for all the details.\n\n\n\n## Route Model Binding\n\nSee [ROUTE-MODEL-BINDING.md](ROUTE-MODEL-BINDING.md) for details.\n\n\n\n## Bugs, Suggestions, Contributions and Support\n\nThanks to [everyone](https:\u002F\u002Fgithub.com\u002Fcviebrock\u002Feloquent-taggable\u002Fgraphs\u002Fcontributors)\nwho has contributed to this project!\n\nPlease use [GitHub](https:\u002F\u002Fgithub.com\u002Fcviebrock\u002Feloquent-sluggable) for reporting bugs, \nand making comments or suggestions.\n \nSee [CONTRIBUTING.md](CONTRIBUTING.md) for how to contribute changes.\n\n\n\n## Copyright and License\n\n[eloquent-sluggable](https:\u002F\u002Fgithub.com\u002Fcviebrock\u002Feloquent-sluggable)\nwas written by [Colin Viebrock](http:\u002F\u002Fviebrock.ca) and is released under the \n[MIT License](LICENSE.md).\n\nCopyright (c) 2013 Colin Viebrock\n","cviebrock\u002Feloquent-sluggable 是一个用于 Laravel 框架中 Eloquent 模型的 slug 生成工具。它能够自动为模型生成 URL 友好的字符串，支持自定义来源字段、分隔符、唯一性检查等配置选项，以确保生成的 slug 符合应用需求。该库还提供了事件监听和路由模型绑定等功能，方便开发者根据具体场景进行扩展或定制。适用于需要在 Web 应用中使用简洁且唯一的 URL 标识符的各种场合，如博客文章链接、产品详情页等。",2,"2026-06-11 03:17:57","top_language"]