I've dig into Drupal menu core to find out a way to build an associative array from a menu tree(eg,the account menu) so that I can output the data as json format. But it seems not possible to do this with Drupal 8. The info I need from a menu tree include title, description, url, and I also need to know whether it has sub menu and if it's enabled. All this can be easily achieved using menu_build_tree()
function in Drupal 7. Please understand I tried the so-called Drupal 8 equivalent of menu_build_tree()
(\Drupal::menuTree()
;) but it just gives me large object using which I don't know how to extract the data I need.
2 Answers
You can load up the menu tree with MenuLinkTree::load
, which will give you an array of menu links to work with. From there it's just a matter of looping through and getting what you need, e.g.
$tree = \Drupal::menuTree()->load('main', new \Drupal\Core\Menu\MenuTreeParameters());
foreach ($tree as $item) {
$title = $item->link->getTitle();
$url_obj = $item->link->getUrlObject();
$has_children = $item->hasChildren;
// etc...
}
The link
is a MenuLinkInterface
, each item itself is a MenuLinkTreeElement
.
It would be preferable to inject the menu.link_tree
service if possible, rather than getting it from \Drupal
.
I'm quite late, but maybe helps someone looking for answers, here's my solution for generating recursive array from menu items.
private function generateSubMenuTree(&$output, &$input, $parent = FALSE) {
$input = array_values($input);
foreach($input as $key => $item) {
//If menu element disabled skip this branch
if ($item->link->isEnabled()) {
$key = 'submenu-' . $key;
$name = $item->link->getTitle();
$url = $item->link->getUrlObject();
$url_string = $url->toString();
//If not root element, add as child
if ($parent === FALSE) {
$output[$key] = [
'name' => $name,
'tid' => $key,
'url_str' => $url_string
];
} else {
$parent = 'submenu-' . $parent;
$output['child'][$key] = [
'name' => $name,
'tid' => $key,
'url_str' => $url_string
];
}
if ($item->hasChildren) {
if ($item->depth == 1) {
$this->generateSubMenuTree($output[$key], $item->subtree, $key);
} else {
$this->generateSubMenuTree($output['child'][$key], $item->subtree, $key);
}
}
}
}
And call that function with
//Get drupal menu
$sub_nav = \Drupal::menuTree()->load('sub-navigation', new \Drupal\Core\Menu\MenuTreeParameters());
//Generate array
$this->generateSubMenuTree($menu_tree2, $sub_nav);
-
Tnaks a lot, your solution solved my problem. I posted your solution here stackoverflow.com/questions/54245942/… Commented Jan 18, 2019 at 12:57