October 1, 2013

Customize WordPress Menu.

If you’re trying to make a fancy navigation menu with CSS, you might have found the default IDs and classes applied by WordPress to the nav menu elements to be quite lacking. However, you can fix that by adding a custom walker function to add your own conditional classes. The custom nav walker function I made below will add the following CSS classes:

CSS Classes
  1. .main-menu to top menu
  2. .sub-menu to menus inside the main-menu
  3. .menu-item to all <li>’s
  4. .main-menu-item to all <li>’s in the main menu
  5. .sub-menu-item to all <li>’s in a sub-menu
  6. .sub-sub-menu to all menus inside a sub-menu
  7. .menu-even/.menu-odd for <ul>’s (alternating)
  8. .menu-depth-# to tell you how deep each menu is
  9. .menu-item-even or .menu-item-odd (alternating)
  10. .menu-item-depth-# to tell you which level menu the <li> is in
  11. .menu-link to links
Optional Features
These requested features were can also be added to the code below. Click on each to be taken to the comment on this page describing how to integrate it.
  1. Omit certain IDs
  2. Check for Post Thumbnail images
This should make styling your Navigation Menus MUCH simpler.
Code
You call the function by supplying the name in the $args when you call the wp_nav_menu function in you theme. So for example, to enable our walker, we would call the menu with this:
Print Registered Nav Menu

  wp_nav_menu(  array( 

    'theme_location'    =>  'navigation_menu_primary', 

    'container'     =>  'div', 

    'container_id'       => 'top-navigation-primary', 

    'conatiner_class'   =>  'top-navigation', 

    'menu_class'         => 'menu main-menu menu-depth-0 menu-even', 

    'echo'           => true, 

    'items_wrap'         => '<ul id="%1$s"  class="%2$s">%3$s</ul>', 

    'depth'          => 10, 

    'walker'         => new themeslug_walker_nav_menu 

) );  // thanks nick 


This would create the nav menu for the location “navigation_menu_secondary” give it a div wrapper with an id and class, and the first level menu will get the added classes main-menu, menu-depth-0, andmenu-even. Now on to our custom walker function:
Custom Nav Menu Walker Function

  class themeslug_walker_nav_menu  extends Walker_Nav_Menu  { 


// add  classes to ul sub-menus 

function start_lvl(  &$output, $depth ) { 

    //  depth dependent classes 

    $indent = (  $depth >  0  ? str_repeat( "\t", $depth ) : '' ); //  code indent 

    $display_depth = (  $depth + 1);  // because it counts the first submenu as 0 

    $classes =  array( 

        'sub-menu', 

        ( $display_depth %  2  ? 'menu-odd' : 'menu-even' ), 

        (  $display_depth >=2  ? 'sub-sub-menu' : '' ), 

        'menu-depth-' .  $display_depth 

        ); 

    $class_names =  implode( ' ', $classes ); 

    //  build html 

    $output .=  "\n" .  $indent .  '<ul class="' . $class_names .  '">' .  "\n"; 

} 

// add  main/sub classes to li's and links 

 function start_el(  &$output, $item, $depth, $args ) { 

    global $wp_query; 

    $indent = (  $depth > 0  ? str_repeat( "\t", $depth ) : '' ); //  code indent 

    //  depth dependent classes 

    $depth_classes =  array( 

        (  $depth == 0 ?  'main-menu-item' : 'sub-menu-item' ), 

        (  $depth >=2  ? 'sub-sub-menu-item' : '' ), 

        (  $depth % 2 ?  'menu-item-odd' : 'menu-item-even' ), 

        'menu-item-depth-' .  $depth 

    ); 

    $depth_class_names =  esc_attr( implode( ' ', $depth_classes ) ); 

    //  passed classes 

    $classes =  empty( $item->classes ) ? array() : (array) $item->classes; 

    $class_names =  esc_attr( implode( ' ', apply_filters( 'nav_menu_css_class', array_filter(  $classes ),  $item ) ) ); 

    //  build html 

    $output .=  $indent .  '<li id="nav-menu-item-'. $item->ID . '" class="' .  $depth_class_names . ' ' .  $class_names .  '">'; 

    //  link 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 .= '  class="menu-link ' . ( $depth > 0  ? 'sub-menu-link' : 'main-menu-link' ) .  '"'; 

    $item_output = sprintf(  '%1$s<a%2$s>%3$s%4$s%5$s</a>%6$s', 

        $args->before, 

        $attributes, 

        $args->link_before, 

        apply_filters(  'the_title', $item->title, $item->ID ), 

        $args->link_after, 

        $args->after 

    ); 

    //  build html 

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

} 

} 

Tip: In this case, you could choose to extend Walker_Nav_Menu instead of Walker, and then you wouldn't need to define $db_fieldsmanually.
In order to utilize this custom walker class, you would call wp_nav_menu() (likely from within a theme file) and pass it a new instance of the custom Walker child class.

You Might be Interested

WordPress eStore

Kindle Apps