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.
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);
}
}
}
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!
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.
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.
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);
}
You can try this:
function menu_tree_set_path($menu_name, $path = NULL)
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);
}
?>
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;
}
}
}
精彩评论