Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Slug Generator Laravel Package

ausi/slug-generator

Generate clean, customizable slugs for URLs and filenames using PHP’s Transliterator (CLDR). Supports many scripts (Cyrillic, Greek, CJK), locale-aware conversions, configurable valid chars and delimiters, and consistent ASCII output via simple options.

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Installation**
   ```bash
   composer require ausi/slug-generator

Add to composer.json if using a monorepo or custom package management. Note: Now fully compatible with PHP 8.0.

  1. Basic Usage

    use Ausi\SlugGenerator\SlugGenerator;
    
    $slugGenerator = new SlugGenerator();
    $slug = $slugGenerator->generate('Café au lait');
    // Output: "cafe-au-lait"
    
  2. First Use Case: Blog Post Slugs

    $title = "How to Build a Laravel API in 2024";
    $slug = $slugGenerator->generate($title);
    // Output: "how-to-build-a-laravel-api-in-2024"
    
  3. Laravel Integration Add to config/app.php under aliases:

    'SlugGenerator' => Ausi\SlugGenerator\SlugGenerator::class,
    

    Then inject via constructor or resolve via app(SlugGenerator::class). Note: Type-hinting now works seamlessly with PHP 8.0.


Implementation Patterns

Common Workflows

1. Model Events (Laravel)

// In Post model
protected static function boot()
{
    static::creating(function ($post) {
        $post->slug = app(SlugGenerator::class)->generate($post->title);
    });
}

2. Form Request Validation

use Ausi\SlugGenerator\SlugGenerator;

public function rules()
{
    return [
        'title' => 'required|string',
        'slug'  => 'nullable|unique:posts,slug,' . request()->post,
    ];
}

public function withValidator($validator)
{
    $validator->after(function ($validator) {
        $slug = app(SlugGenerator::class)->generate($this->title);
        $validator->errors()->addUnless(
            $this->slug === $slug || !Post::where('slug', $slug)->exists(),
            'slug',
            'A slug has already been generated for this title.'
        );
    });
}

3. Dynamic Route Slugs

Route::get('/posts/{slug}', [PostController::class, 'show'])
    ->where('slug', '[\w\-]+');
// In PostController
public function show(string $slug) // PHP 8.0 type hinting
{
    $post = Post::where('slug', $slug)->firstOrFail();
    // ...
}

4. Customizing Slugs

$slugGenerator = new SlugGenerator();
$slugGenerator->setOptions([
    'separator' => '-',
    'lowercase' => true,
    'remove_accents' => true,
    'limit' => 100,
    'transliterate' => true, // Improved fallback rules in v1.1.1
]);
$slug = $slugGenerator->generate('Café au lait!');
// Output: "cafe-au-lait"

5. Service Layer Abstraction

// app/Services/SlugService.php
class SlugService
{
    public function generateUniqueSlug(string $modelClass, string $field, string $value): string
    {
        $slug = app(SlugGenerator::class)->generate($value);
        $count = $modelClass::where($field, 'like', $slug . '%')->count();

        return $count > 0 ? $slug . '-' . $count : $slug;
    }
}
// Usage in controller
$slug = app(SlugService::class)->generateUniqueSlug(Post::class, 'slug', $request->title);

Integration Tips

  1. Database Indexing Ensure the slug column in your database is indexed for performance:

    Schema::create('posts', function (Blueprint $table) {
        $table->string('slug')->unique();
        $table->index('slug');
    });
    
  2. SeoMetaPackage Integration If using spatie/laravel-seo, sync slugs with meta titles:

    public function getSlug(): string
    {
        return $this->slug ?: app(SlugGenerator::class)->generate($this->title);
    }
    
  3. Testing Mock the slug generator in tests:

    $this->app->instance(SlugGenerator::class, Mockery::mock(SlugGenerator::class));
    
  4. Caching Generated Slugs Cache slugs for frequently accessed models:

    $slug = Cache::remember("slug_{$post->id}", now()->addHours(1), function () use ($post) {
        return app(SlugGenerator::class)->generate($post->title);
    });
    

Gotchas and Tips

Pitfalls

  1. Unicode Handling

    • The package now uses updated CLDR fallback rules in v1.1.1 for better Unicode support.
    • Fix: Test with your app’s supported languages. For rare scripts, explicitly enable transliteration:
      $slugGenerator->setOptions(['transliterate' => true]);
      
  2. Collisions

    • Slugs may still collide if not validated.
    • Fix: Use the service layer pattern to append counters.
  3. Performance

    • Generating slugs for large datasets remains potentially slow.
    • Fix: Batch processing or queue jobs.
  4. Separators in Input

    • Input like "Hello, World!" may produce unexpected results.
    • Fix: Customize punctuation and separator options:
      $slugGenerator->setOptions([
          'punctuation' => 'replace',
          'separator' => '_',
      ]);
      
  5. PHP 8.0 Type Safety

    • Ensure your code uses proper type hints (e.g., string return types) to leverage PHP 8.0 improvements:
      public function generate(string $text): string
      

Debugging

  1. Log Generated Slugs

    $slugGenerator->generate($title, function (string $slug) {
        Log::debug("Generated slug: {$slug} from '{$title}'");
    });
    
  2. Inspect Options Dump the current options to debug:

    dd($slugGenerator->getOptions());
    
  3. Character-by-Character Debugging Check how individual characters are processed:

    $slugGenerator->setCallback(function (string $char, int $index, string $slug) {
        Log::debug("Processing char '{$char}' at index {$index} in '{$slug}'");
    });
    

Tips

  1. Custom Separators Use underscores for SEO-friendly URLs:

    $slugGenerator->setOptions(['separator' => '_']);
    
  2. Preserve Keywords Avoid truncating important keywords:

    $slugGenerator->setOptions(['limit' => 50]);
    
  3. Localization Generate slugs in the model’s locale:

    $slug = app(SlugGenerator::class)->generate(__($post->title));
    
  4. Fallback for Empty Input Handle empty/whitespace-only input:

    $slug = $slugGenerator->generate($title ?: 'untitled-post');
    
  5. Extend the Generator Create a custom generator for project-specific rules:

    class CustomSlugGenerator extends SlugGenerator
    {
        public function generate(string $text): string
        {
            $slug = parent::generate($text);
            return preg_replace('/-+/', '-', $slug);
        }
    }
    
  6. Environment-Specific Config Override options per environment:

    'options' => [
        'separator' => env('SLUG_SEPARATOR', '-'),
        'limit'     => env('SLUG_LIMIT', 100),
        'transliterate' => env('SLUG_TRANSLITERATE', false),
    ],
    
  7. Avoid Overwriting Use updateIfChanged to prevent unnecessary database updates:

    if ($post->title !== $request->title && $post->slug !== $slug) {
        $post->slug = $slug;
        $post->save();
    }
    
  8. Bulk Processing For bulk operations, batch slug generation:

    $titles = $posts->pluck('title');
    $slugs = collect($titles)->map(function (string $title) {
        return app(SlugGenerator::class)->generate($title);
    });
    
  9. PHP 8.0 Features Leverage PHP 8.0 features like named arguments for clarity:

    $slug = $slugGenerator->generate(
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui