Modifying the current query with pre_get_posts
Pre_get_posts is a hook
“pre_get_posts” is a WordPress hook that allows you to modify the current query. Just a quick reminder: when you’re visiting any page of a WordPress install, the system creates a query that depends on the url you’re visiting. This is basically what the template hierarchy does. The “pre_get_posts” hook is called after the query variable object is created, but before the actual query is run. That’s why this allows you to modify the query before results are printed on your screen. That’s pretty useful to modify for example an archive page, the results of a search, or a custom post type page. Here’s an info about “pre_get_posts” in the codex:
The pre_get_posts action gives developers access to the $query object by reference (any changes you make to $query are made directly to the original object – no return value is necessary).
That’s important to note that the $query object passed to your function is passed by reference. That’s to say that you don’t need to declare globals variables and you don’t need to return a value. Any changes you make to the object from inside your function are made to the original immediately.
Targeting the main query
Most part of the time when you access a page on a WordPress website, you’re loading more than queries, thats why it’s important to be aware of the query you want to modify when using “pre_get_posts”. A great method to know it, is to use the
is_main_query() update: $query->is_main_query(). Here is what the codex says about is_main_query() function:
This function enables someone to hook into `pre_get_posts` and modify *only* the main query. This is a boolean function, meaning it returns either TRUE or FALSE. NOTE: admin screens also have a main query and this function can be used to detect it there.
NOTE: Mark Jaquith explained me via Twitter that the is_main_query() function must not be used anymore as it’s useless, and the conditional statement should be done through $query->is_main_query();
— Mark Jaquith (@markjaquith) 27 janvier 2013
Here is a small example using is_main_query and pre_get_posts:
This code is simply taking off posts from category ID 5 from the main query.
Going a bit further
But you can go further, you can for example query only posts from a specific type and with a custom meta field key equal to a determined value. In the code below, we are targeting only custom post type called “portfolio” where meta key “project_type” is set to “design”, that’s a typical query that can be used on a portfolio page:
That’s not all, you can for example define a posts per page number:
You can also define a query that lists posts from a specific date:
And finally here is a sample to display posts older than the current date. This one is a bit more complex, because we need to use the “posts_where” filter:
As we saw, “pre_get_posts” is really powerful and can really helps you to customize the current query. This is also a good method to modify a query made from a plugin without modify the core plugin files (or the theme core files). So i really encourage you to have a deep leep to that hook and use it in your own developments!