Update #2: Using Twitter Bootstrap Dropdown Menus with WordPress

 

02/17/12 – Updated! Click here for the latest code. After some testing, there were a few fixed to clean up the HTML.

02/13/12 – This code has been updated to work with Twitter Bootstrap 2.0. Click here to see the latest update.

 


Okay, third time is a charm? After finding a trac ticket for the missing has_children parameter here, I’ve made some changes that get the previous extended walker class that I posted working in more (hopefully all) situations. In WordPress 3.4, this should be fixed and rewriting the display_element function shouldn’t be necessary.

The problem with the previous post was that it relied on last_query containing the menu query. I thought that because the menu functions were still running, the menu query would logically be the last query run. This was true on one test theme, but not on another.

Get the gist – https://gist.github.com/1597994

class Bootstrap_Walker_Nav_Menu extends Walker_Nav_Menu {

	function start_lvl( &$output, $depth ) {

		//In a child UL, add the 'dropdown-menu' class
		$indent = str_repeat( "\t", $depth );
		$output	   .= "\n$indent</pre>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">\n";</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">}</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$li_attributes = '';</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$class_names = $value = '';</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$classes = empty( $item->classes ) ? array() : (array) $item->classes;</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">//Add class and attribute to LI element that contains a submenu UL.</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">if ($args->has_children){</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$classes[] = 'dropdown';</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$li_attributes .= 'data-dropdown="dropdown"';</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">}</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$classes[] = 'menu-item-' . $item->ID;</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">//If we are on the current page, add the active class to that menu item.</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$classes[] = ($item->current) ? 'active' : '';</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">//Make sure you still add all of the WordPress classes.</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$class_names = ' class="' . esc_attr( $class_names ) . '"';</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$output .= $indent . '';</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">//Add attributes to link element.</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : '';</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : '';</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : '';</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : '';</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$attributes .= ($args->has_children) ? ' class="dropdown-toggle"' : '';</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$item_output = $args->before;</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$item_output .= '';</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$item_output .= '';</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$item_output .= $args->after;</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">}</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">//Overwrite display_element function to add has_children attribute. Not needed in >= WordPress 3.4</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">if ( !$element )</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">return;</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$id_field = $this->db_fields['id'];</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">//display this element</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">if ( is_array( $args[0] ) )</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$args[0]['has_children'] = ! empty( $children_elements[$element->$id_field] );</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">else if ( is_object( $args[0] ) )</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$args[0]->has_children = ! empty( $children_elements[$element->$id_field] );</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$cb_args = array_merge( array(&$output, $element, $depth), $args);</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">call_user_func_array(array(&$this, 'start_el'), $cb_args);</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$id = $element->$id_field;</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">// descend only when the depth is right and there are childrens for this element</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">if ( ($max_depth == 0 || $max_depth > $depth+1 ) && isset( $children_elements[$id]) ) {</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">foreach( $children_elements[ $id ] as $child ){</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">if ( !isset($newlevel) ) {</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$newlevel = true;</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">//start the child delimiter</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$cb_args = array_merge( array(&$output, $depth), $args);</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">call_user_func_array(array(&$this, 'start_lvl'), $cb_args);</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">}</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">}</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">unset( $children_elements[ $id ] );</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">}</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">if ( isset($newlevel) && $newlevel ){</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">//end the child delimiter</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$cb_args = array_merge( array(&$output, $depth), $args);</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">call_user_func_array(array(&$this, 'end_lvl'), $cb_args);</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">}</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">//end this element</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">$cb_args = array_merge( array(&$output, $element, $depth), $args);</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">call_user_func_array(array(&$this, 'end_el'), $cb_args);</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">}</ul>
</ul>
<ul class="\&quot;dropdown-menu\&quot;">
<ul class="\&quot;dropdown-menu\&quot;">}</ul>
</ul>
&nbsp;
<ul class="\&quot;dropdown-menu\&quot;">
About these ads

19 responses

