iflamberg
iflamberg

Reputation: 13

How do I dynamically set the active menu item?

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.

Upvotes: 1

Views: 19086

Answers (8)

batMask
batMask

Reputation: 744

You can also use hook_translated_menu_link_alter()

/**
 * Implements hook_translated_menu_link_alter()
 */
function Module_translated_menu_link_alter(&$item, $map) {

    if ($item['menu_name'] == 'menu-name') {

        //check first two arg from url
        $path = arg(0)."/".arg(1);

        //add class active-trail if path match
        if (strpos($item['link_path'], $path) !== false) {
            $item['in_active_trail'] = true;

        }

    }
}

Upvotes: 0

tmsimont
tmsimont

Reputation: 2711

mongolito404's answer almost worked for me.

BUT it kills your local tasks (tabs)

SO for some reason it works if you call the tasks before doing what mongolito404 said to do... like this:

<?php

    //call local tasks first
    menu_local_tasks(0);    

    //then do what mongolito did    
    $path = drupal_get_normal_path('galleries/lastgallery');
    if($path && $menu_item = menu_get_item($path)) {
      menu_set_item(NULL, $menu_item);
    }
?>

Upvotes: 0

Chris
Chris

Reputation: 21

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.

Upvotes: 2

geo
geo

Reputation: 9

You can try this:

function menu_tree_set_path($menu_name, $path = NULL)

Upvotes: 0

Pierre Buyle
Pierre Buyle

Reputation: 4873

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);
    }
  }
}

Upvotes: 8

jmlnik
jmlnik

Reputation: 2887

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!

Upvotes: 4

mirzu
mirzu

Reputation: 1831

I was able to achieve something simular to what you are trying to do by using a combination of menu_set_active_item() and menu_execute_active_handler()

It took a little while to realize that I needed both. I was using a custom menu handler to create "clean urls" from Solr filter combinations. the $path variable is the internal drupal path that I am hiding, and the menu handler is what the user sees in their browser.

I then used custom_url_rewrite_outbound() to convert all relevant search links on the site to the format I wanted.

Below are the relevent parts of the code. I'm not sure if this is what you are looking for, but it might give you some ideas. I was impressed at how much you could control what the user saw and what Drupal was aware of internally. The proper menu items were active, and everything else worked as expected.

function myModule_search_menu(){
  $items['browse/%menu_tail'] = array(
    'title' => 'browse',
    'description' => 'Search Replacement with clean urls.',
    'page callback' => 'myModule_search_browse',
    'access arguments' => array('search content'),
    );
}

function myModule_search_browse(){
   /* do lots of fancy stuff */
   menu_set_active_item($path);
   return menu_execute_active_handler($path);
}

Upvotes: 0

James An
James An

Reputation: 1383

I'm not sure if you want to change the active item to affect which page is loaded (which would need to be done early in the page load to make a difference), or if you simply want to superficially highlight the "galleries/lastgallery" link as if it were the active link.

If you just want to make it appear as if the "galleries/lastgallery" link is the active one, that can be done by overriding the template_preprocess_page() function. There, you can rebuild the primary (or secondary) menu and add logic to give the link to "galleries/lastgallery" the "active" (and/or "active-trail") class.

Upvotes: 0

Related Questions