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

Moonshine Title With Slug Laravel Package

bugo/moonshine-title-with-slug

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package with Composer and confirm the MoonShine version constraint before wiring it into a resource:

composer require dragomano/moonshine-title-with-slug

First places to look:

  • The README for the exact TitleWithSlug::make(...) signature and supported MoonShine major version.
  • composer.json for the moonshine/moonshine constraint; MoonShine 3 field APIs differ from 2.x.
  • The package service provider for asset publishing, Blade view registration, or config.
  • resources/views if you need to customize the two-input markup.
  • src/Fields for the field class and any exposed configuration methods.

The first practical use case is a blog post or page resource where an editor types a title and expects a URL slug to be generated automatically. Replace the usual pair of Text fields with the package field:

use Dragomano\MoonshineTitleWithSlug\Fields\TitleWithSlug;

public function fields(): array
{
    return [
        TitleWithSlug::make('title', 'slug'),
        // ...
    ];
}

Confirm the argument order in the README for 0.1; the key point is that the field owns both the title and slug columns.

Implementation Patterns

Basic CRUD integration. Add the field to the resource’s fields() method and remove the separate title/slug inputs. Keep the underlying columns fillable on the model and present in the migration.

Validation belongs in the resource or a FormRequest. The field renders two inputs, but do not rely on field-level rules alone. Validate both columns and enforce slug uniqueness:

use Illuminate\Validation\Rule;

public function rules(): array
{
    return [
        'title' => ['required', 'string', 'max:255'],
        'slug' => [
            'required',
            'string',
            'max:255',
            Rule::unique('posts', 'slug')->ignore($this->getItem()?->getKey()),
        ],
    ];
}

Add a database unique index on slug as the final safeguard.

Use the slug for route model binding. On the model:

public function getRouteKeyName(): string
{
    return 'slug';
}

Then generate URLs with route('posts.show', $post). If editors can change slugs after publishing, store old slugs and add redirects so existing links do not break.

Keep index and detail views readable. A composite field is usually form-oriented. Hide it on index and show a normal text field instead:

TitleWithSlug::make('title', 'slug')->hideOnIndex(),
Text::make('Slug', 'slug')->hideOnForm(),

Add a server-side fallback for imports and API writes. The package’s auto-generation is primarily an admin-form convenience. For seeders, imports, or API-created records, normalize the slug in the model:

use Illuminate\Support\Str;

protected static function booted(): void
{
    static::saving(function (self $post) {
        if (blank($post->slug)) {
            $post->slug = Str::slug($post->title);
        }
    });
}

Decide the overwrite policy early. For drafts, regenerating the slug as the title changes is useful. For published content, changing the title should not silently rewrite the URL. If the package always regenerates, lock the slug field after publication or enforce the rule in a model observer.

Test inside MoonShine modals and relation forms. MoonShine uses Alpine/Livewire-style interactivity. If the field works on a full-page form but not in a modal, the package’s JavaScript may not be initializing after the dynamic render.

Gotchas and Tips

  • 0.1 is a first public release. Treat the API as unstable, pin it (0.1.*), and review the diff before upgrading to 0.2.
  • Verify MoonShine compatibility first. Installing a field built for MoonShine 2 into a MoonShine 3 panel can produce a blank field or a class error. Check the package’s Composer constraint before debugging your resource.
  • Client-side and server-side slugs can disagree. If the package transliterates in JavaScript and your model fallback uses Str::slug, Cyrillic, accented characters, and emoji may produce different results. Pick one source of truth or make the server-side normalizer match the frontend behavior.
  • Test non-Latin titles. Auto-transliteration is the main failure point for non-English content. If a title produces an empty slug, add a fallback such as the record ID or a random suffix.
  • Client-side generation does not check uniqueness. Two posts with the same title can produce the same slug. Rely on validation plus the database unique index.
  • Do not trust the submitted slug. A browser extension or crafted request can bypass the JavaScript generator. Always validate and normalize server-side.
  • Clear caches after install or publish. Run php artisan optimize:clear and any MoonShine asset/install command recommended by the README. Stale compiled assets are a common reason the slug script appears not to run.
  • Inspect the rendered input names when validation fails. The field must submit title and slug under the names your rules expect. If the package uses array names or nested keys, adjust the resource rules accordingly.
  • Composite fields are poor candidates for sorting, searching, and filters. Use the underlying slug column with a normal Text field for index filters and searchable columns.
  • Check CSP and asset loading. If your admin panel has a strict Content Security Policy, the package’s inline or published JavaScript may be blocked. Confirm in the browser console before changing field code.
  • Extension points are likely the Blade view and the field class. Publish the package views if a tag is documented; otherwise override the field’s view or extend the class. For slug history, redirects, and uniqueness guarantees, keep that logic in your application rather than the field.
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.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
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