Artisan commands
php artisan sluggable:regenerate "App\Models\Product" # backfill empty slugs
php artisan sluggable:regenerate "App\Models\Topic" --locale=de # backfill a new locale
php artisan sluggable:regenerate "App\Models\Product" --mode=stale --history --dry-run
php artisan sluggable:regenerate "App\Models\Product" --mode=all --force --chunk=1000 --queue
php artisan sluggable:indexes "App\Models\Topic" --column=slug --dry-run
php artisan sluggable:duplicates "App\Models\Product" --column=slug --locale=sk{model} accepts a class name or a morph alias; it must be an Eloquent model implementing Sluggable. Each command is also on the facade, for scheduled tasks, deploy scripts and your own commands:
use RoundlyConsulting\Sluggable\Enums\RegenerationMode;
use RoundlyConsulting\Sluggable\Facades\Slugs;
Slugs::model(Product::class)->regenerate(mode: RegenerationMode::Stale, withHistory: true, dryRun: true);
Slugs::model(Product::class)->queueRegeneration(mode: RegenerationMode::All, chunk: 1000, force: true);
Slugs::model(Topic::class)->indexes(dryRun: true);
Slugs::model(Product::class)->duplicates(column: 'slug', locale: 'sk');sluggable:regenerate
| Option | Effect |
|---|---|
--mode=missing | Default. Fill empty slugs and missing locales. |
--mode=stale | Recompute; replace only values whose base changed (no churn), and drop a suffix whose bare base is free again. |
--mode=all | Recompute everything; asks for confirmation unless --force. |
--column, --locale | Restrict the run; --locale=de backfills a new locale. |
--chunk | Rows per chunk (1–10000, default 500). |
--dry-run | Print up to 20 changes (key, column, locale, old → new); write nothing. |
--history | Record retired values even for definitions without keepHistory(). |
--without-events | Do not dispatch SlugChanged. |
--force | Bypass locks (lockWhen / locked) and the confirmation. |
--queue | Dispatch one RegenerateSlugsJob per chunk of keys. |
Rows are scanned without global scopes (trashed and scoped-away rows included), chunked by key, and each changed row is saved normally — history and events as usual. Locks are respected unless --force. The queued job serialises ids and options, never models. SlugsRegenerated fires at the end of each run or queued chunk, but not on dry runs.
sluggable:indexes
Runs SlugIndexes::forModel() for the model and prints the DDL, the indexes that already exist and a summary. Run it after adding a locale to create that locale’s indexes, and with --dry-run to preview. Definition errors, such as colliding locales, fail the command.
sluggable:duplicates
Lists values a unique index would reject — grouped by scope values, locale and slug, without global scopes — plus values longer than maxLength; a notUnique() column gets no index, so only its over-long values are listed. Run it before adding an index to existing data. It only reports: it never changes data and exits with 0 either way.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.