1. Skip to Navigation
  2. Skip to Content
our blog

Output a Bootstrap Dropdown Menu In Your WordPress Theme Using a Custom Nav Walker

Bootstrap, for the unfamiliar, is an HTML/CSS/Javascript template for building new websites that was spun out of Twitter. It includes factored versions of many common UI elements, one of which is the dropdown menu. You can see an example of this type of menu on the Bootstrap home page (the fixed navigation bar at the top).

Unfortunately, WordPress’s wp_nav_menu function does not output the classes Bootstrap is looking for, and we need to add more markup than is possible via the options for wp_nav_menu. This is a perfect time to use a custom Nav Walker Class .

(In an earlier post we outlined the basics of how to make your own custom nav walker for WordPress. We’ll expand on that template now, to create a nav walker that we can use to output Bootstrap menus.)

You can download the completed source here: Bootstrap Nav Walker for WordPress. The code is also available at the bottom of this post.

How To Use The Bootstrap Nav Menu In Your WordPress Theme:

1) Download the Bootstrap_Walker class and upload it to your server (into your theme folder).

2) Include the bootstrap-walker.php file in your functions.php

3) Add code like this to your header where you want the nav menu to appear

<?php wp_nav_menu( array( 
	'container' => 'div',
	'container_class' => 'nav-collapse collapse',
	'theme_location' => 'primary',
	'menu_class' => 'nav',
	'walker' => new Bootstrap_Walker(),									
	) );
?>

Note: this example assumes you’ve already registered a menu naned ‘primary’. If not, add this code to your functions.php as well:

<?php
add_action( 'after_setup_theme', 'register_my_menus' );
 
function register_my_menus() {
	register_nav_menus( array(
		'primary' => __( 'Primary Navigation', 'your_theme_name' ),
	) );
}
?>

That’s it!

Note: huge thanks to apfelbox on the WordPress support forums for his code to add a hasChildren property to items in a nav walker. Great code!

Bootstrap Nav Walker Source (save this code and include it in your theme)

View raw source

<?php
    /* Bootstrap_Walker for Wordpress
     * Author: George Huger, Illuminati Karate, Inc
     * More Info: http://illuminatikarate.com/blog/bootstrap-walker-for-wordpress
     *
     * Formats a Wordpress menu to be used as a Bootstrap dropdown menu (http://getbootstrap.com).
     *
     * Specifically, it makes these changes to the normal Wordpress menu output to support Bootstrap:
     *
     *        - adds a 'dropdown' class to level-0 <li>'s which contain a dropdown
     *         - adds a 'dropdown-submenu' class to level-1 <li>'s which contain a dropdown
     *         - adds the 'dropdown-menu' class to level-1 and level-2 <ul>'s
     *
     * Supports menus up to 3 levels deep.
     * 
     */
    class Bootstrap_Walker extends Walker_Nav_Menu
    {    
 
        /* Start of the <ul>
         *
         * Note on $depth: Counterintuitively, $depth here means the "depth right before we start this menu". 
         *                   So basically add one to what you'd expect it to be
         */        
        function start_lvl(&$output, $depth)
        {
            $tabs = str_repeat("\t", $depth);
            // If we are about to start the first submenu, we need to give it a dropdown-menu class
            if ($depth == 0 || $depth == 1) { //really, level-1 or level-2, because $depth is misleading here (see note above)
                $output .= "\n{$tabs}<ul class=\"dropdown-menu\">\n";
            } else {
                $output .= "\n{$tabs}<ul>\n";
            }
            return;
        }
 
        /* End of the <ul>
         *
         * Note on $depth: Counterintuitively, $depth here means the "depth right before we start this menu". 
         *                   So basically add one to what you'd expect it to be
         */        
        function end_lvl(&$output, $depth) 
        {
            if ($depth == 0) { // This is actually the end of the level-1 submenu ($depth is misleading here too!)
 
                // we don't have anything special for Bootstrap, so we'll just leave an HTML comment for now
                $output .= '<!--.dropdown-->';
            }
            $tabs = str_repeat("\t", $depth);
            $output .= "\n{$tabs}</ul>\n";
            return;
        }
 
        /* Output the <li> and the containing <a>
         * Note: $depth is "correct" at this level
         */        
        function start_el(&$output, $item, $depth, $args) 
        {    
            global $wp_query;
            $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
            $class_names = $value = '';
            $classes = empty( $item->classes ) ? array() : (array) $item->classes;
 
            /* If this item has a dropdown menu, add the 'dropdown' class for Bootstrap */
            if ($item->hasChildren) {
                $classes[] = 'dropdown';
                // level-1 menus also need the 'dropdown-submenu' class
                if($depth == 1) {
                    $classes[] = 'dropdown-submenu';
                }
            }
 
            /* This is the stock Wordpress code that builds the <li> with all of its attributes */
            $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
            $class_names = ' class="' . esc_attr( $class_names ) . '"';
            $output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names .'>';            
            $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
            $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
            $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
            $attributes .= ! empty( $item->url )        ? ' href="'   . esc_attr( $item->url        ) .'"' : '';
            $item_output = $args->before;
 
            /* If this item has a dropdown menu, make clicking on this link toggle it */
            if ($item->hasChildren && $depth == 0) {
                $item_output .= '<a'. $attributes .' class="dropdown-toggle" data-toggle="dropdown">';
            } else {
                $item_output .= '<a'. $attributes .'>';
            }
 
            $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
 
            /* Output the actual caret for the user to click on to toggle the menu */            
            if ($item->hasChildren && $depth == 0) {
                $item_output .= '<b class="caret"></b></a>';
            } else {
                $item_output .= '</a>';
            }
 
            $item_output .= $args->after;
            $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
            return;
        }
 
        /* Close the <li>
         * Note: the <a> is already closed
         * Note 2: $depth is "correct" at this level
         */        
        function end_el (&$output, $item, $depth, $args)
        {
            $output .= '</li>';
            return;
        }
 
        /* Add a 'hasChildren' property to the item
         * Code from: http://wordpress.org/support/topic/how-do-i-know-if-a-menu-item-has-children-or-is-a-leaf#post-3139633 
         */
        function display_element ($element, &$children_elements, $max_depth, $depth = 0, $args, &$output)
        {
            // check whether this item has children, and set $item->hasChildren accordingly
            $element->hasChildren = isset($children_elements[$element->ID]) && !empty($children_elements[$element->ID]);
 
            // continue with normal behavior
            return parent::display_element($element, $children_elements, $max_depth, $depth, $args, $output);
        }        
    }
