Exclude Private, Draft pages from Primary Nav when using custom menu

I had a similar problem and here is the best solution I could come up with. The reason (I think) that private or non-published items show up in menus is that the menu items are themselves posts and have their own post_status. That means that in a situation where a page is marked private, the menu item for that page can still be set to publish, and is displayed. I wrote a filter callback for the wp_nav_menu_objects hook which looks at the post_status for the object that the menu item stands for, and removes it from the menu if that object is private. In my case, private pages was the concern, but one can easily adapt this for drafts. I also allow the menu items to be displayed if the user is logged in, whatever his capabilities are, whereas WP by default limits access to a private page to administrators and editors. This also can easily be adapted.

function jj_filter_private_pages_from_menu ($items, $args) {
    foreach ($items as $ix => $obj) {
        if (!is_user_logged_in () && 'private' == get_post_status ($obj->object_id)) {
            unset ($items[$ix]);
        }
    }
    return $items;
}
add_filter ('wp_nav_menu_objects', 'jj_filter_private_pages_from_menu', 10, 2); 

It seemed to me easier and more appropriate to filter the menu items than to hide them with CSS, your milage may vary.

To limit menu items for private pages to administrators and editors you should be able to substitute current_user_can ('read_private_pages') for !is_user_logged_in ().

Leave a Comment