Tag Archives: dropdown

Update #1: 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.

01/12/12 – 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 work in all situations, so I need to revisit this. I absentmindedly left my laptop power cable at work, so it may be a day or so.


In my first post, I wrote an extended walker class for using Twitter Bootstrap dropdown menus in WordPress without a bunch of hackarounds. Originally, I was using a ‘search and replace’ method for this, which worked, but it was pretty obvious to me that it wasn’t the best way to do it.

I replaced it now with a more true-to-WordPress way to do it, which I think will be more future-proof.

The reason that this is a bit tricky is that WordPress really doesn’t have a has_children type of property available inside of the start_el function. Instead of doing ‘search and replace’, inside of the start_el function, I pull the last_result, which will a cached copy of the menu query. I’ve seen others run a new query, but I didn’t want to run a new database query for every single menu item if I didn’t have to. I then run through this and check for any entry where the current menu item $item->ID is the parent. I set a has_children boolean so that once I have proof that it’s a daddy (or mommy), I don’t waste effort checking all of the other entries. I then make sure that if it’s the current page it get’s an active class, and apply the dropdown-toggle class to the appropriate link element.

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

class Bootstrap_Walker_Nav_Menu extends Walker_Nav_Menu {

	function start_lvl( &$output, $depth ) {

		$indent = str_repeat( "\t", $depth );
		$output	   .= "\n$indent<ul class=\"dropdown-menu\">\n";

	}

	function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
		global $wpdb;
		$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

		$li_attributes = '';
		$has_children = false;
		$class_names = $value = '';

		$classes = empty( $item->classes ) ? array() : (array) $item->classes;
		$classes[] = 'menu-item-' . $item->ID;
		$classes[] = ($item->current) ? 'active' : '';

		foreach($wpdb->last_result as $a) {
			if ( $a->meta_key == '_menu_item_menu_item_parent' && $a->meta_value == $item->ID && $has_children == false){
				$has_children = true;
				$classes[] = 'dropdown';
				$li_attributes .= 'data-dropdown="dropdown"';
				break;
			}
		}

		$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
		$class_names = ' class="' . esc_attr( $class_names ) . '"';

		$id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
		$id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';

		$output .= $indent . '<li' . $id . $value . $class_names . $li_attributes . '>';

		$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        ) .'"' : '';
		$attributes .= ($has_children) 				? ' class="dropdown-toggle"' 					   : '';

		$item_output = $args->before;
		$item_output .= '<a'. $attributes .'>';
		$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
		$item_output .= '</a>';
		$item_output .= $args->after;

		$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
	}

}
Advertisements

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.

01/12/12 – All fixed, see my new post: Update #2: Using Twitter Bootstrap Dropdown Menus with WordPress

01/11/12 – I’ve since found a better way to handle these and posted a new post here.


Bootstrap is a toolkit from Twitter designed to kickstart development of webapps and sites.
It includes base CSS and HTML for typography, forms, buttons, tables, grids, navigation, and more. – twitter.github.com/bootstrap

I love Twitter’s Bootstrap toolkit. I’ve used it a few times now and I look for every excuse to play around with it. When I use a toolkit like Bootstrap, I really try to leave the toolkit alone and free of modifications. One problem with trying to use Bootstrap and WordPress together is getting the html correct. This goes for a number of things, but doubly for menus. If your html is not correct, the css rules will not take effect and you’ll be left with an unstyled bit of blah.

For example: to use a dropdown menu with Bootstrap, you need to add a
data-dropdown="dropdown" attribute to the appropriate <li> element.

This may not be the best way, but here’s how I did it.
WordPress puts together structured information like this using a “Walker” class. For a menu, that Walker is Walker_Nav_Menu. We will want to extend that class in order to modify how it puts the menu together. Then we’ll make sure that we specify our custom walker when we display our menu.

Here’s we’ll extend the standard walker and add the data-dropdown="dropdown", as well as the neccessary dropdown-toggle class to the link. It goes in your functions.php file.

class Bootstrap_Walker_Nav_Menu extends Walker_Nav_Menu {

function start_lvl( &$output, $depth ) {

$indent = str_repeat( “\t”, $depth );

$li_finder = ‘

    1. jQuery
    2. bootstrap-dropdown.js
    3. script.js

    This is because your script relies on bootstrap.js, which in turn relies on jQuery.

    As anyone will tell you, it’s best practice in situations like this to place your javascript right before your </body> tag.

    There are likely more efficient ways to extend the Walker class, but this is a somewhat less-hacky way than what I’ve seen done. The nice thing is that it works with the stock Bootstrap CSS and there’s no need to do anything in the WordPress backend other than structure your menus as you usually would. It could easily be made into a plugin, I suppose… but it’s a pretty specific, contextual thing.

%d bloggers like this: