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