Good day, im really struggling to get the active trail for primary links to work on D6.

iv tried this with no luck http://drupal.org/node/216763

This works on all menus but the primary and secondary links......

function jucallme_menu_item($link, $has_children, $menu = '', $in_active_trail = FALSE, $extra_class = NULL) {
  $class = ($menu ? 'expanded' : ($has_children ? 'collapsed' : 'leaf'));
  if (!empty($extra_class)) {
    $class .= ' '. $extra_class;
  }
  if ($in_active_trail) {
    $class .= ' active-trail';
  }
  return '<li class="'. $class .'">'. $link . $menu ."</li>\n";
}

if any one has some advice please help.

Comments

lathan’s picture

Iv set the "Source for the secondary links:" to primary as to achieve a parent child relation ship, i just want to get the parent set to active/active-trail.

gpk’s picture

There are loads of posts about this but they can take a while to wade through. One for example: http://drupal.org/node/140491.

The problem is that http://api.drupal.org/api/function/menu_primary_links/5 and callees and theme('links', ...) [check your page.tpl.php] never call theme('menu_item', ...). Rather, theme('menu_item_link', ...) gets called. (Don't forget that the layout of primary/secondary links is rather different from the tree-like layout of the Navigation menu or other menus when put in a block.)

Rather than try and "get this right" themeing-wise I usually just do a simple string substitution, e.g. directly in page.tpl.php:
print str_replace('-active"', '-active active-trail"', theme('links', $primary_links, array('class' => 'primary-links')))

The -active gets added to items in the trail by http://api.drupal.org/api/function/menu_primary_links/5.

Update: also the Theme developer module might be very useful to you: http://drupal.org/project/devel (highlights which theme functions/templates are used to generate any output of interest).

gpk
----
www.alexoria.co.uk

Rowanw’s picture

There was a patch here to add this feature to the Nice Menus module, so you might find some clues in the code of that patch.

Btw, your link above returns access denied for me.

--
How to override HTML in Drupal

lathan’s picture

This is a Drupal 6 install I'm working from, all the references you have given me so far are Drupal 5.

Seems that content has moved...

I used the first link in the results off. http://www.google.com/search?client=safari&rls=en-us&q=drupal+6+Primary+...

gpk’s picture

Oh joy, even the vaguely useful -active class suffix has been removed in D6, and the page describing how to fix the active trail in D6 has been unpublished!!!

>references you have given me so far are Drupal 5
Erm yes, whooops, well spotted!

For now, this link works, whether the content is any good is another matter ... actually maybe that's why the page is currently not available on d.o. ... http://66.102.9.104/search?q=cache:yPNb0HgyeK4J:drupal.org/node/216763+d...

[rant] Really this should be bog standard in core default stuff ... [/rant]

gpk
----
www.alexoria.co.uk

lathan’s picture

a bit more reading http://drupal.org/node/184955 and then there is this http://drupal.org/node/216242 but thats also not working when i try that.

seems that active trail is a real issue.. o boy.

gpk’s picture

As I stared out of the kitchen window meditating on the mix of superb themeing features and basic themeability omissions in D6, it occurred to me that part of the problem is that as implemented primary and secondary links don't do tree-structured menus at all well, perhaps because that is not what they were originally designed to do.

However the Nav menu does it all very nicely, including an "active-trail" class.

So perhaps the trick is to filch code from the core Nav menu block. We would need
- a call to get the top level menu items of a desired menu (the primary links) but no children
- another call to get the children of the currently active (or in active trail) top level menu, but none of their children (I'm sure the functions that return menu structures can have a flag set to control whether or not you get the kids).

Then use the same themeing functions as used in the Nav menu block.

Finally, squirt this all into page.tpl.php somehow.

Probably not too hard once you've found the right functions to use ... I think the place to look first would be user.module, in function user_block() with $delta == 1.

[Update]
I was too hasty. The Nav block is just http://api.drupal.org/api/function/menu_tree/6. http://api.drupal.org/api/function/menu_tree_output/6 (which is really a themeing function) looks promising, but to use the output from http://api.drupal.org/api/function/menu_tree_page_data/6 you'd need to strip the relevant parts out of the returned array. Might still be the easiest way.

Or have a play with the theme developer module ... might highlight a theme function that you can re-implement to do a check to see if each menu item is in the return value of http://api.drupal.org/api/function/menu_get_active_trail/6.

gpk
----
www.alexoria.co.uk

sepeck’s picture

Primary and Secondary links are historical oddities and designed as tools with a very specific set of capabilities. They are the result of evolution of versions. If you can accomplish the same thing with a conventional menu, then that would be the way to go.

-Steven Peck
---------
Test site, always start with a test site.
Drupal Best Practices Guide -|- Black Mountain

-Steven Peck
---------
Test site, always start with a test site.
Drupal Best Practices Guide

lathan’s picture

I think we could get the active trail added here, im just not sure how to make this evaluate all the levels.

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

<?php
function theme_links($links, $attributes = array('class' => 'links')) {
  $output = '';

  if (count($links) > 0) {
    $output = '<ul'. drupal_attributes($attributes) .'>';

    $num_links = count($links);
    $i = 1;

    foreach ($links as $key => $link) {
      $class = $key;

      // Add first, last and active classes to the list of links to help out themers.
      if ($i == 1) {
        $class .= ' first';
      }
      if ($i == $num_links) {
        $class .= ' last';
      }
      if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))) {
        $class .= ' active';
      }
      $output .= '<li class="'. $class .'">';

      if (isset($link['href'])) {
        // Pass in $link as $options, they share the same keys.
        $output .= l($link['title'], $link['href'], $link);
      }
      else if (!empty($link['title'])) {
        // Some links are actually not links, but we wrap these in <span> for adding title and class attributes
        if (empty($link['html'])) {
          $link['title'] = check_plain($link['title']);
        }
        $span_attributes = '';
        if (isset($link['attributes'])) {
          $span_attributes = drupal_attributes($link['attributes']);
        }
        $output .= '<span'. $span_attributes .'>'. $link['title'] .'</span>';
      }

      $i++;
      $output .= "</li>\n";
    }

    $output .= '</ul>';
  }

  return $output;
}
?>
gpk’s picture

OK yes that might be a lot easier. I think the thing might be to do a print_r() or var_dump() on each $link to see what's inside. If there is nothing already stored to flag in active-trail then maybe check for presence of the relevant bit of $link in http://api.drupal.org/api/function/menu_get_active_trail/6.

And/or use http://api.drupal.org/api/function/theme_menu_item/6 and/or http://api.drupal.org/api/function/theme_menu_item_link/6 as appropriate ... the former in particular looks useful ...

So basically yes, a custom function to theme the primary links is in order.

gpk
----
www.alexoria.co.uk

gpk’s picture

Well I played around with Devel themer module. Very revealing, everyone should have a go!. Some points

1. In the Nav links, as we know, the "active-trail" class is added to the <li> by http://api.drupal.org/api/function/theme_menu_item/6.

2. The "active" class is added to the links themselves i.e. the <a> tag by http://api.drupal.org/api/function/l/6, by checking $_GET['q'] directly.

3. In the same way, the "active" class is also added to the <li> element for primary/secondary links by http://api.drupal.org/api/function/theme_links/6.

TBH I think the easiest way of getting what you want is to make a 1 line addition to http://api.drupal.org/api/function/menu_navigation_links/6 in menu.inc (see the patch attached to the top of this issue http://drupal.org/node/202245) and then make the suggested change to theme.inc not there but in your own implementation of theme_links().

If you don't want to hack core, or write a module, then it can probably still be done by re-impementing theme_links(). Unfortunately http://api.drupal.org/api/function/menu_get_active_trail/6 doesn't seem very useful here. Your best bet AFAICS would be to call http://api.drupal.org/api/function/menu_tree_page_data/6 and scan the returned array to check, for each item in the primary and secondary links, if in_active_trail is set. menu_tree_page_data() is what is used to generate the primary and secondary links in the first place and the one line hack fixes this issue "at source" by adding the active trail flag as appropriate when the links are first generated.

gpk
----
www.alexoria.co.uk

lathan’s picture

Well i went for the core 'hack' for now, was the simplest. Thank you so much for the feed back gpk this really helped me.

PS: 'not there but in your own implementation of theme_links()' also saved me 20 min.. lol.

ROCKING! i've active trails now.

