Installation:
composer require nunomaduro/laravel-sluggable
Publish the config (optional):
php artisan vendor:publish --provider="NunoMaduro\LaravelSluggable\SluggableServiceProvider"
First Use Case:
Apply the #[Sluggable] attribute to an Eloquent model:
use NunoMaduro\LaravelSluggable\Sluggable;
class Post extends Model
{
use Sluggable;
#[Sluggable(['source' => 'title', 'unique' => true])]
public function getSlugOptions(): array
{
return [];
}
}
source: The attribute to generate the slug from (e.g., title).unique: Ensure slugs are unique (default: false).Trigger Slug Generation:
Call save() on the model. The slug will auto-generate and populate the slug column (default column name, configurable in config/sluggable.php).
Basic Slug Generation:
$post = new Post(['title' => 'How to Slug in Laravel']);
$post->save(); // Auto-generates slug: `how-to-slug-in-laravel`
Custom Slug Logic:
Override getSlugOptions() for dynamic behavior:
public function getSlugOptions(): array
{
return [
'source' => 'title',
'unique' => true,
'separator' => '-',
'maxLength' => 100,
'onUpdate' => true, // Regenerate on update
];
}
Multi-Field Slugs: Combine multiple fields:
#[Sluggable(['source' => ['category', 'title'], 'separator' => '/'])]
Manual Slug Updates: Force regeneration:
$post->updateSlug();
#[Sluggable] with API resources to ensure consistent slugs in responses.Route::modelBinding() for clean URLs:
Route::get('/posts/{post:slug}', [PostController::class, 'show']);
use Illuminate\Validation\Rule;
$request->validate([
'slug' => ['required', Rule::unique('posts')->ignore($post)],
]);
Unique Slugs:
unique: true is set, the package appends a suffix (e.g., -2) to avoid collisions.config/sluggable.php for unique_strategy (default: suffix).Case Sensitivity:
lowercase: false in getSlugOptions().Column Mismatch:
slug.config/sluggable.php:
'column' => 'custom_slug_column',
Performance:
unique: true if not needed.Log Slug Generation:
Enable debug mode in config/sluggable.php:
'debug' => env('SLUGGABLE_DEBUG', false),
Check Laravel logs for slug generation details.
Test Edge Cases:
// Test slug collision handling
$post1 = new Post(['title' => 'Test']);
$post2 = new Post(['title' => 'Test']);
$post1->save(); // slug: `test`
$post2->save(); // slug: `test-2` (if unique: true)
Custom Slug Generator:
Implement NunoMaduro\LaravelSluggable\Contracts\SlugGenerator:
class CustomSlugGenerator implements SlugGenerator
{
public function generate($value, array $options): string
{
return str_replace(' ', '_', strtolower($value));
}
}
Register in config/sluggable.php:
'generator' => \App\Services\CustomSlugGenerator::class,
Event Listeners:
Listen for sluggable.generated events to log or transform slugs:
Sluggable::generated(function ($model, $slug) {
// Custom logic (e.g., analytics)
});
Translatable Slugs:
Use spatie/laravel-translatable + #[Sluggable] for multilingual slugs:
#[Sluggable(['source' => 'title', 'translatable' => true])]
How can I help you explore Laravel packages today?