2

I want to show on a list of taxonomy with corresponding posts counts of published items only. Checking the WP documentation, It seems I can ALMOST achieve that by using the get_terms function https://developer.wordpress.org/reference/functions/get_terms/ but I get ALL the posts counts including draft and trashed.

$taxonomy = 'item_category';
  $args =  array(
    'hide_empty' => false,
    'orderby'    => 'name',
    'order'      => 'ASC'
  );
$terms = get_terms( $taxonomy , $args );

foreach( $terms as $term ) {
  echo $term->name . ' - ' . $term->count . '<br/>';
}

Does WP have a built in args to display it from the get_terms function because I don't see it under the documentation? Is there any other functions or filter that I can try to achieve my desired output?

1
  • 2
    The count property on terms is only published posts. You can see in the source for _update_post_term_count(). Commented Oct 26, 2017 at 7:26

2 Answers 2

3

Checked the source, and it seems the only way to get this done is filtering the output count for each term, you can achieve that by inserting this filter before your get_terms call. Note that this will now always display published item count so be careful on its usage.

function get_terms_filter_published( $terms, $taxonomies, $args ) {
  global $wpdb;
  $taxonomy = $taxonomies[0];
  if ( ! is_array($terms) && count($terms) < 1 ) {
    return $terms;
  }

  $filtered_terms = array();
  $ctr = 0;
  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");
    $published_terms[ $ctr ] = $term;
    if ( intval($result) > 0 ) {
        $published_terms[ $ctr ] = $term;
    } else {
        // you can comment this out if you don't want to show empty terms
        $published_terms[ $ctr ]->count = 0;
    }
    $ctr++;
  }
  return $published_terms;
}

add_filter('get_terms', 'get_terms_filter_published', 10, 3);

$taxonomy = 'item_category';
$args =  array(
  'hide_empty' => false,
  'orderby'    => 'name',
  'order'      => 'ASC'
);
$terms = get_terms( $taxonomy , $args );

foreach( $terms as $term ) {
  echo $term->name . ' - ' . $term->count . '<br/>';
}
0

A bit late to the party, but I was looking for something similar.

I'd like to propose an alternate method that doesn't query the database X amount of times in a loop, in the case that you have a large amount of terms.

function get_published_terms( $taxonomy ) {
    global $wbdb;
    $sql = $wpdb->prepare( "SELECT * FROM `wp_terms`
        LEFT JOIN `wp_term_taxonomy` ON (`wp_term_taxonomy`.`term_id` = `wp_terms`.`term_id`)
        LEFT JOIN `wp_term_relationships` ON (`wp_term_relationships`.`term_taxonomy_id` = `wp_term_taxonomy`.`term_taxonomy_id`)
        LEFT JOIN `wp_posts` ON (`wp_posts`.`ID` = `wp_term_relationships`.`object_id`)
        WHERE ( `wp_term_taxonomy`.`taxonomy` = %s)
        AND `wp_posts`.`post_type` = 'post'
        AND `wp_posts`.`post_status` = 'publish'        
        GROUP BY `wp_terms`.`term_id`
        ORDER BY `wp_terms`.`name` ASC;",
        $taxonomy
    );
    $results = $wpdb->get_results( $sql );
    if ( $results ) {
        return $results;
    }
    return false;
}

// example usage:
$companies = get_published_terms( 'company' );
if ( $companies ) {
    echo '<ul class="company-list">';
    foreach ( $companies as $company ) {
        echo '<li>' . $company->name . ' (' . $company->count . ')</li>';
    }
    echo '</ul>';
}

Of course, this may not be as safe if the database schema changes in the future.

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.