Blog

Built by maltpress


Built by maltpress

Just a quicky… WordPress custom nav walkers

Normal service will resume soon, hopefully, but I’ve not had time to think for a while.

One of the reasons is an awful lot of WordPress dev work, and I’m hoping to share some of the fancy stuff I’ve been doing soon (the one site I know I can shout about is utterly beautiful, and does brilliant things). To keep you tantalised, I came across an issue today which is probably reasonably common but for which Google didn’t seem to want to help.

If you’re doing a navigation menu and calling it with wp_nav_menu you may well want to separate each menu item with a character; I seem to remember many acccessibility guidelines suggesting menu items be separated by a non-linking, non-css “divider” (i.e. a character not a border-left or border-right). Now, one way to do this would be to use css, an :after pseudo-element, and the “content” property… but that’s not supported by early IE (bleurgh!) and is a bit silly, accessibility-wise, because although it is actually popping a character in, it’s reliant on a stylesheet being loaded, so it won’t work for screen readers, etc.

You could do it with Javascript, too; but again, accessibility-wise, this isn’t a great solution, and the less Javascript you can do the better; it’s less future-proof, more prone to bugs (if your Javascript is anything like mine, that is) and again can be turned off by the end user.

The solution: custom walkers.

A custom walker basically takes the normal menu walker class (the thing which reads through the menu items and decides how to display them) and adapts it to your own crazy whims. In this case, we want to get rid of the standard WordPress <li> elements and replace them with a pipe, but only between each nav item, not either side, so it looks like:

Home | Another | Third item | Final

So here’s how:

First: register your menu in the functions.php file for your theme (here I’m creating a footer menu):

register_nav_menu('footer_navigation', 'Footer navigation');


Second: add the menu items, calling your new walker class, to the place you want them:

$footer_args = array(
  'theme_location'  => 'footer_navigation',
  'container'       => 'nav',
  'container_id'    => 'footerNav',
  'depth' => '1',
  'walker' => new Footernav_Walker
 );
wp_nav_menu($footer_args);

Finally: extend the normal walker class to create your Footernav_Walker (or whatever you call it) – see http://wordpress.stackexchange.com/questions/14037/menu-items-description/14039#14039 for loads more info and the original code:

class Footernav_Walker extends Walker_Nav_Menu
{
 /**
 * Start the element output.
 *
 * @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. May be used for padding.
 * @param  array $args    Additional strings.
 * @return void
 */
 function start_el(&$output, $item, $depth, $args)
 {

  if ( ! empty ($item->title) ) {
   $classes     = empty ( $item->classes ) ? array () : (array) $item->classes;

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

  ! empty ( $class_names )
  and $class_names = '';

  $attributes  = '';

  ! empty( $item->attr_title )
  and $attributes .= ' title="'  . esc_attr( $item->attr_title ) .'"';
  ! empty( $item->target )
  and $attributes .= ' target="' . esc_attr( $item->target     ) .'"';
  ! empty( $item->xfn )
  and $attributes .= ' rel="'    . esc_attr( $item->xfn        ) .'"';
  ! empty( $item->url )
  and $attributes .= ' href="'   . esc_attr( $item->url        ) .'"';

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

  $item_output = $args->before;

  // the following if... statement basically ignores the first menu item
  // (so we don't start the list with a pipe):
  if($item->menu_order>=2) {
    $item_output .= ' | '; }
    $item_output .= "<a $attributes>"
    . $args->link_before
    . $title
    . '</a>'
    . $args->link_after
    . $args->after;

    // Since $output is called by reference we don't need to return anything.
    $output .= apply_filters(
    'walker_nav_menu_start_el'
    ,   $item_output
    ,   $item
    ,   $depth
    ,   $args
    );
   }  
 }
}


Ta da! Job’s a goodun’.

Back to blog



4 comments

Len Rooney

July 9, 2012 at 7:45 pm

Have you tested this in WP 3.4.1? I just cut and pasted your code into my theme. The menu works so my wp_nav_menu() is using all the right menu names, but the walker function doesn’t fire. I also tried with ‘walker’ => new Description_Walker().

I can’t figure out what’s wrong. I’ve used similar walkers before in WP 3.2, but that same code doesn’t work in 3.4.1 either.

 

Adam

July 11, 2012 at 11:29 am

I have just tested in 3.4.1 and it’s fine… but there could be some sort of issue with versions of PHP. Are you running the latest? Can you get it working on a localhost installation? Have you tried with wp_debug on? If so, what errors are you getting?

One thing worth trying is removing the parentheses from the walker class name in the array of arguments. They’re not actually needed, and I’m not sure why I include them sometimes. For me and the server settings I have they make no difference, but they might for you.

 

Len Rooney

July 11, 2012 at 1:24 pm

Thanks fro the reply Adam!

I found the source of the trouble was a plugin, WordPress Access Control, which is somehow crippling my site’s ability to register new classes via functions.php. Functions are fine, but I just can’t register a new class with this plugin installed. I’ll chase this issue down further with the plugin developers and those who know their way around WP’s OPP.

 

Peter

December 19, 2012 at 1:32 pm

Thanks Len, you saved my day!

 

Leave a comment


By using this site you consent to our use of cookies. To find out more, see our privacy policy. Continue