A CakePHP behavior to automatically create and store slugs.
- Input data can consist of one or many fields
- Slugs can be unique and persistent, ideal for lookups by slug
- Multibyte aware, umlauts etc will be properly replaced
Key | Default | Description |
---|---|---|
label | `null` |
|
field | `'slug'` | The slug field name |
overwriteField | 'overwrite_slug' | The boolean field/property to trigger overwriting if "overwrite" is false |
mode | `'url'` |
|
separator | `-` | The separator to use |
length | `null` | Set to 0 for no length. Will be auto-detected if possible via schema. |
overwrite | `false` |
has the following values
|
unique | `false` |
has the following values
|
case | `null` |
has the following values
|
replace | see code | Custom replacements as array. `Set to null` to disable. |
on | `'beforeRules'` | `beforeSave` or `beforeMarshal` or `beforeRules`. |
scope | `[]` | Certain conditions to use as scope. |
tidy | `true` | If cleanup should be run on slugging. |
Attach it to your models in initialize()
like so:
$this->addBehavior('Tools.Slugged');
We want to store categories and we need a slug for nice SEO URLs like /category/[slugname]/
.
$this->addBehavior('Tools.Slugged',
['label' => 'name', 'unique' => true, 'mode' => 'ascii']
);
Upon creating and storing a new record it will look for content in "name" and create a slug in "slug" field.
With the above config on "edit" the slug will not be modified if you alter the name. That is important to know. You cannot just change the slug, as the URL is most likely indexed by search engines now.
If you want to do that, you would also need a .htaccess rewrite rule to 301 redirect from the old to the new slug. So if that is the case, you could add an "overwrite field" to your form.
echo $this->Form->field('overwrite_slug', ['type' => 'checkbox']);
Once that boolean checkbox is clicked it will then perform the slug update on save.
If we just append the slug to the URL, such as /category/123-[slugname]
, then we don't need to persist the slug.
$this->addBehavior('Tools.Slugged',
['label' => 'name', 'overwrite' => true, 'mode' => 'ascii', 'unique' => true]
);
Note that we don't need "unique" either then.
Each save now re-triggers the slug generation.
You can pass your own callable for slugging into the mode
config.
And you can even use a static method on any class this way (given it has a static slug()
method):
$this->addBehavior('Tools.Slugged', ['mode' => [MySlugger::class, 'slug']]);
Tip: Use 'mode' => [Text::class, 'slug']
if you want to avoid using the deprecated Inflector::slug()
method.
Don't forget the use statement at the top of the file, though (use Tools\Utility\Text;
).
If you quickly want to find a record by its slug, use:
->find()->find('slugged', slug: $slug)->firstOrFail();
etc