To see this problem illustrated, go to http://2012[dot]hapticssymposium[dot]org (replace '[dot]' with '.' - I don't want this page to be indexed by search engines just yet). Look at the Conference tab, and compare how it looks on the Conference -> Registration page (the Conference tab is "active" and the correct color) and Conference -> Schedule page (the Conference tab is not active and the wrong color). Is there any way to fix this?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Dane Powell’s picture

Here are screenshots to illustrate: notice that both pages in the screenshots ("Registration" and "Schedule") should fall under the "Conference" tab. Yet, the Conference tab is not set as active when visiting Schedule.

I really have no idea where to start with this- I'd really appreciate some guidance.

mcaden’s picture

I got this working on mine. What I did was add:

function menu_tree_full($menu_name = 'navigation') {
  $tree = array();
  if (!isset($menu_output[$menu_name])) {
    $tree = menu_find_active_trail(menu_tree_all_data($menu_name));
  }
  return $tree;
}

/**
 * Wrapper function
 */
function menu_find_active_trail(&$menu_tree) {
  $item = menu_get_item();
  _menu_find_active_trail($menu_tree, $item);
  return $menu_tree;
}
/**
 * Recursive function to find the active menu and the active trail in the given tree.
 */
function _menu_find_active_trail(&$menu_tree, $item) {
  foreach($menu_tree as &$menu_item) {
    $link = &$menu_item['link'];
    if ($link['href']==$item['href']) { // Found the exact location in the tree
      $link['active'] = TRUE;
      $link['in_active_trail'] = TRUE;
      return true;
    } else {
      if ($menu_item['below']) {
        $result = _menu_find_active_trail($menu_item['below'], $item);
        $link['in_active_trail'] = $result;
        if ($result) 
        {
          $link['active'] = TRUE;
          $link['in_active_trail'] = TRUE;
          return true;
        }
      }
    }
  }
  return false;
}

to template.php at the end. (adapted from here)

I then changed lines 102-105 from this:

  // primary links markup
  if (theme_get_setting('menu_type') == 2) { // use mega menu
    $vars['mainmenu'] = theme('mega_menu', array('menu' => menu_tree_all_data(theme_get_setting('menu_element'))));
  }

to this:

  // primary links markup
  if (theme_get_setting('menu_type') == 2) { // use mega menu
    $vars['mainmenu'] = theme('mega_menu', array('menu' => menu_tree_full(theme_get_setting('menu_element'))));
  }

and then in theme/theme.inc at about line 129 I added:

      if ($value['link']['in_active_trail']) {
        $options['attributes']['class'] = array('active');
      }
Dane Powell’s picture

Thank you SO much- that did the trick. Surely this is not such an unusual request, and many others could benefit from it being solved- do you view this as a problem with Marinelli or with the core menu system? What would be the best way to get this fixed permanently (instead of having to maintained a patched version of Marinelli)?

mcaden’s picture

Status: Active » Needs review

Core does this automatically. However, marinelli does a lot of overriding and bypasses the portion of core that populates the active trail. What the stuff I changed does is manually figure out the active trail.

You should be able to use sub-theming. Or, hopefully this will be considered helpful enough that it'll get committed.

mcaden’s picture

FileSize
3.05 KB

Here's a patch file.

Lioz’s picture

hi mcaden , thanks for the patch I'm testing it

Dane Powell’s picture

Just FYI, the code in #2 works on rather "vanilla" setups, but I've just installed Context and realized this error still occurs if you use Context to set a child link as active (the parent link is not made active)

I'm assuming the patch is identical to the code you posted in #2.

Dane Powell’s picture

Similarly- even if you tell Contexts to make the parent link active, the parent link is not made active.

mcaden’s picture

Hmm...can't think of any scenario that wouldn't work with this, and I'm not familliar with Context.

Dane Powell’s picture

Okay, I think I sort of understand- _menu_find_active_trail only compares the href of the current page to the href of the menu items to determine if the current page is in the active trail. What Context does is to force a menu item to be active based on (for instance) the content type of the page. Thus, it makes sense that this patch doesn't work with Context- if the current page isn't part of the menu tree at all, _menu_find_active_trail won't match anything, even though Context is saying "yes, this is part of the active trail" by making a menu item active.

It seems to me that the solution should be to not only check whether the href of the current page matches any href in the menu, but also check whether any menu items are active and thus should be part of the active trail.

