Menus

The filament-menus plugin is a small menu builder for the public site: it owns the data and a Filament resource, plus a cached render API. It is a first-party Qcentic package (Plugins) and one of the navigation pieces a clone enables per Build a product.

What the plugin owns

  • Table — a single menu_items table. There is no separate menus table; a menu is the value of the location column. The migration ships with the package.
Column Type Notes
id bigint Primary key
location string header or footer — the menu name
label string Link text
url string(2048) Absolute URL or app-relative path (/about)
icon string, nullable Blade icon name (e.g. lucide-github); resolved by the app
target string _self (default) or _blank
position unsigned int Order within a location; default 0
created_at / updated_at timestamp

Index on (location, position) drives the ordered reads.

  • ModelMenuItem (Mamenein\FilamentMenus\Models\MenuItem). Fillable location, label, url, icon, target, position. Constants LOCATION_HEADER / LOCATION_FOOTER and TARGET_SELF / TARGET_BLANK. On creating, position auto-increments to max(position) + 1 for that location; on saved / deleted, the location cache is busted (and the previous location's cache when an item is moved).
  • ResourceMenuItemResource in the panel, navigation group Site, label Menus, icon Heroicon::OutlinedBars3, sort 10. Form: location select, label, url, icon, target. Table: label (searchable), location badge, url (truncated), icon (toggleable), target badge, position (sortable, drag-to-reorder); a location filter; reordering busts all caches.
  • Plugin objectFilamentMenusPlugin (getId() returns menus), registered with $panel->plugin(FilamentMenusPlugin::make()).

Render API

MenuItems::for('header') returns an ordered, cached Collection<int, MenuItem> for one location. Results are cached per location under filament-menus.{location} for one day, stored as plain attribute arrays (binary-safe for libSQL cache stores). MenuItems::forget($location) and MenuItems::forgetAll() bust manually. Uncached access (tooling, seeds): MenuItem::forLocation('header').

What the plugin does NOT ship

Public Blade. The package stops at the data and the render API; the clone iterates the collection in its own layout and decides the markup, classes, and icon set. The plugin is look-neutral by design (Build a product).

Authorization

MenuItemResource::canAccess() gates the resource to users with the super_admin role — Spatie permission, surfaced in the panel by Filament Shield. The same super-admin gate is used across the first-party plugins.

Status

v1 ships flat items only (no nesting) and the two fixed locations, header and footer. Deeper topic pages — custom locations, nesting, Shield permission matrix per role — will be added as the plugin's scope is locked.

flowchart LR
    A["MenuItemResource (panel)"] --> B["menu_items table"]
    B --> C["MenuItems::for(location)"]
    C --> D["clone layout render"]
    B -.saved/deleted.-> E["forget(location) cache"]
    E --> C

See also

Built by Qcentic