Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drupal Menu System - Outputting a Tree One Level Down

Tags:

tree

menu

drupal

I've been reading through the various menu functions in Drupal, but there are sooo many, and I've reached a point of utter confusion and despair... Hoping one of the smarties here can help me out...

Basically, I have four levels to my menu. I'm trying to create a tree that outputs from the second level down.

So, the menu looks like this: LEVEL ONE > Sublevel A > Sublevel I > Sublevel a

I'm trying to output the menu tree beginning with Sublevel A (i.e., Sublevel A > Sublevel I > Sublevel a)

But, can't for the life of me figure out how to do that... I tried simply getting the mlid of the Sublevel A menu (in this case 69), and then

<?php print theme_menu_tree(69); ?>

but it just prints out '69'. Not at all what I expected...

Anyone know how to do this?

like image 222
phpN00b Avatar asked Dec 03 '09 18:12

phpN00b


3 Answers

The Menu Block module will do exactly what you need. (It uses similar logic to the custom function presented above).

like image 163
jhedstrom Avatar answered Oct 14 '22 14:10

jhedstrom


I always wondered why there is no function for this in core, but afaik there is none.

So it looks like we need to roll our own, walking a complete menu tree until we find the subtree we need:

/**
 * Extract a specific subtree from a menu tree based on a menu link id (mlid)
 *
 * @param array $tree
 *   A menu tree data structure as returned by menu_tree_all_data() or menu_tree_page_data()
 * @param int $mlid
 *   The menu link id of the menu entry for which to return the subtree
 * @return array
 *   The found subtree, or NULL if no entry matched the mlid
 */
function yourModule_menu_get_subtree($tree, $mlid) {
  // Check all top level entries
  foreach ($tree as $key => $element) {
    // Is this the entry we are looking for?
    if ($mlid == $element['link']['mlid'])  {
      // Yes, return while keeping the key
      return array($key => $element);
    }
    else {
      // No, recurse to children, if any
      if ($element['below']) {
        $submatch = yourModule_menu_get_subtree($element['below'], $mlid);
        // Found wanted entry within the children?
        if ($submatch) {
          // Yes, return it and stop looking any further
          return $submatch;
        }
      }
    }
  }
  // No match at all
  return NULL;
}

To use it, you first need to get the tree for the whole menu, using menu_tree_page_data() or menu_tree_all_data(), depending on what you need (check the API definitions for the difference). Then you extract the subtree you want, based on the mlid. This subtree can then be rendered into HTML via menu_tree_output():

$mlid = 123; // TODO: Replace with logic to determine wanted mlid
$tree = menu_tree_page_data('navigation'); // TODO: Replace 'navigation' with name of menu you're interested in
// Extract subtree
$subtree = yourModule_menu_get_subtree($tree, $mlid);
// Render as HTML menu list
$submenu = menu_tree_output($subtree);

Disclaimer: I am not sure if this is a good/proper way to do it - it is just the solution I came up with after going through the same procedure as the OP, that is, reading through the whole menu module functions, always wondering if I'm missing the obvious somewhere...

like image 42
Henrik Opel Avatar answered Oct 14 '22 14:10

Henrik Opel


Still on the path of custom functions... Today - why looking for something totally different - I found yet another colleague facing the same problem and coming up with yet another solution.

The original post is here. The following is the c&p of the code snippet there.

// will return all menu items under "administration".
print theme('menu_tree_by_path','admin');

// will return links to all node submission forms
print theme('menu_tree_by_path','node/add');

// return the correct menu array by path
function menu_get_mid_by_path($path) {
// oddly, menu_get_item accepts a path, but returns the parent id.
  $menu = menu_get_item(null, $path);
  if (isset($menu['children'])) {
// so we have to extract the mid for theme_menu_tree from one of the child items
    if ($pid = end($menu['children'])) {
      $menu = menu_get_item($pid);
      return $menu['pid'];
    }
  }
}

//theme the crap out of it
function theme_menu_tree_by_path($path) {
  if ($mid = menu_get_mid_by_path($path)) {
    return theme('menu_tree', $mid);
  }
} 
like image 30
mac Avatar answered Oct 14 '22 12:10

mac