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 using a WordPress Menu to create a navigation structured like this:

  • Home
  • About
  • Contact
    • Sub Page

Using this code from kuroi's response here I'm able to add first-menu-item and last-menu-item classes to the list items above:

function add_first_and_last($output) {
    $output = preg_replace('/class="menu-item/', 'class="first-menu-item menu-item', $output, 1);
    $output = substr_replace($output, 'class="last-menu-item menu-item', strripos($output, 'class="menu-item'), strlen('class="menu-item'));
    return $output;
}
add_filter('wp_nav_menu', 'add_first_and_last');

However the last-menu-item class is being added to the Sub Page list item (because it's the last) rather than to the Contact list item.

Question: How can I make this function apply only to the top level items of a menu?

Thanks!

share|improve this question

3 Answers 3

up vote 1 down vote accepted

I would lean very much towards a custom walker for this but I think I've managed to make it work using part of that code and some of my own.

function add_position_classes_wpse_100781($classes, $item, $args) {
  static $fl;
  if (0 == $item->menu_item_parent) {
    $fl = (empty($fl)) ? 'first' : 'middle';
    $classes[] = $fl.'-menu-item';
  } 
  return $classes;
}
add_filter('nav_menu_css_class','add_position_classes_wpse_100781',1,3);

function replace_class_on_last_occurance_wpse_100781($output) {
    $output = substr_replace(
      $output, 
      'last-menu-item ', 
      strripos($output, 'middle-menu-item'), 
      strlen('middle-menu-item')
    );
    return $output;
}
add_filter('wp_nav_menu', 'replace_class_on_last_occurance_wpse_100781');

What I did was add first-menu-item and middle-menu-item to top level items only with the first filter on nav_menu_css_class. Then with the second filter I replaced the last occurrence of middle-menu-item with last-menu-item.

It works for the few test cases I tried.

share|improve this answer
    
Fantastic, works for me! Many thanks. –  AlecRust May 26 '13 at 15:02

something like this:

function add_first_and_last_classes_wpa100781($items) {
    $items[1]->classes[] = 'first';
    $items[count($items)]->classes[] = 'last';
    return $items;
}

add_filter('wp_nav_menu_objects', 'add_first_and_last_classes_wpa100781');
share|improve this answer
1  
This code adds the last class to the last submenu item, not to the last top level item, which is what I understand the question to require. –  s_ha_dum May 26 '13 at 14:24

I have little fix on Bainternet code, because this code not work if last item has sub item

function wpb_first_and_last_menu_class($items) {
    $items[1]->classes[] = 'first-menu-item'; // add first class

    $cnt = count($items);
    while($items[$cnt--]->post_parent != 0); // find last li item
    $items[$cnt+1]->classes[] = 'last-menu-item'; // last item class
    return $items;
}
add_filter('wp_nav_menu_objects', 'wpb_first_and_last_menu_class'); //filter to iterate each menu
share|improve this answer

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.