Skip to main content

History, events and immutability

SlugChanged

Polyslug\Events\SlugChanged fires whenever a current slug is created or changed — previous is null on first generation. It is the natural hook for cache busting, search reindexing, or sitemap regeneration:

use Polyslug\Events\SlugChanged;

Event::listen(function (SlugChanged $event) {
// $event->model, $event->locale, $event->slug, $event->previous
});

SlugRedirected

Enable polyslug.analytics.enabled to also dispatch Polyslug\Events\SlugRedirected on every self-healing redirect — the requested key, the canonical URL, the model, the locale and the status. It is a fire-and-forget hook for measuring link rot, warming a cache, or purging a CDN.

// config/polyslug.php
'analytics' => ['enabled' => true],

It is off by default, and even when on it is only the event dispatch — nothing writes synchronously on the hot path unless your listener does. The event is keyed on the stable model rather than on the churny slug, so a rename does not double-count.

Both payloads are listed in the events reference.

Immutable slugs

Freeze a model's slug after its first generation so later edits to the source never move it — ideal for permalinks:

#[Polyslug(source: 'title', immutable: true)]

Editing the title of a frozen model is then a no-op as far as the URL is concerned: no new slug, no redirect, no history entry. Use it where the URL is a citation — a published regulation, an issued invoice, a press release — and correcting a typo in the headline must not move the document.

setSlug() remains the deliberate escape hatch for setting a locale's slug explicitly.

Reading the history

Superseded slugs are kept so old URLs keep resolving, and read newest-first:

$model->slugHistory(); // superseded slugs for the active locale, newest first
$model->slugHistory('de'); // for an explicit locale

History is per locale, and it holds only superseded slugs — the current one comes from currentSlug(). Nothing prunes it, which is what keeps every URL you have published resolvable; see Gone and superseded for the deliberate ways to retire a URL.