2

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!

2

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.

2

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
0

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');
  • 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
0

I would recommend:

1) skip adding the first menu item class. That's extra php that you don't need. Using ul > li:first-child will let you target the first menu item in either CSS or as a jQuery selector. :first-child has great browser support (more than :last-child, so I would add a class for the last menu item).

2) Find the last top-level menu item and add a class to it. Drop this code into your theme's functions.php file and it will add a class to only the last top-level navigation item instead of the very last navigation item like many of the code snippets in the other answers here.

// Add a class to the last top-level menu item
function fancy_last_menu_item_class($items) {
    // Create an empty array to hold the array ID's of top level menu items
    $topLevelMenuItemIDs = array();

    // Loop through all of the menu $items
    for($i=0,$count=count($items);$i<$count;$i++){
        // Check if the 'menu_item_parent' property is set to '0'
        if($items[$i]->menu_item_parent == 0){   
            // This item has no parent menu items, so it's top-level.
            // Add its array ID to the top level menu item IDs array.
            $topLevelMenuItemIDs[] = $i;
        }
    }

    // Count how many top level nav items were found, so you can target the last one
    $topLevelMenuItemCount = count($topLevelMenuItemIDs);

    // Add a class to the last top level navigation item.
    $lastMenuItemClass = 'last-menu-item';
    $items[$topLevelMenuItemIDs[--$topLevelMenuItemCount]]->classes[] = $lastMenuItemClass;

    // Return the items with the altered last item
    return $items;
}
// Hook the last menu item class to the wp_nav_menu_objects filter
add_filter('wp_nav_menu_objects', 'fancy_last_menu_item_class');

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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