Drupal 7 - Nice Menus Module - How to display menu item description

Spiderstave
Spiderstave used Ask the Experts™
on
Hi everyone,

I'm working on a Drupal 7 install using Nice Menus. I need to display the descriptions for the menu items. I know I need to modify my sub-theme's template.php to overwrite the Nice Menus theme, but I'm having a hard time figured out what to update. I just need it to look like this:

<li>Menu Name<br>Menu Description</li>

Does anyone know how to achieve this?

Thanks!
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Are you using a starter theme like Zen? Since you're doing a subtheme, I'm just curious because I'm relatively certain I actually have the code to do that in D6 written already -- and it would be easy to bring it to D7.

Either way, and from looking at the Nice Menus module code I would say that the actual menu item itself can be themed with:

YOURTHEMENAME_menu_item()

Actually, scratch that, I think that's D6. Or completely incorrect. At first glance you'd probably need theme_menu_link():

http://api.drupal.org/api/drupal/includes%21menu.inc/function/theme_menu_link/7

So take this function:

function YOURTHEMENAME_menu_link(array $variables) {
  $element = $variables['element'];
  $sub_menu = '';

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

Open in new window


There are elements already in there for description (variable is $element['#title']) and the regular menu text (is that $element['#localized_options'] ? Just my best guess...). With a little tinkering you should be able to get the format you want.

However, this will probably cause havoc if you have more than one menu since it'll theme every.single.menu.link on the site. A little if-then logic might help clear that up, depending on your theme.

Totally hacked this solution together so your mileage may vary. When coding, I almost never get it right the first time, or without killing it with a few syntax errors here, or a major memory explosion there, or perhaps a nice, cozy infinite loop.

Mike
BTW, that goes in template.php. :D

Author

Commented:
Hi Mike,

Thanks a lot for your response! I am using a base theme, Omega: http://drupal.org/project/omega

This is actually my first Drupal install. I've primarily worked with creating custom Wordpress themes, and I'm finding a little more PHP heavy lifting in Drupal than I'm used to. I usually have some explosions in my code as well, but every now and then it works the first time and I do a little happy dance.

Annnnyway, thanks for pointing me in the right direction. You're correct, I only need to do this for the primary drop-down, not all of the menus, so some additional logic will be necessary. I'll be working on this today and will update once I've tinkered a bit.
Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

Author

Commented:
Hi Mike,

Okay, been working on this for awhile and have defined two core issues:

1) Using the function you pointed me towards, I can modify the menu system. I've updated it like so:

function jfgs_menu_link(array $variables) {
  $element = $variables['element'];
  $sub_menu = '';

  if ($element['#below']) {
    $sub_menu = drupal_render($element['#below']);
  }
  $output = l($element['#title'], $element['#href'], $element['#localized_options']);
  $description = $element['#title'];
  return '<li' . drupal_attributes($element['#attributes']) . '>' . $output . "<p>" . $description . "</p>" . $sub_menu . "</li>\n";
}

Open in new window


With of course "jfgs" being my theme name.

It works great, except the $element['#title'] variable is actually the primary menu name, so it's just rewriting the menu name twice. So far, I've been unable to determine how I can gain access to the menu item description.

2) As you mentioned, I'll need to apply this to a single menu only. At the bottom of the comments on the function page you linked to here: http://api.drupal.org/api/drupal/includes%21menu.inc/function/theme_menu_link/7

There are two comments discussing how to target a single menu.

Comment 1:

"I don't see it documented elsewhere that you can implement a THEMENAME_menu_link__MENU_NAME() function as an override for a specific menu.

See http://drupal.org/node/254940#theme-suggestions-for-menus."

Comment 2 (reply):

"To target specific menu, use the name of the menu from admin/structure/menu page (replace any hyphens with underscores) and append your theme name to the beginning of the function.

Make any menu specific changes to the body of the function and you are done!"

I've tried both of these approaches, which resulted in the following:

