i have this code below to show links for my custom taxonomy on my custom posts. I want it to show only the categories that have published posts in them. This mostly works but if i put all the posts in a certain category to draft, it still shows up as a link, but when a user clicks the link it goes to a 404 page because there are no active links on it.
How can i make it just show the link for a category if there are PUBLISHED posts and not if there are only drafts or if the category has no posts?

//list terms in a given taxonomy 
$args = array( 'hide_empty=0' );
$terms = get_terms( 'product_category', $args );
if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) {
    $count = count( $terms );
    $i = 0;
    $term_list = '<div class="product-category-list">';
    foreach ( $terms as $term ) {
        $term_list .= '<a class="activeunderline" href="' . esc_url( get_term_link( $term ) ) . '" alt="' . esc_attr( sprintf( __( 'View all post filed under %s', 'my_localization_domain' ), $term->name ) ) . '">' . $term->name . '</a>';
        if ( $count != $i ) {
            $term_list .= ' &middot; ';
        else {
            $term_list .= '</div>';
    echo $term_list;
  • 1
    you set hide_empty to false in your code, this will show terms whether or not they have posts assigned.
    – Milo
    May 3, 2016 at 4:53
  • This seems like it might be helpful, but i'm not sure what to do with it. I tried changing to hide_empty=1, but there was no change.
    – rudtek
    May 3, 2016 at 5:15
  • I changed it, but nothing changed. It's hiding categories that dont have any posts, butit's not hiding categories that only have draft posts.
    – rudtek
    May 3, 2016 at 5:30

1 Answer 1


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;
  • this works! THANK YOU. I'll take your cautions into account though. I really appreciate it.
    – rudtek
    May 3, 2016 at 16:12
  • actually, i'm getting some errors now: [03-May-2016 20:07:44 UTC] PHP Warning: Missing argument 2 for hide_draft_terms() in functions.php on line 68 [03-May-2016 20:07:44 UTC] PHP Warning: Missing argument 3 for hide_draft_terms() in /functions.php on line 68 additionally, it hides all categories for posts in the backend and so i cant see my regular post categories. any idea what that means?
    – rudtek
    May 3, 2016 at 20:16
  • @rudtek I updated the code, I haven't tested it myself, so be cautious. I took out the is_admin() if statement from the function itself and wrapped it around everything. Let me know how it goes.
    – N00b
    May 4, 2016 at 16:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.