OK, so here is the deal. I'm not as PHP savvy as I'd like to be and I need help figuring this one out.

I'm designing a site with impossibly complicated menu design, and in order to style it correctly I need some specific tags. I've read every related post for the last four days, and found some things that work, and a lot of things that don't work. Yes, I've already tried MenuTrails and NiceMenus and a host of other hacks that don't do this. Here is what I need to do:

I need the Parent Menu LI to be active when that page is active. When any of the children of that page are selected I need the Parent LI to remain active. Can someone please help me to combine the two codes I provided below so that I can finally get some sleep.

For instance if someone is on the Sram page both the Sram (child) and the Parts (parent) would have an active LI:
Parts
---Shimano
---Sram
---Suntour

Whereas if someone was on the Parts node the LI will be active, so the children can be displayed.
Parts
---Shimano
---Sram
---Suntour

So far I've used this code to make the parent item active:

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 ((drupal_get_normal_path($item['path']) == $_GET['q']) // if menu item path...
  || (drupal_is_front_page() && $item['path'] == '<front>')) { // or front page...
    $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";

}

And I've used this code to make the children and parents active:

function phptemplate_menu_item($mid, $children = '', $leaf = TRUE) {
$active_class = in_array($mid, _menu_get_active_trail()) ? ' active' : '';
return '<li class="'. ($leaf ? 'leaf' : ($children ? 'expanded' : 'collapsed')) . $active_class .'">'. menu_item_link($mid) . $children ."</li>\n";

}

By the way if your going to DrupalCon in Boston I'd be happy to buy you a round at FELT on Tuesday night for this simple PHP assist ;)

Comments

add1sun’s picture

Hm, so I don't think I'm following what your need is because it seems like your second function there is doing what you are asking - a menu item and its parent, if any, will get the active class added to the li. What is that second function *not* doing for you?

Note: you can also just write that first line as:

$active_class = menu_in_active_trail($mid) ? ' active' : '';

Lullabot loves you | Be a Ninja, join the Drupal Dojo

Drupalize.Me, The best Drupal training, available all the time, anywhere!

primalmedia’s picture

The second function does put an "active" class on both the parent and the child LI when I'm on the child page.
But then I'm on the parent page there is no active on the LI class unless I use the first code.

For Instance, when I'm using the second code both "Parts"(parent) and "Sram"(child) are LI active if I'm on the Sram page.
Parts
---Shimano
---Sram
---Suntour

However if I'm on the "Parts" (parent) page and I'm using the second code, only nothing is active.

Parts
---Shimano
---Sram
---Suntour

When I use the first code the "Parts" page is active, and I haven't figured out a way to combine the two so that I get the best of both worlds. Is there an easy way to merge these two codes?

Thanks again for your help.

add1sun’s picture

There must be something else going on then, because just adding the snippet to the garland template.php file I get your desired behavior. The parent and child LI are marked active if a child is selected and the top level menu item LI is marked active if it is selected directly.

This is your same snippet, just cleaned up a little.

function phptemplate_menu_item($mid, $children, $leaf) {
  $active_class = menu_in_active_trail($mid) ? ' active' : '';
  return '<li class="'. ($leaf ? 'leaf' : ($children ? 'expanded' : 'collapsed')) . $active_class .'">'. menu_item_link($mid) . $children ."</li>\n";
}

Lullabot loves you | Be a Ninja, join the Drupal Dojo

Drupalize.Me, The best Drupal training, available all the time, anywhere!

primalmedia’s picture

I just took the Garland template, replaced mine, and attached the code as you've resent it, and I'm having the same problem. It's weird because the code you provided definitely achieves the desired result when the child is selected, but it doesn't work when the parent is selected, unless I use the other code. Even with a clean template. I'm not sure that it makes a difference, but this is a new install of 5.7.

The only thing I can think of which might make a difference is that because of the complexity of the design I have to call my menus from a Content Template, like this:

<?php 
$block = module_invoke('menu', 'block', 'view', 87); 
print $block['content'];
?>

Do you think that could make the difference?

primalmedia’s picture

I modified the theme to allow the menu to be called from a block as specified in page.tpl.php, however I still cannot get the menu to work correctly. Would you mind uploading your template.php which works correctly. Perhaps I can use your code to make it work.

I'd be happy to compensate anyone for their time that can help me find a fix for this...

