Skip to main content

Headless CMS

A content platform adds types over time — pages, articles, landing pages, case studies. Adding a route file entry per type is the kind of duplication that eventually falls out of sync with the models.

// config/polyslug.php — map each type to its model
'types' => [
'pages' => \App\Models\Page::class,
'articles' => \App\Models\Article::class,
],

// one catch-all route resolves the right model from {type}
Route::get('/{type}/{polyslug}', [ContentController::class, 'show'])->middleware('polyslug.canonical');

The {polyslug} binding is registered by the package, so the route stays cacheable and no Route::bind() of your own is needed. An unknown type or an unresolvable slug is a 404; self-healing works exactly as it does on a per-type route.

Adding a content type is then a one-line config change.

Resolving outside a route

The same lookup is available directly, which is what a preview endpoint or an import command wants:

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

It returns null for an unknown type or an unresolvable value.

Publish state still applies

The resolver honors each model's polyslugResolveQuery(), so registering a type does not make its drafts reachable.

See also