Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I'm looking for a solution to adjust the output of wp_nav_menu only on a specific navigation menu. I have my menu:

wp_nav_menu(
    array(
        "container"         => "nav",
        "container_class"   => "container",
        "container_id"      => "nav",
        "fallback_cb"       => false,
        "menu_class"        => "six columns omega main-nav sf-menu",
        "theme_location"    => "main-nav"
    )
);

The Problem

I need to find a way insert <span>[number]</span> inside of the anchor element. [number] represents the number of the item starting at 1. Here's a visual:enter image description here

The structure of the the menu would be:

<li class="...">
    <a href="#"><span>01.</span>Home</a>
</li>
<li class="...">
    <a href="#"><span>02.</span>Services</a>
</li>
<li class="...">
    <a href="#"><span>03.</span>Portfolio</a>
</li>

Currently, I am using a jQuery hack. This works but there's no guarantee that the user can merely disable JavaScript. I've looked at:

I have an idea that extending the walker class is necessary but my ultimate confusion lies with building the links manually and inserting dynamic information before link text is printed. The Stack Overflow question does it but does not explain how to get there.

Addendum

To get the precise result that I wanted see pastebin. $item->title needed to be modified in order to follow the HTML structure as listed above.

share|improve this question

1 Answer 1

up vote 2 down vote accepted

You just need to create your own walker class and extend start_el method. This method builds a link and you will be able to add your span before it:

class Wpse8170_Menu_Walker extends Walker_Nav_Menu {

    var $number = 1;

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

        $class_names = $value = '';

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

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

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

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

        // add span with number here
        if ( $depth == 0 ) { // remove if statement if depth check is not required
            $output .= sprintf( '<span>%02s.</span>', $this->number++ );
        }

        $atts = array();
        $atts['title']  = ! empty( $item->attr_title ) ? $item->attr_title : '';
        $atts['target'] = ! empty( $item->target )     ? $item->target     : '';
        $atts['rel']    = ! empty( $item->xfn )        ? $item->xfn        : '';
        $atts['href']   = ! empty( $item->url )        ? $item->url        : '';

        $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args );

        $attributes = '';
        foreach ( $atts as $attr => $value ) {
            if ( ! empty( $value ) ) {
                $value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
                $attributes .= ' ' . $attr . '="' . $value . '"';
            }
        }

        $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 );
    }

}

After it you will be able to use this class in your wp_nav_menu function call:

wp_nav_menu(
    array(
        "container"         => "nav",
        "container_class"   => "container",
        "container_id"      => "nav",
        "fallback_cb"       => false,
        "menu_class"        => "six columns omega main-nav sf-menu",
        "theme_location"    => "main-nav",
        "walker"            => new Wpse8170_Menu_Walker(),
    )
);
share|improve this answer
    
Do I need to inlude the class in the same file as the navigation or does this happen automatically via the hook system? –  djthoms Oct 4 '13 at 16:45
    
Create a separate wpse8170-menu-walker.php file in the root of your theme. Copy class into this file. Add this include 'wpse8170-menu-walker.php' into your template. –  Eugene Manuilov Oct 4 '13 at 17:17
    
Many thanks! I realized I was doing a n00b error by editing the wrong file, lol –  djthoms Oct 5 '13 at 16:18

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.