I have two custom post types ‘country’ and ‘city’ and a shared taxonomy ‘flag’.
If I use:
<?php $flags = get_terms('flag', 'orderby=name&hide_empty=0');
I get a list of all terms in the taxonomy, but I want to limit the list to the post type ‘country’.
How can I do it?
Using the new solution
<?php
$flags = wpse57444_get_terms('flags',array('parent' => 0,'hide_empty' => 1,'post_types' =>array('country')));
foreach ($flags as $flag) {
$childTerms = wpse57444_get_terms('flags',array('parent' => $flag->term_id,'hide_empty' => 1,'post_types' =>array('country')));
foreach ($childTerms as $childTerm) {
echo $childTerm->name.'<br />';
}
}
?>
I can’t echo $childTerm->name. Why?
I’m afraid this isn’t possible natively (yet?). See this trac: http://core.trac.wordpress.org/ticket/18106
Similarly on the taxonomy admin page the post count reflects all post types. (
I’m pretty sure there is a trac ticket for that too)http://core.trac.wordpress.org/ticket/14084
See also, this related post.
New solution
Having written the one below, I’ve released a much better way (alteast in the sense that you can do more) is to use the filters provided in the
get_terms()
call. You can create a wrapper function that usesget_terms
and (conditionally) adds a filter to manipulate the SQL query (to restrict by post type).The function takes the same arguments as
get_terms($taxonomies, $args)
.$args
takes the additional argument ofpost_types
which takes an array|string of post types.But I can’t gurantee that everything works ‘as expected’ (I’m thinking padding the count). It does appear to work using just default the
$args
forget_terms
.Usage
Original work-around
Inspired from the above trac ticket, (tested, and it works for me)
Usage
or
Two custom post types ‘country’ and ‘city’ and a shared taxonomy ‘flag’. You want to limit the list to the post type ‘country’.
Here is a more simple solution:
@stephen-harris’s answer above only worked for me partially. If I tried to use it twice on the page, it didn’t work. Also, the idea of burying mysql queries like that worries me – I think its better practice to use core methods to achieve a solution, to avoid conflicts with future WP updates. Here is my solution, based on some comment #7 on on the Trac ticket he reference
Usage:
This works for only one post type and one taxonomy, because that is what I needed, but it wouldn’t be too hard to modify this to accept multiple values.
There was some mention on that Trac thread that this may not scale well, but I’m working on a pretty small scale and have had no problems with speed.
[edit] This is a comment on the excellent answer by Stephen Harris.
It doesn’t return any terms if used with multiple post types like this
$flags = wpse57444_get_terms('flags', array('post_types' => array('country','city')));
. This is because $wpdb->prepare sanitizes the $post_types_str string top.post_type IN('country,city')
while it should bep.post_type IN('country','city')
. See this ticket: 11102. Use the solution from this topic to get around this: https://stackoverflow.com/a/10634225I also tried to use @Stephen Harris’s answer, but the query I needed was quite hard to write as a single query and using the filter pieces.
Furthermore, I also needed to use that function multiple times in the same page and I solved the problem declaring the
wpse_filter_terms_by_cpt
function outside the wrapper function.Anyways @Mark Pruce’s answer in my opinion fits better, for the same reasons he said, even though it needs you to make one more query (and the related loop) to prepare the args for the
wp_get_object_terms
function.