問題描述
想像一個 CPT,讓我們稱之為”News” 。本新聞郵件類型主要用於在首頁上顯示短消息內容。但其中有些新聞將會更長,要求僅在首頁上顯示摘錄,並具有單一視圖。這個規則可能是我把所有的文字都放在首頁的時候,而只是有時候輸入內容。
到目前為止我所想到的
如果沒有需要單獨的頁面,我將禁用 publicly_queryable 。
只要留下一個視圖的一切,做一個重定向回到首頁,如果內容是空的,聽起來像一個髒的黑客。
只是過濾那些沒有內容可能不足夠。重寫規則怎麼辦?插件生成站點 Map?搜索?
還有什麼我錯過的嗎?我主要是為了實現這個方向,而不是一般的實現方向。
最佳解決方案
我的想法很簡單:使用'publicly_queryable' => TRUE 註冊 CPT,然後在沒有查詢到沒有內容的單個消息時,有條件地使發佈類型不可公開查詢。
這意味着在註冊了帖子類型後,我們必須更改'publicly_queryable'參數。一些簡單的事情:所有的 post 類型的對象都保存在全局變量 $wp_post_types 中,所以假設 CPT slug 是’news’,只需使用
$GLOBALS['wp_post_types']['news']->publicly_queryable = FALSE;
我們將能夠禁用新聞 CPT 的查詢。
第二個問題是有條件地禁用。
我們知道所有帖子都有一個 url,即使是 non-queryable,但是當訪問 non-queryable CPT 的單個帖子的 URL 時,WordPress 發送 404 響應。
這發生在 WP::parse_request()方法內,所以運行我們的條件邏輯的最佳位置就在請求解析發生之前,所以最好的選擇是過濾器鈎子'do_parse_request'(在 WP::parse_request()的第一行觸發) 。
所以我們的工作流應該是:
-
'do_parse_request'內部檢查請求是否為單個消息 -
如果#1 為是,請檢查所請求的新聞是否沒有內容
-
如果#2 為是,則將消息 CPT 的
publicly_queryable參數設置為 FALSE -
主查詢發生後,將
publicly_queryable參數重置為 TRUE
最困難的部分是#1,因為一旦 WordPress 尚未解析請求,我們就不能使用任何 conditional tags,也就是説 is_singular( 'news' )太早了。
只有可以看看 url,幸運的是 url_to_postid()的功能將幫助我們完成這項任務。
那就是説我們可以寫一個簡單的類來實現我們的工作流程:
class SingleCptEnabler {
private $id = -1;
private $cpt_slug;
function __construct( $cpt_slug ) {
$this->cpt_slug = $cpt_slug;
}
/**
* Run on 'do_parse_request' filter, and enable publicly_queryable
* when a single news having content is required
*/
function setup() {
if (
current_filter() === 'do_parse_request'
&& $this->isSingle()
&& ! $this->hasContent()
) {
// when 'wp' hook is fired main query already happen
add_action( 'wp', array( $this, 'enable' ) );
$this->disable();
}
}
/**
* Query DB to get post content of the current queried news
*/
function hasContent() {
if ( (int) $this->id <= 0 ) {
return;
}
$post = get_post( $this->id );
$content = ! empty( $post ) && $post->post_type === $this->cpt_slug
? apply_filters( 'the_content', $post->post_content )
: FALSE;
return ! empty( $content );
}
/**
* Enable publicly_queryable argument for news CPT
*/
function enable() {
$GLOBALS['wp_post_types'][$this->cpt_slug]->publicly_queryable = TRUE;
}
/**
* Disable publicly_queryable argument and reset id
*/
function disable() {
$GLOBALS['wp_post_types'][$this->cpt_slug]->publicly_queryable = FALSE;
$this->id = -1;
}
/**
* Check if the current url is for a singular news
*/
function isSingle() {
$this->id = -1;
if ( ! is_admin() ) {
$this->id = (int) url_to_postid( add_query_arg( array() ) );
}
return (int) $this->id > 0;
}
}
在這個類在一個活動的插件或主題 functions.php(或更好的文件需要從那裏),我們只需要調用'do_parse_request'過濾器鈎子上的 SingleCptEnabler::setup(),傳遞給類構造函數 CPT slug:
add_filter( 'do_parse_request', function( $do ) {
$news_enabler = new SingleCptEnabler( 'news' );
$news_enabler->setup();
return $do; // we don't want to affect the filter results
} );
類是可重複使用的,它也可以用於多個 CPT,例如如果我們想要相同的行為’news’ 和’commentary’ CPT 我們可以做:
add_filter( 'do_parse_request', function( $do ) {
$news_enabler = new SingleCptEnabler( 'news' );
$commentary_enabler = new SingleCptEnabler( 'commentary' );
$news_enabler->setup();
$commentary_enabler->setup();
return $do; // we don't want to affect the filter results
} );
現在,當你想要一些消息有一個完整的內容,只需填寫發佈內容 (編輯器),否則只是填寫摘錄。
唯一的缺點是,打開的單數新聞頁面將會減慢,因為需要額外的工作。
參考文獻
注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。