Customize which menu item is marked active

WordPress adds a class of .current-menu-item to menu items when you are on that page. But sometimes you might want a menu item marked active in other instances.

On my website, I wanted the “Blog” menu item to be marked active any time you’re in the blog (blog homepage, category archive, single post…). I wanted “Code” marked active any time you’re in the code section (Code Snippets listing, Code Tag, Single Code Snippet). And I wanted “Case Studies” marked active when viewing the case study section (Case Study Listing and Single Case Study).

Luckily WordPress provides a filter for that: nav_menu_css_class

The filter includes four parameters:

  • $classes (array) – the current CSS classes on the menu item
  • $item (object) – the current menu item object
  • $args (array) – the arguments for the current menu (what was passed to wp_nav_menu())
  • $depth (integer) – the menu item’s depth in the menu

For this we will only use the first three parameters. I only want my customizations to apply to my menu in the ‘header’ theme location, so I check that first. Then I see if we’re on a page I want marked active (ex: is_singular( 'post' )) and if I have the right menu item selected (ex: 'Blog' == $item->title). If all of those conditions are met, I add a class of .current-menu-item to the menu item.

<?php
/*
* Customize Menu Item Classes
* @author Bill Erickson
* @link http://www.billerickson.net/customize-which-menu-item-is-marked-active/
*
* @param array $classes, current menu classes
* @param object $item, current menu item
* @param object $args, menu arguments
* @return array $classes
*/
function be_menu_item_classes( $classes, $item, $args ) {
if( 'header' !== $args->theme_location )
return $classes;
if( ( is_singular( 'post' ) || is_category() || is_tag() ) && 'Blog' == $item->title )
$classes[] = 'current-menu-item';
if( ( is_singular( 'code' ) || is_tax( 'code-tag' ) ) && 'Code' == $item->title )
$classes[] = 'current-menu-item';
if( is_singular( 'projects' ) && 'Case Studies' == $item->title )
$classes[] = 'current-menu-item';
return array_unique( $classes );
}
add_filter( 'nav_menu_css_class', 'be_menu_item_classes', 10, 3 );
view raw functions.php hosted with ❤ by GitHub

I’ve placed this code in my theme’s functions.php file. Normally I recommend using a Core Functionality plugin for code snippets, but this one relates directly to the theme. On my next theme I might not have a ‘header’ theme location for a menu, or I might not want these menu items marked active.

Bill Erickson

Bill Erickson is the co-founder and lead developer at CultivateWP, a WordPress agency focusing on high performance sites for web publishers.

About Me
Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk

Reader Interactions

Comments are closed. Continue the conversation with me on Twitter: @billerickson

Comments

  1. Sharon says

    Hello Bill!

    Thanks so much for this great customization tip!

    Would this also apply to pages? For instance, I would like to have 3 sub-pages of a main menu item for the mobile version of my website (in-the-works). I do not want these sub-pages included in the main navigation. Instead, I would like the primary menu page to be highlighted, when a visitor lands on each of these 3 sub-pages.

    Would your snippet work for something like this? Do you have any clues as to how I could apply it to a custom mobile menu?

    Thanks again!
    Sharon

  2. Maria Campbell says

    Thanks so much Bill for all your posts. They are so awesome, and I learn a lot! It makes me love Genesis even more.

  3. David says

    Hi Bill,
    thank you. i just use it for a site. very smart. i previously manually add custom class in menu item and style it conditionally in CSS (compared to body class).

    just a small improvement:
    when we set current-menu-class in a complex conditional, sometimes we can get double class(es). we can remove duplicate classes using array_unique:

    return array_unique( $classes );

    of course, duplicate css class still works, but it is much cleaner without duplicate 🙂
    i also use array_unique when filtering body class, post class, etc.

    thanks again for the tips.

    • Bill Erickson says

      Good call! While not necessary on body_class and post_class since they already run through array_unique after the filter (here and here), the nav menu css classes don’t go through array_unique (here).

      I’ve updated my code above to reflect this suggestion.

      • David says

        I didn’t know that wp updated body class and post class with array_unique.

        I just check 3.x and array unique is not available in core.
        probably sometime in wp 4.x

        I hope core team will the also add that in all dynamic classes.

        thanks for the information.
        I’ll put it in my check list to remove array unique in body class & post class filter.

  4. Ivan says

    Hi Bill.
    Thanks for the snippet. I was wandering how to do this for a while.

    Is there any reason you are not using if()…. elseif() statement rather than going thru each if? the code don’t look like it can get in more than one if statement. That won’t be noticeable speed improvement … but will optimize the code.

  5. Melissa Jean Clark says

    This is great! Thanks so much for sharing your code. I’m not as well-versed in filters with WP – I was using a bit of jQuery to accomplish this. This approach is much better!

  6. Aaron Jerad says

    Thanks this worked great. I was using jQuery, but this is much better!

    In my case it was likely that menu item titles were going to change. So I used the menu item ID instead, like this:

    if( ( is_singular( ‘post’ ) || is_category() || is_tag() ) && 1648 == $item->ID )
    $classes[] = ‘current-menu-item’;

    I also needed to add a class to the current menu item’s parent or ancestor so simply duplicated the conditional like this:

    if( ( is_singular( ‘post’ ) || is_category() || is_tag() || is_singular( ‘custom-post-type ) || is_tax( ‘custom-taxonomy’ ) && 1360 == $item->ID )
    $classes[] = ‘current-page-ancestor’;

    • Sonam says

      Hi Aaron –

      I’m trying to get this working with genesis and woo-commerce, so on all the sub categories for shop , the shop menu item stays highlighted as current – but no luck so far. Any ideas how to do this?

      Thanks

  7. Jim says

    Hi Bill

    Thanks for sharing. Just trying to work this out.

    What is the 10,3 at the end of your code?

    I’m trying to figure out how to show “menu-item-74” as selected if is_front_page()

    • Bill Erickson says

      10 is the priority of my filter, and 3 is the number of arguments being passed to my function. More information here.

      If you do print_r( $item ); you can see all the available parameters you can use. I think there’s something like $item->ID which will have the menu item ID, so you can do if( is_front_page() && $item->ID == 74 )