camya/filament-title-with-slug
Installation:
composer require camya/filament-title-with-slug
Publish the config (optional):
php artisan vendor:publish --provider="Camya\FilamentTitleWithSlug\FilamentTitleWithSlugServiceProvider" --tag="config"
First Usage: Add the component to a Filament form in your resource:
use Camya\FilamentTitleWithSlug\Components\TitleWithSlugInput;
public static function form(Form $form): Form
{
return $form
->schema([
TitleWithSlugInput::make(
fieldTitle: 'title',
fieldSlug: 'slug',
),
// Other fields...
]);
}
Model Requirements:
Ensure your model has title and slug fields (or adjust the field names in the component).
Creating a Blog Post Resource:
TitleWithSlugInput in the form() method of your Filament resource."Hello World" → "hello-world").Basic Integration:
TitleWithSlugInput::make(
fieldTitle: 'name', // Customize field names
fieldSlug: 'url',
columnSpanFull: true, // Full-width layout
)
->required(),
Custom Slug Generation: Override the default slugifier (e.g., for SEO-friendly URLs):
TitleWithSlugInput::make(
fieldTitle: 'title',
fieldSlug: 'slug',
slugifier: fn(string $title) => Str::slug($title, '-').'-custom',
)
Dynamic "Visit" Links: Use a route helper to generate clickable URLs:
TitleWithSlugInput::make(
fieldTitle: 'title',
fieldSlug: 'slug',
visitRoute: fn($record) => route('posts.show', $record),
)
Conditional Slug Editing: Disable slug editing for specific records (e.g., admin-only):
TitleWithSlugInput::make(
fieldTitle: 'title',
fieldSlug: 'slug',
disableSlugEditing: fn($record) => $record->is_admin,
)
Localization: Translate labels via config or language files:
TitleWithSlugInput::make(
fieldTitle: 'title',
fieldSlug: 'slug',
titleLabel: __('filament-title-with-slug::title'),
slugLabel: __('filament-title-with-slug::slug'),
)
Validation: Combine with Filament’s validation rules:
TitleWithSlugInput::make(
fieldTitle: 'title',
fieldSlug: 'slug',
)->rules([
'title' => 'required|max:255',
'slug' => 'required|unique:posts,slug,'.$record->id,
]),
Livewire Hooks: Extend functionality with Livewire events:
protected static function getUpdatedSchema(Form $form): array
{
return array_merge($form->getSchema(), [
TitleWithSlugInput::make(...)->afterStateUpdated(fn($state, $set) => {
// Custom logic after slug/title changes
}),
]);
}
Dark Mode: The component supports Filament’s dark mode out-of-the-box. No additional config needed.
Slug Conflicts:
unique validation fails, ensure your model’s slug field is indexed in the database.slugifier to handle edge cases (e.g., accented characters):
slugifier: fn($title) => Str::ascii($title)->slug('-'),
Route Resolution:
visitRoute returns null or invalid, the "Visit" link will be hidden. Test with:
visitRoute: fn($record) => $record->slug ? route('posts.show', $record) : null,
Livewire State:
$record->slug updates outside the component—use the component’s built-in logic to prevent desync.Config Overrides:
config/filament-title-with-slug.php) takes precedence over defaults. Override globally:
'default_slugifier' => fn($title) => Str::slug($title, '_'),
Slug Not Updating:
fieldTitle/fieldSlug names match your model’s fillable fields.slugifier callback isn’t throwing errors (wrap in try-catch for debugging).CSS/Styling Issues:
npm run dev
Livewire Errors:
php artisan cache:clear
php artisan view:clear
Custom Components: Extend the base component for reusable logic:
class CustomTitleWithSlugInput extends TitleWithSlugInput
{
protected static string $defaultSlugifier = 'custom-slugifier';
// Override methods as needed
}
Event Listeners: Listen for slug changes in your model:
protected static function booted()
{
static::saved(function ($model) {
if ($model->wasChanged('slug')) {
// Log or trigger side effects
}
});
}
Testing: Use Filament’s testing helpers to assert slug behavior:
$this->create(Post::class, [
'title' => 'Test Post',
'slug' => null, // Should auto-generate
]);
$this->assertDatabaseHas('posts', ['slug' => 'test-post']);
TitleWithSlugInput::make(
fieldTitle: 'title',
fieldSlug: 'slug',
slugSuggestions: fn($query) => $query->limit(10), // Limit DB queries
)
How can I help you explore Laravel packages today?