get_terms()
doesn’t have built-in feature that excludes draft posts because it keeps track of only total posts term is attached to. I made a quick search and found this snippet but be warned:
- It affects all
get_terms()
functions on your site (I excluded admin area) - There’s a SQL query in
foreach
loop – it will affect performance - More terms returned
==
bigger performance hit - I do not recommend testing it on live website
- You might get away with it if your traffic is not super high
This is probably the reason why there’s no native support for that – it’s either query in loop or WordPress would need to keep track of both drafts and public posts count which is not perfect either.
This is a very hacky solution and I wouldn’t use it myself. It might also require few modifications.
If you’re willing to try it, add this to functions.php
:
// Make sure that we're not in admin area
if( ! is_admin() ) {
add_filter( 'get_terms', 'hide_draft_terms' );
function hide_draft_terms( $terms, $taxonomies, $args ) {
global $wpdb;
$taxonomy = $taxonomies[0];
if( ! is_array( $terms ) && count( $terms ) < 1 )
return $terms;
$filtered_terms = array();
foreach ( $terms as $term ) {
$result = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts p JOIN $wpdb->term_relationships rl ON p.ID = rl.object_id WHERE rl.term_taxonomy_id = $term->term_id AND p.post_status="publish" LIMIT 1" );
if ( intval( $result ) > 0 ) {
$filtered_terms[] = $term;
}
}
return $filtered_terms;
}
}