Skip to content

Instantly share code, notes, and snippets.

@matgargano
Created April 11, 2017 12:20
Show Gist options
  • Save matgargano/aba9b60c8b24f9c7889f3fd143bd607d to your computer and use it in GitHub Desktop.
Save matgargano/aba9b60c8b24f9c7889f3fd143bd607d to your computer and use it in GitHub Desktop.
pre_get_posts vs request
http://wordpress.stackexchange.com/questions/139834/obliterate-the-main-query-and-replace-it
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 the is_* 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 to WP_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).
add_filter( 'request', function( array $query_vars ) {
// triggered also in admin pages
if ( is_admin() )
return $query_vars;
// you should check also for page slug, because when pretty permalink are active
// WordPress use 'pagename' query vars, not 'page_id'
$id = isset($query_vars['page_id']) && (int) $query_vars['page_id'] === 84;
// remember to replace "slug" with real page slug
$name = isset($query_vars['pagename']) && $query_vars['pagename'] === 'slug';
if ( ( $id || $name) && ! isset($query_vars['error']) ) {
$query_vars = array('category_name' => 'special-announcement');
}
return $query_vars;
});
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.
shareimprove this answer
edited Dec 19 '15 at 14:42
answered Apr 1 '14 at 6:20
gmazzap♦
31.4k24484
Works great! I am on (and want to stay on) front-page.php for this task, and it looks as though the front page has zero query_vars. So I added empty($wp->query_vars) to the if statement. if ( $id || $name || empty($wp->query_vars) ) { ... And I did end up using template_include to force WordPress to stay on (or, rather, choose) front-page.php. – Don Apr 1 '14 at 13:28
A word to the wise for anyone who finds this question/answer useful: the answer above uses php 5.3.0+ Anonymous Functions and as of this writing, WordPress only requires php 5.2.4 so alter the code as needed. Using the answer (anon function) and the question (pure callback) as examples, you should be fine. – Don Apr 1 '14 at 13:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment