Hiding them with CSS is problematic, as they still get sent over the wire and still expose what could be sensitive information to anyone who looks at the source, to those who disable CSS for whatever reason (e.g. blind users — CSS just slows them down to no real benefit), and to hacker scripts and the like.
No, we need a way to allow menu items to be added to a menu that reference a page or post, but to only show or even send those menu items over the wire if the page or post to which they refer has been fully and publicly Published. Not Draft, not Pending, not Private, not Scheduled (until the scheduled time has passed), and certainly not Trashed.
Here’s a solution I found at another place which I modified slightly (add to theme’s functions.php
):
function exclude_draft_nav_items( $items, $menu, $args )
{
global $wpdb;
//add your custom posttypes to this array
$allowed_posttypes = array( 'post', 'page' );
$sql = "SELECT ID FROM {$wpdb->prefix}posts WHERE (post_status!='publish') AND ID=%d && post_type=%s";
foreach ( $items as $k => $item )
{
if( in_array($item->object, $allowed_posttypes) )
{
$query = $wpdb->prepare( $sql, $item->object_id, $item->object );
$result = $wpdb->get_var( $query );
if( $result ) unset($items[$k]);
}
}
return $items;
}
add_filter( 'wp_get_nav_menu_items', 'exclude_draft_nav_items', 10, 3 );