我的想法很简单:register the CPT using \'publicly_queryable\' => TRUE
然后有条件地使帖子类型在查询没有内容的单个新闻时不可公开查询。
这意味着我们必须改变\'publicly_queryable\'
注册post类型后的参数。简单的事情:所有post types对象都保存在全局变量中$wp_post_types
因此,假设CPT slug是“新闻”,只需使用
$GLOBALS[\'wp_post_types\'][\'news\']->publicly_queryable = FALSE;
我们将能够禁用新闻CPT查询。
第二个问题是when 有条件禁用。
我们知道,所有帖子都有一个url,即使是不可查询的,但是当访问不可查询CPT的单个帖子的url时,WordPress会发送404响应。
这发生在WP::parse_request()
方法,所以运行条件逻辑的最佳位置是在请求解析发生之前,所以最佳选择是过滤器挂钩\'do_parse_request\'
(在WP::parse_request()
).
因此,我们的工作流程应该是:
内部\'do_parse_request\'
检查请求是否针对单个新闻如果#1为是,检查请求的新闻是否没有内容如果#2为是,设置publicly_queryable
新闻CPT重置的参数为FALSEpublicly_queryable
在主查询发生后,参数为TRUE最难的部分是#1,因为一旦请求还没有被WordPress解析,我们就不能使用conditional tags, i、 e.现在打电话还太早is_singular( \'news\' )
.
幸运的是,唯一可能的是查看urlurl_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
(或者更好的是在那里需要的文件中)我们只需要调用
SingleCptEnabler::setup()
在
\'do_parse_request\'
过滤器挂钩,将CPT段塞传递给类构造函数:
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,例如,如果我们希望“新闻”和“评论”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
} );
现在,当你想让一些新闻有完整的内容时,只需填写文章内容(编辑),否则只需填写摘录。
唯一的缺点是,由于需要额外的工作,单一的新闻页面打开速度会变慢。