gpk’s picture

You could also call your theme function mytheme_primary_secondary_links() and call theme('mytheme_primary_secondary_links(), ...) in page.tpl.php if you wanted to separate things out more. Might not really be necessary though.

gpk
----
www.alexoria.co.uk

randysofia’s picture

Drupal 6: This worked for me. This is something that should be built into core. It seems relatively basic. So to clarify:

Inside /includes/menu.inc:
The function: menu_navigation_links

You want to add ONE LINE:
$l['in_active_trail'] = $item['link']['in_active_trail'];

Inside:

  foreach ($tree as $item) {
    if (!$item['link']['hidden']) {
      .....
    }
  }

Then override your theme_links function and use something like:

      if (!empty($link['in_active_trail'])) {
        $class .= ' selected';
      }
jrabeemer’s picture

I know you just didn't hack core... :-(

frankie_2304’s picture

can you put this in other words? (i'm new to drupal and i can't rly understand what i have to do )

Rowanw’s picture

Context module is in early stages of development, take a look: http://www.developmentseed.org/blog/2008/apr/09/context-ui

--
How to override HTML in Drupal 6

Rob T’s picture

http://drupal.org/node/60737#comment-126546

I used this mod in common.inc in Drupal 5.x, and it works like a charm on numerous sites. It's based on url path, which was perfect for my clean, pathauto'd URLs.

The function is different in 6.x, and my attempts to work the 5.x mod in were unsuccessful. Could a similar modification to function "l" in common.inc be a workable solution?

Rob T’s picture

I played around with that 5.x mod to function l (common.inc) that I liked so much, and in my brief testing I seem to have active primary and secondary links based on path working...

I took this mod - http://drupal.org/node/60737#comment-126546 - and made what I thought were the logical adjustments to the code. My new function l in common.inc (Drupal 6.2) is below.

There are 2 inserts... each is preambled by a commented (Added next x lines for active...)

function l($text, $path, $options = array()) {
 // Added next 2 lines for active path trail - 1 of 2 inserts based on http://drupal.org/node/60737#comment-126546
  $active_url = check_url(url($_GET['q']));
  $link_url = check_url(url($path, $options));

 // Merge in defaults.
  $options += array(
      'attributes' => array(),
      'html' => FALSE,
    );

  // Append active class.
  if ($path == $_GET['q'] || ($path == '<front>' && drupal_is_front_page())) {
    if (isset($options['attributes']['class'])) {
      $options['attributes']['class'] .= ' active';
    }
    else {
      $options['attributes']['class'] = 'active';
    }
 } 
  // Added next 8 lines for active path trail - 2 of 2 inserts based on http://drupal.org/node/60737#comment-126546
    else if (strpos( $active_url, $link_url) === 0 ) {
    if (isset($options['attributes']['class'])) {
      $options['attributes']['class'] .= ' active';
    }
    else {
      $options['attributes']['class'] = 'active';
    }
 }

  // Remove all HTML and PHP tags from a tooltip. For best performance, we act only
  // if a quick strpos() pre-check gave a suspicion (because strip_tags() is expensive).
  if (isset($options['attributes']['title']) && strpos($options['attributes']['title'], '<') !== FALSE) {
    $options['attributes']['title'] = strip_tags($options['attributes']['title']);
  }

  return '<a href="'. check_url(url($path, $options)) .'"'. drupal_attributes($options['attributes']) .'>'. ($options['html'] ? $text : check_plain($text)) .'</a>';
}

Feedback is welcomed. If I see anything break, I'll be sure to report back.

Iztok’s picture

This works great, thank you for this solution.

I only have one question: how to set that this will not work for home (root) link. Now I get Home button always highlighted. Yes its a bit funny, you hardly got it done and now I want to disabled it :)

tnx

Rob T’s picture

Like I stated in the post above, i don't really know what I'm doing. This could be a very bad mod. I've tried to get this "function l" change via an override in template.php, because I think more eyes will be attracted to it. But I haven't yet been able to do it with success.

Since you're using it... On my 5.x branch w/ this common.inc mod, I seem to recall having to make the homepage something other than "/node". Because we're dealing with path to make the active trail, the first part of the URL is also the same path as the homepage. Hence, Drupal now thinks that is part of the active trail.

