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?


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 '16 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 – Matt May 23 '17 at 16:12
  • 1
    What about var_dump($link); exit;? – mradcliffe May 23 '17 at 17:06
  • 1
    same problem as @Matt – GiorgosK Nov 13 '17 at 21:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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