Wordpress - Should I use Pre Get Posts or WP_Query
pre_get_posts
will run the same query, so both will take same time. But, If you utilize pre_get_posts
action you will save one or more SQL queries. Right now, WordPress is running default query and then you run your query with this function which replace the results of the default query (resulting, default query is of no use). Below is how you can move your $args
to
function custom_pre_get_posts($query, $posttype='dealers', $poststatus='publish', $paidvalue='1', $taxtype='any_default_value', $geo='any_default_value', $brands='any_default_value') {
// filter your request here.
if($query->is_category) {
$args = array(
'post_type' => $posttype,
'post_status' => array($poststatus),
'orderby' => 'rand',
'posts_per_page' => 30,
'meta_query' => array(
array(
'key' => 'wpcf-paid',
'value' => array($paidvalue),
'compare' => 'IN',
)
),
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => $taxtype,
'field' => 'slug',
'terms' => $geo
),
array(
'taxonomy' => 'brands',
'field' => 'slug',
'terms' => $brands
)
)
);
$query->query_vars = $args;
}
}
add_action('pre_get_posts', 'custom_pre_get_posts');
Late answer as the most upvoted answer will break your query and simply isn't true in some major points.
The main WP_Query and it's filters
First, WordPress internally uses query_posts()
(a thin wrapper around WP_Query
that shouldn't be used in themes or plugins) to do a WP_Query
. This WP_Query
is acting as the main loop/query. This query will run through a lot of filters and actions until the actual SQL query string is built. One of those is pre_get_posts
. Others are posts_clauses
, posts_where
, etc. that also allow you to intercept the query string building process.
An in depth look at what happens inside core
WordPress runs the
wp()
function (inwp-includes/functions.php
), which calls$wp->main()
($wp
is an object of class WP, which is defined inwp-includes/class-wp.php
). This tells WordPress to:
- Parse the URL into a query specification using
WP->parse_request()
-- more on that below.- Set all the is_ variables that are used by Conditional Tags using
$wp_query->parse_query()
($wp_query
is an object ofclass WP_Query
, which is defined inwp-includes/query.php
). Note that in spite of this function's name, in this caseWP_Query->parse_query
doesn't actually do any parsing for us, since that is done before-hand byWP->parse_request()
.- Convert the query specification into a MySQL database query, and run the database query to get the list of posts, in function WP_Query->get_posts(). Save the posts in the $wp_query object to be used in the WordPress Loop.
Source Codex
Conclusion
If you really want to modify the main query, then you can use a wide variety of filters. Simply use $query->set( 'some_key', 'some_value' );
to change data there or use $query->get( 'some_key' );
to retrieve data to do conditional checks. This will save you from doing a second query, as you're altering the SQL query only.
If you have to do an additional query, then go with a WP_Query
object. This will add another query to the DB.
Example
As answers always work better with an example, you here got one really nice one (props to Brad Touesnard), that simply extends the core object and therefore is pretty reusable (make a plugin out of it):
class My_Book_Query extends WP_Query
{
function __construct( $args = array() )
{
// Forced/default args
$args = array_merge( $args, array(
'posts_per_page' => -1
) );
add_filter( 'posts_fields', array( $this, 'posts_fields' ) );
parent::__construct( $args );
}
public function posts_fields( $sql )
{
return "{$sql}, {$GLOBALS['wpdb']->terms}.name AS 'book_category'";
}
}
You can then run your second/additional query like you can see in the following example. Don't forget to reset your query afterwards.
$book_query = new My_Book_Query();
if ( $book_query->have_posts() )
{
while ( $book_query->have_posts() )
{
$book_query->the_post();
# ...do stuff...
} // endwhile;
wp_reset_postdata();
} // endif;
Please check out the answers at When to use WP_query(), query_posts() and pre_get_posts.
It is a great ressource if you have any doubts in mind.