add1sun’s picture

I'm just using the regular template.php that comes with garland. Have you tried adding the snippet to core themes in Drupal just to see if it works there vs. your custom theme? That is add the snippet to a core theme and then switch the site theme to it and check it. That might help narrow it some.

Lullabot loves you | Be a Ninja, join the Drupal Dojo

Drupalize.Me, The best Drupal training, available all the time, anywhere!

primalmedia’s picture

The other reason it makes sense to merge these two scripts is to add an "first" and "last" class to the LI. The first script does this, but the second one does not.

primalmedia’s picture

So I looked it over in the Garland theme, and it still does not work for my menus, but it does work for the Admin Menus, so what's the difference?

I'm actually trying to make the Child and grand-children LI active! What I'm actually trying to do is this.

When I'm on the "Child" page I need the LI to be active.

-Parent
--Child
---grand-child

And when I'm on the "grand-child" page I need the "Child" LI to remain active, or I need both the "Child" and "grand-child" to be active, like an Active Trail.

-Parent
--Child
---grand-child

I guess this would be easy if I was only looking to make the parent and child active. Hopefully somebody out there will have a genius solution on how to make this happen.

primalmedia’s picture

Thanks to Rowan at Gorton Studios (http://www.gortonstudios.com) a solution has been found. I met Rowan at DrupalCon 2008 in Boston, and he had this very cool solution:

 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 ((drupal_get_normal_path($item['path']) == $_GET['q']) // if menu item path...
   || ( strpos( drupal_get_path_alias($_GET['q']),  drupal_get_path_alias($item['path']) ) === 0 )
   || (drupal_is_front_page() && $item['path'] == '<front>')) { // or front page...
     $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";
 }

If you use this solution, please post on this forum so we can keep track of how many beers I owe him. This problem hurt my brain for about a week, and I'm happy to have it behind me. The Bottom line is that Drupal menus don't have great support for menu hierarchies. Another option would be to set up your entire links under the Primary Links and use the menutrim module.

ronan’s picture

Glad I could help out. It should be noted that this hack requires that your path aliases be reflective of the hierarchy of your site (eg: page/subpage/thirdlevel). It should be further noted that this hack is a little hacky... caveat emptor on this one.

If you use this solution, please post on this forum so we can keep track of how many beers I owe him.

Yes I agree, everybody should post on this topic, and as often as possible :)

Also, it's no big deal, but that should be an 'n' not a 'w' in my name.

------------------------------------
Ronan - Gorton Studios - http://www.gortonstudios.com/

------------------------------------
Ronan
Founder - NodeSquirrel - https://www.nodesquirrel.com/
Agency Tools Lead - Pantheon - https://www.pantheon.io/

Rob T’s picture

I've been using this core hack to common.inc to achieve the same thing on 5.x projects - active menu trails based on path.
http://drupal.org/node/60737#comment-126546

I tried your code for template.php, but I can't get it working in 6.x. And I can't the function l modification (common.inc) in 5.x to work. There are other 6.x active menu tricks, but none are providing me path-based active trails.

I'd love to get a path-based, active trailed primary-secondary links menu working in 6.x.

I like that your solution for 5.x is template.php-based. I'd rather not hack core. But at the same time, I really want my primary and secondary links activated by path.

Any advice would be appreciated.

Rob T’s picture

I just posted over here regarding my playing around with that common.inc - function l modification that I liked so much in 5.x.

http://drupal.org/node/243156#comment-812700

I really have no idea what I did here, but so far it's properly making active my primary and secondary links based on path.

jptaranto’s picture

Great, it works... almost. This is what I'm using, it's a slight variation on the code above:

<?php
function themename_menu_item($mid, $children = '', $leaf = TRUE) {
  $item = menu_get_item($mid);

  if ((drupal_get_normal_path($item['path']) == $_GET['q']) || 
  (strpos(drupal_get_path_alias($_GET['q']),  drupal_get_path_alias($item['path'])) === 0 ) || 
  (menu_in_active_trail($mid)==TRUE) ||
  (drupal_is_front_page() && $item['path'] == '<front>')) {
    $active_class = ' class="active"';
  } else {
    $active_class = '';
  }

  return '<li'.$active_class.'>'.menu_item_link($mid) . $children ."</li>\n";
}
?>

