4

I know I can load the node's menu item like so:

$node_id = $node->id();
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
$result = $menu_link_manager->loadLinksByRoute('entity.node.canonical', array('node' => $node_id));

But to use a menu structure in a breadcrumb I need to load all parent menu items. I feel like the menu service provides such a function but I dont get anything out of the documentation. This here seems pretty mighty but it really lacks documentation.

Edit: I've already came this far:

$node_id = $node->id();
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
$menu_link = $menu_link_manager->loadLinksByRoute('entity.node.canonical', array('node' => $node_id));

if (is_array($menu_link) && count($menu_link)) {
  $menu_link = reset($menu_link);
  if ($menu_link->getParent()) {
    $parents = $menu_link_manager->getParentIds($menu_link->getParent());
    dpm($parents);
  }
}

and it gives me:

Array
(
  [menu_link_content:2fd24ddd-19e2-4e8f-9764-839b3f51139e] => menu_link_content:2fd24ddd-19e2-4e8f-9764-839b3f51139e
  [menu_link_content:e30b827f-bc67-4892-b23f-28b23188ffd4] => menu_link_content:e30b827f-bc67-4892-b23f-28b23188ffd4
)

Is there an easy way to get those titles?

4 Answers 4

10

Even shorter using the MenuActiveTrailInterface.

$node_id = $node->id();
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
$menu_link = $menu_link_manager->loadLinksByRoute('entity.node.canonical', array('node' => $node_id));
$currentPluginId = $menu_link->getPluginId();
$trailIds = $this->menuActiveTrail->getActiveTrailIds('main');

foreach (array_reverse($trailIds) as $key => $value) {
  if ($value && $value !== $currentPluginId) {
    $breadcrumb->addLink(
      new Link(
        $menu_link_manager->createInstance($value)->getTitle(),
        $menu_link_manager->createInstance($value)->getUrlObject()
      )
    );
  }
}
2
  • Where would you initialize the breadcrumb variable to begin with?
    – Amy
    Commented Sep 14, 2018 at 15:58
  • @ref : drupal.org/node/2240003
    – JFC
    Commented Jul 29, 2019 at 20:53
7

In case it help anyone I used a combination of Alex's solutions to write a function that returns the parent menu item for the current node.

function mymodule_get_parent_menu_title() {
  $menu_link_manager = \Drupal::service('plugin.manager.menu.link');

  $node_id = \Drupal::routeMatch()->getRawParameter('node');
  if ($node_id) {
    $menu_link = $menu_link_manager->loadLinksByRoute('entity.node.canonical', array('node' => $node_id));
  }
  else {
    return '';
  }

  if (is_array($menu_link) && count($menu_link)) {
    $menu_link = reset($menu_link);
    if ($menu_link->getParent()) {
      $parents = $menu_link_manager->getParentIds($menu_link->getParent());
      $parent = reset(array_reverse($parents));
      $title = $menu_link_manager->createInstance($parent)->getTitle();

      return $title;
    }
  }

  return '';
}
0

So, this code works but I doubt that this is the most performant way of doing it...

$node_id = $node->id();
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
$menu_link = $menu_link_manager->loadLinksByRoute('entity.node.canonical', array('node' => $node_id));

if (is_array($menu_link) && count($menu_link)) {
  $menu_link = reset($menu_link);
  if ($menu_link->getParent()) {
    $parents = $menu_link_manager->getParentIds($menu_link->getParent());
    if (is_array($parents) && count($parents)) {
      $_parents = array();
      foreach ($parents as $key => $uuid) {
        $uuid_parts = explode(':', $uuid);
        $_parents[] = array_pop($uuid_parts);
      }

      $mlc_ids = \Drupal::database()
        ->select('menu_link_content', 'mlc')
        ->fields('mlc', ['id'])
        ->condition('uuid', $_parents, 'IN')
        ->execute()
        ->fetchCol();

      if (is_array($mlc_ids) && count($mlc_ids)) {
        $titles = \Drupal::database()
          ->select('menu_link_content_data', 'mlcd')
          ->fields('mlcd', ['title', 'link__uri'])
          ->condition('id', $mlc_ids, 'IN')
          ->execute()
          ->fetchAllKeyed();

        foreach ($titles as $title => $entityUri) {
          $breadcrumb->addLink(new Link($title, Url::fromUri($entityUri)));
        }
      }
    }
  }
}

edit: but this does not even add menu items that do not come from nodes (for instance from views). See my other answer!

0

Alex, your previous code works well, thanks !

For making it works with views or other routes, you have to use :

  $route_name = \Drupal::service('current_route_match')->getRouteName();

instead of using the node's route

Something like

$menu_link_manager = \Drupal::service('plugin.manager.menu.link');

  $node_id = \Drupal::routeMatch()->getRawParameter('node');

  if ($node_id) {
    $menu_link = $menu_link_manager->loadLinksByRoute('entity.node.canonical', array('node' => $node_id));
  }
  else {
    $route_name = \Drupal::service('current_route_match')->getRouteName();
    $menu_link = $menu_link_manager->loadLinksByRoute($route_name);
  }

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.