lara-zeus/delia
Delia is a Laravel menu builder from Lara Zeus that makes it easy to define, store, and render navigation menus. Configure menus in code or the database, then output them in Blade with a clean, simple API for fast, maintainable site navigation.
Pin the Filament major before anything else. Delia is a Filament panel plugin, not a general-purpose Laravel package — 3.0.0's entire release note is "support filament 5", so it's a hard cutover. Verify resolution before touching composer.lock:
# Filament 5 panels
composer require lara-zeus/delia:^3.0 --dry-run
# Filament 3/4 panels — stay on the 2.x line
composer require lara-zeus/delia:^2.0 --dry-run
The dry run is the real spec: it tells you the PHP floor, Laravel floor, Livewire constraint, and whether Delia's composer.json requires filament/filament: ^5.0 exclusively or permits ^4.0|^5.0. The most likely failure mode isn't Delia itself — it's a resolution conflict that blocks your Filament upgrade.
Install, publish, migrate, refresh assets.
composer require lara-zeus/delia:^3.0
php artisan vendor:publish --tag=delia-config # verify tag in README
php artisan vendor:publish --tag=delia-migrations
php artisan migrate
php artisan filament:upgrade
php artisan optimize:clear
Bookmarks are per-user rows, so a migration is the expected shape — but confirm it exists in database/migrations/. If the tag names differ (likely, given how thin the docs are), run php artisan vendor:publish bare and pick the LaraZeus\Delia provider interactively.
Register the plugin per panel. Read src/ for the actual plugin class and make() signature rather than copying a snippet off a blog — this is the integration point most likely to have shifted across the major bump:
// app/Providers/Filament/AdminPanelProvider.php
public function panel(Panel $panel): Panel
{
return $panel->plugins([
\LaraZeus\Delia\DeliaPlugin::make(),
]);
}
Where to look first, in order:
CHANGELOG.md plus the 3.0.0 diff — the one-line note is not a spec.src/*Plugin.php — what gets registered (resources, pages, widgets, render hooks) tells you where the bookmark UI actually appears.database/migrations/* — the schema, and critically whether there's a tenant or panel discriminator.config/delia.php — knobs, and whether it names a model/table you're expected to override.First use case: pilot on one resource-dense internal panel. Pick the panel where "where do I go?" is a real complaint — a dozen-plus resources, internal users. Register Delia there, log in as a non-super-admin, bookmark three resources, log out and back in, confirm persistence. That round trip validates registration, migration, persistence, and per-user scoping in five minutes. On a five-resource panel this is a solution without a problem — skip it.
Gate registration behind a flag so removal is one line. The cheapest de-risking for a low-adoption dependency is making it per-panel and per-environment:
->plugins(array_filter([
config('features.delia') ? \LaraZeus\Delia\DeliaPlugin::make() : null,
]))
Enable on staging first; hold production until the pilot clears.
Treat the plugin as the default and config as the override. Register the plugin, publish the config, customize through config keys. Only reach into source (fork, extend the model, edit the migration) when a key genuinely doesn't exist — and record it when you do, because that's the line where "we use Delia" becomes "we maintain a fork of Delia".
Model and table overrides are the usual first customization — renaming the table if bookmarks collides with something you built, or pointing at an app-level model to add relations and scopes:
// config/delia.php
return [
'table' => 'delia_bookmarks',
// 'model' => \App\Models\Bookmark::class,
];
If you override the model, keep the package's interface intact — the plugin's own Livewire components will fail at runtime in a way that's tedious to trace otherwise.
Scope by tenant and panel if you're multi-tenant. Read the migration before writing feature code. If there's no tenant column, per-user bookmarks in a multi-tenant panel leak across tenants the moment a user belongs to more than one. Mitigations, in order of preference:
where('tenant_id', filament()->getTenant()->id).This is genuinely yours to verify — the vendor has no visibility into your tenancy model.
Layer it on top of native navigation, don't replace it. Delia's value is a "pinned/frequently used" surface over the nav tree. Keep the standard groups intact so muscle memory survives and let bookmarks be the shortcut. If Filament's own navigation pinning covers your case, price the internal build first — a pivot table plus a nav render hook is roughly a day of work and removes the upgrade coupling entirely.
Test the toggle in Livewire, not by clicking. The failure you care about most is silent: bookmarks stop persisting after a bump and nobody notices for a quarter. One assertion catches it:
Livewire::actingAs($user)
->test(\LaraZeus\Delia\Livewire\BookmarkButton::class, ['resource' => $resource])
->call('toggle')
->assertOk();
$this->assertDatabaseHas('delia_bookmarks', [
'user_id' => $user->id,
]);
Adjust the component class and payload to whatever src/Livewire actually contains — that's the point: the test pins the contract you verified by reading source, so a major bump surfaces as a red build rather than a helpdesk ticket.
Seed realistic users in staging. Bookmarking is a UX feature and UX features need users with habits. Two or three seeded accounts with different bookmark sets lets you sanity-check ordering, empty states, and "what does a brand-new user see" without asking a real admin to fake it.
Ride the Filament 5 upgrade branch. If you're already moving 4 → 5, Delia 3.0.0 goes on the same branch, same PR ideally: bump Filament, bump Delia, republish assets, migrate, smoke-test nav and toggle. Write down "revert composer.lock, roll back migration, clear caches" before you start.
The published package description does not describe this package. What's floating around describes "structured, dynamic menus… nestable menu structures… Blade rendering helpers" — that's a menu builder, not a bookmark manager. Trust the repo name, the release notes, and src/. If you onboard someone from the description alone, they'll be looking for a config array of menu items that doesn't exist.
The one-line release note is not documentation. "3.0.0 — support filament 5" tells you nothing about whether 2.x was dropped, whether config keys moved, whether the registration contract changed, or whether the schema migrated. Diff composer.json between tags, diff the plugin class, read the migration. Budget an hour; it's the difference between a clean upgrade and a 5pm debug session.
Stale compiled CSS is the classic "it upgraded but looks broken." If you run a custom Tailwind theme, recompile against the Filament 5 preset after the bump. Published Blade views from an older version silently fall out of sync — republish and re-diff anything you edited.
Check cascade behaviour on user and resource deletion. Bookmarks are user-generated rows tied to users. If the FK isn't cascadeOnDelete, deleting a user leaves orphan rows — quiet data-hygiene debt that surfaces months later as a weird count. Same question on the resource side: what happens to a bookmark pointing at a resource that no longer exists? Delete a throwaway user in staging and find out.
Authorization is yours to verify. Can a user bookmark a resource they later lose access to, and does the bookmark list respect policies? If Delia renders bookmarks without re-checking canAccess() on the target, you'll surface links straight to 403s. Wrap retrieval in your own visibility filter — cheap to add, embarrassing to discover from a user.
Watch the nav-render query pattern on your biggest panel. If bookmark state resolves per-resource per-request, a 200-item nav becomes an N+1 on every admin page load. Open the large panel with query logging on, count queries against baseline. Catch it in the pilot.
Multi-panel apps need a decision, not a default. If you run admin, support, and customer-facing panels, register Delia only where internal users live. Customer-facing surfaces are out of scope for a package with these adoption signals — the blast radius of an untested UX regression there isn't worth a bookmark button.
Assume bus factor one; plan the fork. 7 stars, 0 dependents, MIT. That license is the real mitigation: the surface area is a table plus a nav hook, so forking is cheap. Name an internal owner, write the fork decision into the ADR now, pin ^3.0.x, and watch the tracker for a couple of weeks after the Filament 5 line settles.
Version-pair discipline. filament/filament: ^5.0 and lara-zeus/delia: ^3.0 move together; a panel on Filament 4 stays on Delia 2.x. Commit the lockfile, and when a Filament patch lands mid-sprint, run the Livewire toggle test before merging — that's exactly the class of breakage a patch-level bump can introduce in a plugin this thin.
How can I help you explore Laravel packages today?