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.