0

Does anyone know how I can theme the entire li output for an expanded menu item?

For instance, the output is

I want to change the output to:

Is there a way to theme this output, like there is a way to theme specifically the expanded menu item output, like there is to theme other li outputs, such as below...?

function theme_menu_tree__main_menu_link($variables) {
  return '<li class="menuitem">'.$variables['tree'].'</li>';
}

My current code

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

  if ($element['#below']) {
    foreach ($element['#below'] as $key => $val) {
      if (is_numeric($key)) {             
        $element['#below'][$key]['#theme'] = 'menu_link__main_menu_inner'; // 2 lavel <li>
      }
    }
    $element['#below']['#theme_wrappers'][0] = 'menu_tree__main_menu_inner';  // 2 lavel <ul>
    $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";
}

2 Answers 2

1

You can get the complete (main) menu tree with this in your THEME_preprocess_page

  // Get the entire main menu tree
  $main_menu_tree = menu_tree_all_data('main-menu');

  // Add the rendered output to the $main_menu_expanded variable
  $vars['main_menu_expanded'] = menu_tree_output($main_menu_tree);

Then you can pass that to a theme function in your page template:

<?php print theme('links__system_main_menu', array(
  'links' => $main_menu_expanded,
  'attributes' => array(
    'id' => 'main-menu',
    'class' => array('nav', 'navbar-nav'),
  ),
)); ?>

I've been using the function below to create a Bootstrap ready dropdown menu - you can clearly see how the submenus are themed by checking the $link['#below'] part of the array.

    /**
     * Implements hook_links__system_main_menu().
     *
     * @param array $vars
     * @return string
     *  Themed HTML for bootstrap 3 ready main menu.
     */
    function YOURTHEME_links__system_main_menu($vars) {
      // Get the active trail
      $menu_active_trail = menu_get_active_trail();
      // Initialise our custom trail.
      $active_trail = array();

      // Get current path
      $dest = drupal_get_destination();
      if (is_string($dest['destination'])) {
        $paths = explode('/', $dest['destination']);
        // Loop through and add all active paths
        foreach ($paths as $path) {
          // Read previous element added to active trail (using array values
          // preserves original array).
          $safe = array_values($active_trail);
          $previous = array_pop($safe);
          if ($previous) {
            $active_trail[] = $previous . '/' . $path;
          }
          // Or this is the first one
          else {
            $active_trail[] = $path;
          }
        }
      }

      // UL classes
      $class = implode($vars['attributes']['class'], ' ');
      $html = '<ul class="' . $class . '" id="' . $vars['attributes']['id'] . '">';

      // Iterate links to build menu.
      foreach ($vars['links'] as $key => $link) {

        // Check this is a link not a property.
        if (is_numeric($key)) {
          $sub_menu = '';
          $li_class = array();
          $a_class = array();

          // Check if link is in active trail and add class.
          if (in_array($link['#original_link']['link_path'], $active_trail)) {
            $li_class[] = 'active-trail';
          }
          if ($link['#original_link']['link_path'] == end($active_trail)) {
            $li_class[] = 'active';
          }
          // Check if last element in list and see if LI contains actual link
          $link['#attributes']['class'][] = strtolower(str_replace(array('& ', ' '), array('', '-'), $link['#title']));
          $link_title = $link['#title'];

          if (isset($link['#localized_options']['attributes'])) {
            $link['#attributes'] = array_merge($link['#localized_options']['attributes'], $link['#attributes']);
          }

          // Check if we have a submenu.
          if (!empty($link['#below'])) {
            // Check if lvl 1, if higher do other stuff
            if ($link['#original_link']['depth'] < 2) {
              $li_class[] = 'dropdown';
              $link_title .= '<b class="caret"></b>';
              $link['#attributes']['class'][] = 'dropdown-toggle';
              $link['#attributes']['data-toggle'] = 'dropdown';
            } else {
              $li_class[] = 'dropdown-submenu';
              $link_title .= '<b class="caret"></b>';
            }
            // Theme submenu
            $sub_menu = theme('links__system_main_menu', array('links' => $link['#below'], 'attributes' => array('class' => array('dropdown-menu'))));
          }
          // Build classes string
          $classes = '';
          if (!empty($li_class)) {
            $classes = ' class="' . implode($li_class, ' ') . '"';
          }
          $html .= '<li' . $classes . '>' . l($link_title, $link['#href'], array('html' => 'true', 'attributes' => $link['#attributes'])) . $sub_menu . '</li>';
        }
      }
      $html .= '</ul>';
      return $html;
    }
3
  • Thanks bloke_zero. Is there any way I can integrate that dropdown-toggle section of code in my own code? (see my first post)
    – caustic
    Commented Mar 9, 2015 at 15:54
  • Yes, the problem is that if you just provide your own theme function then you're theming a menu which by default doesn't have all the submenu items expanded, just the one for the active path. You can either tick all the menu items as expanded in the admin settings or you can do something like have detailed above using menu_tree_all_data('main-menu') and menu_tree_output($main_menu_tree). You can then pass that to your theme function.
    – bloke_zero
    Commented Mar 10, 2015 at 10:55
  • it's awesome ... Commented Nov 16, 2016 at 7:52
0

use hook_theme and create the menu theme registry. see the below example code

function yourthemename_theme() {

return array(

'custom_menu_theme' => array(

  'template' => 'custom_menu',
),

}

the above code custom_menu is template file name.

this registry print using theme function in drupal.

1
  • Hi Sachin, could you give me some example code on how this would work? I can't see how I'd do it; maybe I'm missing something. Thanks
    – caustic
    Commented Mar 8, 2015 at 18:49

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.