I have a few different menu trees - the first is my primary links, i'm using <?php print theme('menu_tree',variable_get('menu_primary_menu',0)); ?> to print them so I can use suckerfish drop downs. The second is my taxonomy menu, just a standard custom menu inside a block.

The above code works great on the primary menu, but doesn't work on the custom menu.

My paths look like this:

Primary -

home
shop
contact

Taxonomy -

shop/animals
shop/botanical

Now if I'm on shop/animals, "Shop" in the primary menu is marked as active, and if I am at shop/animals/bear "Shop" in the primary menu is still active, but "Animals" isn't active in the taxonomy menu.

Feel free to have a look: www.tonysheffield.com/working

shv_rk’s picture

hello,

I tried to use this code, however when I refresh the page i get blank page.
I am usung drupal 6.x and my own theme.
I added the code insdie my theme templaye.php file
what I am doing wrong?

chunty’s picture

I've not read the detail of this post just the title so sorry if this reponse is way off beam but I'm using a module called activemenu for handling the issue of parent/child active state - I didn't need any php just css and the module.

C

shv_rk’s picture

the only think I need now is to replace the active class from a tag <a> to <li> I can do the rest with css!
do you know how can I do that? activemenu does not seems to be sth I want!

any ideas?

chunty’s picture

I'm wondering if in fact this is core functionality already because on a second look I found that I'm not using active menu.....but on viewing my souce code all my li tags (which are active) including primarylinks have an "active-trial" class on them which I've used (I'd just forgotten how I'd done it)

So its either core or its "menu block" or "menu breadcrumb"....or its something else completely different I can't find in my modules list and I've forgotten about.

Have a look at your source code and see if that class exists for you.

C

shv_rk’s picture

I know what is that, that is menutrail plugin (I guess)
that adds active classes to the list items, I installed that pluging and it works fine with
normal menu and menu pages, however it for some reasons it does not work properly with my category menu.
it does not affecting it at all.
I am creating a product category menu with taxonomy menu but it is not working fine. even I treid to create the menu
without taxonomy menu still is not working.
there is even a plugin called taxonomy menu trail which should add active classes to list items.
for some reasons that does not work for me either! :(
anyway, I am doing it with javascript, it is doing my job but I am not ebtirely happy with it! (don't like to use to much JS )

 $(document).ready(function() {
                //Adds an active class to the parent li of the active a
                $("ul.menu a.active").parent("li").addClass("active");
            });

anyway, I need to find another way to do it in some point.

madra’s picture

old thread i know, but it came up when i was searching for the answer to - i think - a similar problem.

i may be misunderstanding the original poster here, as i'm not sure from your nifty diagram whether your menus are drop-down or not. but i had a similar problem with a submenu under my primary links and was able to get the functionality i wanted just using CSS:

primary menu:

HOME | PROFILE | GALLERY | GIFTS | SHOP | CONTACT

if SHOP is selected a secondary menu appears:

ONLINE | STORE LOCATION | STOCKISTS

[i made the submenu with the menu block module, setting its parent item: menu to be 'primary links' and item: to be 'shop'. then when i made my 'online', 'store' and 'stockists' page, i set each's parent item to 'shop' and url path settings to [eg] 'shop/stockists'. i then set the page specific visibility settings to only show that menu on 'shop' and 'shop/*' - that gave me my submenu, which would only appear on the SHOP page and each of ONLINE, STORE LOCATION and STOCKISTS.

that was fine as it went, but i had the same prob as [i think!] you had; when i selected ONLINE, STORE LOCATION or STOCKISTS the SHOP menu reverted to its inactive state. i used CSS and the fact that the parent menu item acquires an 'active-trail' class, when a child item is active, to fix the problem and now SHOP stays styled as active when either of ONLINE, STORE LOCATION or STOCKISTS are selected, but if SHOP is selected on its own then ONLINE, STORE LOCATION or STOCKISTS become inactive.

here's the CSS:

#primary  li a:active, /* normal CSS :active selector - just in case! */
#primary  li a.active, /* normal primary link active menu item */
#primary  li.active-trail a /* primary link parent of an active submenu item */
{
    /* insert CSS styling here */
}
NexusStar’s picture

I know that this threads are very old but I bang my head for two days how to make this work on Drupal 7 can anyone point me how it can be implemented

Entering The Dip and trying to win over it.