问题描述
有一个long-standing WordPress核心错误(#16373),其中如果自定义查询变量被注册并存在于查询字符串中,查询将不会设置is_front_page()为真,即使'page' == get_option( 'show_on_front' )。完整的详细信息在trac门票中,但最终结果是首页返回无效页面而不是get_option( 'page_on_front' )。
我有一些用例,我需要将自定义查询变量传递到首页上的查询字符串(使用表单传递注册的查询变量,这些变量反过来用于过滤主题选项 – front-end主题选项演示)。 above-mentioned trac车票被关闭为无效,所以我需要一个work-around。
我可以轻松地强制前头模板,就像这样:
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' );
但是,基础查询条件不受影响。因此,任何依赖于is_front_page()的代码都是true(例如,仅在站点首页上显示的滑块)仍然无法正常呈现。
我试图在pre_get_posts修改$query,但这似乎没有工作:
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' );
查询条件不被修改。我是否在我的回调中错误地尝试?是否有不同/更好的方式强制查询条件,特别是is_front_page()?
Edit
请注意,设置page_id可以在pre_get_posts回调中工作:
$query->set( 'page_id', get_option( 'page_on_front' ) );
如果省略template_include过滤器,则显示的页面确实是分配给首页的页面;然而,使用get_page_template(),而不是get_front_page_template()。因此,在pre_get_posts中设置page_id确实会导致is_page()为真。但是上述的bug阻止了is_front_page()被设置为true。
编辑2
Per @ toscho的请求,这里有一些查询var代码,用于上下文。
注册查询变量:
/**
* 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' );
(foo,bar和baz是主题选项 – 背景,各种颜色等)
如何使用它们只是为主题选项添加一个过滤器 – 该部分超出了问题的范围,因此我将在此省略。
它们通过自定义Widget在前端输出。小工具输出只是一个表单。以下是一个表单域的示例:
<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; ?>" />
生成的查询字符串on-submit:
www.example.com/?foo=some_value
最佳解决方案
你检查了is_front_page()的哪一部分导致它返回false?
我可以通过跟踪从trac机票的设置重现问题。在我的这个函数内,调用is_page()返回false。
我猜这是因为$wp_query->set()用于page_id,而is_page只是导致query_vars被改变,你不会改变“查询状态”本身。
我可以通过将这两行添加到您的代码来创建一个解决方法:
$query->is_page = true;
$query->queried_object = get_post(get_option('page_on_front') );
在页面正确显示(在我的设置中)导致的页面(尽管URL中存在query_var),还有is_front_page()返回true。
我希望这有助于你进一步。
如果您查看WP_Query类的定义,您将看到有一个变量$query_vars和一个变量$is_page。
您使用的set功能($query->set( 'is_page', true );)仅设置query var:
function set($query_var, $value) {
$this->query_vars[$query_var] = $value;
}
它不会更改保存在$query->is_page = true中的状态信息,而是设置查询var $query->query_vars['is_page'] = true。
如果您来自OOP-approach并将WP_Query::set()理解为经典的class-setter功能,那么这是有点误导的 – 它不是。
次佳解决方案
我也在那张Trac票里回答,但是我认为这里的基本问题比这更简单。
你正在挂钩在demo_foo,demo_bar,demo_baz作为”Query variables”,但他们不是;至少不是在意图上。
虽然URL后的foo = bar字符串通常称为查询字符串,但”query variables”实际上只是影响主查询的变量。如果你不挂钩一个变量,它不会消失,它不会被主要的WP_Query对象读取。
在你的情况下,这似乎正是你想要的。您的变量是主题选项,它们不是主要查询(它从数据库获取帖子)的一部分。您没有使用它们来选择要显示的帖子,您正在使用它们来设置主题选项等。
如果你不把它们挂接成query_vars,那么它们根本不会影响主WP_Query对象。您将不得不从主要的$ _GET超级全局获取它们,而不是使用get_query_var,您将不得不对其进行适当的清理,以防止反射性XSS攻击(使用esc_attr或任何适当的),但这应该通过消除它来解决您的主要问题该代码首先引起问题,而不是添加额外的解决方法。
参考文献
注:本文内容整合自Google/Baidu/Bing辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。