J.me

Filter get_terms to return only terms with published post

So you are using custom taxonomy. You add terms to the taxonomy, and add the terms to your posts. Then, you use get_terms and list all your terms. Everything works fine, terms that doesn’t have any posts will not be returned if you set hide_empty argument to true. Now you move some of your posts to draft and you get a problem. Terms that doesn’t have any published posts still returned. This lead to 404 error when you click on the link of this term. It doesn’t look good now, we need to remove term that doesn’t have any published post.

So how to do that? The answer is by using WordPress filter. This piece of code below will solve the problem.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function get_terms_filter( $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;
}
add_filter('get_terms', 'get_terms_filter', 10, 3);

The code work like this. We add a filter to the get_terms hook. This hook is called before the terms is returned, so it is perfect to place the filter here. Next, we check each returned terms and see if they have any published post, by using our own query. Why didn’t I use the WordPress WP_Query instead? The answer is I can’t get it to work, beside, it builds a pretty complicated query that might increase your WordPress site load time if it is used too much. Using our own query, we make sure it only use the query that we need. If our query returned that the term has a published post, we add this term to our new array which we use to store the filtered terms. Finally, we return the filtered terms.

Now, when you are using get_terms, you will filter out all terms that doesn’t have any published post. 🙂

Hope that helps. I have a hard time to explain the situation, so let me know if it doesn’t clear.

Thank you.

10 comments | Leave a comment

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.