Skip to main content

Polymorphic routing

Serve every content type through one route. Register the type map:

// config/polyslug.php
'types' => [
'page' => \App\Models\Page::class,
'article' => \App\Models\Article::class,
],

Then bind a {type}/{polyslug} route — the {polyslug} parameter resolves to the right model based on {type}, and self-healing still applies:

Route::get('/{type}/{polyslug}', [ContentController::class, 'show'])
->middleware('polyslug.canonical');

The polyslug route binding is registered by the package itself, so no Route::bind() call of your own is needed and the route stays safe to cache.

An unknown type or an unresolvable slug yields a 404. Every registered class must be an Eloquent model implementing Sluggable.

Resolving manually

$model = app(\Polyslug\PolyslugResolver::class)->resolve('page', 'my-title_aB3xK');

resolve() returns null for an unknown type or an unresolvable value — the caller turns that into a 404. Use it wherever you need the same lookup outside a route, for example in a preview endpoint or a console command.

The gate still applies

The polymorphic resolver honors polyslugResolveQuery() exactly like a bound route does, so a draft or a foreign tenant's record is a 404 here too. Registering a type in polyslug.types does not widen what is reachable.

See the headless CMS recipe for the full wiring.