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

Menus Laravel Package

laravel-enso/menus

Database-driven menu management for Laravel Enso: define and organize application menus, render hierarchical navigation, and control item visibility through the Enso permission system. Integrates cleanly with Enso's core modules and UI components.

View on GitHub
Deep Wiki
Context7

Getting Started

The menus package is a management layer for Laravel Enso's main application menu — it gives you a database-backed menu tree plus a Vue-based admin UI to add, remove, reorder, and nest menu entries without touching code.

Minimal steps:

  1. Require it inside an existing Enso application (it assumes laravel-enso/enso core is installed):
    composer require laravel-enso/menus
    
  2. Publish and run its migrations (Enso packages register their own service providers, so this is usually):
    php artisan vendor:publish --tag=menus-migrations
    php artisan migrate
    
    If the package ships seeders (default root menu, dashboard entry, etc.), run php artisan db:seed --class=MenuSeeder or the Enso equivalent.
  3. Confirm the package's routes are loaded — check routes/ inside the vendor folder or php artisan route:list | grep menu to see the CRUD endpoints it exposes.
  4. Log into the Enso admin UI and look for the Menus section in the sidebar (or navigate directly to /admin/menus on a stock Enso install). That screen is the primary day-to-day surface.

First use case: add a top-level nav entry for a module you just built — give it a name, an icon (Font Awesome class used by Enso), a link/route, and a sort order. Then reorder it by drag-and-drop in the UI and confirm it persists across reloads.

Where to look first in the repo:

  • src/ — models, controllers, resources, policies.
  • database/migrations/ — the schema (columns like name, icon, link, parent_id, order, is_active are the usual suspects; verify against the migration).
  • resources/js/ — the Vue components driving the drag-and-drop / form behavior.
  • README.md — for the exact publish tags and any post-install Artisan commands.

Implementation Patterns

Treat the UI as the source of truth, not seeders. Enso's menu is designed to be edited at runtime. Seed only the bootstrap tree (dashboard, system settings) and let admins manage everything else through the UI. If you hard-code menu items in seeders, they'll drift from the live structure and any future migration of the menu table will clobber hand edits.

Programmatic creation for module installers. When you write an Enso module that should register its own menu entry, create it in the module's service provider or seeder rather than documenting "go add a menu item":

Menu::create([
    'name'      => 'Reports',
    'icon'      => 'fa-file-alt',
    'link'      => '/reports',
    'parent_id' => null,
    'order'     => Menu::max('order') + 1,
]);

Keep this idempotent (firstOrCreate on link or name) so re-running the seeder is safe.

Gate menu visibility by permission. Enso's menu items are typically shown conditionally based on the current user's permissions (usually a permission column or a relationship to Enso's roles/permissions tables — check the model). Wire your new menu entry to the same permission your route/controller uses; otherwise you'll show links that 403.

Build the tree once per request. If you need the menu outside the Enso frontend (e.g., a Blade layout or an API for a SPA), expose it through a small service that loads all rows and assembles the parent/child tree in one query, rather than lazy-loading children recursively. A flat get()->groupBy('parent_id') avoids N+1.

Cache the rendered tree, bust on write. Menu reads happen on every page load; writes happen rarely. Cache the built array with a key like enso.menus.tree.{$userId} or permission-agnostic enso.menus.tree plus a per-user filter at render time. Clear the cache in an observer on the Menu model (saved, deleted) or in the package's controller hooks.

Frontend integration. If you're extending the Vue side, reuse the package's components for the menu editor rather than writing your own drag-and-drop; the ordering logic and persistence format are already wired. For the actual navigation rendering, feed the tree into Enso's sidebar component via the existing API endpoint.

Testing. Factories aren't always shipped; define a local MenuFactory for feature tests and assert on ordering after a simulated reorder request. Test the permission gate explicitly — that's where most menu bugs live.

Gotchas and Tips

  • order and parent_id are the fragile fields. Reordering via drag-and-drop rewrites order values; if you also edit them manually in seeders you'll get duplicate/gapped ordering. Always append with max('order') + 1 and never assume contiguous integers.
  • Depth is usually unlimited but the UI may not be. Before allowing nested items, check whether the Vue component supports arbitrary nesting; if it's capped at two levels, enforce that in a form request so the API doesn't accept deeper trees the UI can't render.
  • Deleting a parent may orphan children. Check whether the migration uses onDelete('cascade') or restrict. If children aren't cascaded, either soft-delete the subtree or reparent children to the grandparent in a deleting observer.
  • Permissions are checked downstream. A visible menu item doesn't grant access — Enso's route middleware and policies do. If users can click but get a 403, the menu's permission binding and the controller's policy/permission check are out of sync; fix both together.
  • Cache invalidation is the classic bug. Menu updates that don't clear the cache look like "the UI didn't save." Confirm the package already caches (some Enso modules use a CacheService) and whether it invalidates on save; if not, add an observer.
  • Icon column expects Enso's icon conventions (usually Font Awesome class names). An unknown class renders as a blank square in the sidebar with no console error — easy to miss.
  • Translations: menu names are often translatable via Enso's __() conventions. If you need i18n, store a translation key rather than a literal label; otherwise the label is English-only in every locale.
  • Route vs URL in the link column. Pick one convention (or check whether the package supports both). Mixing route('reports.index') and /reports works until you rename a route; route() strings break silently if routes are cached but the name changed.
  • php artisan route:cache will hide broken link values because the URL never gets validated — sanity-check menu links after deploying route-cache changes.
  • Extension points: for custom behavior (e.g., role-based filtering, extra columns), prefer model observers and a custom service that wraps the package's model rather than forking the vendor code. The package is small (16 stars), so upgrade churn is low but so is upstream support — pin the version in composer.json and verify the migration columns directly in the repo before relying on field names above.
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