There are lots of good resources on how to alter the main query, or add secondary loops…
But I actually want to completely replace the main query with a different query altogether.
I am hijacking one of my pages to serve, essentially, as a category page. (Note I am changing from “page” to “post” in my effort to do this.) But when I alter the main query by doing this:
function front_page_announcements( $query ) {
if ( $query->query_vars['page_id'] == 84 && $query->is_main_query() && !$query->is_admin ) {
$query->set("category_name", "special-announcement");
$query->set("page_id", NULL);
}
}
add_action( 'pre_get_posts', 'front_page_announcements' );
I end up getting every page (not post) in the database. What I actually want is every post (not page) with a category id of 3
, or special-announcement
in my case.
I don’t want to make unnecessary calls to the database, so it seems like the pre_get_posts
action hook is what I’ll want, but I can’t figure it out. Even just setting $query = new WP_Query('cat=3')
doesn’t seem to work.
When
'pre_get_posts'
is fired, there are a lot of things that WordPress has already done like setup all the query variables (also the query you don’t send) and setup all the conditional properties (all theis_*
properties). So, if you want completely replace the query you should reset all that things and set your own.In fact, even if your code works, WordPress will use
page.php
as template.However there’s a simpler approach: act before WordPress do all the things.
A good place is the
'request'
filter hook, at that time WordPress has created the query vars from url and is going to pass that vars toWP_Query
, and you can intercept and change query arguments before are sent.That action is fired by
WP
class, and pass the query vars to be set (see code).Replace
'slug'
with the real slug of your page, then let WordPress do its work.Note that I’ve not check for main query, because
'request'
is triggered only for main query.If you want to use a specific template, you should use a filter on
template_include
otherwise'category.php'
(or the right template according to template hierarchy) will be used.