function jfgs_menu_link_menu_primary_navigation(array $variables) {

As well as:

function jfgs_menu_primary_navigation(array $variables) {

But both of those stopped the change from appearing at all, even on the targeted menu, so I'm assuming I may need to place the logic to target within the function itself.

And of course, I'm remembering to "Clear All Caches" any time I update the template.php file.

So, these appear to be the two hurdles to finding a complete solution. If you have any ideas, or anyone else that is reading this, I'd very much appreciate it!

Thanks,

John
John,

That is one of the best posts I've read here, ever. And for some reason you were always ahead of me one step. And I think we have the same sense of humor because I LOLed.

I know for a fact that I've done this in 6. It's just a matter of finding out which project it was. But that's just the code way of doing it...

...there might be a module for it.

I'm totally swamped at the moment but perhaps I can hop back in a little later to see. If you don't hear from me (or anybody else) by tomorrow then post again and it'll remind me to come back.

Goooooood luck!

Mike

Author

Commented:
Thanks :)

I found an example of exactly what I'm trying to do in Drupal 6:

function theme_links__system_main_menu($links, $attributes = array('class' => 'links')) {
  global $language;
  $output = '';
  dpm($links);
  if (count($links) > 0) {
    $output = '<ul' . drupal_attributes($attributes) . '>';

    $num_links = count($links);
    $i = 1;

    foreach ($links as $key => $link) {
      $class = $key;

      // Add first, last and active classes to the list of links to help out themers.
      if ($i == 1) {
        $class .= ' first';
      }
      if ($i == $num_links) {
        $class .= ' last';
      }
      if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))
           && (empty($link['language']) || $link['language']->language == $language->language)) {
        $class .= ' active';
      }
      $output .= '<li' . drupal_attributes(array('class' => $class)) . '>';

      if (isset($link['href'])) {
        // This is where the magic happens
        if (isset($link['attributes']['title'])) {
          // By default the menu system stores the menu item's 
          // 'Description' in the title attribute of the link 
          // that is created. We can use this to reformat the 
          // link with the description in the output as well
          $link_description = '<span class="link_description">' .
                              check_plain($link['attributes']['title']) . '</span>';
        }
        // Pass in $link as $options, they share the same keys.
        // Add the link description on to the link
        $output .= l($link['title'], $link['href'], $link) . $link_description;
      }
      else if (!empty($link['title'])) {
        // Some links are actually not links, but we wrap these in <span> for adding title and class attributes
        if (empty($link['html'])) {
          $link['title'] = check_plain($link['title']);
        }
        $span_attributes = '';
        if (isset($link['attributes'])) {
          $span_attributes = drupal_attributes($link['attributes']);
        }
        $output .= '<span' . $span_attributes . '>' . $link['title'] . '</span>';
      }

      $i++;
      $output .= "</li>\n";
    }

    $output .= '</ul>';
  }

  return $output;
}

Open in new window


Unfortunately it doesn't work in Drupal 7.

I'll repost later with an update. Thanks for your offer to help on the weekend!

Author

Commented:
Also found a step-by-step tutorial for exactly what I'm trying to achieve, but it's for Drupal 5 :P http://drupal.org/node/470558

Author

Commented:
I've come a bit further on this, but still beating my head against a wall.

I can get the proper description to display with this:

$description = $element['#localized_options']['attributes']['title'];

Open in new window


But that causes Nice Menus to freak out and start throwing errors:

Notice: Undefined index: attributes in jfgs_menu_link() (line 47 of C:\wamp\www\JFGS7\sites\all\themes\jfgs\template.php).
Notice: Undefined index: attributes in jfgs_menu_link() (line 47 of C:\wamp\www\JFGS7\sites\all\themes\jfgs\template.php).

I've looked into it and it looks like that error may be a Nice Menus bug, and can be worked around by disabling PHP Error Notices. That doesn't sound like a very good solution to me, though, so hoping I can correct it properly.