?>

13 Responses to Output a Bootstrap Dropdown Menu In Your WordPress Theme Using a Custom Nav Walker

  1. Greg McGee says:

    I really want to use this. I get this error after installing as you instruct. I’m using WP 3.4.2 with “Portfolio Press”.

    Fatal error: Class ‘Bootstrap_Walker’ not found in /home/content/39/9913339/html/wp-content/themes/portfolio-press/header.php on line 51

  2. Greg McGee says:

    Figured that part out! Forgot to “INCLUDE” the class! Now, it runs, but doesn’t do anything. IT does not minimize the menus as advertised. Now what?

    • George Huger says:

      Hey Greg –

      Can you paste in the your code where you’re calling wp_nav_walker and I’ll take a look? A pastie would be ideal.

      Thanks for reading!

      -George

  3. Aaron says:

    Thank you! This really helped me out. :) Before I thought I’d have to completely restyle my nav based on wordpress defaults.

  4. karol says:

    Hello, I have the same problem than above but the problem is that I have included the calss already and still, it shows

    Fatal error: Class ‘Bootstrap_Walker’ not found in /home2-1/c/carolir/public_html/wordpress/wp-content/themes/mytheme/header.php on line 63

    could I get some help?

  5. karol says:

    I included in functions.php (the bootstrap class)

  6. karol says:

    Hei, never mind, it was stupid, I saved the class.php with all the   and html tags, it was not a proper php anyway, now is working, thanks a million for this workaround! (all morning with a headache to combine bootstrap and sub-menus…)

  7. Denny says:

    Any ideas how I could get the output of my menu urls to point to https not http?

  8. ThisGuy says:

    Thanks for creating this! Works awesome in Bootstrap 3.0.1. — WP 3.7.1

  9. Heather says:

    “Output a Bootstrap Dropdown Menu In Your WordPress Theme Using a Custom Nav Walker | Illuminati Karate, Inc.
    ” was a fantastic post. If perhaps it included alot more pictures this would
    certainly be even even better. Cya ,Sonja

  10. Ian says:

    Hi, I’m developing a wp site locally using bootstrap, and I’ve included your bootstrap walker, but there is a white space of say 20px under the admin bar that appears when I add the code. Any ideas where this might have come from? Been scratching my head for a few hours now… thanks

Leave a Reply

Your email address will not be published. Required fields are marked *


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>