4
  • I have a content type on my site called "Articles".
  • I created a view that lists the nodes of this content type. It's path is "/articles"
  • For that view, I created a menu item in my main menu, "Articles".
  • I used the pathauto module for all my nodes of this content type to have the path articles/[node:title]

My question is, I want the menu item to remain highlighted if the user is viewing a single article node, or if the user is viewing the view.

I solved the issue by using theme_menu_link() function in my template.php file for my theme (code below). Being new to the Drupal API, is there a better way to do it?

What I did:

function mytheme_menu_link(array $variables) {

  //Some variables, we're using
  $element = $variables['element'];
  $sub_menu = '';

  //#href is an element inside the item
  $the_path = drupal_lookup_path('alias', $element['#href']) ?: $element['#href'];

  //Compare the path to the actual URI (using sub-function), and if they match, then add a new CSS class
  //either: 'uri-active' or 'uri-active-trail'
  switch(mytheme__menu_detect_uri($the_path)) {
    case 1:  $element['#attributes']['class'][] = 'path-active'; break;
    case -1: $element['#attributes']['class'][] = 'path-active-trail'; break;
  }

  //If there are sub-menu items under this, render those too
  if ($element['#below']) {
    $sub_menu = drupal_render($element['#below']);
  }

  //Return the output
  $output = l($element['#title'], $element['#href'], $element['#localized_options']);
  return '<li' . drupal_attributes($element['#attributes']) . '>' . $output . $sub_menu . "</li>\n";
}

/**
 * Detect if a given path matches the current URI, as detected
 * from reading the current_path() alias from Drupal
 *
 * @param string $path_to_check  The path to check
 * @param string $check_against  The path to check against (leave blank for current path)
 * @reutrn int   1 = Matches, 0 = No Match, -1 = In Active Path
 */
function mytheme__menu_detect_uri($menu_item_path, $actual_path = NULL)
{
  if (is_null($actual_path))
    $actual_path = drupal_lookup_path('alias', current_path()) ?: current_path();

  //Compare em
  if (strcasecmp($menu_item_path, $actual_path) == 0)
   return 1;
  elseif (strlen($actual_path) > strlen($menu_item_path) && strcasecmp(substr($actual_path, 0, strlen($menu_item_path)), $menu_item_path) == 0)
    return -1;
  else
    return 0;
}
2

the context module allows you to highlight a menu item if certain condition (like a path) has been met.

2
/**
 * Implements hook_node_view().
 */
function MY_MODULE_node_view($node, $view_mode) {

  // Just make a blog menu item active during viewing blog post detailed page.
  if ($view_mode == 'full' && !empty($node->type) && $node->type == 'blog_post') {
    menu_tree_set_path('main-menu', 'blog');
  }
}
1

Context works but is a bit overkill if you only want to highlight the menu items. The Menu Trail By Path module does this automatically according to your path aliases. There is also the Menu Position module which offers some more functionality and settings.

1

If this is meant sole for user experience on the website, as far as I know, there's a possibily to do so via CSS. Using menu attributes module, you can add a class to that particular list item. Then, any view page should have a class for the body element and you can style the right classes for the view, same with the attributes for single article style format. No need to write a bunch of php code insead of one or two lines via CSS.

0

To make any menu active on certain content type use menu_set_active_item($path) function.

/**
 * Implements hook_node_view().
 */
function hook_node_view($node, $view_mode) {

  if ($view_mode == 'full' && !empty($node->type) && $node->type == 'article') {
    menu_set_active_item('[MENU_PATH]');
  }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.