Skip to main content
Added non-plugin method per OP request
Source Link
Joey Yax
  • 851
  • 5
  • 7

Per your request, non-plugin route. I didn't test this for any errors, just adapted from the class above but it should at least get you in the right direction:

add_filter( 'nav_menu_css_class', 'nav_parent_class', 10, 2 );

function nav_parent_class( $classes, $item ) {
    $cpt_name = 'service';
    $parent_slug = 'services';

    if ( $cpt_name == get_post_type() && ! is_admin() ) {
        global $wpdb;

        // remove any active classes from nav (blog is usually gets the currept_page_parent class on cpt single pages/posts)
        $classes = array_filter($classes, ($class == 'current_page_item' || $class == 'current_page_parent' || $class == 'current_page_ancestor'  || $class == 'current-menu-item' ? false : true ));

        // get page info
        // - we really just want the post_name so it cane be compared to the post type slug
        $page = get_page_by_title( $item->title, OBJECT, 'page' );

        // check if slug matches post_name
        if( $page->post_name == $parent_slug ) {
            $classes[] = 'current_page_parent';
        }

    }

    return $classes;
}

Per your request, non-plugin route. I didn't test this for any errors, just adapted from the class above but it should at least get you in the right direction:

add_filter( 'nav_menu_css_class', 'nav_parent_class', 10, 2 );

function nav_parent_class( $classes, $item ) {
    $cpt_name = 'service';
    $parent_slug = 'services';

    if ( $cpt_name == get_post_type() && ! is_admin() ) {
        global $wpdb;

        // remove any active classes from nav (blog is usually gets the currept_page_parent class on cpt single pages/posts)
        $classes = array_filter($classes, ($class == 'current_page_item' || $class == 'current_page_parent' || $class == 'current_page_ancestor'  || $class == 'current-menu-item' ? false : true ));

        // get page info
        // - we really just want the post_name so it cane be compared to the post type slug
        $page = get_page_by_title( $item->title, OBJECT, 'page' );

        // check if slug matches post_name
        if( $page->post_name == $parent_slug ) {
            $classes[] = 'current_page_parent';
        }

    }

    return $classes;
}
Source Link
Joey Yax
  • 851
  • 5
  • 7

I usually include the following parent variable, filter and method in my plugins to account for this case. I've never been sure if this is the "right" way of going about it, but feels better than applying it with javascript.

class Plugin_Name {
    private $parent = 'services'; // ideally this is a setting in your plugin, not a hard-coded variable in case the page slug changes

    function __construct() {
        // Add classes to 'parent'
        add_filter( 'nav_menu_css_class', array( &$this, 'nav_parent_class' ), 10, 2 );
    }
    
    function nav_parent_class( $classes, $item ) {

        if ( $this->nicename == get_post_type() && ! is_admin() ) {
            global $wpdb;

            // remove any active classes from nav (blog is usually gets the currept_page_parent class on cpt single pages/posts)
            $classes = array_filter($classes, ($class == 'current_page_item' || $class == 'current_page_parent' || $class == 'current_page_ancestor'  || $class == 'current-menu-item' ? false : true ));

            // get page info
            // - we really just want the post_name so it cane be compared to the post type slug
            $page = get_page_by_title( $item->title, OBJECT, 'page' );
            
            // check if slug matches post_name
            if( $page->post_name == $this->parent ) {
                $classes[] = 'current_page_parent';
            }

        }
        
        return $classes;
    }
}