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.

2 Answers 2


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. May 18, 2012 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. Jul 2, 2013 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, 2012 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, 2012 at 22:02
  • 1
    Cool, something new learned today!
    – brasofilo
    May 17, 2012 at 22:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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