I was reading Stephen Harris's excellent answer to this question regarding the use of WP_query(), query_posts() and pre_get_posts.

He says "pre_get_posts is a filter, for altering any query. It is most often used to alter only the 'main query'."

It is possible to use pre_get_posts to filter only a specific secondary query created with WP_Query? eg.

$my_secondary_loop = new WP_Query(...);
if( $my_secondary_loop->have_posts() ):
    while( $my_secondary_loop->have_posts() ): $my_secondary_loop->the_post();
       //The secondary loop

Any help much appreciated.


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


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 );
  • Thank you so much Milo. This is really very helpful. I always wondered if it was possible to set your own query var. – Ben Pearson May 18 '12 at 5:52
  • How can I use this trick for archive page? I don't want to rewrite the whole query again for archive page but want to use this technique. – Rohit Pande Jul 2 '13 at 9:17

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.

  • What about Milo's technique? I've never seen it before... – brasofilo May 17 '12 at 21:56
  • His technique will work. Ive never used it for pre_get_posts but have for other filters like posts_where – Chris_O May 17 '12 at 22:02
  • 1
    Cool, something new learned today! – brasofilo May 17 '12 at 22:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.