Question

Im having a problem with my menu and custom post type.

I have a custom post type of "services". I have created new page for it called Services. On that page Im displaying a list of all the post from that custom post type. The current-menu-item class is working as itended.

But the problem is when I click on one of the services and go to mysite.com/services/service-1, the current-menu-item from services page in menu dissapears. I need to show that this current post is a child of Services page.

All of the menu items have the same HTML:

<li id="menu-item-23" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-23"><a href="http://localhost/wordpress/sluzby/">Služby</a></li>

There is no CSS class that I could use to style this link as parent. Something like current-menu-parent or something. How could I fix this? Thanks.

Was it helpful?

Solution

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;
    }
}

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;
}

OTHER TIPS

This code add class 'current-menu-item' to parent item menu of your child CPT or custom taxonomy or default single post, in case you do not have a nested menu structure in the admin panel - only if you have 'level 0' menu. For example - if you have Page Product, which display products grid and you go to the single product - WP will not see the parent menu item. The code below improve this:

function additional_active_item_classes( $classes = array(), $menu_item = false ) {
    // custom taxonomy
    if ( $menu_item->title == 'Custom Tax Name Page' && is_tax('custom_tax') ) {
        $classes[] = 'current-menu-item';
    }
    // custom post type single
    if ( $menu_item->title == 'Custom Post Type Page' && is_singular('products') ) {
        $classes[] = 'current-menu-item';
    }
    // blog post single
    if ( $menu_item->title == 'Blog Page' && is_singular('post') ) {
        $classes[] = 'current-menu-item';
    }
    return $classes;
}
add_filter( 'nav_menu_css_class', 'additional_active_item_classes', 10, 2 );

Final code:

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

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

        // get page info (we really just want the post_name so it can 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;
}

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

Normally there is a class of .current-menu-ancestor added to parent items in the navigation.

If its not there have a look at this post: How to include the 'current-menu-ancestor' class on a custom post type menu in Wordpress?

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