.on web development, Drupal, PHP, photography, and the like.

Drupal template.php Menu Snippit

Posted by root
08.10th.2008

Filed under:

This Drupal PHP snippit generates first/last and active classes for a menu and its sub menu's. It's great for when you have a couple different kinds of menu layouts. For example, the primary links are a drop down menu with a coloured active state and the footer menu has vertical bars between list elements, but not at the end.

The snippit generates active states which follow through from top level menus as well as sub menu's, picking out the first and last links in each list. Below, the top level link 'Link 2' class is active and its submenu 'sub two' link and list item are active as well as having 'last' class in the list < li >.

<ul class="menu">
  <li class="leaf first"><a href="/">Link 1</a>
  <li class="expanded active"><a href="/en/node/4">Link 2</a>
    <ul class="menu">
      <li class="leaf first"><a href="/en/node/9">sub one</a></li>
      <li class="leaf last active"><a href="/en/node/1" class="active">sub two</a></li>
    </ul>
  </li>
  <li class="leaf"><a href="/">Link 3</a></li>
  <li class="leaf"><a href="/">Link 4</a></li>
  <li class="leaf last"><a href="/">Link 5</a></li>
</ul>

Mix the above with some CSS, you have all the control over your menu's. Attached is a text file with three functions you copy/paste into your template.php. (function phptemplate_menu_tree, function phptemplate_menu_tree_improved, function phptemplate_menu_item) These functions are not new in Drupal, in fact, you can search on their site for this and a few will result in either: add active class to menu's OR add first/last class to menu's, but not both. :( What I did, was, merge a couple phptemplate_menu_xx functions together to satisfy both types of output (active and first/last). Enjoy!

function phptemplate_menu_tree($pid = 1) {
  if ($tree = phptemplate_menu_tree_improved($pid)) {
    return "\n<ul class=\"menu\">\n". $tree ."\n</ul>\n";
  }
}
 
function phptemplate_menu_tree_improved($pid = 1) {
  $menu = menu_get_menu();
  $output = '';
 
  if (isset($menu['visible'][$pid]) && $menu['visible'][$pid]['children']) {
    $num_children = count($menu['visible'][$pid]['children']);
    for ($i=0; $i < $num_children; ++$i) {
      $mid = $menu['visible'][$pid]['children'][$i];
      $type = isset($menu['visible'][$mid]['type']) ? $menu['visible'][$mid]['type'] : NULL;
      $children = isset($menu['visible'][$mid]['children']) ? $menu['visible'][$mid]['children'] : NULL;
      $extraclass = $i == 0 ? 'first' : ($i == $num_children-1 ? 'last' : '');
      $output .= theme('menu_item', $mid, menu_in_active_trail($mid) || ($type & MENU_EXPANDED) ? theme('menu_tree', $mid) : '', count($children) == 0, $extraclass);   
    }
  }
  return $output;
}
 
function phptemplate_menu_item($mid, $children = '', $leaf = TRUE, $extraclass = '') {
  $item = menu_get_item($mid); // get current menu item
  // decide whether to add the active class to this menu item
 if((($link_item['path']=='<front>') && ($front==$_GET['q'])) ||
    (menu_in_active_trail($mid))){
    $active_class = ' active'; // set active class
  } else { // otherwise...
    $active_class = ''; // do nothing
	}
 return '<li class="'. ($leaf ? 'leaf' : ($children ? 'expanded' : 'collapsed')) . ($extraclass ? ' ' . $extraclass : '') . $active_class .'">'. menu_item_link($mid, TRUE, $extraclass) . $children ."</li>\n";
}

Related Content: Dropping Horizontal Menu's in Drupal