Model API
The HasPolyslug trait provides the implementations; the Sluggable interface is the
type your code and the package both depend on.
Reading slugs
| Method | Returns | Notes |
|---|---|---|
currentSlug(?string $locale = null) | ?string | The current slug for the given (or active) locale, or null. |
slugLocales() | list<string> | The locales that currently have a slug. |
polyslugAddressLocales() | list<string> | Only on a model implementing ProvidesAddressLocales — the locales it is served under, when that differs from the locales it holds a slug for. |
slugHistory(?string $locale = null) | list<string> | Superseded slugs for a locale, newest first. |
slugs() | MorphMany | The raw slug rows, for when you need more than the helpers give. |
Route keys and paths
| Method | Returns | Notes |
|---|---|---|
getRouteKey() | string | Laravel's hook; returns the canonical route key so route() and url() are correct by default. |
polyslugRouteKey(?string $locale = null) | string | The {slug}_{encodedId} key for the given (or active) locale — or the slug/path alone, with no delimiter and no token, on an idLess model. |
polyslugRouteKeyForLocale(string $locale) | string | The same for an explicit locale — never reads the ambient app locale. Use it in sitemaps, queued jobs, feeds and CLI. |
polyslugPath(?string $locale = null, int $maxDepth = 20) | string | The slash-joined slug path (ancestors plus own) for a nested model; the own slug when not nested. |
shortLink(?string $locale = null) | string | A stable short-link token for this model and locale. |
Preloading
| Method | Returns | Notes |
|---|---|---|
static polyslugPreload(iterable $models) | void | Warms the identity tokens for a whole set in one round trip — the companion to eager-loading slugs. See rendering a list of links. |
The only static on this list, because it works on a set rather than on one model:
$pages = Page::query()->with('slugs')->paginate();
Page::polyslugPreload($pages);
Write it unconditionally. On an encoder that derives its token from the key alone — Sqids,
UUID, ULID, the raw key — it is a no-op, and deliberately a silent one: an optimization hint
you can only write after learning which encoder is configured is a configuration question in
disguise. Models are grouped by their resolved encoder, so a set whose members carry
different #[Polyslug(encoder: ...)] attributes is still correct. Anything in the iterable
that is not an instance of the model you called it on is skipped rather than fataling — a
hint must not be able to break a render.
Writing slugs
| Method | Returns | Notes |
|---|---|---|
setSlug(string $locale, ?string $source = null) | void | Write the current slug for a locale from the given source, or from the model's own source. Bypasses immutable. |
polyslugSync(?string $locale = null) | void | Generate or refresh the current slug from the model's source. Idempotent, and a no-op when a current slug exists and either the source is unchanged or the model is immutable. |
polyslugOnDeleted() | void | Apply the delete policy: cascade slug rows on hard or force delete, release on soft-delete when configured. |
Multilingual output
| Method | Returns | Notes |
|---|---|---|
polyslugUrls(callable $urlUsing) | array<string, string> | An absolute URL per locale that has a current slug and is routable. |
hreflangLinks(callable $urlUsing, ?string $xDefault = null) | array<string, string> | The above plus a reciprocal, self-referential x-default. Empty when there are no URLs. |
hreflangTags(callable $urlUsing, ?string $xDefault = null) | HtmlString | Rendered <link rel="alternate" hreflang="…"> tags. |
sitemapAlternateTags(callable $urlUsing, ?string $xDefault = null) | HtmlString | Rendered <xhtml:link rel="alternate" hreflang="…"> alternates for a sitemap entry. |
The callable receives (string $locale, string $routeKey) and returns an absolute URL.
Hooks you override
| Method | Default | Purpose |
|---|---|---|
polyslugResolveQuery(Builder $query): Builder | no-op | The resolution gate. Constrain which rows a slug may resolve to. |
polyslugIsRoutable(?string $locale = null): bool | true | The output filter. Keep a model or locale out of hreflang sets and sitemaps. |
polyslugParent(): ?Sluggable | null | The parent in a nested hierarchy. |
polyslugSupersededBy(): ?Sluggable | null | The successor a superseded model redirects to. |
polyslugIsGone(): bool | false | Whether the model is permanently gone. |
polyslug(): PolyslugConfig | (not implemented) | Only on models implementing ConfiguresPolyslug — computed configuration. |
polyslugResolutionScope(): ?array | null | The scope a slug-only lookup happens in, as column => value. Only needed when the scope lives in the URL rather than the environment — see Slug-only URLs. |
polyslugRobotsDirective(?string $locale = null): string|array | 'none' | The robots directive a gated locale gets — see laravel/head integration. Only consulted when polyslugIsRoutable() said no, and must still contain noindex or none. |
polyslugReservedWords(array $inherited): array | returns $inherited | Filter, replace or clear the reserved words this model inherits. Offered the model's own reserved, polyslug.reserved.global and the route-derived words. |
Gate-respecting lookup
polyslugResolveByKey(mixed $key): ?static resolves this model type by primary key
through polyslugResolveQuery(), so tenant and visibility scoping applies on every
path — including /go short links. Prefer it over find() anywhere a gated lookup is
what you mean.
polyslugResolveSelf(): ?static re-resolves this instance through its own gate: the same
row when the caller may see it, null when it may not. On a model that came from route
binding it is a no-op — binding already went through the gate. It is for a model you obtained
some other way and are about to disclose something about, which is exactly what the package
does with a polyslugSupersededBy() successor before rendering its route key into a
Location header.
Blade
@polyslugHreflang($model, $resolver)
The directive shorthand for hreflangTags().