laravel-sluggable

repository·main·Indexed 23 days ago

https://github.com/spatie/laravel-sluggable

A Laravel package that automatically generates unique slugs for Eloquent models upon creation or update. It features automatic collision handling with suffixes, self-healing URLs via 308 redirects to maintain link integrity, and support for translatable slugs through spatie/laravel-translatable. The package allows for custom slug generation and route key logic by overriding action classes such as GenerateSlugAction and BuildSelfHealingRouteKeyAction.

Tokens
12K
Snippets
39
Records
76
Agent score
77%

What's inside spatie/laravel-sluggable

  1. Overview of package features

    main

    Beyond basic slug generation, laravel-sluggable provides:

    • Self-healing URLs: Uses {slug}-{id} route keys and 308 redirects to ensure old links don't break when slugs change.
    • Translatable slugs: Integrates with spatie/laravel-translatable to support one slug per locale.
    • Overridable actions: Allows you to swap the slug generator or self-healing logic with your own classes via configuration.
    • Laravel Boost skill: Includes a bundled skill to help AI assistants use the package effectively.
  2. What the Laravel Boost skill covers

    main

    The Laravel Boost skill is activated when an AI assistant query mentions slugs, permalinks, the HasSlug trait, the HasTranslatableSlug trait, the #[Sluggable] attribute, SlugOptions, findBySlug, self-healing URLs, or stale slug redirects.

    It provides guidance on:

    • Choosing between the #[Sluggable] attribute and the HasSlug trait.
    • Generating migrations for slug columns (including the nullable then unique backfill pattern and JSON requirements for translatable slugs).
    • Configuring separator, length, language, uniqueness, and scope.
    • Wiring implicit route binding via the slug column.
    • Enabling self-healing URLs and customizing the 308 redirect via the SelfHealing facade.
    • Swapping default action classes via config/sluggable.php.
  3. Key features of laravel-sluggable

    main

    The package provides several advanced capabilities:

    • Unique slugs: Automatic collision handling with suffixes.
    • Self-healing URLs: Uses primary keys in routes to maintain link integrity via 308 redirects.
    • Translatable slugs: Supports spatie/laravel-translatable via the HasTranslatableSlug trait.
    • Overridable actions: You can swap the slug generator or self-healing logic via a configuration file.
    • Laravel Boost compatibility: Automatically discovered by AI assistants for scaffolding.
  4. New features in v4

    main

    The following features are available in v4 and do not require migration:

    • #[Sluggable] Attribute: An alternative to using the HasSlug trait. Existing trait-based models remain fully supported.
    • Self-healing URLs: Can be enabled via selfHealing() on the slug options or by setting selfHealing: true on the attribute (disabled by default).
    • Overridable Actions: You can configure the following actions via config/sluggable.php:
      • generate_slug
      • build_self_healing_route_key
      • extract_identifier_from_self_healing_route_key
    • Laravel Boost Skill: A bundled skill to assist AI agents in using the package.
  5. Enable self-healing URLs to prevent broken links

    main

    By default, changing a slug will break existing links (returning a 404). To prevent this, you can enable selfHealing.

    When selfHealing is enabled, the route key format changes to {slug}-{id}. Because the primary key (id) is included in the URL, Laravel can still resolve the model even if the slug has changed. When a user visits an old URL, the package will issue a 308 redirect to the current slugged URL.

  6. How to override underlying actions

    main

    The package allows you to swap out the low-level logic for three core operations by providing custom action classes in the configuration. To ensure compatibility and type-checking, your replacement classes must extend the default action class provided by the package.

    The three available actions are:

    1. generate_slug: Handles slug generation during create and update events.
      • Default: Spatie\Sluggable\Actions\GenerateSlugAction
    2. build_self_healing_route_key: Composes the route key string (default format is {slug}{separator}{id}).
      • Default: Spatie\Sluggable\Actions\BuildSelfHealingRouteKeyAction
    3. extract_identifier_from_self_healing_route_key: Parses an incoming route value back into its slug and identifier components.
      • Default: Spatie\Sluggable\Actions\ExtractIdentifierFromSelfHealingRouteKeyAction
  7. Implement self-healing URLs

    main

    Self-healing URLs combine the slug with the primary key (e.g., hello-world-5). This allows the slug portion to change without breaking existing links; if a user visits an old slug, the package automatically performs a 308 redirect to the new canonical URL.

    Requirements:

    • You must use the HasSlug trait. Using selfHealing: true on the #[Sluggable] attribute without the trait will throw a SelfHealingRequiresTrait error.

    Configuration

    Enable it via SlugOptions:

    public function getSlugOptions(): SlugOptions
    {
        return SlugOptions::create()
            ->generateSlugsFrom('title')
            ->saveSlugsTo('slug')
            ->selfHealing();
    }

    You can also customize the separator between the slug and the ID:

    ->selfHealing(separator: '--'); // route key: "hello-world--5"

    Behavior

    • GET /posts/hello-world-5200 OK (Canonical)
    • GET /posts/outdated-slug-5308 redirect to /posts/hello-world-5
    • GET /posts/hello-world-99404 (ID 99 does not exist)
  8. How `skipGenerateWhen()` works in v4

    main

    In v4, the closure passed to skipGenerateWhen() is evaluated on every save, rather than being cached once. This allows the closure to react to changes in the model's state during the lifecycle of a single request.

    Note: The SlugOptions::$skipGenerate boolean property has been removed. If you were accessing this property directly, you must switch to using the closure-based skipGenerateWhen() method.

    return SlugOptions::create()
        ->generateSlugsFrom('title')
        ->saveSlugsTo('slug')
        ->skipGenerateWhen(fn () => $this->state === 'draft');
  9. Choose between the Sluggable attribute and the HasSlug trait

    main

    The package offers two ways to configure slug generation on an Eloquent model:

    1. #[Sluggable] attribute: Best for most standard use cases. It is a lightweight way to define source and destination columns directly on the class.
    2. HasSlug trait: Required if you need advanced features like callables for source columns, custom scopes, custom suffix generators, translatable slugs, findBySlug(), or self-healing URLs.

    Note: If both are present on a model, the HasSlug trait takes precedence and the attribute is ignored.

  10. How Self-healing URL requests behave

    main

    Once enabled, bind your model to a route normally. The package handles the {slug}-{id} pattern automatically.

    Request Behavior Table:

    Incoming pathResult
    /posts/hello-world-5200 OK with the resolved model.
    /posts/outdated-slug-5308 Permanent Redirect to /posts/hello-world-5.
    /posts/hello-world-99404 Not Found when id 99 does not exist.
    /posts/hello-world404 Not Found, no identifier in the URL.

    Note on 308 Redirects: The package uses 308 instead of 301 to ensure that the HTTP request method (e.g., PUT, PATCH, DELETE) is preserved during the redirect. This prevents 405 Method Not Allowed errors on resource routes.