WordPress Dropdown Menu with Bootstrap

bootstrap

A tutorial about how to build a dropdown menu in WordPress using Twitter's Bootstrap framework

Step One: build a demo page with Bootstrap dropdown nav menu

We'll start by building a single page static mockup to ensure that we have all the Bootstrap elements working correctly before introducing the WordPress functionality. Head over to the Twitter Bootstrap page to download the files in order to get started.

Create a basic HTML file with the following navigation menu markup:

<nav id="navbar-name-here" class="navbar navbar-static">
  <div class="navbar-inner">
    <div class="container">

<ul class="nav">
  <li><a href="#">Home</a></li>
  <li class="dropdown">
    <a href="#">Item1</a>
    <ul class="dropdown-menu">
      <li><a href="#">Submenu Item1</a></li>
      <li><a href="#">Submenu Item2</a></li>
      <li><a href="#">Submenu Item3</a></li>
      <li><a href="#">Submenu Item4</a></li>
    </ul>
  </li>
  <li class="dropdown">
    <a href="#">Item2</a>
    <ul class="dropdown-menu">
    	<li><a href="#">Submenu Item1</a></li>
    	<li><a href="#">Submenu Item2</a></li>
    	<li><a href="#">Submenu Item3</a></li>
    </ul>
  </li>
</ul>
      
    </div>
  </div>
</nav> <!-- #navbar-name-here -->

Include in the <head> the three key files; jQuery, Bootstrap CSS and Bootstrap JS:

<link rel="stylesheet" type="text/css" href="css/bootstrap.css">
<script src="js/jquery-1.8.2.min.js"></script>
<script src="js/bootstrap.min.js"></script>

Note: you can include the JavaScript files at the bottom of the file, if you're that way inclined, however this tutorial assumes everything is in the <head>.

Now we can attach Bootstrap's dropdown() method to each of the menu items which have the dropdown class:

<script>  
$(document).ready(function() {
	$('.dropdown > a').dropdown();
});
</script>

Note: you'll need to use the direct child selector (>) to ensure that you're only attaching dropdown() to the a elements that belong to the li elements with the dropdown class, but not all the a elements.

Bootstrap's default behaviour is to display the sub menu only when the menu item is clicked. If we want the traditional on hover behaviour, we need to add the following CSS:

ul.nav li.dropdown:hover ul.dropdown-menu {
    display: block;    
}

Step Two: integrating Bootstrap into WordPress

Firstly, we need to ensure that jQuery and the two Bootstrap files are being loaded by our WordPress theme. Add the following code to the functions.php file to enqueue these files into the wp_head() function:

if (!is_admin()) {
    // jQuery (optional loading via Google CDN)
    wp_deregister_script('jquery'); 
    wp_register_script('jquery', ('http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js'), false);   
    wp_enqueue_script('jquery');
    // Bootstrap JS
    wp_enqueue_script('bootstrap', '/wp-content/themes/yourtheme/js/bootstrap-min.js', null, null, false);
    // Bootstrap CSS
    wp_enqueue_style( 'bootstrap', '/wp-content/themes/yourtheme/css/bootstrap.css', null, null, null);
}

Note: you can also load the Bootstrap files via the Bootstrap CDN

For the rest of this tutorial, I will assume that we already have a navigation menu up and running in our theme. See this tutorial if you need more information about setting up a menu with the wp_nav_menu() function.

Before we can attach the dropdown() method to our navigation menu, we need to make some modifications to how WordPress outputs the menu code. Firstly, we need the class dropdown added to each list item which contains a sub menu list.

Add the following code to your functions.php file: Use this custom walker to handle the output modification: wp-bootstrap-navwalker

