Why do Custom Nav Menus generate so many classes on list items? Can I manage this somehow?

wordpress.stackexchange https://wordpress.stackexchange.com/questions/23

  •  16-10-2019
  •  | 
  •  

Question

Below is an example. 3 classes attached to each item, except current item, which has 6. Can I pare this down somehow?

<ul id="menu-global-nav" class="sf-menu">
<li id="menu-item-63" class="menu-item menu-item-type-post_type current-menu-item page_item page-item-5 current_page_item menu-item-63"><a href="#">Home</a></li>
<li id="menu-item-30" class="menu-item menu-item-type-post_type menu-item-30"><a href="#">Services</a>
   <ul class="sub-menu">
   <li id="menu-item-39" class="menu-item menu-item-type-post_type menu-item-39"><a href="#">Case Studies</a></li>
   <li id="menu-item-38" class="menu-item menu-item-type-post_type menu-item-38"><a href="#">Story Discovery</a></li>
   </ul>
</li>
<li id="menu-item-32" class="menu-item menu-item-type-post_type menu-item-32"><a href="#">Company</a></li>
<li id="menu-item-29" class="menu-item menu-item-type-post_type menu-item-29"><a href="#">Why Case Studies?</a></li>
<li id="menu-item-28" class="menu-item menu-item-type-post_type menu-item-28"><a href="#">Case Study Showcase</a></li>
<li id="menu-item-27" class="menu-item menu-item-type-post_type menu-item-27"><a href="#">Resources</a></li>
<li id="menu-item-26" class="menu-item menu-item-type-post_type menu-item-26"><a href="#">Online Store</a></li>
<li id="menu-item-25" class="menu-item menu-item-type-post_type menu-item-25"><a href="#">Contact Us</a></li>
</ul>
Was it helpful?

Solution

I'm going against the majority on this one :)

Yes, it can be a good idea to strip it down. Personally I'm keeping only the current-xxx type classes and replacing them with active, and active-parent (for active parent or ancestor items).

Why?

  • around the web, active has became the standard class for active menu items (on top of that WP has inconsistent class naming conventions between its' own class names).
  • you get to write less CSS rules; the bandwidth that you save might not be much, but it certainly makes the CSS file more readable

Updated code:

// for custom menus 
add_filter('nav_menu_css_class', 'normalize_wp_classes', 10, 2);

// for the page menu fallback (wp_list_pages)
add_filter('page_css_class', 'normalize_wp_classes', 10, 2);

/**
 * @param  $classes array
 * @param  $item object
 * @return array
 */
function normalize_wp_classes(array $classes, $item = null){

  // old classes to be replaced with 'active'
  $replacements = array(
    'current-menu-item',
    'current-menu-parent',
    'current-menu-ancestor',
    'current_page_item',
    'current_page_parent',
    'current_page_ancestor',
  );

  // if any of the classes above are present,
  // return an array with a single class ('active')
  return array_intersect($replacements, $classes) ? array('active') : array();
}

Update: For anyone using this code, the active-parent class is no longer required (unless you still need IE 6 support). Using the child selector (>) you can effectively style the active parent and active child any way you want.

OTHER TIPS

The wp_nav_menu function gives you the ability to modify the ID and Class for both the container and the menu. But not the LI elements.

If you take a look at the source where it is building the LI elements ( start_el() function); You can see it is using the filter nav_menu_css_class; The filter will take the array you give it (of strings) and use it to build out the class tags.

Note: From what I see in the code, if you pass it an empty array. Wordpress will still include the class attribute for the LI element, it will just be empty.

All those classes are for useful hooking into javascript for something like superfish, not just because of IE6.

Also, without a class such as current_page_item, you wouldn't be able to highlight the current page within the navigation.

Flexibility is the key. Add all the classes, unique ones for unique items in the list, give the end designer a lot of flexibility in styling. But I do agree, that is a buttload of classes. A decent HTML programmer, designer could do the equivalent with much less code.

EDIT: Made it more clear what I meant, no disrespect intended

Modified from One Trick Pony's code as it didn't work for me with a current version of WP (3.5.1).

Added the dashed classes as WP now includes both underscored and dashed versions of the page hierarchy classes.

Changed array_diff -> array_intersect as diff returns all the classes instead of the filtered list.

// for custom menus
add_filter('nav_menu_css_class', 'normalize_wp_classes', 10, 2);

// for the page menu fallback (wp_list_pages)
add_filter('page_css_class', 'normalize_wp_classes', 10, 2);

/**
 * @param  $classes array
 * @param  $item object
 * @return array
 */
function normalize_wp_classes($classes, $item){

  // old class => new class
  $replacements = array(
    'current-menu-item'     => 'active',
    'current-menu-parent'   => 'active-parent',
    'current-menu-ancestor' => 'active-parent',
    'current_page_item'     => 'active',
    'current_page_parent'   => 'active-parent',
    'current_page_ancestor' => 'active-parent',
    'current-page-item'     => 'active',
    'current-page-parent'   => 'active-parent',
    'current-page-ancestor' => 'active-parent'
  );

  // do the replacements above
  $classes = strtr(implode(',', $classes), $replacements);
  $classes = explode(',', $classes);

  // remove any classes that are not present in the replacements array,
  // and return the result

  return array_unique(array_intersect(array_values($replacements), $classes));
}

I wouldn't recommend paring it down. Yes, the markup might look bloated, but this is the only way you can really narrow down the styling if you want your site to look good in, say, IE6. Keep in mind that IE6 doesn't natively support multiple selectors (i.e. li.menu-item.current will break and default to li.current), so if you're doing any fancy CSS and want it to work with IE6, it's better to have a lot of class selectors available than not enough.

So, in reality, you could pare the list down to class="menu-item" ... but if you're going to ever have a menu with more than one post type, you'll need menu-item-type-post_type ... and if you want to do fancier filtering, you'll benefit from the menu-item-## class as well.

Remember, no one will likely ever see the actual code behind your site, and having multiple classes defined won't hurt anything.

@Ray Gulick: I hate to dive in but I concur with @Dan Gale, @EAMann and @Insanity5902. The "bloat" doesn't cause any tanbgible problems and enables a designer to theme the menu in a lot of flexible ways.

I'm curious why the "bloat" bothers you? I know it's not pretty but next to nobody will ever see it. If its a performance concern that are hundreds of other things to address first such as reducing HTTP requests and shaving the sizes of your images the latter of which will probably have an order of magnitude more benefit.

Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top