将CPT限制为有时只有一个查看页面

时间:2014-08-13 作者:kraftner

想象一个CPT,让我们称之为“新闻”。此新闻帖子类型主要用于在首页内联显示短新闻。但其中一些新闻的篇幅会更长,要求只在头版显示摘要,并且只有一个视图。规则可能是,我总是将所用的文本放在摘录的首页上,而有时只输入内容。

到目前为止,我的想法是:

如果没有人需要单独的页面,我只会禁用publicly_queryable 为了它。

如果内容为空,只需为所有内容保留一个视图并重定向回frontpage,听起来像是一个肮脏的黑客行为。

仅仅过滤那些没有内容的内容可能是不够的。重写规则呢?生成网站地图的插件?搜索

我还遗漏了什么吗?我主要是寻找关于实现这一点的一般方向的提示,而不一定是实现。

2 个回复
最合适的回答,由SO网友:gmazzap 整理而成

我的想法很简单: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
} );
现在,当你想让一些新闻有完整的内容时,只需填写文章内容(编辑),否则只需填写摘录。

唯一的缺点是,由于需要额外的工作,单一的新闻页面打开速度会变慢。

SO网友:Welcher

仅仅过滤那些没有内容的可能是不够的

为什么不呢?这似乎是最简单的解决方案。

除非我误解了你的意图,否则检查帖子是否有内容,如果有,只显示一个链接,似乎会让你达到你想要的目的。

在帖子类型的单个模板上,只需进行检查,如果没有帖子内容,则重定向回主页。

编辑:

您可以尝试使用add\\u rewrite\\u rule()为包含内容的新闻项创建虚拟页面。使用query\\u vars过滤器添加新的查询变量,然后使用template\\u重定向操作加载适当的模板。

结束

相关推荐