Hi all -
So I wanted to run something by the community. I have often had a situation like this: Let's say you have a bunch of nodes, and each belongs to multiple taxonomy terms. You want those taxonomy terms to have menu items, so that site visitors can click on them to see all the nodes that belong to each term.
Great, that's all easy to do with the taxonomy and menu modules. However, when a user clicks on "Term A" in the menu and then clicks "Node 1" from the list of node he then sees, on Node 1's page, Term A is no longer shown to be "active" -- so the user loses his sense of place on the site. Also, there's a further complication: Node 1 happens to belong to both Term A and Term C. That means that we can't just arbitrarily create a menu item for the node and stick it under one of those terms' menu items, because it belongs equally to both.
Have other people run into problems like this? I feel like it happens all the time -- basically, whenever you have a large number of nodes that you don't want to give menu items to, but that you want to seem to belong to some menu item or another.
So here's my solution -- it has a module component, and a theme component. I'm calling it "node adopt" for now.
Module bit
function nodeadopt_nodeapi(&$node, $op, $a3 = NULL, $page = FALSE) {
if ($op == 'view' && $page == TRUE && $node->type == 'faculty') {
$location = nodeadopt_unorphan_node($node);
menu_set_location($location);
}
}
/*
* 'Inspired' by menutrails.module.
*/
function nodeadopt_unorphan_node($node) {
// this should only fire if the menu isn't already active
$item = menu_get_item(NULL, 'node/'.$node->nid);
// type = 4 is for a callback
if ($item['type'] == 4) {
global $base_path;
$server_and_base = 'http://' . $_SERVER['SERVER_NAME'] . $base_path;
if(strpos($_SERVER['HTTP_REFERER'], $server_and_base) !== FALSE) {
$language_path_arg = module_exists('i18n') ? 3 : 0; // account for i18n's extra path stuff, if it's installed.
$parent_path_alias = substr($_SERVER['HTTP_REFERER'], strlen($server_and_base) + $language_path_arg);
$parent_path = drupal_get_normal_path($parent_path_alias);
$full_menu = menu_get_menu();
$mid = $full_menu['path index'][$parent_path];
$_SESSION['immediate_parent_mid'] = $mid;
if ($mid > 0) {
// Follow the parents up the chain to get the trail.
while ($mid && ($item = menu_get_item($mid))) {
$location[] = $item;
$mid = $mid = $item['pid'];
}
$location = array_reverse($location);
$location[] = array('path' => 'node/'.$node->nid, 'title' => $node->title);
}
return $location;
}
}
}
Theming bit
/*
* Implementation of theme_menu_item_link() that looks for a session var set by nodeadopt_unorphan_node().
* If it's there, the link currently being spit out is the "acting parent" for the current node, and so
* it needs to be given class=active.
*/
function nodeadopt_menu_item_link($item, $link_item) {
$full_menu = menu_get_menu();
$mid = $full_menu['path index'][$item['path']];
$att = !empty($item['description']) ? array('title' => $item['description']) : array();
if($mid == $_SESSION['immediate_parent_mid']) {
$att['class'] = 'active';
unset($_SESSION['immediate_parent_mid']);
}
return l($item['title'], $link_item['path'], $att, isset($item['query']) ? $item['query'] : NULL);
}
I'd really appreciate any thoughts about this. I'm particularly curious to know if there is any good reason not to use $_SESSION. Thanks!