Multiple column lists navigation using wp_nav_menu
Intro
Working on a recent project I had to made use of ‘multiple column lists’, based on the article ‘CSS Swag: Multi-Column Lists‘ at A List Apart. For more control over the items in the list, I wanted to use the WordPress custom menus. This is the final result:

The CSS
The CSS is pretty straight forward. You can see a basic example here: http://www.alistapart.com/d/multicolumnlists/example6.html
Instead of using a different class for each and every list item, I wanted to useĀ ‘firstcolumn’, ‘secondcolumn’ and so on for the list items and ‘colheader’ for the items at the top.
/* http://www.alistapart.com/d/multicolumnlists/example6.html */
* html ul li{position:relative;}
ul li{line-height:1.2em;margin:0;padding:0;}
ul li.colheader{margin-top:-104px;} /* I'm using pixels here, but generally it is 'list item count' x 'line-height' (4*1.2) */
ul li.firstcol{margin-left:0em;}
ul li.secondcol{margin-left:160px;} /* a width + padding */
ul li.thirdcol{margin-left:320px;}
ul li a{display:block;width:145px;height:16px;padding:0 0 0 15px;margin:0 0 10px 0;}
ul li a:hover, ul li.current_page_item a{color:#adadad;}
This creates the basic CSS for the list items.
The PHP code
The wp_nav_menu function provides filters and an option to provide your own Walker class which we will use here. Basically, all we need to add is a item counter and add additional CSS classes at certain postitions. Based on the original ‘Walker_Nav_Menu’ class, not much needs to be added:
First, we need to have a variable ‘$item_count’ to keep the list items count:
class my_footer_menu_walker extends Walker {
var $item_count = 0;
/**
* @see Walker::$tree_type
* @since 3.0.0
* @var string
*/
var $tree_type = array( 'post_type', 'taxonomy', 'custom' );
....
Next, we need to modify the function ‘start_el’ by adding the previously declared variable and add our custom CSS classes to the generated list items:
function start_el(&$output, $item, $depth, $args) {
global $wp_query, $item_count;
$indent = ( $depth ) ? str_repeat( "t", $depth ) : '';
$class_names = $value = '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes[] = 'menu-item-' . $item->ID;
# START adding column classes
if($item_count <= 3)
{
$classes[] = 'firstcol';
}
if($item_count == 4)
{
$classes[] = 'colheader';
}
if($item_count > 3 &amp;amp;&amp;amp; $item_count <= 7)
{
$classes[] = 'secondcol';
}
if($item_count == 8)
{
$classes[] = 'colheader';
}
if($item_count > 7 &amp;amp;&amp;amp; $item_count <= 13)
{
$classes[] = 'thirdcol';
}
# END adding column classes
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
$class_names = ' class="' . esc_attr( $class_names ) . '"';
....
Finally, at the end of the function we need to increase the counter:
... $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args ); $item_count ++; }
The full code:
# Custom walker class for the wp_nav_menu
class my_footer_menu_walker extends Walker
{
var $item_count = 0;
/**
* @see Walker::$tree_type
* @since 3.0.0
* @var string
*/
var $tree_type = array( 'post_type', 'taxonomy', 'custom' );
/**
* @see Walker::$db_fields
* @since 3.0.0
* @todo Decouple this.
* @var array
*/
var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );
/**
* @see Walker::start_lvl()
* @since 3.0.0
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of page. Used for padding.
*/
function start_lvl(&amp;amp;$output, $depth) {
$indent = str_repeat("t", $depth);
$output .= "n$indent<ul class="sub-menu depth-$depth">n";
}
/**
* @see Walker::end_lvl()
* @since 3.0.0
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of page. Used for padding.
*/
function end_lvl(&amp;amp;$output, $depth) {
$indent = str_repeat("t", $depth);
$output .= "$indent</ul>n";
}
/**
* @see Walker::start_el()
* @since 3.0.0
*
* @param string $output Passed by reference. Used to append additional content.
* @param object $item Menu item data object.
* @param int $depth Depth of menu item. Used for padding.
* @param int $current_page Menu item ID.
* @param object $args
*/
function start_el(&amp;amp;$output, $item, $depth, $args) {
global $wp_query, $item_count;
$indent = ( $depth ) ? str_repeat( "t", $depth ) : '';
$class_names = $value = '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes[] = 'menu-item-' . $item->ID;
# Hack for adding column classes
if($item_count <= 3)
{
$classes[] = 'firstcol';
}
if($item_count == 4)
{
$classes[] = 'colheader';
}
if($item_count > 3 &amp;amp;&amp;amp; $item_count <= 7)
{
$classes[] = 'secondcol';
}
if($item_count == 8)
{
$classes[] = 'colheader';
}
if($item_count > 7 &amp;amp;&amp;amp; $item_count <= 13)
{
$classes[] = 'thirdcol';
}
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
$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 .'>';
$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 ) .'"' : '';
# A little hack to disable clicking on links
$is_clickable = get_post_meta($item->object_id, 'link_disabled', true);
$jsarg = ($is_clickable == '1') ? 'onclick="return false;"' : '';
$item_output = $args->before;
$item_output .= '<a'. $attributes .' '.$jsarg.'>';
$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 );
$item_count ++;
}
/**
* @see Walker::end_el()
* @since 3.0.0
*
* @param string $output Passed by reference. Used to append additional content.
* @param object $item Page data object. Not used.
* @param int $depth Depth of page. Not Used.
*/
function end_el(&amp;amp;$output, $item, $depth) {
$output .= "</li>n";
}
}
The Menu
Left to do is tell the wp_nav_menu to use our custom walker class:
wp_nav_menu( array( 'container_class' => '', 'container' => '', 'theme_location' => 'footer', 'walker' => new my_footer_menu_walker ) );
That’s it. ;-)
Please leave your comments, I’d like to know how you modify your menus.




mack
Nice piece of code, shall use it in my next wordpress website!
derek
Does this work on dropdown menues? I have a horizontal navigation bar and I need to split the subpages of a few of the menu items into multiple (2) column. Basically, when you hover over a menu item I want the dropdown to output the sub pages in two columns – is that possible?
Pete
Yes, doable but you might want to check out the WordPress jQuery Mega Menu Plugin, or the commercial UberMenu, or you can build your own.
Alex
It`s nice)
kevin
Hey Pete, nice snippet – looks like a lot of work for just a simple side by side list but certainly offers more control. If people don’t care about ugly source you could just use CSS, but the result with this is much cleaner.
Pete
Thanks! ;-)
shamas
thanks,cool!