Weave 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

Nova Sluggable Laravel Package

drobee/nova-sluggable

A Laravel Nova field for generating and managing URL slugs from a title or other attribute. Adds a sluggable input to Nova resources, creating unique, SEO-friendly slugs automatically and keeping them in sync as records are edited. A simple drop-in field for Eloquent models.

View on GitHub
Deep Wiki
Context7

Getting Started

Before you touch Composer. This package is inert outside Laravel Nova. Confirm Nova is installed and licensed first, then pin down three things before composer require:

  1. Your Nova major (composer show laravel/nova). The May 2024 release most likely targets Nova 4. If you're on Nova 5, treat compatibility as unverified and test on a branch.
  2. A unique index on the slug column. The field is a control surface, not a persistence guarantee:
Schema::table('posts', function (Blueprint $table) {
    $table->string('slug')->unique()->nullable()->after('title');
});
  1. A model-level slug trait as the actual source of truth. spatie/laravel-sluggable is the common pairing:
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;

class Post extends Model
{
    use HasSlug;

    public function getSlugOptions(): SlugOptions
    {
        return SlugOptions::create()
            ->generateSlugsFrom('title')
            ->saveSlugsTo('slug');
    }
}

Install.

composer require drobee/nova-sluggable

Read the source before writing against it. The field class in vendor/drobee/nova-sluggable/src/ is small — a few dozen lines. The README is thin, so confirm the actual fluent method names (->from(), ->separator(), ->readonly(), update semantics) from the code rather than assuming they match the docs. Fifteen minutes here saves you a broken form later.

First use case: a Post resource. Register the field next to Title, branch it, load the create form, and verify the compiled JS actually renders and auto-fills as you type. If the input is blank, stop — do not build on top of a broken asset pipeline.

Implementation Patterns

Basic registration. Put the slug field as a sibling of the source attribute so the generate action lives in context:

use Drobee\NovaSluggable\Slug;

public function fields(Request $request)
{
    return [
        ID::make()->sortable(),
        Text::make('Title')->rules('required', 'max:255'),
        Slug::make('Slug')
            ->from('title')
            ->separator('-')
            ->rules('required', 'max:255', 'unique:posts,slug,{{resourceId}}'),
    ];
}

The unique rule with {{resourceId}} is what prevents the duplicate-on-update failure that slug fields commonly trip over. The field itself won't enforce it.

Read-only vs editable. Default to read-only for editors who shouldn't own URLs; expose editing only where regeneration is genuinely desired:

Slug::make('Slug')->from('title')->readonly(),   // auto-generate, no hand-editing
Slug::make('Slug')->from('title'),                // editable + regenerate

Always pair with the model trait. The field gives editors a control; the trait guarantees that API writes, imports, and Model::create() calls still produce a slug. Without the trait you get a silent inconsistency — editor forms work, API endpoints write null — which is the worst failure mode because it surfaces in production, not in the admin.

Standardise one field type app-wide. If you adopt this, use it everywhere you need slug UX. Mixing Nova's native Slug field on some resources and this package on others doubles the asset pipeline you'll debug on every Nova bump.

Decide update semantics explicitly. Most implementations sync on create only. Stakeholders will be surprised when a title typo fix leaves the old slug (and potentially a broken public URL) in place. Write the acceptance criterion down, then verify the field's behavior matches it — don't infer from the README.

Test the render, not just the install. A Nova endpoint smoke test catches asset regressions on upgrade:

public function test_post_slug_field_renders()
{
    $this->actingAs($this->admin())
        ->get('/nova-api/posts/fields')
        ->assertOk();
}

Also test transliteration with real content — an accented or CJK title — before assuming the field handles it.

Gotchas and Tips

  • Asset compilation is the top failure mode. Small Nova field packages ship prebuilt JS/CSS. If assets were built against a different Nova toolchain, the field renders blank or throws console errors even though composer require succeeded. Test the rendered form as part of installation acceptance — it's the cheapest check and the most common reason for a silent failure.
  • The generation is client-side. Slug derivation happens as the editor types in the browser. That means the field only fires when the form is loaded and JS is healthy. Anywhere the source attribute is set programmatically — seeding, importing, an API POST — the field never runs. Your trait is the safety net.
  • Uniqueness belongs to the database. Unique index plus the unique:...,{{resourceId}} rule. Never rely on the field alone; concurrent creates will collide.
  • Transliteration gaps. Non-Latin titles can produce empty or malformed slugs. If your content is multilingual, test it before rollout and fall back to the model trait's transliteration configuration rather than the field's client-side behavior.
  • Don't silently overwrite hand-curated slugs. If any records have manually tuned URLs, snapshot the slug column and gate the write-back before enabling editable mode — an SEO regression is expensive to unwind.
  • Nova version compatibility needs a gate. Pin a narrow patch range and add a CI job that boots Nova and renders a resource form. Compatibility won't track Nova releases in lockstep, so CI is what converts a silently broken field into a build failure.
  • Nova licensing in CI. Nova is paid and privately hosted. Without the Nova repository credentials in CI, composer install fails on this field — and every other Nova field — before any test runs.
  • Compare against Nova's native field first. Nova 4+ ships a first-party Slug field with source syncing. If it already covers your requirements, the correct call is not adding this dependency. Do the comparison before the spike, not after.
  • Fork is a legitimate exit, not a failure. MIT, small surface, zero known dependents — vendoring the field into app/Nova/Fields is fully reasonable if upstream goes quiet or a Nova 5 patch never lands. Pre-agree the fork owner and the removal path (delete package, strip ->make() calls) before committing.
  • Assign a named maintainer. Zero dependents means no community backstop; the field will rot silently until a form breaks. Budget one compatibility patch per Nova/Laravel major and put a person against it.
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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums