How do I dynamically set the active menu item?

18,386

Solution 1

For similar purpose, I used menu_set_item(). You should leave the $path argument NULL and use the menu item for the internal path of 'galleries/lastgallery' as $router_item.

function custom_nodeapi(&$node, $op, $a3 = NULL, $a4  = NULL) {
  if ($op == 'view' && $node->nid == 31) {
    $path = drupal_get_normal_path('galleries/lastgallery');
    if($path && $menu_item = menu_get_item($path)) {
      menu_set_item(NULL, $menu_item);
    }
  }
}

Solution 2

As tmsimont pointed out, using menu_set_item() has side-effects...

A quick look at menu_set_item() and menu_get_item() shows us that they trigger hooks and database calls (). Not perfect.

If you're using Drupal 7.9+, there's a new function called menu_tree_set_path() that will do the trick:

menu_tree_set_path('user-menu', 'shopping-cart');

The first argument is the menu name followed by the path you want to select.

NOTE: This does not apply the .active class but applies .active-trail instead so you'll have to update your CSS to accommodate both!

Solution 3

I know I'm a bit late in the game here and this already has an answer but I thought I'd post this in case it helps someone

With reference to the problem of menu_set_item(NULL, $menu_item) killing local tasks - it's not limited to this.

I found that when using the discuss module it didn't load the block. I think the issue is that by doing something like:

$path = drupal_get_normal_path('galleries/lastgallery');
$menu_item = menu_get_item($path);
menu_set_item(NULL, $menu_item);

You effectively tell drupal you're on a different page/item.

The solution that worked for me was this:

$menu_item = menu_get_item();
$menu_item['href'] = 'galleries/lastgallery';
menu_set_item(NULL, $menu_item);

This seems to just play with the href and leave rest alone so local tasks still work and so did disqus.

Share:
18,386
iflamberg
Author by

iflamberg

Updated on June 16, 2022

Comments

  • iflamberg
    iflamberg almost 2 years

    For example, I have "node/31". And I want drupal to set menu active item to "galleries/lastgallery" if node/31 is viewed. How to do it?

    <?php
    function custom_nodeapi (&$node, $op, $a3 = NULL, $a4  = NULL){
        if ($op == 'view' && $node->nid == 31) {
               ???
            }
    }
    ?>
    

    Updated: I know I can use menu_set_active_item. But in this case tabs (View/Edit etc. tabs) will be not displayed. I believe it should be done with menu_set_active_trails, or may be menu_get_item/menu_set_item somehow, but I can't figure how exactly.

  • gagarine
    gagarine over 11 years
    menu_tree_set_path() is a better option.
  • Nadeem Ahmed
    Nadeem Ahmed over 11 years
    Indeed but menu_tree_set_path() has been introduced in Drupal 7, the question is for Drupal 6.
  • gagarine
    gagarine over 11 years
    This do not work for the front page... I try to use <front> as a path without success.
  • jmlnik
    jmlnik over 11 years
    To use aliases, you could potentially wrap the path in drupal_get_normal_path(), eg: menu_tree_set_path('my-menu', drupal_get_normal_path('<front>')). Let me know if it works and I'll update the answer.