Change record status: 
Project: 
Introduced in branch: 
8.x
Description: 

Change description

All tree related functions in menu.inc have been moved to multiple services provided by the Drupal core:

  • plugin.manager.menu.link provides an instance of \Drupal\Core\Menu\MenuLinkManagerInterface
  • menu.link_tree provides an instance of \Drupal\Core\Menu\MenuLinkTreeInterface
  • menu.active_trail provides an instance of \Drupal\Core\Menu\MenuActiveTrailInterface
  • menu.parent_form_selector provides an instance of \Drupal\Core\Menu\MenuParentFormSelectorInterface

An additional service provides helper methods for access checking and other manipulations of the tree

  • menu.default_tree_manipulators provides an instance of \Drupal\Core\Menu\DefaultMenuLinkTreeManipulators

The menu.link_tree service is the most likely to be used by developers in modules and is available using the method \Drupal::menuTree().

The following Drupal 7 functions have been removed from menu.inc. Where it exists, the corresponding Drupal 8 MenuTree method is indicated.

Drupal 7 Drupal 8
menu_tree() no single replacement - use: MenuLinkTreeInterface::load() + MenuLinkTreeInterface::transform() + MenuLinkTreeInterface::build()
menu_tree_output() MenuLinkTreeInterface::build()
menu_tree_all_data() MenuLinkTreeInterface::load()
menu_tree_set_path() n/a (must override menu.active_trail service)
menu_tree_get_path() MenuActiveTrailInterface::getActiveLink()
menu_tree_page_data() MenuLinkTreeInterface::load()
menu_build_tree() MenuLinkTreeInterface::transform()
menu_tree_collect_node_links() n/a (internal to implementation)
menu_tree_check_access() DefaultMenuLinkTreeManipulators::checkAccess()
menu_tree_data() n/a (internal to implementation)
menu_parent_options() MenuParentFormSelectorInterface::getParentSelectOptions()or better to use MenuParentFormSelectorInterface::parentSelectElement()

Code example

The Toolbar module builds a menu tree. Previously it used functions from menu.inc. Now it has been updated to use the menu.link_tree service.

Drupal 7

// Retrieve the administration menu from the database.
$tree = toolbar_get_menu_tree();

// Add attributes to the links before rendering.
toolbar_menu_navigation_links($tree);

$menu = array(
  '#heading' => t('Administration menu'),
  'toolbar_administration' => array(
    '#type' => 'container',
    '#attributes' => array(
      'class' => array('toolbar-menu-administration'),
    ),
    'administration_menu' => menu_tree_output($tree),
  ),
);

Drupal 8 after addition of services

Example from function _toolbar_do_get_rendered_subtrees(). [Note: A better example is needed to show how we would get at the individual links. This code sample appears to show the way, but this code seems to fail if the tree is used for anything besides rendering a menu.]

  $menu_tree = \Drupal::service('toolbar.menu_tree');
  // Load the administration menu. The first level is the "Administration" link.
  // In order to load the children of that link and the subsequent two levels,
  // start at the second level and end at the fourth.
  $parameters = new MenuTreeParameters();
  $parameters->setMinDepth(2)->setMaxDepth(4)->onlyEnabledLinks();
  // @todo Make the menu configurable in https://www.drupal.org/node/1869638.
  $tree = $menu_tree->load('admin', $parameters);
  $manipulators = array(
    array('callable' => 'menu.default_tree_manipulators:checkAccess'),
    array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
    array('callable' => 'toolbar_menu_navigation_links'),
  );
  $tree = $menu_tree->transform($tree, $manipulators);
  $subtrees = array();
  // Calculated the combined cacheability of all subtrees.
  $cacheability = new CacheableMetadata();
  foreach ($tree as $element) {
    /** @var \Drupal\Core\Menu\MenuLinkInterface $link */
    $link = $element->link;
    if ($element->subtree) {
      $subtree = $menu_tree->build($element->subtree);
      $output = \Drupal::service('renderer')->renderPlain($subtree);
      $cacheability = $cacheability->merge(CacheableMetadata::createFromRenderArray($subtree));
    }
    else {
      $output = '';
    }
  }

See also another change record example of building a tree.

Impacts: 
Module developers
Themers