In Drupal 5 you can do:


$output = menu_tree(5);

where 5 is the $mid of any menu item and you obtain the html for the subtree.

In D6 since menu_tree takes the menu internal name as argument you can only specify the entire menu.

What is the method now to render a menu subtree?

Comments

Daniel Wentsch’s picture

That's exactly the wall I'm standing in front of right now, too :(
I just need to render 3rd-level submenus of 2nd-level nodes somewhere in my template.. any suggestions?

kjl’s picture

Looking at the way the book module finds submenus in Drupal 6+, I'd guess this got harder:

http://api.drupal.org/api/function/book_menu_subtree_data/6

nosro’s picture

Looking at a complete tree obtained with menu_tree_page_data(), the top most menu elements get keys like '50000 MenuTitle ###'

50000 is an offset which increments over the menu items 50001, 50002, ... I don't know what that offset is about. There is a comment about this in the nice menu module: "// Menu sets these ghetto-ass keys in _menu_tree_check_access()."

### is the mlid (I think that equates to the 'mid' or 'pid' in D5 menu system?).

Something like this might work for you - although this will only search the first level of the menu. (This code is untested, and probably not optimized, maybe someone will improve on this in the thread)

  $fulltree = menu_tree_page_data('my_menu');
  foreach ($fulltree as $subtree_key => $subtree_data) {
    if (strstr($subtree_key,' 123 ')) { // check if mlid 123 is part of the menu key
      $subtree = subtree_data['below']; // get the subtree branching from that entry
      break; // take first match and stop looking
    }
  }
  menu_tree_output($subtree);
arthurf’s picture

[edit 2 ] Sorry misunderstood the question. Orson's snipit should do the job fine for top levels. Seems like there should be an easier way, but there doesn't seem to be an obvious way to get at lower levels of the menus. Here's an approach where you can specify the menu that you're using and the id from which you want to generate

<?php

// print the end product of the code. This will generate the menu benath
// mlid 2 in the navigation menu
print(_mymenu_subtree('navigation', 2));


/**
 * Wraps the subtree finder function
 * @param $menu_name
 * @param $mlid
 * @return string
 */
function _mymenu_subtree($menu_name, $mlid) {
  static $trees;
  if ($trees[$mlid]) { return $trees[$mlid]; }
  // build the menu tree that you want to search through
  $tree = menu_tree_page_data($menu_name);
  // get the subtree from the specified location
  if ($subtree = _mymenu_subtree_recurse($tree, $mlid) ) {
    $trees[$mlid] = $subtree;
    // return the themed tree
    return menu_tree_output($trees[$mlid]);
  }
}


/**
 * Does the menu search for the specified menu link id
 * @param $menu_items
 * @param $mlid
 * @return unknown_type
 */
function _mymenu_subtree_recurse($menu_items, $mlid) {
  foreach ($menu_items as $id => $item) {
    // check the current menu link id against the mlid
    if ($menu_items[$id]['link']['mlid'] == $mlid) {
      // if we found the mlid, return it in the correct format
      return $return[$id] = array($id => $menu_items[$id]);
    }
    else {
      // if there are sub items, search through these as well
      if ($item['below']) {
        $tree = _mymenu_subtree_recurse($item['below'], $mlid);
      }
    }
  }
  // we found data; return it
  if ($tree) { return $tree; }
  return false;
}
?>
8w_gremlin’s picture

With the above code, all I'm getting back is

<ul class="menu">
<li id="menu-item-" class="collapsed">
<a href="/drupal/"/>
</li>
</ul>

Now I'm using primary-links as my menu... perhaps I'm doing something wrong
using drupal 6.8

mattyoung’s picture

Have a look at the nice_menus module. It does this. Here is its code, watch how it pick up submenu:

function theme_nice_menu_tree($menu_name, $mlid = NULL, $menu = NULL) {
  // Load the full menu array.
  $menu = isset($menu) ? $menu : menu_tree_all_data($menu_name);

  // For custom $menus and menus built all the way from the top-level we
  // don't need to "create" the specific sub-menu and we need to get the title
  // from the $menu_name since there is no "parent item" array.

  // Create the specific menu if we have a mlid.
  if (!empty($mlid)) {
    // Load the parent menu item.
    $item = menu_link_load($mlid);
    $title = check_plain($item['title']);
    // Narrow down the full menu to the specific sub-tree we need.
    for ($p = 1; $p < 10; $p++) {
      if ($sub_mlid = $item["p$p"]) {
        $subitem = menu_link_load($sub_mlid);
        // Menu sets these ghetto-ass keys in _menu_tree_check_access().
        $menu = $menu[(50000 + $subitem['weight']) .' '. $subitem['title'] .' '. $subitem['mlid']]['below'];
      }
    }
  }
  // Otherwise just set a title and move on.
  else {
    // Get the title from the DB since we don't have it in the $menu.
    $result = db_result(db_query("SELECT title FROM {menu_custom} WHERE menu_name = '%s'", $menu_name));
    $title = check_plain($result);
  }

  $output['content'] = '';
  $output['subject'] = $title;

  if ($menu) {
    $output['content'] .= theme('nice_menu_build', $menu);
  }

  return $output;
}

You can just use nice_menus and call theme('nice_menu', 'menu_name', $submenu_id).

illSleepWheniDie’s picture

thanks, I got this working perfectly for drupal 6 with the code above.

bfr’s picture