In some cases you might need to modify the global post query WordPress is performing on any page you are visiting – both admin and frontend. In this guide we will look at which hook to use, and how to change the query arguments to your liking.
Which hook to use
First you need to know which hook to add your code to. We need a hook that happens right after WordPress has set up all arguments, but before the actual query is run. For this we use the action pre_get_posts
.
In this hook you get one parameter; which is a WP_Query
object that WordPress will later run the query with. You make changes to the object – but you don’t need to return it as WordPress will run the query with the modified object.
add_action('pre_get_posts', function($query) { // Add your code here });
Modifying the query most likely requires you to use some conditional tags to specify those cases you want to change it. For example you might want to target the query only in search results, or category views.
Conditional tags
WordPress has a bunch of conditional tags that you can use to specify which cases you want to add your code. A conditional tag is simply a function that returns true or false depending on which state WordPress is in. Examples of common conditional tags are is_admin()
for checking if we currently are in admin or frontend, is_singular()
if we are at a single post or page in frontend, and is_search()
if we are at the search results page.
Note about conditional tags in pre_get_posts
Conditional tags are great and all, but there are some things to keep in mind when using these inside pre_get_posts
.
Firstly, you need to get familiar with the tag is_main_query()
. The action pre_get_posts
is actually run multiple times for each page load. For example pre_get_posts
is run when generating each menu (including those in widgets). In order to modify the actual global query, e.g. posts for a category archive or search results, you need to target the “main query” using is_main_query()
.
Secondly, you need to be aware of cases where you need to check the conditional tags onto the provided object instead of calling the function “independently”. Usually when you use conditional tags, you would write it like this:
if (is_main_query()) { // Do stuff }
However when using pre_get_posts
, there are some conditional tags you need to apply onto the object. For example:
add_action('pre_get_posts', function($query) { if ($query->is_main_query()) { // Add your code here } });
This is an example of checking if we are not in admin, and if we are at the main post query:
add_action('pre_get_posts', function($query) { if (!is_admin() && $query->is_main_query()) { // Add your code here } });
Changing or adding arguments
Since we are working with a WP_Query
object, you can refer to WP_Query’s documentation for how to build your arguments to customize the posts query. Keep in mind that arguments are already populated. In that case you need to append or change existing values. Or remove the ones you want to remove.
You use the set()
function onto the WP_Query
object to set arguments. The method accepts two arguments, the argument key and secondly the value. For example, setting the posts_per_page
argument would be done like this:
add_action('pre_get_posts', function($query) { if (!is_admin() && $query->is_main_query()) { $query->set('posts_per_page', 20); } });
In cases where you want to append or change a pre-existing argument, you would usually do this by first saving the existing argument in a variable. You can use the method get()
for this. Then you modify the variable, by appending or merging arrays or whatnot. And finally you use set()
to replace the modified variable back onto the query object. I recommend using var_dump()
on the object to see what it contains, and this is also a nice way to check if your conditional tags are correct.
Here is a quick example of using get()
(simply checking if it is empty), and if so, add your own arguments with set()
.
add_action('pre_get_posts', function($query) { if (!is_admin() && $query->is_main_query()) { if (!$query->get('meta_query')) { $query->set('meta_query', [/* your arguments here */]); } } });
Note about tax_query
WordPress has separate subclasses for handling the taxonomy (WP_Tax_Query
) part within WP_Query
. If you need to do more complex taxonomy query modifications, the pre_get_posts
action might be too early. Some values might be empty because they are populated later. In this case you might be better off using the action parse_tax_query
instead of pre_get_posts
. Read the documentation for this hook to see if this is for you.
Conclusion
The arguments you add or change depends entirely on what you want to do, but you should now have some insight in strategies to get ahold of the global query. If you need to get some insight into the WP_Query
object and how to use its arguments, my post about how to query posts might be of interest.