Wordpress - Using pre_get_posts with WP_Query

The simplest way is to add the action right before the query and remove it immediately after.

add_action('pre_get_posts', 'some_function_in_functionsphp');
$my_secondary_loop = new WP_Query(...);
remove_action('pre_get_posts', 'some_function_in_functionsphp');

if( $my_secondary_loop->have_posts() ):
    while( $my_secondary_loop->have_posts() ): $my_secondary_loop->the_post();
       //The secondary loop
    endwhile;
endif;
wp_reset_postdata();

EDIT

Another technique you can use is to set your own query var and check for that in a hook:

// tell WordPress about our new query var
function wpse52480_query_vars( $query_vars ){
    $query_vars[] = 'my_special_query';
    return $query_vars;
}
add_filter( 'query_vars', 'wpse52480_query_vars' );

// check if our query var is set in any query
function wpse52480_pre_get_posts( $query ){
    if( isset( $query->query_vars['my_special_query'] ) )
        // do special stuff

    return $query;
}
add_action( 'pre_get_posts', 'wpse52480_pre_get_posts' );

and in the template:

// set the query var (along with whatever others) to trigger the filter
$args = array(
    'my_special_query' => true
);
$my_secondary_loop = new WP_Query( $args );

pre_get_posts fires for every post query:

  • get_posts()
  • new WP_Query()
  • That random recent posts widget your client installed without you knowing.
  • Everything

-- @nacin

With that being said unless you exclude your filter use the conditional: is_main_query() then your filter will fire on your new WP_Query.

If you only want to target your specific new WP_Query then there is no way to do that.