pre_get_posts
Lets you change a query's settings before it runs, such as posts per page, post types or order, without writing a new query.
When it fires
pre_get_posts fires inside WP_Query after the query variables are set but before the database is queried. It runs for every WP_Query: the main query for the page, secondary loops, widgets, and queries in the admin area.
You get the query object itself, so anything you change with $query->set() takes effect straight away.
Parameters
$queryWP_Query |
The WP_Query instance (passed by reference). |
|---|
Example: Show only blog posts in search results
add_action( 'pre_get_posts', function ( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
if ( $query->is_search() && ! $query->get( 'post_type' ) ) {
$query->set( 'post_type', 'post' );
}
} );
Good to know
- Check ! is_admin() and $query->is_main_query() first, or you'll also change menus, widgets and admin lists.
- Use the methods on the object you're given, such as $query->is_search(), rather than the global is_search(), which checks the main query.
- Changing posts_per_page here, instead of running a new query in the template, keeps pagination working.