Create a Foundation 5 'Top bar' menu in Drupal 7.x

The following snippets will output some unique classes for a Drupal 7.x menu based on whether or not child menus are present. There are a number of reasons you might want to do this, but in our case we wanted to implement a Top Bar menu for Foundation 5.

If you aren't already familiar with Drupal theming basics, in particular template suggestions and preprocess functions, you should read up before you proceed since that's obviously too much to cover here.

Include the following in your theme's template.php:

/**
 * Implements hook_preprocess_page().
 */
function mytheme_preprocess_page(&$vars) {  

  // We are overriding the default $main_menu variable output because we need
  // our menu to always be fully expanded. 
  $main_menu = menu_tree_all_data('main-menu');
  $vars['main_menu'] = menu_tree_output($main_menu);
}

/**
 * Overrides theme_menu_tree().
 */
function mytheme_menu_tree__main_menu($vars) {
  
  // Add a class to main menu. This will be overridden for child menus 
  // by the next function.
  return '<ul class="left">' . $vars['tree']    . '</ul>';
}

/**
 * A custom wrapper overrides theme_menu_tree() yet again, but only for
 * child menus. This wrapper is declared in mytheme_menu_link__main_menu().
 */
function mytheme_menu_tree__main_menu__children($vars) {
  
  // Add a 'dropdown' class to a child menu's <ul> element. 
  return '<ul class="dropdown">' . $vars['tree']    . '</ul>';
}

/**
 * Overrides theme_menu_link().
 */
function mytheme_menu_link__main_menu($vars){
  $element = $vars['element'];
  $sub_menu = '';

  // Perform operations on list items with child menus.
  if ($element['#below']) {
    
    // Add 'has-dropdown' class to list item.
    $element['#attributes']['class'][] = 'has-dropdown';

    // Declare a new theme wrapper for this list item's child menu.
    $element['#below']['#theme_wrappers'][0] = 'menu_tree__main_menu__children';
    
    $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";
}

Our implementation of the Foundation 5 Top Bar mark-up in page.tpl.php:

<nav class="top-bar" data-topbar role="navigation">
  <ul class="title-area">
    <li class="name"><!-- empty --></li>
    <li class="toggle-topbar menu-icon"><a href="#"><span></span></a></li>
  </ul>
  
  <section class="top-bar-section">
    <?php if ($main_menu): ?><?php print render($main_menu); ?><?php endif; ?>
  </section>
</nav> <!-- /.top-bar -->

Actual output of $main_menu, with Drupal default classes included:

    <ul class="left">
      <li class="first leaf"><a href="/test.dev3/" class="active">Home</a></li>
      <li class="expanded has-dropdown"><a href="/test.dev3/node/1">About Us</a>
        <ul class="dropdown"><li class="first leaf"><a href="/test.dev3/node/3">History</a></li>
          <li class="last expanded has-dropdown"><a href="/test.dev3/node/4">Management</a>
            <ul class="dropdown">
              <li class="first leaf"><a href="/test.dev3/node/6">Bar Division</a></li>
              <li class="last leaf"><a href="/test.dev3/node/5">Foo Division</a></li>
            </ul>
          </li>
        </ul>
      </li>
      <li class="last leaf"><a href="/test.dev3/node/2">Contact</a></li>
    </ul>

Note that only the top level <ul> element contains the "left" class. List items that contain child menus have the "has-dropdown" class, while the child menus themselves have the "dropdown" class.