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:
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:
- wp_nave-menu(): Add span tags inside a tag that is parent — StackOverflow
- Understanding the Walker Class – Hub.TutsPlus.com
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.
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" => 'Wpse8170_Menu_Walker',
)
);