問題描述
有一個 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 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。