问题描述
想像一个 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 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。