Rendering Menus

Displaying menus in Drupal can get complicated. Here's how to customize them.

Core Menu API

The core menu system provides a way to set up a hierarchical order of links.

Links are defined in *.links.menu.yml files.

The core Menu UI module provides a UI to override the placement of links.

The core Menu Link Content module provides a content entity to create menu links in the UI.

Core Menu Block

To display a menu, place it's block in a page region.

The SystemMenuBlock plugin in core provides a configuration form for loading the menu. You can choose the depth, and force expanding menu links (otherwise it will only expand ones that are set to expand in the UI).

The block uses the MenuLinkTree service to build the output.

See MenuLinkTreeInterface for notes on the functions.

See MenuTreeParameters for the options.

SystemMenuBlock::build() uses MenuLinkTree::getCurrentRouteMenuTreeParameters($menu_name) for defaults, or creates new MenuTreeParameters and sets menu active trail if the "expand all menu links" option is set.

Then it sets min and max depth based on the configured initial visibility level, and number of levels to display.

Then it runs MenuLinkTree::transform() with the default menu manipulators for access and link order.

And finally MenuLinkTree::build() to load a render array.

See menu api notes.

Menu Block Module

Enhances the core menu block with additional options.

Select a parent link as the menu tree root.

Menu Item Extras module

Enhanced link display and mega menus.

Makes Menu Link Content entities fieldable with configurable display, including layout builder.

Since the values are stored on the menu link, caching issues can be avoided.

Uses hook_entity_type_build() to replace the MenuLinkContent entity class with MenuItemExtrasMenuLinkContent, and some additional setup.

MenuItemExtrasMenuLinkContent::preCreate() loads the menu name as the bundle. This means that each menu's fields and display are configured separately.

Uses hook_entity_base_field_info() to add a view mode field to select a display.

A tab is added to menu configuration to adjust the display mode, or it can be configured in the link edit form.

I think the way it's set up is robust, but can be hard to manage. It would be great if there was an organized way to set up a mega menu.

Region is added as an attribute to help with theming.

Uses hook_theme_suggestions_HOOK() to add theme suggestions.

Uses hook_entity_extra_field_info() to add child links.

Uses hook_preprocess_menu() to run MenuLinkTreeHandler->processMenuLinkTree() on the menu items. This sets up the content display and children.

Since the core issue may change how menu links bundles are handled, I'm not sure if this is the best way to go. However, there are a lot of fixes in place to make it work, so keep an eye on the issues to see when things changes.

Tags