twig/string-extra
Twig extension integrating Symfony String: add filters u (UnicodeString methods), slug (AsciiSlugger), and singular/plural (Inflector) to manipulate text, generate slugs, and handle basic inflection directly in Twig templates.
Install Dependencies
Add the package and Symfony's string component via Composer:
composer require twig/string-extra symfony/string:^6.0
Note: Pin symfony/string to ^6.0 to avoid conflicts with Laravel's default dependencies.
Blade Integration (Quick Start)
Register a custom Blade directive in app/Providers/AppServiceProvider.php:
use Illuminate\Support\Facades\Blade;
public function boot()
{
Blade::directive('slugify', function ($expression) {
return "<?php echo \\Symfony\\Component\\String\\UnicodeString::from({$expression})->slug(); ?>";
});
}
Usage in Blade:
<a href="/{{ $post->title | slugify }}">{{ $post->title }}</a>
First Use Case Generate SEO-friendly URLs for blog posts:
<h1>{{ $post->title }}</h1>
<p>URL: <code>/posts/{{ $post->title | slugify }}</code></p>
Output: URL: <code>/posts/laravel-twig-string-extra-guide</code>
Slug Generation
{{ $title | slugify }}{{ 'Hello World' | slug }}<meta property="og:url" content="https://example.com/{{ $post->title | slugify }}">
Pluralization/Singularization
{{ $count }} {{ 'item' | pluralize }}{{ 5 | plural('item') }}{{ $count }} {{ 'notification' | pluralize }}
Output: 5 notificationsText Wrapping (UnicodeString)
{{ $text | unicodeString | titlecase }}{{ 'café' | u | titlecase }}<h2>{{ $userInput | unicodeString | capitalize }}</h2>
Laravel Form Requests
Combine with Symfony’s String for input sanitization:
// app/Http/Requests/SanitizeInput.php
public function rules()
{
return ['title' => 'required|string'];
}
public function sanitize($input)
{
return \Symfony\Component\String\UnicodeString::from($input)
->trim()
->lowercase();
}
Template Usage:
<input type="text" value="{{ $sanitizedTitle | titlecase }}">
Dynamic Meta Tags
Generate og:title and og:description in Blade:
<meta property="og:title" content="{{ $post->title | truncate(60) }}">
<meta property="og:description" content="{{ $post->excerpt | truncate(150) }}">
Localization
Use with Laravel’s Str::of() for multilingual support:
{{ $translatedText | slug }} <!-- e.g., "Café" → "cafe" -->
Caching Strategies Cache slugs in a model method to avoid repeated template processing:
// app/Models/Post.php
public function getSlugAttribute()
{
return cache()->remember("post-slug-{$this->id}", now()->addHours(1), function () {
return \Symfony\Component\String\UnicodeString::from($this->title)->slug();
});
}
Template:
<a href="/{{ $post->slug }}">{{ $post->title }}</a>
Symfony Version Conflicts
symfony/string:^5.4. The package requires ^6.0.composer.json:
"conflict": {
"symfony/string": "6.0.*"
}
replace if conflicts persist:
"replace": {
"symfony/string": "6.0.0"
}
Blade Directive Caching
php artisan view:clear
storage/framework/views for compiled files.Unicode Edge Cases
Café → cafe-au-lait).$slug = \Symfony\Component\String\UnicodeString::from('Café au lait')->slug();
// Output: "cafe-au-lait"
Performance in Loops
{{ $items | map('slugify') }}) is slow.// Controller
$items = collect($items)->map(fn ($item) => [
'slug' => \Symfony\Component\String\UnicodeString::from($item->title)->slug(),
]);
Template:
@foreach($items as $item)
<a href="/{{ $item->slug }}">{{ $item->title }}</a>
@endforeach
Twig vs. Blade Syntax
| slug (Twig) and slugify() (Blade) can confuse teams.Check Registered Directives Dump Blade directives to verify registration:
dd(collect(Blade::$directives)->keys()->all());
Symfony String Methods Explore all available methods:
$string = \Symfony\Component\String\UnicodeString::from('Hello World');
$string->titlecase(); // "Hello World"
$string->camelcase(); // "helloWorld"
$string->snakeCase(); // "hello_world"
Fallback for Missing Packages
If twig/string-extra fails, use Symfony’s String directly in Blade:
{{ \Symfony\Component\String\UnicodeString::from($text)->slug() }}
Custom Filters
Extend the StringExtension for project-specific needs:
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
class CustomStringExtension extends AbstractExtension
{
public function getFunctions()
{
return [
new TwigFunction('custom_slug', [$this, 'customSlug']),
];
}
public function customSlug($text)
{
return \Symfony\Component\String\UnicodeString::from($text)
->slug()
->prepend('custom-');
}
}
Register in config/twig.php:
'extensions' => [
\Twig\Extra\String\StringExtension::class,
App\Extensions\CustomStringExtension::class,
],
Blade Macros Create reusable macros for complex operations:
Blade::macro('seoSlug', function ($text) {
return \Symfony\Component\String\UnicodeString::from($text)
->slug()
->lower();
});
Usage:
<meta property="og:url" content="/{{ seoSlug($post->title) }}">
Form Request Integration Combine with Laravel’s Form Requests for input sanitization:
// app/Http/Requests/SanitizeTitle.php
public function rules()
{
return ['title' => 'required|string'];
}
public function prepareForValidation()
{
$this->merge([
'title' => \Symfony\Component\String\UnicodeString::from($this->title)
->trim()
->titlecase(),
]);
}
Template:
<h1>{{ $request->title }}</h1> <!-- Already sanitized -->
How can I help you explore Laravel packages today?