When WordPress matches a menu item to the current URL, it automatically adds the current-menu-item class so the front end can highlight that item. But when a site has several custom post types, you may also want the post type archive menu item to receive that class while viewing a single item from that post type.
For example, if the single URL is http://abc.com/box/small-box, you may want the archive menu item for http://abc.com/box/ to receive the current-menu-item class as well.
Add a current menu class for single post type views with nav_menu_css_class
One straightforward way to do this is to compare the current post type slug with the menu item URL string. The code below demonstrates the idea. It works, although it is not perfectly rigorous and can still produce edge-case bugs.
add_filter( 'nav_menu_css_class', function ( $classes, $item ) {
global $post;
if ( ! $post ) {
return $classes;
}
$post_type_object = get_post_type_object( get_post_type( $post->ID ) );
if ( ! $post_type_object || empty( $post_type_object->rewrite['slug'] ) ) {
return $classes;
}
$current_post_type_slug = $post_type_object->rewrite['slug'];
if ( false !== strpos( trim( $item->url, '/' ), $current_post_type_slug ) ) {
$classes[] = 'current-menu-item';
}
return array_unique( $classes );
}, 10, 2 );
One important note: this approach only works reliably when the permalink structure is set to Post name. If the site uses a different permalink structure, you should test carefully and adapt the logic.
Possible bugs and how to think about fixing them
Imagine a post type named box and a site domain like www.express-box.com. In that case the string box appears in the domain itself, so a naive URL comparison can end up adding the current-menu class to multiple menu items by mistake.
One way to reduce that risk is to exclude the domain part of the URL before comparing strings. Since the post type slug typically appears immediately after the domain in the path, you can use a regular expression to extract the relevant path segment first and then compare that segment to the current post type slug.
The same general technique can also be adapted to highlight category or custom taxonomy archive menu items while viewing a single post. The exact implementation will differ, but the idea is similar.
