NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages

Open source

Sluggable for Laravel

Install
composer require roundly-consulting/sluggable-for-laravel
Requires: PHP ^8.4 · Laravel ^12.0|^13.0

Overview

Single- and multi-language slugs for Eloquent. Store a plain string slug or a json/jsonb locale map with one slug per language, declare any number of slug columns per model, and keep them unique globally or per scope — enforced by engine-native unique indexes. On top come locale-aware route model binding, validation rules, Artisan tooling and an optional slug history that 301-redirects old URLs. Native Laravel only, MIT-licensed, with zero third-party runtime dependencies — and with the default options every slug matches Str::slug() for ordinary input of up to 255 characters.

What you get

Locale-map slugs

Plain string slugs or json/jsonb locale maps — one slug per language, each transliterated by that language’s rules.

Str::slug() compatible

With the default options every slug matches Str::slug() for ordinary input of up to 255 characters, so adopting the package keeps the URLs you already have.

Race-safe uniqueness

Unique globally, per tenant or per parent — backed by engine-native unique indexes and an automatic retry when two writers collide.

Locale-aware routing

Implicit, scoped and soft-deleted route bindings resolve by slug in the current locale, with an optional primary-key fallback.

SEO slug history

Retired slugs 301-redirect to the current URL without revealing drafts, trashed rows or other tenants’ records.

Policies & locks

Decide how updates, hand-typed slugs and empty sources behave, and freeze a slug once a page is published.

Facade, DI or Artisan

Slugs::model(Product::class) backfills slugs, audits duplicates and builds indexes — or inject SlugManager, run an action or use Artisan.

Documentation

Installation

Install via Composer; publish the config, translations and slug-history migration only when you need them.

Configuration

Every config key with its default and env variable — formatting, uniqueness, update policy, locales, limits, retries and history.

Quick start

Add the HasSlug trait and the Sluggable contract — with zero config, a unique slug is generated from name on create.

Slug definitions

Declare any number of slug columns with slugOptions() or #[Slug] attributes — sources, formatting, uniqueness, lifecycle and routing.

The Slugs facade

One entry point for everything that is not a model hook — flat verbs for one model, and Slugs::model(Product::class) for class-wide work.

DI and actions

Inject SlugManager for the facade’s API without static calls, or run the action behind a method directly with its DTO.

Formatting & suffixes

How the pipeline transliterates, strips and truncates — plus separators, affixes, reserved words, custom sluggers and collision suffixes.

Locale maps

Multi-language slugs in one json/jsonb column — per-locale transliteration, target locales, fallback chains and your own locale source.

Update, manual & lock policies

Control when slugs regenerate, how hand-typed values are treated, what an empty source does, and how to freeze a slug.

Uniqueness & concurrency

Global, scoped or closure-based uniqueness, soft-delete handling, bounded probing and an automatic retry when two writers collide.

Schema & unique indexes

Blueprint macros for slug columns and engine-native unique indexes for string and locale-map slugs on PostgreSQL, MySQL and SQLite.

Querying

Find models by slug — exact locale or the fallback chain, any locale, lists — with scopes that stay safe for count() and paginate().

Route model binding

Implicit, custom-column, scoped and soft-deleted route binding by slug, locale-aware URLs and an optional primary-key fallback.

Slug history & redirects

Keep retired slugs and 301-redirect old URLs to the current one — without revealing drafts, trashed rows or other tenants’ records.

Validation

UniqueSlug and ValidSlug rules with the exact generation semantics — scoped, locale-aware and safe against cross-tenant probing.

Events & exceptions

SlugChanged, SlugCollisionRetried and SlugsRegenerated events, plus the typed exception hierarchy behind every failure.

Artisan commands

Backfill and regenerate slugs, create engine-native indexes, and audit duplicates before adding a unique index.

Adoption & limitations

Map the options of an existing slug setup onto sluggable, compose it with other traits, and know exactly where its limits are.

Testing

Test slug generation, events, history redirects and queued regeneration in your own Pest suite through the public API — no special setup.

Requirements

PHP 8.4+ with ext-json and ext-mbstring, Laravel 12 or 13, and PostgreSQL, MySQL/MariaDB or SQLite for the unique-index DDL.

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 crypto

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