TL;DR: I released a CakePHP 5.x plugin that validates user-input URL slugs against reserved words and application routes to prevent collisions.

What Does This Plugin Do?
In web applications, you often want to let users choose their own profile URL slug – something like example.com/nojimage.
But if a user registers a slug like admin, login, or api, it collides with your application’s routes and causes serious problems.
SlugGuard is a CakePHP 5.x plugin that prevents these slug collisions. It provides three validation rules:
- SlugValidator – Format check (lowercase alphanumerics and hyphens only, must start and end with alphanumeric)
- IsNotReservedSlug – Checks against approximately 710 reserved words (
admin,login,api,settings, etc.) - IsNotRouteConflict – Dynamically checks against routes registered in CakePHP
Installation
composer require elstc/cakephp-slug-guard
bin/cake plugin load Elastic/SlugGuard
After loading the plugin, run the migration to create the reserved words table.
bin/cake migrations migrate --plugin Elastic/SlugGuard
bin/cake slug_guard sync
The sync command imports approximately 710 built-in reserved words into the database. These cover common terms from admin, dashboard, login, api to social media names like facebook, twitter, and github.
Usage
Reserved Word & Route Conflict Check (Application Rule)
Add IsNotReservedSlug and IsNotRouteConflict in your table class’s buildRules method.
use Elastic\SlugGuard\Model\Rule\IsNotReservedSlug;
use Elastic\SlugGuard\Model\Rule\IsNotRouteConflict;
// In your Table class
public function buildRules(RulesChecker $rules): RulesChecker
{
$rules->add(new IsNotReservedSlug('slug'), 'reservedSlug', [
'errorField' => 'slug',
'message' => 'This slug is reserved',
]);
$rules->add(new IsNotRouteConflict('slug'), 'routeConflict', [
'errorField' => 'slug',
'message' => 'This slug conflicts with an existing route',
]);
return $rules;
}
Pass the field name to check as the constructor argument. You can use it for fields other than slug – for example, username.
Slug Format Check (Validator)
SlugValidator is used as a Validator provider. It allows only lowercase alphanumerics and hyphens, and also enforces length constraints.
use Elastic\SlugGuard\Validation\SlugValidator;
// In your Table class
public function validationDefault(Validator $validator): Validator
{
$validator->setProvider('slugValidator', SlugValidator::class);
$validator->add('slug', 'validSlug', [
'rule' => ['isValid'],
'provider' => 'slugValidator',
'message' => 'Only lowercase alphanumerics and hyphens are allowed',
]);
return $validator;
}
The default length is 4 to 24 characters, but you can customize it.
// Change to minimum 3, maximum 32 characters
$validator->add('slug', 'validSlug', [
'rule' => ['isValid', 3, 32],
'provider' => 'slugValidator',
]);
Managing Reserved Words
You can add, remove, and list reserved words using CLI commands.
# List reserved words
bin/cake slug_guard list
# Search
bin/cake slug_guard list --search admin
# Add a reserved word
bin/cake slug_guard add my-reserved-word
# Remove a reserved word
bin/cake slug_guard remove my-reserved-word
# Import from file (one slug per line, # for comments)
bin/cake slug_guard import path/to/custom-slugs.txt
# Extract routes from your application and add as reserved words
bin/cake slug_guard routes | bin/cake slug_guard add
# Sync config file with database (supports dry-run)
bin/cake slug_guard sync --dry-run
Design Highlights
Dynamic Route Conflict Detection
IsNotRouteConflict dynamically retrieves the first segment of routes registered in CakePHP and checks for collisions. When you change your routing configuration, it automatically picks up the changes – no manual maintenance needed.
Database-Managed Reserved Words
Reserved words are stored in the reserved_slugs table. The slug string itself is used as the primary key, making existence checks fast. In addition to CLI add/remove commands, it supports file imports and stdin input for operational flexibility.
Aside
I’ve had this mechanism for quite a while and needed it in many real projects, but never got around to extracting it as a plugin. Thanks to AI agents, I was able to quickly handle the code cleanup and documentation needed to release it as a plugin, and finally got it published.
For this plugin specifically, the CLI command implementation was almost entirely handled by the AI agent.
So, when building an application that lets users freely input slugs, reserved word checking is a subtle but important concern – forgetting it leads to headaches later. With SlugGuard, format checking, reserved word checking, and route conflict checking are all handled in one place, so you can implement slug input features with confidence.
It works with CakePHP 5.x + PHP 8.2 or later. Give it a try!