Adding an "active" class to primary links - Option 2

There are quite a few posts about setting the active trail properly with primary & secondary links. In Drupal 5.x, its actually handled pretty well if you use the following code to print your primary & secondary links in page.tpl.php

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

This is all good and well, but for us themers, there's a little snag. You cannot use a generic style like a.active to hit the active menu items. By default they've got a bunch of numbers tagged onto the word "active" e.g. menu-1-3-2-active. So, basically, you have to know that menu id number to style it. Throw in 20-30 menu items, and your stylesheet is going to get seriously bloated.

The function that creates the output for the primary and secondary links is in menu.inc and is not a theme function. Hence, no simple theme override in template.php. After trolling the forums and checking out the menutrails module, I hit upon the following technique that seems to work nicely.

Step 1 - override the primary & secondary links function
Yes, you're right, you cannot do a direct theme override, because its not a theme function. But you can redefine the primary and secondary links variables by using _phptemplate_variables, before they get to page.tpl.php.

In template.php add the following code:

<?php
function _phptemplate_variables($hook, $vars = array()) {
  switch (
$hook) {
    case
'page':
     
// reset primary & secondary to use our own function
     
$vars['primary_links'] = new_primary_links();
     
$vars['secondary_links'] = new_secondary_links();
      break;
  }
  return
$vars;
}
?>

If you already have that function in your template.php file (quite likely), then you most likely have the case 'page' bit too. In this case just add inside that section:

      $vars['primary_links'] = new_primary_links();
      $vars['secondary_links'] = new_secondary_links();

Step 2 - rewrite the menu function
Now we can write our own function to create the menu links. For me, the core function was good enough, except for that "active" class. So all I did was copy and paste the functions for primary and secondary links, and add in a separate "active" class. Here's the code (somewhere in template.php):

<?php
/**
* Returns an array containing the primary links - modified to add in a separate "active" class.
*/
function new_primary_links($start_level = 1, $pid = 0) {
  if (!
module_exists('menu')) {
    return
NULL;
  }
  if (!
$pid) {
   
$pid = variable_get('menu_primary_menu', 0);
  }
  if (!
$pid) {
    return
NULL;
  }
  if (
$start_level < 1) {
   
$start_level = 1;
  }
  if (
$start_level > 1) {
   
$trail = _menu_get_active_trail_in_submenu($pid);
    if (!
$trail) {
      return
NULL;
    }
    else {
     
$pid = $trail[$start_level - 1];
    }
  }
 
$menu = menu_get_menu();
 
$links = array();
  if (
$pid && is_array($menu['visible'][$pid]) && isset($menu['visible'][$pid]['children'])) {
   
$count = 1;
    foreach (
$menu['visible'][$pid]['children'] as $cid) {
     
$index = "menu-$start_level-$count-$pid";
      if (
menu_in_active_trail_in_submenu($cid, $pid)) {
       
$index .= "-active active"; // **** HERE'S THE CHANGE
     
}
     
$links[$index] = menu_item_link($cid, FALSE);
     
$count++;
    }
  }

  // Special case - provide link to admin/build/menu if primary links is empty.
 
if (empty($links) && $start_level == 1 && $pid == variable_get('menu_primary_menu', 0) && user_access('administer menu')) {
   
$links['1-1'] = array(
     
'title' => t('Edit primary links'),
     
'href' => 'admin/build/menu'
   
);
  }
  return
$links;
}

/**
* Returns an array containing the secondary links - calls the new primary links function.
*/
function new_secondary_links() {
 
$msm = variable_get('menu_secondary_menu', 0);
  if (
$msm == 0) {
    return
NULL;
  }
  if (
$msm == variable_get('menu_primary_menu', 0)) {
    return
new_primary_links(2, $msm);
  }
  return
new_primary_links(1, $msm);
}
?>

And that's it. Pretty simple really.

Posted in:

Really close

This looks like a clean implementation of adding an active class, however if I have a menu item pointig to , it doesn't set the attribute correctly.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <b> <i> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <h2> <h3> <h4> <blockquote> <img>
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • Lines and paragraphs break automatically.
  • Web page addresses and e-mail addresses turn into links automatically.

More information about formatting options

CAPTCHA
This question is to block spam bots and check if you're human
L
D
T
u
B
H
Enter the code without spaces and pay attention to upper/lower case.
magnanimous-junior