Display Only Posts From Parent Term In WordPress

/ Wordpress / by Paul Robinson / 17 Comments
This post was published back on August 14, 2011 and may be outdated. Please use caution when following older tutorials or using older code. After reading be sure to check for newer procedures or updates to code.

The client had a related posts loop on the single page template that was displaying posts from the same term as the current post. Everything was working fine, until they hit a snag. It seemed that the related loop was pulling in posts from another term. What was the problem? Well for the sake of simplicity let’s call our two terms ‘parent’ & ‘child’. We were displaying the posts from the ‘parent’ term, but it was also pulling in posts from the ‘child’ term as it is it’s child.

It eventually turned out that the term had been mistakenly made a child, but not before I’d figured out away around it. So to stop it going to waste I thought I’d share it.

N.B. Please note that you will require a fair knowledge of WP queries to continue, although if you are stuck please don’t hesitate to drop me an email or a comment.

The Standard ‘Tax Query’

First let’s look at a standard WordPress Taxonomy query.

This is the array you would hand to either query_posts() or WP_Query() to return posts from the terms you have listed.

So, let’s say that we have pulled in posts from the term ‘pop’ under the taxonomy ‘music’. Now let’s pretend for a second there are terms which are the names of sub-genres (dance-pop, Jpop, etc) that are children of the term ‘pop’. If you use the query above it will show posts for all of those terms too.

Now you might want to show all the posts from the children, but what if you don’t? As of this moment (as far as I’m aware) there is no option/parameter to allow you to stop this from happening, so we do a little bit of query trickery instead. Take a look at this:

It’s actually fairly obvious when you think about it. If there is no parameter to auto exclude posts from child terms then why don’t we just tell the query we don’t want those posts using the child terms & the NOT IN operator.

Now there is a big problem with that query & that is the fact it is hard coded. If we add any more children we’ll have to manually add them into the query. Well let’s change that by automating the query. Take a look at this:

There we have it. You may wonder why I’ve added two variables & assigned the name of the taxonomy & parent term to it. Well it’s is simply because if we ever need to change the taxonomy or parent term we can by only changing 1 or 2 lines.

We’ve already been through the query & what that does, so I’ll explain a little about what the two extra lines do. First we have get_term_by() this allows us to get all the information about our parent term, including it’s ID. We then use that ID in the function get_term_children() to bring back any children the term may have. It returns an array of IDs of the children. That is perfect to hand straight into the query.

That’s all there is to it. Hopefully this tutorial has been helpful. Although the code didn’t end up being used on the site, I did get the chance to test it so I know it works. If you have any questions or comments please let me know via the comments below, or the contact page.


Author’s gravatar

Hi Paul,

I was just looking for some complicated hierarchical tax query stuff, so this is helpful getting me on my way. I need to show all the parent posts and 1 featured post from each child that links to the child tax page. have any random ideas for that? this project has literally been the project from hell, but i hope that is the last bit.

Author’s gravatar author

Hmmm. That is a difficult one. I can’t think of anything off the top of my head.

Maybe you could do a tax query that grabs all posts using 'posts_per_page' => -1 from the parent & the children. Then grab the tax children using get_term_children().

Then you could create a blank array outside the post loop, and for each post you could use something like in_array() to see if the posts term id is inside the array given by get_term_children(). If it is display the post & add it’s ID to the blank array. You could then also add an extra condition to the previous in_array() that checks to see if the term ID of the post is also in your other array. If it is just continue on without displaying the post using continue;.

I’m not entirely sure of the code or even if it will work, but it’s the best I can come up with right now. Hopefully, even if I’ve been writing crap, it’s inspired you with how to get it working, lol.

Author’s gravatar

Been thinking of this all day (even while at handball training it’s been on the brain). I would have thought that the query would automatically pull in ALL posts from the child taxonomies, but this doesn’t seem to be the case.

for instance i have a child taxonomy called Branding. Under it I have lets say Nike and Adidas. When I am on the archive for Branding it doesn’t consistently pull in the posts from the Nike and Adidas children.

i’ve just tried doing your post in reverse.. add the get_term_children, but it’s late and my brain is fuzzy.

as always, thanks for the great info!

Author’s gravatar

get_term_children is giving me terms that don’t even exist in my DB. that has to be a sign i need to quit

Author’s gravatar author

Wow! Really. I’ve never come across that problem. I honestly have no idea why it would pull non existent terms up.

The child thing annoys me. I was working on a site recently & it was showing all child posts from the parent taxonomy, but if I tried on my local testing server it would only pull parent posts?!

Author’s gravatar

i think i got it! well i had to delete all the terms and posts from the DB. some wires must have just gotten crossed somewhere.

Author’s gravatar author

Very strange. Glad you seem to have sorted something out though, love to know what the cause was though.

On a side note Internet Explorer is giving me grief again. Managed to fix it, but it just didn’t want to read HTML5 elements properly event with modernizer or a Shiv loaded. I wish people would just upgrade their version of IE so we could build for the latest version and be done with it.

Author’s gravatar

i think i had posts in a term that somehow didn’t exist? very strange.

and man do i feel your pain about IE. i want to build in giant pop-ups to ever site and have it say “freaking upgrade to a REAL browser already”

Author’s gravatar author

Okay… Very odd indeed.

Yep, would love to do something like that. I mean you can use things like Explorer Destroyer to ‘encourage’ people to upgrade, but still I always thought upgrading was a common sense thing. 🙁

Author’s gravatar

strangely I tried your technique to show a list of courses (custom post type) for a client website that has course category (taxonomy) and the logic on the taxonomy.php was modified using query_posts to make it return only courses under the current course area and still getting courses under sub course areas displaying as well…

Please find code below:

global $wp_query;
$current_area = get_query_var( ‘term’ );
$term = get_term_by(‘slug’, $current_area, ‘courseareas’);
$sub_areas = get_term_children($term->term_id, ‘courseareas’);
$args = array_merge( $wp_query->query, array(
‘tax_query’ => array(
‘taxonomy’ => ‘courseareas’,
‘field’ => ‘slug’,
‘terms’ => $current_area,
‘taxonomy’ => ‘sotskurs_courseareas’,
‘field’ => ‘slug’,
‘terms’ => $sub_areas,
‘operator’ => ‘NOT IN’

Author’s gravatar author


This is going to sound awful, but did you have a question or were you just sharing your code?

Author’s gravatar

Sorry, I tried the code in the above article and it still did not give me the expected results, the posts shown still belong to the sub categories of the current taxonomy term, so my question is how do I achieve this: get only posts of the current taxonomy term to display?

Author’s gravatar author

The only thing I can think of is that merging the original query onto the new query is overriding it somehow.

Try the query without merging the original onto it and see if that works.

Author’s gravatar

I finally solved it, a mistake on my part:

the second tax_query array should have ‘id’ instead of ‘slug’…
my bad, anyway thanks guys…
A fresh pair of eyes always does the trick…

Author’s gravatar author

Oh man… I should have spotted that, sorry. 🙁

I blame not enough coffee, lol. Glad you managed to fix it though.

Author’s gravatar

Looks nice, thanks. However will not work for posts assigned to both parent and child taxonomies. Any idea how to fix this?

Author’s gravatar author

Hi Cata,

Unfortunately, as far as I can tell, that can’t be fixed. The only way I can think of is not have a post listed under both child & parent taxonomies.

It may be possible if you can have nested tax queries, since you could have the parent, but not children query, with an additional query that says get parents but not those parents that are also children. I don’t think that is possible at the minute though. Sorry.

Older Comments
Newer Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

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

I'll keep your WordPress site up-to-date and working to its best.

Find out more