And still having the issue with selecting only menu_primary_navigation. The lovely chap gave me this bit:

if ($element['#original_link']['menu_name'] == "main-menu" && isset($element['#localized_options']['attributes']['title'])){
    $element['#title'] .= '<em>' . $element['#localized_options']['attributes']['title'] . '</em>';
  }

Open in new window


Which does allow for easy selection of individual menus, but unfortunately the #original_link variable is not available with Nice Menus. I can get all of this to work rather easily if I disable Nice Menus, but of course, I need Nice Menus for other things.

This is the kind of issue that makes me fantasize about selling my belongings and buying a VW bus. But I shall persevere! If you have any insight I'd certainly appreciate it!

Thanks,

John
Hahahaha awesome. The Vanagon -- oh how I've dreamed of selling my Ferrari, Mercedes, luxury yacht, and BMW collection to get one of those. Or maybe that's that I've dreamed of having all of that. But I digress...

I have a little saying that I use a lot -- not sure if I made it up, or if I lifted it from something I read, but it is "Drupal makes the hard things super easy, but can make the easy things really hard."

I did a little Google search and, of course, came up with your post on Drupal.org (about this). I think the Drupalite who answered that one has a good point about Superfish. Is there anything that you need in Nice Menus that Superfish doesn't have?

I'm a convert from NM to SF (love acronyms). It does a good number more things, and cooler things, than NM. The only downside I've had an issue with is when creating a very custom theme with very picky designers who want the menus to look exactly like the Photoshop original. I end up either having to exclude some of the superfish css files or overriding them the normal CSS way. I don't know if things have changed on that front.

Plus Superfish 1.8 is apparently mobile touchscreen compatible. Everybody who's anybody is going that route (and for really good reason, despite my slight sarcasm).

http://mehrpadin.net/demo/superfish/

That link, although it looks like a marketing piece for a free, open source module (huh?) has a good comparison matrix.

Now, if you can't use superfish then post back. I am actually installing a Drupal 7 shell site tonight or tomorrow so maybe I can just tinker on a live install to see what I can get working.

Don't give up, grasshopper. Drupal's a different world, but once you get the hang of the intricacies you'll never look back.

This was all written stream of consciousness, so I hope it makes sense.

Mike

Author

Commented:
Hi Mike,

Thanks for the comment and encouragement. Love the Drupal quote, and from my limited experience that's incredibly true. I setup the entire structure in one evening, and have spent two days trying to get menu descriptions to display! ;)

But even so, I've already fallen for Drupal. I've worked with Wordpress and Joomla extensively in the past, but this is my first opportunity working with Drupal and I'm really enjoying it. It did take me a few days to wrap my head around the different concepts, but I can I see how it's a very functional system.  

Thanks for the Superfish link. I'm going to give that a shot later tonight. I started out with MegaMenu but ran into problems and someone recommended Nice Menus, which is the only reason I've been using it. Several people have mentioned Superfish, so I'm excited to give it a try. The menu I'm building out is very custom, but I'm pretty confident with CSS and CSS overrides, so as long as it's possible I should be able to customize it pretty well. It does appear that the Nice Menus module is a bit buggy. I think I'll steer clear in the future.

And I LOL'd at your marketing comment. That is a helpful comparison chart, though, and it looks like Superfish is definitely the way to go. Touch screen compatibility is definitely a requirement so that's good to know.

Thanks again for the tips so far. I'll post back after I switch over to Superfish (fingers crossed).

John

Author

Commented:
Superfish is awesome! It came with all the functionality I wanted right out of the box. Just had to check a box and the descriptions appeared. Oh my, I should have used this a long time ago. Thanks for your help and for pushing me in that direction. I was able to setup and completely customize the menu in an afternoon.

Nice Menus should come with a warning, "You don't want this. You want Superfish."

Thanks again for your help!

John

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial