Often a bit of a plague this one. I’ve looked around and there are a fair few solutions out there on offer. But none of them seemed straight forward, lean or versatile enough. Until I stumbled upon this snippet on Github (nb. please note the missing apostrophes around slug on line 12 of Github code).

So what’s going on here? We’re checking the current page to see if it’s of a Custom Post Type, and if it is, we’re noting it’s slug. We then compare the slug to our menu items. If a menu item points towards a URL containing the slug, then bingo, we can tell it to give itself a class (‘current_page_item’).

There is some debate over how clean this is (using the URL slug as the base). In my opinion, it’s certainly good enough. Further, it’s versatile. People are looking for this code so that it works where a CPT’s archive page has been used as the menu item. But by using the URL slug, the code will work on whatever page is used in the menu, so long as it contains the right slug. In my current case that’s really convenient, as I’m not using archive pages.

This works great, but as others noted in the comments, there is a problem if your site also uses a blog (The default ‘post’ post type). When you’re on any single CPT page, if you have a Blog menu, it will remain highlighted as if you were on a single blog post.

That’s where icebottletea’s suggestion comes in handy, but only fixes part of the problem. It removes the highlight of Blog… but it removes it even if you are in fact on a blog post.

My simple fix for this, a fix which to my mind completes this code, is to throw in an ‘if’ statement. We simply check to see that we aren’t on a single blog post. If we aren’t no problem, iceteabottle’s amendment deals with duplicate highlighting. But if we are, then we simply don’t run the code (as we don’t need to).

So that’s it. In brief, we check to see if we are on a single blog post. If we are we needn’t do anything, if we aren’t, we check to see if we are on a CPT post, we get the slug from the URL and check it against menu items, highlighting wherever it shows up. And we force the blog menu item not to highlight.

 

<?php

// CPT Parent pages based on slug
add_action('nav_menu_css_class', 'add_current_nav_class', 10, 2 );
function add_current_nav_class($classes, $item) {

  // Getting the current post details
  global $post;

  // Make sure we're not on a single blog post before running the code...
  if ( !is_singular( 'post' ) ) {
    

    // Getting the post type of the current post
    $current_post_type = get_post_type_object(get_post_type($post->ID));
    $current_post_type_slug = $current_post_type->rewrite['slug'];

    // Getting the URL of the menu item
    $menu_slug = strtolower(trim($item->url));

    // If the menu item URL contains the current post types slug add the current-menu-item class
    if (strpos($menu_slug,$current_post_type_slug) !== false) {
      $classes[] = 'current-menu-item';
    } 

    // as we are not on a single blog post, stop blog menu from highlighting
    else {
      $classes = array_diff( $classes, array( 'current_page_parent' ) );
    }
  }
  
  // Return the corrected set of classes to be added to the menu item
  return $classes;
}
?>