(Sorry if I mix up any terminology, I'm grossly unfamiliar with theming but trying to learn)

mcaden’s picture

hmm...try changing:
if ($link['href']==$item['href']) { // Found the exact location in the tree

to:

if ($link['href']==$item['href'] || $link['active']) { // Found the exact location in the tree

Dane Powell’s picture

Thanks for the suggestion, but unfortunately it doesn't work. When I dpm $menu_tree and $item I see that the child link is not listed as active, even though it's rendered as active. I wonder if marinelli_preprocess_page is being called before Context has a chance to alter the menu or something? Once again, I wonder if it would help to see how core takes care of this and try to duplicate it- I'm not sure exactly what's being overridden by Marinelli.

la7ema’s picture

Hello, mcaden.

Thank you very much for your patch.

It seems to be working fine, except for one thing. After I have added your code to template.php, I get this error message:

Strict warning: Only variables should be passed by reference i menu_tree_full()

The error message then refers to line 286 in template.php. Below are code and line numbers after your code has been added:

283 - function menu_tree_full($menu_name = 'navigation') {
284 -   $tree = array();
285 -   if (!isset($menu_output[$menu_name])) {
286 -     $tree = menu_find_active_trail(menu_tree_all_data($menu_name));
287 -   }
288 -   return $tree;
289 - }

Do you have any ideas how to fix it? I would appreciate your help.

Dane Powell’s picture

Version: 7.x-3.0-beta9 » 7.x-3.0-beta11
FileSize
2.88 KB

Here's a patch based on the code in #2, against 7.x-3.0-beta11

Dane Powell’s picture

Note that if you want to fix this issue (i.e. make the primary menu tab in the active trail to actually appear active) if you are using "classic" primary links rather than megamenu, all you need to do is add the following line around line 44 of css3_graphics.css...
.cssgradients #navigation-primary > ul > li > a.active-trail,

EDIT: Well, that's not "all" you need to do (other css files need editing), but it should get you on the right track... if the maintainer is interested I can generate the full patch...

Whiskey’s picture

I tried the patch in #14, but it wasn't working for me. I have created both a main and secondary menu in my module (with a wildcard plus to_arg function for the secondary menu) and debugging it I found that in the function _menu_find_active_trail the variable $menu_item['below'] never got set. I have no clue why not, but I edited the patch to just look at the path to see if it is a parent or not. This is my fix of the function:

function _menu_find_active_trail(&$menu_tree, $item) {
  foreach ($menu_tree as &$menu_item) {
    $link = &$menu_item['link'];
    if ($link['href'] == $item['href']) { // Found the exact location in the tree
      $link['active'] = TRUE;
      $link['in_active_trail'] = TRUE;
      return true;
    } else {
//      if ($menu_item['below']) {
//        $result = _menu_find_active_trail($menu_item['below'], $item);
//        $link['in_active_trail'] = $result;
//        if ($result)
//        {
//          $link['active'] = TRUE;
//          $link['in_active_trail'] = TRUE;
//          return true;
//        }
//      }
      $findparent = strpos($item['href'], $link['href']);
      if ($findparent !== FALSE) {
        $link['active'] = TRUE;
        $link['in_active_trail'] = TRUE;
        return TRUE;
      }      
    }
  }
  return FALSE;
}

Now it works, so still many thanks for supplying the patch!

Dane Powell’s picture

#16 just produces very strange and unpredictable results on my site. Not sure why.

Unfortunately none of the fixes so far work with Contexts :(

Whiskey’s picture

Well, it is kind of a quick hack. What it does is see if a menu item path is part of the selected menu item path. So if you have a secondary menu item with path mymodule/item1/itemb and a primary menu item with mymodule/item1, that primary menu item will be made active. This works for my setup, however, I guess this can go wrong in cases where the menu path system is more complex. I have never worked with Contexts, so can't help you with that.

Dane Powell’s picture

Finally figured out at least part of the problem with contexts- Context only sets the active class in $vars['main_menu'], but Marinelli doesn't pass $vars['main_menu'] to the mega_menu theming function. Fortunately, the patch in #835090: Context Reaction: Set menu trail takes a slightly different approach- it actually modifies the menu to set the href of the current page to be equal to the desired menu path. That makes everything compatible with the patch in this thread. Phew!

tmehta’s picture

Hi la7ema (#13) or Dane,

After applying the patch in #14, I am receiving the same error as la7ema noted in #13. Did either of you get it fixed?

Update:
I made it work by removing the reference tag in the parameter of the wrapper function.
Here is the updated wrapper function which worked for me:

/**
* Wrapper function
*/
function menu_find_active_trail($menu_tree) {
$item = menu_get_item();
_menu_find_active_trail($menu_tree, $item);
return $menu_tree;
}