// *** use the wp-bootstrap-navwalker instead of this code
// *** it is a much better solution
function astro_add_dropdown_class($classes, $item) {
    global $wpdb;
    $has_children = $wpdb->get_var("
	    	SELECT COUNT(meta_id) 
	    	FROM wp_postmeta 
	    	WHERE meta_key='_menu_item_menu_item_parent' 
	    	AND meta_value='".$item->ID."'
    	");
    // add the class dropdown to the current list
    if ($has_children > 0) array_push($classes,'dropdown'); 
    return $classes;
}

add_filter( 'nav_menu_css_class', 'astro_add_dropdown_class', 10, 2);

Note: you could instead use a custom walker to modify the output of the wp_nav_menu() function, such as this one. Personally, I find this approach to be a bit over my head, although I'd like to understand it one day.

Next, we need the sub menu lists to have the class dropdown-menu, so that Bootstrap's CSS will be applied. By default, wp_nav_menu() outputs the class sub-menu to these lists, so we can use jQuery to add Bootstrap's class alongside this. Add the following script to the head section of your header.php file, ensuring that it comes after the wp_head() function. wp_bootstrap_navwalker takes care of this too!

<script>
// *** wp_bootstrap_navwalker takes care of this too  
// $(document).ready(function() {
//	$('.dropdown .sub-menu').addClass('dropdown-menu');
// });
</script>

Now we need to add the same script from above which attaches the dropdown() method to the appropriate menu items. We can combine the script from step one with the above script, to make it:

<script>  
$(document).ready(function() {
	$('.dropdown > a').append('<b class="caret"></b>').dropdown();
	$('.dropdown .sub-menu').addClass('dropdown-menu');
});
</script>

We've added a little bit extra to the above script; the element <b class="caret"></b> has been inserted into the list item using the append() method. This adds the little down pointing arrow to the list item which contain sub menus as a visual cue for the site visitors.

I hope this tutorial was useful to you; feel free to leave a comment or read my other article from a while back which covers using Superfish jQuery dropdown menu in WordPress

 

Keywords: Twitter Bootstrap WordPress dropdown menu

17 Responses to “WordPress Dropdown Menu with Bootstrap”

  1. Corey Harrison says:

    This work well, however I’m getting a show stopping conflict with the script in the header.php when jquery is called for form validation. Any ideas? Working fine on all other pages.

    Thanks
    Corey

    • Tim says:

      Hey Corey,
      I’d start by checking the order of the javascript files or if you have another plugin loading a second copy of the jQuery library. You could also try using jQuery(document).ready(function(){//code}); instead of the alias version $(document).ready(function(){//code});

      Another favourite debugging technique of mine is to save the entire page as a static HTML file and then pull out as much of the code as possible in a process of elimination. This can help isolate where the problem arises. Often I have found it to be something completely different to what I initially thought it was.

      Let me know how you go.

      • Tim says:

        Oh, I just noticed an error in one of my snippets. It has now been corrected to:
        wp_register_script('bootstrap', '/wp-content/themes/yourtheme/js/bootstrap-min.js', null, null, false);
        wp_enqueue_script('bootstrap');

  2. Sally says:

    Worked for me – thanks for sharing!

  3. Corey Harrison says:

    I know the scripts that are in conflict are from a plugin called event espresso. More specifically a validation and pagination script it is using. Both are in noConflict mode so I’m not sure why they’re in conflict. In the Chrome debugger it’s showing this

    $(document).ready(function() {
    $('.dropdown .sub-menu').addClass('dropdown-menu');
    });

    is what is causing the problems.
    The page is here http://tfa.untiltomorrow.net/event-registration/?ee=2 if you want to take a look.

    Cheers

    • Tim says:

      Hi Corey,

      In my last reply I left out a key element in my first suggestion. It works if you use:
      jQuery(document).ready(function($) { // your code });

      Note the $ defined inside the parentheses of the ready function. This defines ‘$’ as the alias for jQuery within this particular function, without which was causing the console error “Property ‘$’ of object [object Window] is not a function”

      So your script should be:

      jQuery(document).ready(function($) {
      $('.dropdown > a').append('').dropdown();
      $('.dropdown .sub-menu').addClass('dropdown-menu');
      });

      Also, I noticed you have the line with addClass duplicated in your source code. You can remove the block of lines 58-63, as you are have this in the following script.

      Cheers,

      Tim

  4. Corey Harrison says:

    Brilliant! Thank you so much. I’m a total novice with jQuery and script in general so I was getting no where trying to work this out.

    Have a great Christmas! and thanks again.

    Corey

  5. Jan says:

    Thanks for this tutorial. Could you please tell me how to put the wp_nav_menu() -Function into the header.php. I try it with this statement ‘nav’, /* default is ‘div’ */
    ‘container_class’ => ‘header-nav’,
    ‘menu_class’ => ‘sf-menu’,
    ‘theme_location’ => ‘primary’
    ) )?>

    but the output was just a list of my menu items. As can see here http://test.steakability.com/

    • Tim says:

      Hi Jan,
      To use the wp_nav_menu function, you need to register theme_location for the nav menu in your functions.php file. This location will then appear in the Appearance > Menus page in your WP back end. Then you can create a menu and assign it to your theme location, which in my example is called “primary”. Once you have done this, your theme will output the menu you have assigned to the “primary” theme location. For code samples, see the first two steps of this tutorial.

  6. cynthusia says:

    Hi there,
    How would I make the parent link to another page onclick? (“Item1″ in your demo).

    And also how do you incorporate additional 3rd and 4th level navs?

    Thanks!

    • Tim says:

      Hi,
      Once you have configured your navigation within WordPress, all the links would be managed from the Appearance > Menus part of the WP back end.
      3rd & 4th level drop downs are beyond the scope of my article; you would need to add additional CSS to achieve this.
      Tim.

  7. Mark Hallam says:

    Hi,

    How do you seperate the menu from the top of the browser?

  8. della says:

    You have saved me many hours of work today. Got this up and running in 10 minutes! Thanks SO much!!

  9. Michael says:

    You wouldn’t believe how long I had to search for what you explained in this awesome tut!

    Thank you sooooo much for taking the time to share this information… you really saved me :)

    Where did you find out how to incorporate bootstap so well with WP? I’m having trouble finding good documentation outside of the bootstap main site.

    Anyway thank you again

    Cheers!

  10. THX for lesson ;)
    Is this can be used in plugin – can you create that?