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 [...]

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.

array(
        'posts_per_page' => '5',
	'tax_query' => array(
		array(
			'taxonomy' => 'music',
			'field' => 'slug',
			'terms' => 'pop'
		)
	)
);

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:

array(
        'posts_per_page' => '5',
	'tax_query' => array(
		array(
			'taxonomy' => 'music',
			'field' => 'slug',
			'terms' => 'pop'
		),
		array(
			'taxonomy' => 'music',
			'field' => 'slug',
			'terms' => array('jpop', 'dance-pop'),
			'operator' => 'NOT IN'
		)
	)
);

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:

$tax = 'music';
$oterm = 'pop';
$term = get_term_by('slug', $oterm, $tax);
$termChildren = get_term_children($term->term_id, $tax);
$wp_query = new WP_Query();
$wp_query->query(
	array(
		'posts_per_page' => '5',
		'tax_query' => array(
			array(
				'taxonomy' => $tax,
				'field' => 'slug',
				'terms' => $oterm
			),
			array(
				'taxonomy' => $tax,
				'field' => 'id',
				'terms' => $termChildren,
				'operator' => 'NOT IN'
			)
		)
	)
);

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.