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

Knp Menu Bundle Laravel Package

knplabs/knp-menu-bundle

KnpMenuBundle integrates the KnpMenu PHP library with Symfony, making it easy to build feature-rich, flexible menus in your Symfony applications with minimal configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first: KnpMenuBundle is a Symfony bundle (it registers services into Symfony's kernel/bundles.php, ships a DI extension, and leans on Twig helpers + the Symfony request stack). You cannot composer require knplabs/knp-menu-bundle into a Laravel app and get the bundle to boot — there is no bundle registration hook. What you can do is pull in the underlying standalone library (knplabs/knp-menu) and use it directly, then mirror the bundle's idioms in Laravel. Treat this repo as the reference implementation/architecture guide rather than a drop-in dependency.

Minimal path to first use (Symfony reference, so you understand the model before porting it):

  1. composer require knplabs/knp-menu-bundle (requires PHP 8.2+ and a supported Symfony as of v3.8.0).
  2. Enable the bundle in config/bundles.php (Flex does this for you).
  3. Create a menu builder class implementing Knp\Menu\BuilderInterface (or ContainerAwareInterface variants for autowiring).
  4. Register it as a service tagged knp_menu.menu_builder — or, since v3.6, just add #[AsMenuBuilder] and let autoconfiguration handle the tag.
  5. Render in Twig: {{ knp_menu_render('main', {'currentClass': 'active'}) }}.

Where to look first:

  • docs/ in the bundle repo (the canonical usage docs live at symfony.com/bundles/KnpMenuBundle).
  • The KnpMenu core docs — the bundle is thin glue; MenuFactory, ItemInterface::addChild, setUri, setRoute, and MatcherInterface are where the real behavior lives.
  • The default knp_menu.html.twig theme, to see exactly what HTML the renderer emits and which blocks you can override.

First Laravel-appropriate use case: a permission-gated main navigation. Build the tree in a dedicated class (App\Menus\MainMenu), inject it via the container, match "active" items against the current route, and render a Blade partial. The shape of the problem is identical; only the plumbing differs.

Implementation Patterns

One builder class per menu, never inline arrays. The bundle's core value is that menus are services, so they are testable and injectable. In Laravel, mirror this with App\Menus\MainMenuBuilder classes resolved from the container — not Menu::make() calls in a controller.

Shared attributes via a factory extension. The bundle autoconfigures ExtensionInterface implementations (tag knp_menu.factory_extension, autoconfigured since v3.4). Use this to apply a common CSS class, icon, or extras array across every item so individual builders stay DRY:

public function buildOptions(array $options): array
{
    return array_merge(['extras' => ['icon' => null]], $options);
}

Gate visibility with voters, not if statements in builders. Voters (RouteVoter, CallbackVoter — auto-registered since v3.6, plus custom VoterInterface implementations) are the sanctioned place for "should this item be shown/active." Priorities let you order them. In Laravel the equivalent is a small MenuVoter service using Gate::allows() and $request->routeIs(), composed before the tree is rendered.

Active-state control is now configurable. v3.8.0 lets you disable the default RouteVoter via configuration. This matters in multi-section products where a bare route-name match highlights the wrong section; swap in a CallbackVoter keyed on a "section" attribute instead of route names.

Render through a thin adapter, not directly in views. Keep knp_menu_render/ListRenderer calls behind one Blade component or a MenuRenderer service. When you eventually change markup (mega-menu, ARIA roles), you change one template, not 40 files.

Programmatic access for non-render use cases. The MenuProviderInterface (autowirable since 2.2) lets services fetch a built menu — useful for sitemaps, breadcrumb generation, and JSON APIs feeding an SPA. This is where the bundle earns its keep beyond HTML.

Cache the built tree, not the rendered HTML, when items are static. Menu construction is cheap but route/permission-dependent; cache the item list per role/section and re-run the matcher per request. Note the matcher state reset (kernel.reset tag added in 3.6) — replicate this in Laravel if you run under Octane/Swoole.

Gotchas and Tips

  • Do not attempt to install the bundle in Laravel. composer require knplabs/knp-menu-bundle will install, but nothing boots it; you'll get confusing "class not found" for the extension and no Twig helpers. Use knplabs/knp-menu standalone and write your own service provider.
  • PHP 8.2+ is mandatory as of v3.8.0, and Symfony 5 support was dropped in v3.7.0. If your CI or a legacy container is pinned to 8.1, stay on v3.7.x — v3.8.0 simply won't install. There is no Laravel version constraint to fall back on, so pin explicitly.
  • current false positives are the #1 day-to-day complaint. A RouteVoter matching on route name will light up "Blog" for blog.show, blog.index, and any admin route prefixed similarly. Either disable the voter (new in 3.8.0) or attach an explicit extras.section and match on that.
  • Menu builders are private services by default (since 2.2). If you try to $container->get('app.menu.main') in a controller it fails; inject the builder or use the provider instead.
  • Long-running workers leak matcher state. The kernel.reset tag exists precisely because the matcher caches current-item results. Under Octane/queue workers, reset it between jobs or scope it as a singleton per-request.
  • Twig theme overrides are block-based and version-sensitive. v3.4.1 fixed template discovery for templates shipped by the bundle; if you copied the old knp_menu.html.twig into your app, you may be rendering a stale copy. Prefer extending the bundle's template and overriding only item_class, link_class, etc.
  • Labels are auto-translated in the default template (since 2.1.2). If you inject pre-translated strings, you'll get double translation in some locales — set the label and let the renderer translate, or explicitly disable translation on that item.
  • Extension points worth knowing before you reimplement them: ExtensionInterface (shared attributes), VoterInterface (visibility/active logic), MatcherInterface (custom matching), and MenuManipulator (move/slice/reorder a tree at runtime — handy for A/B nav experiments). In Laravel these map cleanly to a factory decorator, Gate-backed voters, a matcher service, and a small tree utility.
  • Docs are split across two repos. When something behaves unexpectedly, check KnpMenu core first — the bundle docs assume you've read it. The bundle's own contribution is almost entirely service wiring and Twig glue.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource