how to get all the menu items below a certain parent in drupal?
Asked Answered
S

5

15

I really only need the mlid and title text for the first level below a certain menu item. Here's what I'm doing at the moment. (It works, but I suspect there may be a more drupal-y way.):

/**
 * Get all the children menu items below 'Style Guide' and put them in this format:
 * $menu_items[mlid] = 'menu-title'
 * @return array
 */
function mymod_get_menu_items() {
    $tree = menu_tree_all_data('primary-links');
    $branches = $tree['49952 Parent Item 579']['below']; // had to dig for that ugly key
    $menu_items = array();
    foreach ($branches as $menu_item) {
        $menu_items[$menu_item['link']['mlid']] = $menu_item['link']['title'];
    }
    return $menu_items;
}

Is there?

Salmanazar answered 26/4, 2010 at 20:53 Comment(0)
E
18

afaik, there isn't (i hope i am wrong). for the while, instead of digging for ugly keys, you can turn your function into a more abstract helper function by simply adding a foreach ($tree). then you can use your own logic to output what you want (mlid, in this case). here is my suggestion:


/**
 * Get the children of a menu item in a given menu.
 *
 * @param string $title
 *   The title of the parent menu item.
 * @param string $menu
 *   The internal menu name.
 * 
 * @return array
 *   The children of the given parent. 
 */
function MY_MODULE_submenu_tree_all_data($title, $menu = 'primary-links') {
  $tree = menu_tree_all_data($menu);
  foreach ($tree as $branch) {
    if ($branch['link']['title'] == $title) {
      return $branch['below'];
    }
  }
  return array();
}
Elisha answered 28/4, 2010 at 21:53 Comment(3)
that's definitely nicer than mine (assuming the titles are unique), except I think you mean == in your if statement. :)Salmanazar
and wait: I'm not testing this, but if ($tree???) shouldn't that maybe be if ($branch...Salmanazar
From a standards point of view: Optional parameters should be after non-optional parameters There should be no space between the function and doc comment. Doc comment - Space after first line of doc comment, full stop instead of ‘format:’ Full stops at the end of param descriptions. Space between the last param and return declaration If there are no matches of $branch[‘link’][‘title’] against $title, $childtree is undefined, which will throw a php notice. Probably easier returning $branch[‘below’] rather than assigning to a variable and breaking and return an empty array on the last line.Fieldwork
G
26

Actually there is an easy way to get that information by using menu_build_tree():

// Set $path to the internal Drupal path of the parent or
// to NULL for the current path 
$path = 'node/123';
$parent = menu_link_get_preferred($path);
$parameters = array(
    'active_trail' => array($parent['plid']),
    'only_active_trail' => FALSE,
    'min_depth' => $parent['depth']+1,
    'max_depth' => $parent['depth']+1,
    'conditions' => array('plid' => $parent['mlid']),
  );

$children = menu_build_tree($parent['menu_name'], $parameters);

$children contains all information you need. menu_build_tree() checks access or translation related restrictions too so you only get what the user really should see.

Gautama answered 23/7, 2012 at 15:11 Comment(1)
Another option is to specify the menu when you call menu_link_get_preferred($path, 'menu_name') then to get children you use menu_build_tree('menu_name', $parameters); Potentially more efficient if a node exists in multiple menus? maybe.Pseudonym
E
18

afaik, there isn't (i hope i am wrong). for the while, instead of digging for ugly keys, you can turn your function into a more abstract helper function by simply adding a foreach ($tree). then you can use your own logic to output what you want (mlid, in this case). here is my suggestion:


/**
 * Get the children of a menu item in a given menu.
 *
 * @param string $title
 *   The title of the parent menu item.
 * @param string $menu
 *   The internal menu name.
 * 
 * @return array
 *   The children of the given parent. 
 */
function MY_MODULE_submenu_tree_all_data($title, $menu = 'primary-links') {
  $tree = menu_tree_all_data($menu);
  foreach ($tree as $branch) {
    if ($branch['link']['title'] == $title) {
      return $branch['below'];
    }
  }
  return array();
}
Elisha answered 28/4, 2010 at 21:53 Comment(3)
that's definitely nicer than mine (assuming the titles are unique), except I think you mean == in your if statement. :)Salmanazar
and wait: I'm not testing this, but if ($tree???) shouldn't that maybe be if ($branch...Salmanazar
From a standards point of view: Optional parameters should be after non-optional parameters There should be no space between the function and doc comment. Doc comment - Space after first line of doc comment, full stop instead of ‘format:’ Full stops at the end of param descriptions. Space between the last param and return declaration If there are no matches of $branch[‘link’][‘title’] against $title, $childtree is undefined, which will throw a php notice. Probably easier returning $branch[‘below’] rather than assigning to a variable and breaking and return an empty array on the last line.Fieldwork
F
3

Have you looked into the Menu block module? Some more details about this module (from its project page):

... have you ever used the Main and Secondary menu links feature on your theme and wondered “how the hell do I display any menu items deeper than that?”

Well, that’s what this module does. It provides configurable blocks of menu trees starting with any level of any menu. And more!

So if you’re only using your theme’s Main menu links feature, you can add and configure a “Main menu (levels 2+)” block. That block would appear once you were on one of the Main menu’s pages and would show the menu tree for the 2nd level (and deeper) of your Main menu and would expand as you traversed down the tree. You can also limit the depth of the menu’s tree (e.g. “Main menu (levels 2-3)”) and/or expand all the child sub-menus (e.g. “Main menu (expanded levels 2+)”).

Frons answered 27/4, 2010 at 14:13 Comment(1)
Menu_block has interesting functions to help you.Jennelljenner
M
1

I use this : Just add your path and eventualy the menu and it will give you the child.

function MY_MODULE_submenu_tree_all_data($path, $menu = 'main-menu', $curr_level = 0,          $rebuilt_path='', $childtree = array()) {
$tree = menu_tree_all_data($menu);
$args = explode('/', $path);

$rebuilt_path = empty($rebuilt_path) ? $args[$curr_level] : $rebuilt_path . '/' .  $args[$curr_level];

foreach ($tree as $branch) {
    if ($branch['link']['link_path'] == $rebuilt_path) {
        $childtree = $branch['below'];
        if ($rebuilt_path != $path) {
            $curr_level++;
            MY_MODULE_submenu_tree_all_data($path, $menu, $curr_level, $rebuilt_path, $childtree);
        }
    }
}

$items = array();
foreach ($childtree as $child) {
    $items[] = l($child['link']['title'], $child['link']['link_path']);
}

    return theme('item_list', array('items' => $items, 'attributes' => array(), 'type' => 'ul'));

}
Marchelle answered 18/3, 2013 at 15:14 Comment(0)
L
1

Here's a helper function to return a whole subtree of a menu, starting at a specified mlid. Some of the other posts only return the direct descendants of the current item; this will return ALL descendants.

By default it gives you the subtree starting with the current page, but you can pass in any menu tree (as returned by menu_build_tree) and any mlid.

function _menu_build_subtree($menu=NULL,$mlid=NULL) {

  if ($menu == NULL || $mlid == NULL) {
    $parent = menu_link_get_preferred();
  }
  $menu = !is_null($menu) ? $menu : menu_build_tree($parent['menu_name']);
  $mlid = !is_null($mlid) ? $mlid : $parent['mlid'];

  foreach ($menu as $branch) {
    if ($branch['link']['mlid'] == $mlid) { 
      return $branch;
    }
    $twig = _menu_build_subtree($branch['below'],$mlid);
    if ($twig) { return $twig; }
  }

  return array();
}
Lacreshalacrimal answered 5/3, 2016 at 21:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.