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

Urlify Laravel Package

voku/urlify

PHP URL slugifier/transliterator (URLify.js port) that converts UTF-8 strings into readable, URL-safe slugs and filenames. Supports many languages via mapping tables with Portable ASCII fallback, plus helpers like downcode/transliterate and custom char rules.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer:

composer require voku/urlify

First Use Case: Convert a blog post title to a URL slug:

use voku\helper\URLify;

$slug = URLify::filter('Laravel 10: New Features & Best Practices');
echo $slug; // "laravel-10-new-features-best-practices"

Where to Look First:


Implementation Patterns

1. Laravel Service Provider Binding

Bind voku/urlify as a singleton for reusable slug generation:

// app/Providers/AppServiceProvider.php
public function register()
{
    $this->app->singleton('slugger', function () {
        return new \voku\helper\URLify();
    });
}

Usage in Controllers:

public function store(Request $request)
{
    $slug = app('slugger')->filter($request->title);
    // Save to database...
}

2. Eloquent Model Accessors

Automatically generate slugs from titles:

// app/Models/Post.php
protected $appends = ['slug'];

public function getSlugAttribute()
{
    return app('slugger')->filter($this->title);
}

Usage:

$post = Post::find(1);
echo $post->slug; // "laravel-best-practices"

3. Form Request Validation

Validate slugs before saving:

// app/Http/Requests/StorePostRequest.php
public function rules()
{
    return [
        'title' => 'required|string',
        'slug' => 'required|string|unique:posts,slug',
    ];
}

public function withValidator($validator)
{
    $validator->after(function ($validator) {
        $slug = app('slugger')->filter($this->title);
        if ($slug !== $this->slug) {
            $validator->errors()->add('slug', 'Slug does not match title.');
        }
    });
}

4. API Response Transformation

Generate slugs in API responses:

// app/Http/Resources/PostResource.php
public function toArray($request)
{
    return [
        'title' => $this->title,
        'slug' => app('slugger')->filter($this->title),
        'url' => route('posts.show', ['post' => $this->slug]),
    ];
}

5. Route Model Binding

Use slugs for dynamic routes:

// routes/web.php
Route::get('/posts/{slug}', [PostController::class, 'show'])
    ->where('slug', '[\w\-]+');

Controller:

public function show(Post $post)
{
    // $post is automatically resolved via slug
}

6. Custom Character Mappings

Extend default replacements for domain-specific needs:

// app/Providers/AppServiceProvider.php
public function boot()
{
    \voku\helper\URLify::add_chars([
        '©' => '(c)', '®' => '(r)', '™' => '(tm)',
    ]);
}

7. Locale-Specific Slugs

Prioritize language rules for multilingual content:

$germanSlug = \voku\helper\URLify::filter('Straße', 60, 'de');
// "strasse" (German-specific rule)

$turkishSlug = \voku\helper\URLify::filter('İstanbul', 60, 'tr');
// "istanbul" (Turkish-specific rule)

8. Bulk Processing

Process arrays of strings (e.g., tags, categories):

$tags = ['Café', 'Naïve', 'Über'];
$slugs = array_map([\voku\helper\URLify::class, 'filter'], $tags);
// ["cafe", "naive", "uber"]

Gotchas and Tips

Pitfalls

  1. Locale Mismatches:

    • German ü becomes ue in de locale but u in tr. Test with target languages.
    • Fix: Explicitly specify locale:
      URLify::filter('Straße', 60, 'de'); // "strasse"
      
  2. Duplicate Slugs:

    • URLify::filter() does not check uniqueness. Handle conflicts in your application logic (e.g., append -2):
      $slug = $this->generateUniqueSlug($title);
      private function generateUniqueSlug($title, $count = 1)
      {
          $slug = URLify::filter($title);
          return Post::where('slug', $slug)->exists()
              ? $this->generateUniqueSlug($title, $count + 1)
              : $slug . ($count > 1 ? "-$count" : "");
      }
      
  3. Reserved Characters:

    • Slugs may still contain invalid URL characters (e.g., #, ?). Sanitize further if needed:
      $cleanSlug = preg_replace('/[^a-z0-9\-]/', '', $slug);
      
  4. Performance:

    • For bulk operations (e.g., migrating 10K posts), benchmark against Laravel’s Str::slug():
      // Benchmark comparison
      $strSlug = Str::slug('Café');
      $vokuSlug = URLify::filter('Café');
      
  5. Custom Rules Overrides:

    • Extending character lists does not override existing rules. New mappings are additive:
      URLify::add_chars(['€' => 'euro']); // Adds to default behavior
      

Debugging Tips

  1. Inspect Transliteration:

    • Use downcode() to see raw transliterated output before filtering:
      echo URLify::downcode('Café'); // "Cafe"
      echo URLify::filter('Café');   // "cafe"
      
  2. Check Language Maps:

    • Verify locale-specific rules by inspecting the package’s language files.
    • Example: Turkish ıi vs. German ßss.
  3. Log Custom Mappings:

    • Debug extended character lists:
      \voku\helper\URLify::add_chars(['€' => 'euro']);
      error_log(print_r(\voku\helper\URLify::get_chars(), true));
      
  4. Test Edge Cases:

    • Validate with:
      • Emojis (may not transliterate).
      • Rare scripts (e.g., Armenian, Georgian).
      • Mixed punctuation (e.g., "Hello! How's it going?").

Extension Points

  1. Custom Separator Logic:

    • Override default hyphenation by extending the separator array:
      URLify::add_array_to_seperator(['/']);
      echo URLify::filter('Hello/World'); // "hello-world"
      
  2. Word Removal:

    • Strip common words (e.g., "the", "a") for cleaner slugs:
      URLify::remove_words(['the', 'a'], 'en');
      echo URLify::filter('The Quick Brown Fox'); // "quick-brown-fox"
      
  3. Facade for Laravel:

    • Create a facade for cleaner syntax:
      // app/Facades/Slugger.php
      namespace App\Facades;
      use Illuminate\Support\Facades\Facade;
      class Slugger extends Facade { public static function getFacadeAccessor() { return 'slugger'; } }
      
      Usage:
      use App\Facades\Slugger;
      $slug = Slugger::filter('Laravel Tips');
      
  4. Fallback to Laravel’s Str::slug:

    • Combine both for robustness:
      public function generateSlug($title)
      {
          $vokuSlug = URLify::filter($title);
          $laravelSlug = Str::slug($title);
          return $vokuSlug === $laravelSlug ? $vokuSlug : $laravelSlug;
      }
      

Configuration Quirks

  1. Default Locale:

    • No default locale is set. Always specify if using language-specific rules:
      // ❌ Unpredictable (uses no locale)
      URLify::filter('Straße');
      
      // ✅ Explicit
      URLify::filter('Straße', 60, 'de');
      
  2. Max Length Parameter:

    • The maxLength parameter truncates after slug generation. Test with long strings:
      echo URLify::filter('A Very Long Title For A Blog Post', 10);
      

// "a-very-lo

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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky