Drupal - How can I access the main menu in template_preprocess_page?

Remember your menu can be a block, and to render it, you just have to load and get its view in a preprocess function.

THEME.theme file

use Drupal\block\Entity\Block;
function THEME_preprocess_page(&$variables) {
  $menu = Block::load('id_main_menu');
  $variables['main_menu'] = \Drupal::entityTypeManager()->getViewBuilder('block')->view($menu);
}

page.html.twig

...
{{main_menu}}
...

Attention
You must create your block 'main_menu' in somewhere, (module install, block structure page...)


I do not recommend hard coding a bunch of stuff in the theme because it increases the difficulty of understanding what is going on in the site for new developers, but this is possible in a couple of different ways. It would be better to use the block and region system.

Using the menu.link_tree service to build from scratch

It is important to realize that this is getting raw data, and without transforming the menu tree, no access check will be done. This may be okay because a main menu should be public, but that is not necessarily the case.

$menu_name = "main_menu"; // I think
$menu_tree = \Drupal::service('menu.link_tree');
$parameters = new \Drupal\Core\Menu\MenuTreeParameters();
$parameters
  ->setMaxDepth(1) // Or however far down the tree you want to go.
  ->onlyEnabledLinks()
  ->excludeRoot();
$tree = $menu_tree->load($menu_name, $parameters);
// $manipulators = [['callable' => 'menu.default_tree_manipulators::checkAccess']];
// $tree = $menu_tree->transform($tree, $manipulators);
foreach ($tree as $item) {
  /** @var \Drupal\Core\Menu\MenuLinkInterface $link */
  $link = $item->link;
}

Using a known block instance programmatically

See @Berdir's answer here: https://drupal.stackexchange.com/a/153195/42650

Tags:

Theming

8