  1. [...] – All fixed, see my new post: Update #2: Using Twitter Bootstrap Dropdown Menus with WordPress 01/11/12 – It seems that last_result didn’t work as I thought it did and won’t [...]

  2. [...] – All fixed, see my new post: Update #2: Using Twitter Bootstrap Dropdown Menus with WordPress I’ve since found a better way to handle these and posted a new post here. Bootstrap is a [...]

  3. I have been looking for something like this but I feel stupid. I don’t understand how to use the class. How do I use this with my theme?

    1. Hi Kyle,
      1: paste the whole Bootstrap_Walker_Nav_Menu class into your functions.php file.
      2: wherever you call the menu (using wp_nav_menu), you make sure to set the “walker” argument to “new Bootstrap_Walker_Nav_Menu()”

      wp_nav_menu( array( ‘walker’ => new Bootstrap_Walker_Nav_Menu() ) );

      check out http://codex.wordpress.org/Function_Reference/wp_nav_menu for more info.

      Hopefully that helps.

      1. Thanks for the quick reply! That works great! Thanks a lot for the help! Definitely adding your blog to my daily rss reader.

      2. Great, I’m glad it worked! I’m going to try and blog a bunch of different ways to incorporate Bootstrap in WordPress as I get free time, but I’ve been holding off since Bootstrap 2.0 comes out in a few weeks.

    2. Since pasting code in a comment didn’t work so well, I updated my gist. Check out the header.php section, that may clear things up:

      1. I never connected the Bootstrap_Walker_Nav_Menu to the walker in the wp_nav_menu for some reason. Hopefully that will help other peps who are thick like me :)

  4. Hi,

    I am struggling to get this to work for me.

    Is it possible for you help me out? I appreciate you don’t offer ‘support’ as such! Any help would be greatly appreciated though.

    1. I haven’t yet updated this to bootstrap 2.0, so that may be the problem, but I’d be happy to help.

      1. Thanks for the very speedy reply.
        I have this test site here: http://www.inspiredworx.com/dev/bigpush2012 I have added your code to the functions.php file and to my header.php template.
        It adds the correct classes to the HTML(as far as I can see), but the dropdown sub-menu doesn’t appear on click as in bootstrap 2.0.

        If I alter the CSS in Firebug to display:visible; then the sub menu appears fine. So it’s almost there!

        I am not too crash hot with PHP so wouldn’t know how to modify your code from above.

        PS. I would love to be able to add the little down-arrow icon too!

        Hit me up on my email addy if you like? huw [at] huwrowlands [dot] co [dot] uk

    2. Can you try using the function in the gist here: https://gist.github.com/1597994 ? It should fix the dropdown and add the dropdown arrow. Sorry, but I haven’t been able to test it, so hopefully everything works. If not, feel free to email me at johnmegahan@gmail.com and I can try to help you get it figured out.

      1. Great! Arrow added thanks. But the submenu doesn’t dropdown when clicking on the Media nav link.

        https://inspiredworx.com/dev/bigpush2012/

        Thanks again for this. :)

      2. Ah, I think I got it. I called the attribute data-dropdown=”dropdown” and it should have been data-toggle=”dropdown” I just updated the gist at https://gist.github.com/1597994/ so hopefully that will fix things.

  5. Working!
    You are awesome! Thank you so much for your help today.

    Very much appreciated.

    Will pass this link on.

    1. Ah, excellent! You’re quite welcome. I’m glad to see it working. Good luck with the site.

  6. This is fantastic. Kudos.

  7. Hey, hope you don’t mind another question :)
    I’ve gotten the above working with Bootstrap’s nav-pills bar and now I want to add a second menu location right next to the first one. It displays fine but the layout is kinda messed up, the second one is displayed to the right on lower than the first menu. Not a clue why…(I can mail you some of my code if you don’t mind :))

    Cheers and thanks for sharing this code with use all!
    /J

    1. yeah, sure, I’ll take a look at it. send it along to: johnmegahan@gmail.com

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: