I have been trying to create a custom menu block which shows a number of menu items with images on the current level.

I am having an issue where the active trail array doesn't return an menu item for the active node on level 4 of my menu. Here is an example of how I get the active trail:

$menu_tree = \Drupal::menuTree();
$menu_parent_tree = \Drupal::menuTree();
$menu_name = 'main';

// Build the typical default set of menu tree parameters.
$parameters = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name);

foreach($parameters->activeTrail as $active_menu_link) {
  if($active_menu_link !== '') {
    $active_menu_id = explode(':', $active_menu_link);
    $entity = \Drupal::entityManager()->loadEntityByUuid($active_menu_id[0], $active_menu_id[1]);


It seems that the issue is mostly related to the fact that the same node is linked to both a child menu item and a parent menu item. If I remove this then the function works as expected. This is the my menu structure.

Menu Structure for Site

The two menu items highlighted in red are both linked to the same node since I want it to act as an overview page for the category. It could be that theres something else I can do to structure the menu differently. I am open to any alternatives on how I can get around this.

1 Answer 1


I resolved this by manipulating the tree object manually further down my module. I checked if the url of the parent object matched any of the child objects via a loop.

$menu_tree = \Drupal::menuTree();
$menu_parent_tree = \Drupal::menuTree();
$menu_name = 'main';

// Build the typical default set of menu tree parameters.
$parameters = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name);

// Setup current link
$currentLinkId = reset($parameters->activeTrail);

// Load the tree based on this set of parameters.
$tree = $menu_tree->load($menu_name, $parameters);

// Get the parent of current menu so we can use its
// children as the links
$tree = $menu_parent_tree->load($menu_name, $parameters);

// Transform the tree using the manipulators you want.
$manipulators = array(
  // Only show links that are accessible for the current user.
  array('callable' => 'menu.default_tree_manipulators:checkAccess'),
  // Use the default sorting of menu links.
  array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
$tree = $menu_parent_tree->transform($tree, $manipulators);

foreach($tree as $key => $menu_item) {
  // Check if the link is the current page?
  $current_internal_path = $menu_item->link->getUrlObject()->toString();
  foreach($menu_item->subtree as $sub_key => $sub_link) {
    $sub_internal_path = $sub_link->link->getUrlObject()->toString();

    if($current_internal_path == $sub_internal_path) {

    // Check if we have another sub tree (we are not the parent). This can happen when a parent
    // link is attached to the same node as a child one.
    if($sub_link->subtree && count($sub_link->subtree)) {
      $lower_level_links = $sub_link->subtree;

      foreach($lower_level_links as $lower_link_key => $lower_level_link) {
        $lower_level_url = $lower_level_link->link->getUrlObject()->toString();
        if($sub_internal_path == $lower_level_url) {
          // Set the active menu level as this.
          $tree = array($sub_link);

// Build up our menu
$menu = $menu_tree->build($tree);

This is perhaps not the cleanest solution with a lot of extra processing required but seems to work in this instance.

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.