I have a custom post type for musician’s profiles, and a taxonomy for their location (categorised hierachically into Countries and then Cities). On the musician’s individual profile pages I need to display a list of musicians in the same city (i.e. the child taxonomy). It’d also be good to display posts in the same country seperately (the parent taxonomy).
The problem seems to be retrieving the taxonomy dynamically, seperating the parent and child taxonomies and using these in a new loop.
I can display a list of the taxonomies, and strip out the links…
$terms = get_the_term_list( $post->ID, 'locations', '', ', ', '' ) ;
echo strip_tags($terms);
… which returns a result like this: New York, USA
And I can easily loop through posts by a fixed taxonomy value…
<?php $my_query = new WP_Query( array( 'locations' => 'new-york', 'showposts' => 10 ) ); ?>
<?php while ($my_query->have_posts()) : $my_query->the_post(); ?>
<li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php endwhile; ?>
But I am having problems combining the two:
as far as I can tell ‘get_the_term_list’ doesn’t have the ability to return only one taxonomy, and there doesn’t seem to be a taxonomy equivalent of ‘get_the_category’.
Any help much appreciated!!!
Hi @George:
Depending on how many musicians you expect to have in your database you could either go the full API route (which is generally preferred, whenever it is vialable) if you are going to have a large number of them (thousands?) you could go with some custom SQL to pull exactly the records you need.
Using the WordPress API approach
The basics of the WordPress API approach are to first call
wp_get_object_terms()
with$post->ID
of your profile musician and your'locations'
taxonomy which will return a list of “term” objects. (Unfortunately you need it to be only one location or this solution falls apart. But ignoring that…)Next you grab the term ID of the first term and pass it plus your
'locations'
taxonomy toget_objects_in_term()
which returns an array of post IDs that have the terms associated for the desired taxonomy. (Note this will include ALL posts that have ANY term associated from your'locations'
taxonomy, which is why this approach is only good for a smaller number of records.)Then you create a
WP_Query
object passing it a query that usespost__in
to filter by the list of musician IDs you received above as well as by your'locations'
taxonomy and its specific city term captured for your profiled musician. Of course you must also remember to filter out the profiled musician using the'post__not_in'
argument.Taken all together I’ve packaged that logic into a function called
get_posts_related_by_taxonomy()
whose source code you can see here (I left out a few details when I explained but hopefully they are reasonably obvious):Now you might use this function in your own loop like so:
Using the Direct SQL approach
As I already said, I prefer the WordPress API when it’s viable. Unfortunately I think you’ll run into performance or memory problems if you have even a reasonably large number of musicians and you use the approach shown above.
As a performant and memory efficient alternate you can use direct SQL to replace everything up to and including the call to
get_objects_in_terms()
in the prior example. The good news is the SQL is straightforward and unlikely to run into a future compatibility issues with new versions of WordPress since the SQL used only references primary and foreign keys and that won’t change unless they completely revamp the taxonomy system, which I think is unlikely.Using SQL I’ve created a different version of the
get_posts_related_by_taxonomy()
function which you will call it exactly the same as the first version is called. The SQL recognizes that the tablewp_term_relationships
simply needs to be joined together by their commonterm_taxonomy_id
field which will relate all the musician records for a given location/(taxonomy) + city/(term) pair. Then we join it to thewp_term_taxonomy
table so we can filter on the taxonomy, and we also filter by the profiled musician on one end of the relationship and we filter to make sure none of the related musicians are the profiled musician on the other end of the relationship. We finally make sure the related musicians post types are equal to our profiled musician’s post type so you can avoid yet one more lookup, in this case we avoid callingget_post()
.Our results from SQL are a nice simple array of post IDs which we can again use with the
post__in
argument ofWP_Query
but this time we don’t need to include thepost__not_in
,taxonomy
orterm
filter$args
and we can tellpost_type
to use'any'
since our SQL query already handled all of those.For the second version, here’s the code you need:
And again, you’ll use this second version of
get_posts_related_by_taxonomy()
in exactly the same way that you used the first version.Hope this helps!
Check out
wp_get_object_terms()
, it’s more general function and whatget_the_category()
uses internally.