I would like to assign the main menu of my site to a variable using template_preprocess_page() so that I can just use something like {{main_menu}} in the page template. Any ideas on how I would go about doing this, without having to assign the Menu to a Region?

2 Answers 2


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);



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

  • A menu is not a block. However the core menu module provides block plugins for each menu (or one plugin with derivatives).
    – mradcliffe
    Feb 19, 2016 at 14:04

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();
  ->setMaxDepth(1) // Or however far down the tree you want to go.
$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

  • 1
    This looks like the route I want to go in, but when performing die(print_r($link)) inside that loop I get a completely blank result. Same happens when I try to print out $tree. I've double checked and the menu name is correct, and the rest of the code is exactly the same. I'm performing this in the preprocess page function
    – Amy
    May 23, 2017 at 16:12
  • 1
    What about var_dump($link); exit;?
    – mradcliffe
    May 23, 2017 at 17:06
  • 1
    same problem as @Matt
    – GiorgosK
    Nov 13, 2017 at 21:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.