replace the WP_Query class in the main query

Ok so it’s doable but could potentially mess up a few things down the line so it’s at your own risk, but then so is everything 🙂

I’ve been trying to do this in order to use a GeoQuery extension class to order events by distance from some location.

The simplest way to do it is this:

add_action( 'after_setup_theme', 'alt_query_class', 1, 0 );
function alt_query_class() {
    if ( ! is_admin() && $GLOBALS[ 'wp_query' ] instanceof WP_Query ) {
         $GLOBALS[ 'wp_the_query' ] = new WP_Query_Extended();
         $GLOBALS[ 'wp_query' ] = $GLOBALS[ 'wp_the_query' ];
    }
}

In your extended query class you would just do what you have above but if your added functionality is something that’s not desirable for every query run then you’d have to do some setup/teardown logic because we’re replacing every instance of WP_Query with the new one.

In my case I used the pre_get_posts filter with a late priority to check whether I needed to add my functionality or not after all the query manipulations were done.

class WP_Query_Extended extends WP_Query {

    function query( $args = array() ) {

        // setup functions
        add_filter( 'pre_get_posts', array( $this, 'check_setup_needed' ), 1000 );

        // run the query
        parent::query( $args );

        // tear down functions
        $this->teardown();
    }

    function check_setup_needed( $query ) {

        // test setup criteria
        if ( $query->get( 'somevar' ) ) {
            $this->setup();
        }

        return $query;
    }

    function setup() {
        // add any filters etc... here
    }

    function teardown() {
        // remove filters etc... here
        remove_filter( 'pre_get_posts', array( $this, 'check_setup_needed' ) );
    }

}

UPDATE:

There’s a big gotcha with this – if someone uses query_posts() eg. could be in a plugin or if you’re writing a plugin then maybe a theme then that function resets the $wp_query global back to a WP_Query instance and there’s no filter with which to change it again afterwards.

If you actually need to do a query_posts() (you shouldn’t!) you can do $wp_query->query( $args ) instead.

Leave a Comment