Installation:
composer require moox/slug
php artisan slug:install
slug:install command publishes the config file (config/slug.php) and creates a migration for the slugs table.First Use Case:
use Moox\Slug\Slug;
$slug = Slug::create('Hello World!');
// Returns: 'hello-world'
use Moox\Slug\Slug;
$slug = Slug::createForModel(new Post(), 'title');
// Generates slug from the `title` attribute of the `Post` model.
Where to Look First:
config/slug.php (customize separators, transliteration, etc.).Moox\Slug\SlugServiceProvider (registers the Slug facade).database/migrations/[timestamp]_create_slugs_table.php (check table structure).Generating Slugs:
$slug = Slug::create('My Awesome Post');
// Output: 'my-awesome-post'
$slug = Slug::create('My Awesome Post', '-', true);
// Output: 'my-awesome-post' (third param: force lowercase)
$slug = Slug::create('Café au Lait');
// Output: 'cafe-au-lait' (handles accented characters).
Model Integration:
use Moox\Slug\HasSlug;
class Post extends Model
{
use HasSlug;
protected $sluggable = 'title'; // Attribute to slugify.
}
$post = Post::find(1);
$post->slug; // Returns the slug (e.g., 'my-awesome-post').
$post = Post::find(1);
$post->title = 'Updated Title';
$post->save(); // Automatically updates the slug.
Dynamic Tabs (Moox Core Feature):
config/slug.php to filter the slugs table:
'tabs' => [
'active' => ['label' => 'Active Slugs', 'value' => 1],
'inactive' => ['label' => 'Inactive Slugs', 'value' => 0],
],
{!! \Moox\Slug\SlugTab::render('active') !!}
Translatable Config:
'translatable' => [
'separator' => [
'en' => '-',
'es' => '_',
],
],
$slug = Slug::create('Hola Mundo', null, true, 'es');
// Output: 'hola_mundo' (uses Spanish separator).
Seeding Slugs:
Use the Slug::createForModel() method in seeders to pre-generate slugs for existing records.
$posts = Post::all();
foreach ($posts as $post) {
$post->slug = Slug::createForModel($post, 'title');
$post->save();
}
Validation: Combine with Laravel validation to ensure slug uniqueness:
use Illuminate\Validation\Rule;
$validator = Validator::make($request->all(), [
'slug' => [
'required',
Rule::unique('slugs')->ignore($post->id),
],
]);
API Responses:
Serialize slugs in API responses using Laravel's App\Http\Resources:
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'slug' => $this->slug,
];
}
Case Sensitivity:
$slug = Slug::create('Hello WORLD', '-', true); // 'hello-world'
Reserved Words:
admin, login). Filter them in the config:
'reserved' => ['admin', 'login', 'api'],
Duplicate Slugs:
unique validation or a custom solution:
$slug = Slug::createUnique('My Post', $post->id);
// Requires extending the Slug class or using a scope.
Performance:
DB::transaction(function () {
Post::chunk(100, function ($posts) {
foreach ($posts as $post) {
$post->slug = Slug::createForModel($post, 'title');
}
Post::whereIn('id', $posts->pluck('id'))->update();
});
});
Config Overrides:
config/slug.php for custom rules..env overrides).'transliterate' => false,
Model Events:
HasSlug events by listening to saving or updating:
Post::saved(function ($post) {
\Log::info('Slug generated:', ['slug' => $post->slug]);
});
Migration Issues:
slugs table isn’t created, run:
php artisan migrate
slugs) and rename them.Custom Slug Generator:
Moox\Slug\Slug class to add logic:
namespace App\Services;
use Moox\Slug\Slug as BaseSlug;
class CustomSlug extends BaseSlug
{
public static function createWithPrefix($string, $prefix = 'app-')
{
return parent::create($prefix . $string);
}
}
Dynamic Separators:
class Product extends Model
{
use HasSlug;
protected $sluggable = 'name';
protected $slugSeparator = '--'; // Custom separator.
}
Slug Storage:
HasSlug trait’s getSlugAttribute:
public function getSlugAttribute()
{
return $this->customSlugs()->value('slug');
}
Transliteration Rules:
config/slug.php:
'transliterate' => [
'ä' => 'ae',
'ü' => 'ue',
'ö' => 'oe',
// Add custom mappings.
],
URL-Friendly Slugs:
Combine with Laravel’s Str::of() for additional URL sanitization:
use Illuminate\Support\Str;
$slug = Str::of(Slug::create('My Post!'))->slug();
// Output: 'my-post' (removes special chars).
SEO Optimization:
Use the slug column in Sitemap or Meta packages (e.g., spatie/laravel-sitemap) for dynamic URLs:
public function toArray()
{
return [
'loc' => url($this->slug),
'lastmod' => $this->updated_at,
];
}
Testing:
Mock the Slug facade in tests:
$this->mock(\Moox\Slug\Slug::class)->shouldReceive('create')
->with('Test')
->andReturn('test-slug');
How can I help you explore Laravel packages today?