There is a long-standing WordPress core bug (#16373) in which, if custom query variables are registered and present in the query string, the query will not set is_front_page()
true, even if 'page' == get_option( 'show_on_front' )
. Full details are in the trac ticket, but the end result is that the front page returns an invalid page instead of get_option( 'page_on_front' )
.
I have a certain use case in which I need to pass custom query variables to the query string on the front page (using a form to pass registered query variables, which are in turn used to filter Theme options – a front-end Theme options demo). The above-mentioned trac ticket was closed as invalid, so I need a work-around.
I can force the front page template easily enough, like so:
function themeslug_force_front_page_template( $template ) {
if ( '' != get_query_var( 'foobar' ) ) { // Registered custom query var
return get_front_page_template();
}
return $template;
}
add_filter( 'template_include', 'themeslug_force_front_page_template' );
However, the underlying query conditionals are not impacted. So any code dependent on is_front_page()
being true
(such as, say, a slider that only displays on the site front page) will still not render properly.
I have attempted to modify $query
at pre_get_posts
, but this does not appear to be working:
function themeslug_force_static_front_page( $query ) {
if ( $query->is_main_query() ) {
if ( 'page' == get_option( 'show_on_front' ) ) {
if ( '' != get_query_var( 'foobar' ) ) { // Registered custom query var
$query->set( 'page_id', get_option( 'page_on_front' ) );
$query->set( 'is_home', false );
$query->set( 'is_page', true );
$query->set( 'is_front_page', true );
}
}
}
}
add_action( 'pre_get_posts', 'themeslug_force_static_front_page' );
The query conditionals are not modified. Am I attempting incorrectly inside my callback? Is there a different/better way to force the query conditionals, in particular is_front_page()
?
Edit
Note that setting the page_id
does work in the pre_get_posts
callback:
$query->set( 'page_id', get_option( 'page_on_front' ) );
If I omit the template_include
filter, the displayed page is, indeed, the page assigned to the front page; however, get_page_template()
is used, rather than get_front_page_template()
. So, setting page_id
at pre_get_posts
does cause is_page()
to be true. But the aforementioned bug prevents is_front_page()
from being set to true
.
Edit 2
Per @toscho’s request, here’s some query var code, for context.
Register query variables:
/**
* Add options-related query variables
*/
function themslug_add_theme_demo_query_vars( $qvars ) {
$qvars[] = 'demo_foo';
$qvars[] = 'demo_bar';
$qvars[] = 'demo_baz';
return $qvars;
}
add_filter( 'query_vars', 'themeslug_add_theme_demo_query_vars' );
(Where foo
, bar
, and baz
are Theme options – background, various colors, etc.)
How they are used is simply to add a filter to a Theme option – that part is out of the scope of the question, so I’ll omit it here.
They are output on the front end via custom Widget. The Widget output is just a form. Here’s an example of one of the form fields:
<h3>Foo</h3>
<input name="demo_foo" id="demo_foo" class="pickcolor" type="text" value="<?php echo $foo_setting; ?>" data-default-color="<?php echo $foo_setting; ?>" />
Generated query string on-submit:
www.example.com/?foo=some_value