Magazine themes often use the WP_Query() function to display a specified number of posts, excerpts, titles etc, on the magazine-style home page. If, like many WordPress users, you assign posts to more than one category, here’s an elegant way of displaying the latest post which belongs to two (or more) specific categories. This method uses the in_category() Template Tag, an excellent function for building complex queries.
Our scenario
For the sake of this article, let’s imagine the following scenario:
You run a WordPress powered site for your local community. You have created categories for each district in your locality – let’s call them uptown, midtown and downtown – and you have created another set of categories for events – let’s say sport, culture and entertainment. And just for the sake of really getting into our scenario, let’s say these categories have these IDs:
- Uptown = 1
- Midtown = 2
- Downtown =3
- Sport =6
- Culture = 7
- Entertainment =8
And finally, let’s say that when you write a post about a new event you always assign it to one of the geographical categories and to one of the event categories.
So here’s the challenge: On the homepage of your site you want to display the latest event for each district eg latest sport event midtown, the latest entertainment event in the uptown district, and so on. Now let’s try to build the code to give us the latest downtown sports event, and in common with the majority of magazine-style themes we’ll use the WordPress function WP_Query to do it.
Your first thought may be to build the query like this:
have_posts()) : $recent->the_post();
?>
If you’re not familiar with the syntax of the WP_Query function, here is an explanation:
- cat=3,6 tells the query to look for posts filed in category IDs 3 and 6, ie “downtown” and “sports”.
- showposts=1 means that the query is limited to outputting 1 post.
- offset=0 means that the query should output the most recent post it finds which meets the other criteria.
Unfortunately, this query won’t give us what we want. Why? Because it will return the latest post in EITHER cat 3 or cat 6 and we need to find the latest post that is in BOTH categories.
For example, if our latest post in the downtown category (cat ID=3) is also categorised as an entertainment event, this post will be found first. As an aside, if a post assigned to cat 3 is ALWAYS also assigned to cat 6, then there is no need to read on because this code will give you exactly what you want – the latest post in cats 3 and 6.
Introducing in_category()
Luckily, WordPress has a way for us to deal with our problem: the in_category() Template Tag.
The in_category() Template Tag (or function) tests whether a post ID is in a specific category, and returns either TRUE or FALSE depending on whether the post is, or is not, in the category. Generally speaking it is used within an if…else statement, so we can think of it working like this: “if I’m in category X, do something, if I’m not, do something else”.
Armed with in_category() we can now tweak our original code so that the output of the WP_Query is passed through a if…else statement and in_category() until we find the latest post which is in BOTH categories “downtown” and “sport”.
Combining in_category() with WP_Query()
We will start with our original code because although, by itself, it might not give us the final output we want, we need to use it to find all posts which belong to our two categories. Here’s the start of our revised code:
have_posts()) : $recent->the_post();
if (in_category(3) && in_category(6)) { ?>
Firstly, you will notice that the &showposts=1 and &offset=0 parameters have been removed from the WP_Query. We don’t need an offset, so we can remove this parameter. We don’t want &showposts=1 because we need the WP_Query to find all posts so that we can then test the output with in_category() until we find the first post which meets our criteria.
Secondly, look at the way the in_category() function is used. For our purposes we need to use it in an if…else statement and as we can only test one category at a time with in_category(), we include it twice, once for each category that we are searching for. We then use the && operator to signify that the post must be in category 3 AND category 6. Exactly what we need!
Thirdly, we add what we will display when the if (in_category()… code is TRUE. In this case, the Post Title followed by the Post Content.
Stopping WP_Query once we’ve found our post
However, you may have spotted that we can’t leave the code like that. As it stands the code will give us ALL posts which are in both categories – and we only want one. Once again, there’s a straightforward solution, and that is to use a variable to stop the WP_Query loop once we’ve found our first post in both categories.
Final code:
have_posts()) : $recent->the_post();
static $counter = 0;
if ($counter == "1") { break; }
else {
if (in_category(3) && in_category(6)) { ?>
Let’s run through the additions to our code.
Adding a counter variable:
static $counter = 0;
This sets a starting point for our counter variable. static prevents the $counter variable from resetting to “0” each time the while… loop is run.
Setting a break point:
if ($counter == "1") { break; }
This if…else statement checks to see if $counter equals 1 and if TRUE, breaks the while… statement and stops the WP_Query loop. This means that we have found our post.
Increment the counter variable:
$counter++;
This increments $counter in the event that the in_category() if…else code returns TRUE. In other words, if TRUE, we have found our post and the $counter variable is incremented by 1. If the post does not meet our in_category() criteria, the in_category() if…else code returns FALSE, this section of code is skipped and $counter is not incremented.
Taking it further
Now that we have a basic code, there are many ways we can modify it to give different results. Here are some examples:
Finding more than one post in 2 categories:
if ($counter == "2") { break; }
Simply change the number to 2 to find two posts, 3 for three posts and so on.
Finding a post which is in 3 categories:
Add another call to in_category() like this:
if (in_category(3) && in_category(6) && in_category(7)) {
And finally…
That’s it for this instalment. Hopefully you can see how useful the in_category() function is, and how easy it is to use it to build complex loops and queries.
Related articles:
Complex loop with in_category(): Part 2 Coming soon!
yaya works, use || for or
Cheers
Shovan
I want to use Or operator instead of And, like this :
if (in_category(3) || in_category(6) && in_category(7)) {
But it is not working Help :S