If you are working with a designer, you really wish there was a template for menu items.

The following solution is for PHPTemplate engine.
It will work if you display your menu using something like this in your page.tpl:

<?php print theme('menu_links', $primary_links); ?>

Please notice: some themes, including Zen, display their menus like this:

 <?php print theme('links', $secondary_links); ?>

I believe my solution will not work in such cases.

Ok, here we go.

Step 1 of 2

override theme_menu_links function by putting the following in your template.php

<?php
/**
 * Duplicates theme_menu_links and, (only for this function), l(), 
 * and adds a template
 */
function phptemplate_menu_links($links) {
  if (!count($links)) {
    return '';
  }
  $level_tmp = explode('-', key($links));
  $level = $level_tmp[0];
  $output = "<ul class=\"links-$level\">\n";
  foreach ($links as $index => $link) {

// extracting HTML classes from link's attributes - we will pass them to the template in a separate variable
    if (isset($link['attributes']['class'])){
      $classes = check_plain($link['attributes']['class']);
      unset($link['attributes']['class']);
    }
    else {
      $classes = '';
    }
// is this an active link? Standard Drupal class for this is 'active', but the designer may want to use another name, so we remove 'active' and set a variable
    if (($link['href'] == $_GET['q']) || (stristr($index, 'active')))  {
      $link_is_active = TRUE;
      $classes = str_replace ('active', '', $classes);
    }
    else {
      $link_is_active = FALSE;
    }

    $link_to = check_url(url($link['href'], $link['query'], $link['fragment'], FALSE));
    $title = check_plain($link['title']);
// we have removed HTML classes, but there may be other attributes, like ID and such, so we pass them to the template
    $link_attributes = drupal_attributes($link['attributes']);

// define variables for use in the template
    $variables = array(
      'link_is_active' => $link_is_active,
      'link_to' => $link_to,
      'classes' => $classes,
      'attributes' => $link_attributes,
      'title' => $title
    );

    $output .= _phptemplate_callback('menu_item', $variables);
  }
  $output .= '</ul>';

  return $output;
}
?>

Step 2 of 2

create a new template, "menu_item.tpl.php" and fill it up with something like this:

<?php
/**
 This template is called from function phptemplate_menu_links() in your template.php
 Available variables are:
       $link_is_active - you can use it to assign class 'active' to the active menu items. The override function REMOVES the automatic assignment, so if you want it, you have to do it in the template;
       $link_to'  - this is what usually goes after your 'href="
       $classes - classes assigned by Drupal;
       $position' - can be used as a class name. Possible values: 'first', 'middle', 'last'.
      'item_id' - unique id of the menu item, looks something like 'menu-1-2-3' or 'menu-1-2-3-active';
      'attributes' - other HTML link attributes, like ID and such, already formatted by Drupal;
      'title' - the text displayed for your link.

 */
?>
  <li id="<?php print $item_id; ?>" <?php if ($link_is_active): ?> class="active"  <?php endif; ?> >
    <a href="<?php print $link_to; ?>" <?php print $attributes; ?> class="<?php print $classes; ?> <?php if ($link_is_active): ?> active <?php endif; ?>" >  <?php print $title; ?>  </a>
  </li>

Step 3 of 2

Watch your designer weep with joy.

Step 4 of 2

Write a better snippet and post it here.

Just to help the searchers

The above code facilitates adding class="active" to the LI tag of any menu. I'm adding this somewhat redundant comment because that should be spelled out for the search engine.

Reasons for wanting the class="active" on the li tag, rather than the nested a tag, are better css support for background images based on state with LI.

Perhaps you are like me, and had this functionality with the $primary_links built-in your theme, but later needed to give some random menu group the same treatment as your primary and/or secondary links. Use the above function in conjunction with theme_menu_tree($mid), and the rest is just some CSS details.

And yeah, it's a designer that will get you into this...

Comments

marcushenningsen’s picture

Thanks for sharing this.

Do you think I would be able to use e.g. an image attached (through imagefield) to the node of a given menu item?

Marcus