{"id":18498441,"url":"https://github.com/datlechin/filament-menu-builder","last_synced_at":"2026-03-07T10:07:37.942Z","repository":{"id":251923124,"uuid":"836480480","full_name":"datlechin/filament-menu-builder","owner":"datlechin","description":"Create and manage menu in your Filament app.","archived":false,"fork":false,"pushed_at":"2025-05-12T08:33:44.000Z","size":1748,"stargazers_count":110,"open_issues_count":9,"forks_count":23,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-12T09:57:36.696Z","etag":null,"topics":["filament","filament-plugin","filamentphp","menu","menu-builder"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/datlechin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"datlechin"}},"created_at":"2024-08-01T00:12:21.000Z","updated_at":"2025-05-12T08:33:47.000Z","dependencies_parsed_at":"2024-08-06T15:38:38.196Z","dependency_job_id":"4afd9c25-9e97-4484-845c-5222e44ebd1e","html_url":"https://github.com/datlechin/filament-menu-builder","commit_stats":null,"previous_names":["datlechin/filament-menu-builder"],"tags_count":19,"template":false,"template_full_name":"filamentphp/plugin-skeleton","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datlechin%2Ffilament-menu-builder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datlechin%2Ffilament-menu-builder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datlechin%2Ffilament-menu-builder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datlechin%2Ffilament-menu-builder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/datlechin","download_url":"https://codeload.github.com/datlechin/filament-menu-builder/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253717584,"owners_count":21952514,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["filament","filament-plugin","filamentphp","menu","menu-builder"],"created_at":"2024-11-06T13:39:54.040Z","updated_at":"2026-03-07T10:07:37.935Z","avatar_url":"https://github.com/datlechin.png","language":"PHP","funding_links":["https://github.com/sponsors/datlechin"],"categories":[],"sub_categories":[],"readme":"# Filament Menu Builder\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/datlechin/filament-menu-builder.svg?style=flat-square)](https://packagist.org/packages/datlechin/filament-menu-builder)\n[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/datlechin/filament-menu-builder/run-tests.yml?branch=main\u0026label=tests\u0026style=flat-square)](https://github.com/datlechin/filament-menu-builder/actions?query=workflow%3Arun-tests+branch%3Amain)\n[![Total Downloads](https://img.shields.io/packagist/dt/datlechin/filament-menu-builder.svg?style=flat-square)](https://packagist.org/packages/datlechin/filament-menu-builder)\n\n![Filament Menu Builder](https://github.com/datlechin/filament-menu-builder/raw/main/art/menu-builder.jpg)\n\nA [Filament](https://filamentphp.com) plugin for creating and managing menus with drag-and-drop ordering, nested items, custom links, and dynamic menu panels.\n\n## Requirements\n\n- PHP 8.3+\n- Filament 5.0+\n- Laravel 12+\n\n## Upgrading\n\n### From v0.7.x (Filament v3) to v1.x (Filament v5)\n\n1. Update your `composer.json`:\n\n```bash\ncomposer require datlechin/filament-menu-builder:^1.0\n```\n\n2. Publish and run the new migration to add the `panel`, `icon`, and `classes` columns:\n\n```bash\nphp artisan vendor:publish --tag=\"filament-menu-builder-migrations\"\nphp artisan migrate\n```\n\nThe upgrade migration is safe to run even on fresh installs — it checks for existing columns before adding them.\n\n3. If you published the config file, re-publish it to pick up any changes:\n\n```bash\nphp artisan vendor:publish --tag=\"filament-menu-builder-config\" --force\n```\n\n## Installation\n\nInstall the package via Composer:\n\n```bash\ncomposer require datlechin/filament-menu-builder\n```\n\nPublish and run the migrations:\n\n```bash\nphp artisan vendor:publish --tag=\"filament-menu-builder-migrations\"\nphp artisan migrate\n```\n\nOptionally publish the config file:\n\n```bash\nphp artisan vendor:publish --tag=\"filament-menu-builder-config\"\n```\n\nOr use the install command:\n\n```bash\nphp artisan filament-menu-builder:install\n```\n\n## Usage\n\nRegister the plugin in your Filament panel provider:\n\n```php\nuse Datlechin\\FilamentMenuBuilder\\FilamentMenuBuilderPlugin;\n\npublic function panel(Panel $panel): Panel\n{\n    return $panel\n        -\u003eplugins([\n            FilamentMenuBuilderPlugin::make(),\n        ]);\n}\n```\n\n### Defining Locations\n\nLocations define where menus can be displayed in your application (e.g., header, footer, sidebar):\n\n```php\nFilamentMenuBuilderPlugin::make()\n    -\u003eaddLocations([\n        'header' =\u003e 'Header',\n        'footer' =\u003e 'Footer',\n    ])\n```\n\n### Custom Menu Panels\n\nMenu panels are sources for adding items to menus. You can create panels from Eloquent models or static items.\n\n#### Model Panel\n\nTo add a panel from an Eloquent model, implement the `MenuPanelable` interface on your model:\n\n```php\nuse Datlechin\\FilamentMenuBuilder\\Contracts\\MenuPanelable;\n\nclass Page extends Model implements MenuPanelable\n{\n    public function getMenuPanelTitle(): string\n    {\n        return $this-\u003etitle;\n    }\n\n    public function getMenuPanelUrl(): string\n    {\n        return route('pages.show', $this);\n    }\n\n    public function getMenuPanelName(): string\n    {\n        return 'Pages';\n    }\n}\n```\n\nThen register it with the plugin:\n\n```php\nuse Datlechin\\FilamentMenuBuilder\\MenuPanel\\ModelMenuPanel;\n\nFilamentMenuBuilderPlugin::make()\n    -\u003eaddMenuPanels([\n        ModelMenuPanel::make()\n            -\u003emodel(Page::class),\n    ])\n```\n\n#### Static Panel\n\nYou can also add static items:\n\n```php\nuse Datlechin\\FilamentMenuBuilder\\MenuPanel\\StaticMenuPanel;\n\nFilamentMenuBuilderPlugin::make()\n    -\u003eaddMenuPanels([\n        StaticMenuPanel::make()\n            -\u003ename('pages')\n            -\u003eadd('Home', '/')\n            -\u003eadd('About', '/about')\n            -\u003eadd('Contact', '/contact'),\n    ])\n```\n\n### Custom Link \u0026 Custom Text Panels\n\nThe custom link panel is shown by default. You can toggle it and also enable the custom text panel (for non-link items like headings):\n\n```php\nFilamentMenuBuilderPlugin::make()\n    -\u003eshowCustomLinkPanel(true)\n    -\u003eshowCustomTextPanel(true)\n```\n\n### Custom Fields\n\nYou can add extra fields to the menu form or the menu item edit form:\n\n```php\nuse Filament\\Forms\\Components\\TextInput;\n\nFilamentMenuBuilderPlugin::make()\n    -\u003eaddMenuFields([\n        TextInput::make('description'),\n    ])\n    -\u003eaddMenuItemFields([\n        TextInput::make('badge'),\n    ])\n```\n\n### Customizing Navigation\n\n```php\nFilamentMenuBuilderPlugin::make()\n    -\u003enavigationLabel('Menus')\n    -\u003enavigationGroup('Content')\n    -\u003enavigationIcon('heroicon-o-bars-3')\n    -\u003enavigationSort(3)\n    -\u003enavigationCountBadge(true)\n```\n\n### Indent / Unindent\n\nNested menu items are supported via indent/unindent actions. This is enabled by default:\n\n```php\nFilamentMenuBuilderPlugin::make()\n    -\u003eenableIndentActions(true)\n```\n\n### Translatable Menus\n\nThe plugin has built-in support for multilingual menu titles. No additional packages are required — translatable fields are stored as JSON and the form UI shows locale tabs.\n\n#### Setup\n\n1. Enable translatable on the plugin with your desired locales:\n\n```php\nFilamentMenuBuilderPlugin::make()\n    -\u003etranslatable(['en', 'nl', 'vi'])\n```\n\n2. Publish and run the translatable migration to convert existing columns from `string` to `json`:\n\n```bash\nphp artisan vendor:publish --tag=\"filament-menu-builder-translatable-migrations\"\nphp artisan migrate\n```\n\nThe migration automatically wraps existing string data in the default locale (`en`). To change the default locale, edit the `$defaultLocale` property in the published migration before running it.\n\n#### Configuring Translatable Fields\n\nBy default, only `MenuItem.title` is translatable. You can customize which fields are translatable:\n\n```php\nFilamentMenuBuilderPlugin::make()\n    -\u003etranslatable(['en', 'nl', 'vi'])\n    -\u003etranslatableMenuItemFields(['title'])  // default\n    -\u003etranslatableMenuFields(['name'])       // opt-in: make Menu name translatable too\n```\n\n#### Rendering Translated Titles\n\nIn your Blade views, use `resolveLocale()` to display the title in the current app locale:\n\n```blade\n@foreach($menu-\u003emenuItems as $item)\n    \u003ca href=\"{{ $item-\u003eurl }}\"\u003e\n        {{ $item-\u003eresolveLocale($item-\u003etitle) }}\n    \u003c/a\u003e\n@endforeach\n```\n\n`resolveLocale()` handles both string and array values — it returns the translation for `app()-\u003egetLocale()`, falls back to the first available translation, or returns the string as-is for non-translatable setups.\n\n#### Spatie Translatable Compatibility\n\nThe JSON data format is fully compatible with [Spatie Laravel Translatable](https://github.com/spatie/laravel-translatable). If you later add the `HasTranslations` trait to a custom model, the plugin detects it automatically and skips its own JSON casting — Spatie's mutators take over seamlessly.\n\n```php\nuse Spatie\\Translatable\\HasTranslations;\n\nclass CustomMenuItem extends MenuItem\n{\n    use HasTranslations;\n\n    public array $translatable = ['title'];\n}\n```\n\n### Custom Models\n\nYou can replace the default models with your own:\n\n```php\nFilamentMenuBuilderPlugin::make()\n    -\u003eusingMenuModel(CustomMenu::class)\n    -\u003eusingMenuItemModel(CustomMenuItem::class)\n    -\u003eusingMenuLocationModel(CustomMenuLocation::class)\n```\n\n### Rendering Menus\n\nRetrieve a menu by its location in your views or controllers:\n\n```php\nuse Datlechin\\FilamentMenuBuilder\\Models\\Menu;\n\n$menu = Menu::location('header');\n```\n\nThis uses caching under the hood for performance. The cache is automatically busted when menus or menu items are updated.\n\nLoop through menu items:\n\n```blade\n@if($menu)\n    \u003cnav\u003e\n        \u003cul\u003e\n            @foreach($menu-\u003emenuItems as $item)\n                \u003cli class=\"{{ $item-\u003eclasses }} {{ $item-\u003eisActive() ? 'active' : '' }}\"\u003e\n                    @if($item-\u003eurl)\n                        \u003ca href=\"{{ $item-\u003eurl }}\" target=\"{{ $item-\u003etarget }}\"\u003e\n                            {{ $item-\u003eresolveLocale($item-\u003etitle) }}\n                        \u003c/a\u003e\n                    @else\n                        \u003cspan\u003e{{ $item-\u003eresolveLocale($item-\u003etitle) }}\u003c/span\u003e\n                    @endif\n\n                    @if($item-\u003echildren-\u003eisNotEmpty())\n                        \u003cul\u003e\n                            @foreach($item-\u003echildren as $child)\n                                \u003cli\u003e\n                                    \u003ca href=\"{{ $child-\u003eurl }}\"\u003e{{ $child-\u003eresolveLocale($child-\u003etitle) }}\u003c/a\u003e\n                                \u003c/li\u003e\n                            @endforeach\n                        \u003c/ul\u003e\n                    @endif\n                \u003c/li\u003e\n            @endforeach\n        \u003c/ul\u003e\n    \u003c/nav\u003e\n@endif\n```\n\n#### Active State Detection\n\nMenu items provide methods for checking if they match the current URL:\n\n```php\n$item-\u003eisActive();                 // exact URL match\n$item-\u003eisActiveOrHasActiveChild(); // matches self or any descendant\n```\n\n### MenuItem Properties\n\n| Property   | Type     | Description                           |\n|------------|----------|---------------------------------------|\n| `title`    | string\\|array | The display title (array when translatable) |\n| `url`      | ?string  | The URL (null for text-only items)    |\n| `target`   | string   | Link target (`_self`, `_blank`, etc.) |\n| `icon`     | ?string  | Icon identifier (e.g. `heroicon-o-home`) |\n| `classes`  | ?string  | CSS classes for the item              |\n| `type`     | string   | Panel name / source type (accessor)   |\n| `children` | Collection | Nested child items                  |\n\n## Testing\n\n```bash\ncomposer test\n```\n\n## Changelog\n\nPlease see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatlechin%2Ffilament-menu-builder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdatlechin%2Ffilament-menu-builder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatlechin%2Ffilament-menu-builder/lists"}