Some configuration, perhaps w/the Front Page module, looks to be what I did to overcome this shortcoming. On my 6.x, for whatever reasons, I'm not experiencing this issue, at least not yet. I also think this mod effects breadcrumbs in some way.

Another issue will be similar URLs. For example: http://mydomain.com/option1... if a link with this hack mod, this URL -- mydomain.com/option10 will also show as active. All my major link paths are unique enough to prevent this on my 5.x. and on my 6.x project, I am actually going to take advantage of this behavior.

If you have some success with assigning a different default home page, please report back. In my 5.x use case, I was using a panel as my front page, so it worked out fine.

KrisBulman’s picture

this works for me, thanks!! looked everywhere for a solution, and this is the only one that seemed to do it for me.

brf123’s picture

Rob-
Just a post to tell you that this works great in 6.6 and saved me on a project. Thanks so much.
Brett

pvanderspek’s picture

I'm looking into what I'd have to do to move my current 5.7 installation to 6.2. Although I cannot start yet as I want to wait for stable releases of Views and CCK, I am looking into which problems I might expect. Currently I'm also using an active menu trail. For that I'm using the Menu Trails module. From the discussion in this thread I'm guessing this module doesn't work anymore in 6.2?

gpk’s picture

5.x modules need to be updated before they work with 6.x. Sometimes this is trivial; other times more significant changes are needed.

Menu Trails is not listed here http://groups.drupal.org/node/5036 and there doesn't seem to be a 6.x version of the module in the offing as yet http://drupal.org/project/issues/menutrails. Suggest you open a new issue for the project requesting info on when a 6.x version might be available http://drupal.org/node/add/project-issue/menutrails.

In the meantime the methods described above may be adequate for you, depending on your requirement.

gpk
----
www.alexoria.co.uk

hardik2403’s picture

Hi,
I had a similar issue of making the primary link active when, any of its corresponding sub-links are active.

I am sure everybody must have overridden their theme_links functions to get their menus styles working.

Only two lines of code have to be added to get the active-trails working

// function found in includes/theme.inc - line 537
<?php
function phptemplate_links($links, $attributes = array(class' => 'links')) { 

....
....
// somewhere in the middle of the function
      // Already present
      if ($i == 1) {
        $class .= ' first';
      }
      if ($i == $num_links) {
        $class .= ' last';
      }
      
      // Next 2 lines added for active trails 
      
      if($link['attributes']['class'] == 'active-trail'){
        $class .= ' active-trail';
      }
      
      // Already present	
      if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))) {
        $class .= ' active';    // Sets the bubble to park on the current page
      }

......
....
}
?>

Hardik

gpk’s picture

Hmm an 'active-trail' class should be present by default even for primary links, since 6.3. However it's not entirely consistent with the way this is done in other menus: http://drupal.org/node/249571#comment-941281.

gpk
----
www.alexoria.co.uk

mssarath’s picture

  if($link['in_active_trail']){
        $class .= ' active-trail';
  }

these two lines can be used instead of class. worked for 6.2

free ecards

PinkChocobo’s picture

I'm not sure exactly where to post what worked for me since there are so many threads open on this one subject, but this works for me in D6 using Barlow theme. I'm using the Primary Menu as parent menu and the secondary menu as the children of each separate link (secondary links set to primary links)

ie)
[link1] link2 link3
childoflink1 childoflink1 childoflink1

link1 [link2] link3
childoflink2 childoflink2 childoflink2 childoflink2

I used this in my stylesheet

.links a.active:visited, .links .active-trail a{
color:#990000;
text-decoration:none;
}

When I looked at the HTML source, the li had the correct active-trail class set, but the a did not include the active class and therefore was not working properly. If you do not have the li active-trail class, it could be because I installed the "Menu Trails" Module http://drupalmodules.com/module/menu-trails.

(I included the a.active:visited because the first link of the secondary child menu worked and the selected primary menu parent link included the active class as it should, it was just the rest of the child links that when clicked on, the parent link lost the the active class.)

This can be considered a work around, it's not really a good solution. Hope this helps at least as a temporary solution, I don't have the skill or the time to change the php to say if li class="active-trail", then a class="active".

RyanFC’s picture

works great!