Here's what I have: A custom menu (side nav) that mimics the main/secondary menu tree which shows the entire subtree of the root menu item (Dine, Play, Stay) you're under.

enter image description here

This sidenav can be shortened with a checkbox field in the content type. If checked, the sidenav shows the checked page as the root and all children, recursively, but omits any parents of the checked page. I've successfully created that menu and this all works on the checked pages.

enter image description here

This yields:

enter image description here

This is done by creating both menus, then adding a "hide" css class to one of them in the template_preprocess_page() function, depending on the checkbox of the current node.

MY ISSUE: The final thing I need it to do is when you are on a CHILD page of a parent with the shortened nav checked, I need it to still show that shortened nav. So on the example above, when on the Visitor FAQ page, it needs to show the shortened menu from Visitor Tips (with the current page bolded or whatever). So it needs to grab the field from the parent node, and if it is true, grab the shortened submenu array, which I've done, but I haven't been able to render the menu tree array into html correctly.

Here's the current code for grabbing the submenu (from the full menu), and it saves the menu array in $alternateSecondaryMenu. I also tried saving in $vars['secondary_nav'], which is the key Drupal uses for the rendered menu array, but I think the menu has already rendered by the time it calls preprocess_page(). I just can't figure out how to render that menu tree. (The menu is 4 levels deep, level 0 being the root menu item, so this only happens on level 1 or level 2.)

In template.php:

function THEME_preprocess_page(&$vars) {

  // Follow active-trail and check if short/long menu is toggled
  // ***********************************************************
  if(!empty($vars['secondary_nav'])) {

    // Level 1
    foreach($vars['secondary_nav'] as &$topmenuitem) { // for each top level item
      if(!empty($topmenuitem['#title'])) { 
        if(in_array('active-trail', $topmenuitem['#attributes']['class'])) { // check if in active-trail (parent)

          // load the node of the parent menu item
          $firstnid = str_replace('node/','',$topmenuitem['#href']);
          $firstnode = node_load($firstnid);

          // check for shortened menu checkbox
          if (array_key_exists('field_show_menu_as_parent',$firstnode) && $firstnode->field_show_menu_as_parent && $firstnode->field_show_menu_as_parent['und'][0]['value']) {

            dsm("1. YES, shortened menu.");

            // Saving this submenu in these variables
            $vars['secondary_nav'] = $topmenuitem; // this is the drupal-made array that shows the menu in question
            $alternateSecondaryMenu = $topmenuitem; // just saving to some other variable, too.

          } else {
            dsm("1. NO shortened Menu for you!");

          // Level 2 (same as level one)
          foreach($topmenuitem['#below'] as &$secondmenuitem) {
            if(!empty($secondmenuitem['#title'])) {              
              if(in_array('active-trail', $secondmenuitem['#attributes']['class'])) {
                $secondnid = str_replace('node/','',$secondmenuitem['#href']);
                $secondnode = node_load($secondnid);
                if (array_key_exists('field_show_menu_as_parent',$secondnode) && $secondnode->field_show_menu_as_parent && $secondnode->field_show_menu_as_parent['und'][0]['value']) {
                  dsm("2. YES, shortened menu.");              
                  $vars['secondary_nav'] = $secondmenuitem;
                  $alternateSecondaryMenu = $secondmenuitem;
                } else {
                  dsm("2. NO shortened menu for you!");

  // Only renders an <li> of the current node, not the <ul> or the children <li>, even though it has the whole menu tree.
  // doesn't render anything because this preprocess_page() is called after the elements of the page have already rendered, right?

I am using Panelizer to display and Menu Block to create the menu (only modules that ones that might be relevant).

Do I need to call the theme_menu_tree() and theme_menu_link() functions on this array again to render it, somehow? I wasn't able to get render() or drupal_render() to work. Also tried doing this with menu_preprocessing/tree functions but was having difficulty getting the checkbox value in the nodes. Any ideas or help would be GREATLY appreciated.


1 Answer 1


This is sort of a hackish solution but probably the easiest to set up. I would suggest rendering the every level in the entire menu tree the same in all locations. You can omit the parents by deleting them in jQuery.

Based upon the location URL pattern or other criteria (for example your boolean checkbox could affect the body element class) you can pick the chunk of the menu you want to use at jQuery.ready time on the client side.

If the element is initially set as 'display: none;' then you can do this cherrypicking and then show the element. (In some recent cases I found it easier to get the menus into shape this way on the client side than fighting with different rendering parameters. The end result is about the same and it is easy for PHP to generate the same menu everywhere quickly).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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