Using pre_get_posts with WP_Query

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’.”

Read More

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
    endwhile;
endif;
wp_reset_postdata();

Any help much appreciated.

Related posts

Leave a Reply

2 comments

  1. 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 );
    
  2. 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.