In the earlier parts of this series, you've learned how WP_Query
is structured and what its properties and methods are. The next stage is to understand the various arguments you can use with it and how best to do so.
WP_Query
has a large number of possible arguments, which makes it extremely flexible. As you can use it to query just about anything held in your wp_posts
table, it has arguments for every permutation of query you might want to run on your content.
In this tutorial I'll look at two types of argument for categories and tags:
The arguments for these two taxonomies are similar but do have some differences you need to know about if you're going to use them effectively.
A Recap on How Arguments Work in WP_Query
Before we start, let's have a quick recap on how arguments work in WP_Query
. When you code WP_Query
in your themes or plugins, you need to include four main elements:
- the arguments for the query, using parameters which will be covered in this tutorial
- the query itself
- the loop
- finishing off: resetting post data
In practice this will look something like the following:
<?php $args = array( // Arguments for your query. ); // Custom query. $query = new WP_Query( $args ); // Check that we have query results. if ( $query->have_posts() ) { // Start looping over the query results. while ( $query->have_posts() ) { $query->the_post(); // Contents of the queried post results go here. } } // Restore original post data. wp_reset_postdata(); ?>
The arguments are what tells WordPress what data to fetch from the database and it's those that I'll cover here. So all we're focusing on here is the first part of the code:
$args = array( // Arguments for your query. );
As you can see, the arguments are contained in an array. You'll learn how to code them as you work through this tutorial.
Coding Your Arguments
There is a specific way to code the arguments in the array, which is as follows:
$args = array( 'parameter1' => 'value', 'parameter2' => 'value', 'parameter3' => 'value' );
You must enclose the parameters and their values in single quotation marks, use => between them, and separate them with a comma. If you get this wrong, WordPress may not add all of your arguments to the query or you may get a white screen.
Category Parameters
Let's start with category parameters. The options you have here are as follows:
cat
(int): use category id.category_name
(string): use category slug (NOT name).category__and
(array): use category id.category__in
(array): use category id.category__not_in
(array): use category id.
Note that for none of these do you use the name of your category. Even the category_name
parameter takes the slug as its value, not its name. I tend to use this one rather than the ID as when I come back to my code at a later date, slugs are easier to identify than IDs. However if you think your site users might change the slug for one or more categories, I recommend using the ID to avoid any problems.
Let's take a look at how you use each of these.
The cat
Parameter
The cat
parameter is straightforward: just use a single category ID or a string of category IDs.
Querying for one category looks like this:
$args = array( 'cat' => '12' );
Querying for multiple categories looks like this:
$args = array( 'cat' => '12, 13, 14' );
The above will tell WordPress to fetch posts that are in any of the categories listed. If you want to find posts in every one of an array of categories, you use the category_and
parameter, of which more shortly.
You can also use the cat
parameter to find posts that are in one category but not another, by using a minus sign before the category ID as follows:
$args = array( 'cat' => '12, -13' );
The above would query posts in category 12 but not in category 13.
The category_name
Parameter
The category_name
parameter uses the category slug, not the name (confusing, I know!). Again you can use it with a single category or with a string of categories to find posts that are in any of the categories.
To query posts in a single category you add:
$args = array( 'category_name' => 'my-slug' );
And to find posts in one or more of a number of categories, use this:
$args = array( 'category_name' => 'my-slug, your-slug, another-slug' );
As with the cat
parameter, this won't find posts that are in all of the categories, but it will find posts in any of the categories.
The category__and
Parameter
If you want to find posts that are in all of an array of categories, this is the parameter you use. It takes the category IDs for its value. So to find posts in all of three categories, you would use:
$args = array( 'category__and' => array( '12', '13', '14' ) );
Note that this uses an array not a string, so you code it differently. The parameter has two underscores in its name: use just one and it won't work.
The category__in
Parameter
The next parameter looks for posts in one or more of an array of categories. It actually works in the same way as the cat
parameter, and also takes the category ID as its value.
So to query posts in one or more of an array of categories, you would use:
$args = array( 'category__in' => array( '12', '13', '14' ) );
The above would fetch posts from one or more of these categories.
The category__not_in
Parameter
The category__not_in
parameter does as you would expect: it queries posts which are not in a category or an array of categories.
To exclude posts from one category, you would use the following:
$args = array( 'category__not_in' => '12' );
And to exclude posts from an array of categories:
$args = array( 'category__not_in' => array( '12', '13', '14' ) );
This would exclude posts from any of these categories.
Tag Parameters
Tags have slightly different parameters from categories: you can't work out what they might be based on your knowledge of category parameters, I'm afraid!
The tag parameters are:
tag
(string): use tag slug.tag_id
(int): use tag id.tag__and
(array): use tag ids.tag__in
(array): use tag ids.tag__not_in
(array): use tag ids.tag_slug__and
(array): use tag slugs.tag_slug__in
(array): use tag slugs.
Let's look at each of these.
The tag
Parameter
The tag
parameter takes the tag slug for its value and can be used to find posts with one tag or with any of a string of tags.
So to find posts with one tag you use:
$args = array( 'tag' => 'my-tag' );
And to find posts with tags from an array of tags:
$args = array( 'tag' => 'my-tag, your-tag, another-tag' );
Note that the above queries posts with any of the tags in the array, not all of them.
The tag_id
Parameter
The tag_id
parameter works in a similar way to the cat parameter: it takes the tag ID and can be used with a single tag or multiple tags.
To find posts with a single tag you use this:
$args = array( 'tag_id' => '21' );
To find posts with one or more tags from a string of tag IDs:
$args = array( 'tag_id' => '21, 22, 23' );
You can also use tag_id
to exclude tags, either when using it for single tags or multiple tags.
So to query posts except those with a given tag, you'd use:
$args = array( 'tag_id' => '-21' );
While to find posts with one of two tags but without another tag, you'd use this:
$args = array( 'tag_id' => '21, -22, 23' );
So the above will query posts with either or both of tags 21 or 23 but not tag 22.
The tag__in
Parameter
This parameter lets you find posts with one or more of an array of tags. It works in the same way as tag when used with an array:
$args = array( 'tag_in' => array( '21', '22', '23' ) );
This will query posts with any or all of the tags listed. If you want to find posts with all of the tags, you use tag__and
, which I'll cover in a moment.
The tag__not_in
Parameter
The tag__not_in
parameter lets you query posts which don't have a given tag or array of tags.
Use it like this to exclude one tag:
$args = array( 'tag__not_in' => array( '21' ) );
Note that you still need to use an array even though you're only using one tag. For more tags, use:
$args = array( 'tag__not_in' => array( '21', '22', '23' ) );
This will query posts that don't have any of the above tags.
The tag_slug__and
and tag_slug__in
Parameters
These two parameters behave in exactly the same way as the tag__and
and tag__in
parameters, except that you use that tag slug in your arrays instead of the tag ID.
So for example to find posts which have both of a pair of tags, you use tag__slug_in
:
$args = array( 'tag_slug__in' => array( 'my-tag', 'your-tag', 'another-tag' ) );
This finds posts with any of these tags. You could also use the tag parameter with a string of tag slugs to achieve the same result.
To include posts with all of a set of tags, use tag_slug__and
:
$args = array( 'tag_slug__and' => array( 'my-tag', 'your-tag', 'another-tag' ) );
Instead of querying posts with any of the tags, this only queries posts that have all of the tags.
Advanced Use of Categories and Tags with WP_Query
Let’s take a look at some advanced uses of category and tag arguments with WP_Query
, based on questions raised in the comments to this article.
List Subcategories of a Category
To list the subcategories of a given category (with a link to the subcategory archives for each), you wouldn’t use WP_Query
. Instead you’d use wp_list_categories()
, which outputs a list of categories with links to their archives. To output the subcategories of a specific category, use the ‘child_of'
argument.
Here’s the code:
<?php $args = array ( ‘child_of’ => 5 ); wp_list_categories( $args ); ?>
Substitute the 5
in the code above for the ID of the category whose subcategories you want to list.
Display The First Post from a Category in One Element Then More Posts in Another Element
This is a useful technique if you want to highlight the most recent post from a category, maybe including the excerpt and featured image for that post, and then show a list of the next few posts from the category.
You do this by using the 'posts_per_page'
and 'offset'
arguments.
The simplest way to do this is to write two separate queries. The first uses 'posts_per_page' => 1
to just fetch the first post. The second query uses'offset' => 1
to fetch posts after the first post, and also uses 'posts_per_page'
to define how many posts to output.
Here’s the code:
<?php // first query - one post $args = array( 'cat' => 2, 'posts_per_page' => 1 ); // Custom query. $query = new WP_Query( $args ); // Check that we have query results. if ( $query->have_posts() ) { // Start looping over the query results. while ( $query->have_posts() ) { $query->the_post(); // Contents of the queried post results go here. } } // Restore original post data. wp_reset_postdata(); // second query - three posts $args = array( 'cat' => 2, 'posts_per_page' => 3, 'offset' => 1 ); // Custom query. $query = new WP_Query( $args ); // Check that we have query results. if ( $query->have_posts() ) { // Start looping over the query results. while ( $query->have_posts() ) { $query->the_post(); // Contents of the queried post results go here. } } // Rewind the query. rewind_posts(); ?>
An alternative method, which involves fewer calls to the database, is to write one query and then loop back through that query a second time, rewinding the query and using a variable to make sure the post output by the first loop isn’t repeated.
You can find more about using one query for multiple loops in our tutorial on the subject.
Display Posts From Multiple Categories
If you want to display posts that are in a given category and also in one or more of your other categories, you use the cat
and category__in
arguments. For each of these you use the category ID.
Imagine you want your posts to be category 1 and also in one or more of categories 2, 3 and 5.
Here are the arguments you would use for this:
$args = array( 'cat' => '1', 'category__in' => array ( '2', '3', '5' ) );
Summary
Querying your posts by category and/or tag is something there's a good chance you'll have occasion to do with WP_Query
. By using the arguments above, and combining them where necessary, you can create powerful arguments to extract exactly the data you need from the database.
If you want to learn more about WP_Query, check out some of my other posts in the Mastering WP_Query series.
-
WordPressMastering WP_Query: Using the Loop
-
WordPressMastering WP_Query: Actions and Filters
-
WordPressWP_Query Arguments: Status, Order and Pagination
-
WordPressMastering WP_Query: 10 Useful Examples
No comments:
Post a Comment