过滤GET_ADVIENT_POST()对于私人帖子,如何修改Join/在哪里?

时间:2014-04-08 作者:nimmolo

编辑3-根据G.M.的建议进行修订。代码运行时无错误,但相邻的后过滤器仍不过滤。代码注释中注意到的更改,帖子底部注意到的当前问题

编辑2-反映以下G.M.的代码建议。我对修改后的join/where-filter函数应该放在哪里感到困惑,所以我添加了更多的mu-plugin代码结构

编辑1-反映了凯撒在下面的评论,提供了示例。此外,我还错误地知道是哪种代码过滤了我的帖子。问题与Members插件无关

我有一个mu插件过滤我的WP查询,这样在索引循环中,访问者只能看到他们可以阅读的帖子。它通过为帖子作者提供为每个帖子分配多级成员分类的能力来实现这一点。

在最低(公共)级别,该职位没有附加任何成员分类。

以下是mu插件中的查询过滤器:

if ( ! class_exists ( \'Site_Members_Taxonomy\' ) ) {

class Site_Members_Taxonomy
{
    //define( \'LANG\', \'some_textdomain\' ); deleted LANG, was throwing errors

    public $post_types = array( \'post\', \'page\', \'gallery\' );
    public $tax = \'membership\';
    public $tax_label; // CHANGE: made these three vars public

    public function __construct()
    {
    $this->tax_label = __( \'Membership\' );

    // plugin defines taxonomy and membership meta and then:

    add_action( \'pre_get_posts\', array( &$this, \'filter_query\' ) );

    /**
     * Modify the query based on membership taxonomy
     */
    function filter_query( $query ) {

        //quit right now if in admin
        if( is_admin() ) return;

        $tax_query = \'\';
        $terms = $this->get_terms_to_exclude(); // see function below

        if( $terms ) 
            $tax_query = array(
                   array(
                        \'taxonomy\' => $this->tax,
                        \'field\' => \'slug\',
                        \'terms\' => $terms,
                        \'operator\'=>\'NOT IN\'
                    )
            );

        // if after all that we have a tax query to make, lets do it!
        if ( $tax_query )
            set_query_var(\'tax_query\', $tax_query);

    }

    } //end class

    global $Site_Members_Taxonomy;
    $Site_Members_Taxonomy = new Site_Members_Taxonomy();

}

// finally, outside the class definition, there is a function `members_can_view` to be used as a conditional to hide/show various template tags etc.
到目前为止,一切顺利。这个过滤器工作得很好。

问题是,在单贴视图中,next_post_link()previous_post_link() 不要使用过滤器,这样访问者就可以导航到他们想要的帖子cannot 阅读我想过滤这些帖子的链接,只显示下一篇他们可以阅读的帖子的链接。

我基本上希望在get\\u nextigation\\u post()上使用上面的查询过滤器。

在里面WP core trac for link-template.php (以及下面链接的Kaiser帖子)我发现next_post_link(), get_next_post()get_adjacent_post() 通过以下筛选器运行相邻的post查询:

  • get_{$adjacent}_post_join
  • get_{$adjacent}_post_where
  • get_{$adjacent}_post_sort

REWRITE JOIN/WHERE FILTER

我试着按照G.M.的回答改写了JOIN/WHERE。正如他所说,它非常紧密地基于wp核心函数,tr和tt有不同的名称,排除的术语直接传递给函数。

此功能当前在站点上处于活动状态,不会引发错误,但也不会正确过滤相邻的帖子查询。

Current Question: 在下面的函数filter\\u neighbent中将$excluded\\u terms从slug转换为id时,我是否正确构建了数组?我如何记录排除的条款并了解发生了什么?

    // Filters for get_adjacent_posts() so they don\'t show up in single-post navigation  
    // These filters are added within function __construct{} noted above
    // CHANGE: &$this to $this

    add_filter( \'get_previous_post_where\', array( $this, \'filter_adjacent\' ) );
    add_filter( \'get_next_post_where\', array( $this, \'filter_adjacent\' ) );
    add_filter( \'get_previous_post_join\', array( $this, \'filter_adjacent\' ) );
    add_filter( \'get_next_post_join\', array( $this, \'filter_adjacent\' ) );


    /**
     * These functions added within mu-plugin class:
     *
     * First, modify excluded terms based on membership taxonomy
     * 
     * NOTE: Excluded terms may be an array
     */

    function get_terms_to_exclude() {

        // if a real admin or "level1" we won\'t change tax query at all
        if( current_user_can ( \'manage_options\' ) || current_user_can ( \'view_level1_posts\' ) )
            return false;

        // default/public will exclude all upper level posts
        // in other words, all posts with membership taxonomy
        $terms = array( \'level1\',\'level2\',\'level3\' );

        // if a level3 reader we\'ll exclude level1 and level2 posts
        if( current_user_can ( \'view_level3_posts\' ) )
            $terms = array( \'level1\', \'level2\' );

        // if at level2 level we\'ll exclude level1 level posts
        if( current_user_can ( \'view_level2_posts\' ) )
            $terms = array( \'level1\' );

        return $terms;

    }


    /**
     * Next, use these terms to filter the get_adjacent_post JOIN/WHERE
     */

    function filter_adjacent( $clause ) {

        if ( substr_count( current_filter(), \'_post_join\' ) ) { // filtering join

            if ( empty($clause) ) $clause = \'\';
            global $wpdb;
            $clause .=
                " INNER JOIN {$wpdb->term_relationships} AS trmship ON p.ID = trmship.object_id
                INNER JOIN {$wpdb->term_taxonomy} ttmship
                ON trmship.term_taxonomy_id = ttmship.term_taxonomy_id";
            return $clause;

        } elseif ( substr_count( current_filter(), \'_post_where\' ) ) { // filtering where

            $excluded_term_slugs = get_terms_to_exclude();
            if ( ! $excluded_term_slugs ) return $clause; // nothing to filter if no terms
            $excluded_terms = array(); // we needs term ids, let\'s convert slug in terms ids
            foreach ( $excluded_term_slugs as $slug ) {
                $t = get_term_by( \'slug\',  $slug, \'membership\' );
                if ( ! $t || is_wp_error($t) ) continue;
                $excluded_terms[] = $t;
            }
            // something wrong in get_level_term_to_exclude()?
            if ( empty($excluded_terms) ) return $where; 

            $posts_in_ex_terms_sql = 
                " AND ttmship.taxonomy = \'membership\'
                AND ttmship.term_id NOT IN (" . implode( $excluded_terms, \',\' ) . \')\';
            // return filtered where clause
            return $clause. $posts_in_ex_terms_sql;
        }
    }

1 个回复
SO网友:gmazzap

首先,我建议您使用函数返回要排除的术语,这将帮助您在不同的位置获取它们,而无需重复代码,例如在“pre\\u get\\u posts”过滤器和相邻的post过滤器中。

因此:

function get_level_term_to_exclude() {
  if ( current_user_can (\'manage_options\') || current_user_can (\'view_level1_posts\') ) {
    return false;
  }
  $terms = array( \'level1\', \'level2\', \'level3\' );
  if( current_user_can ( \'view_level2_posts\' ) ) {
    $terms = array( \'level1\' );
  }
  if( current_user_can ( \'view_level3_posts\' ) ) {
    $terms = array( \'level1\', \'level2\' );
  }
  return $terms;
}
为了简洁起见,我删除了注释,但是您的代码注释得很好,我的注释就是从那里删除的。我只是把管理员的检查放在函数顶部。

之后,一般来说,JOIN 条款can\'t 过滤任何没有WHERE, 和WHERE 如果使用中未定义的表名,则将失败JOIN, so不存在连接方法和where方法,但存在连接方法和where方法。

在core中,排除术语的过滤通过以下两种方式完成\'WHERE\'JOIN, 事实上,在第1183行,您可以看到:

"WHERE p.post_date $op %s AND p.post_type = %s
 AND p.post_status = \'publish\' $posts_in_ex_terms_sql"
内部if ( ! empty( $excluded_terms ) ) { 第1154行的声明

在线#1141:

if ( $in_same_term || ! empty( $excluded_terms ) ) {
   $join = " INNER JOIN $wpdb->term_relationships AS tr ON p.ID = tr.object_id
        INNER JOIN $wpdb->term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id";
The$posts_in_ex_terms_sql 以以下方式设置在第1173行:

$posts_in_ex_terms_sql = $wpdb->prepare(
  " AND tt.taxonomy = %s
   AND tt.term_id NOT IN (" . implode( $excluded_terms, \',\' ) . \')\', $taxonomy
);
我认为,当$excluded_terms 不为空。。。如果它对core有效,那么它也应该对您有效。

因此,您可以使用"get_{$adjacent}_post_where" 过滤"get_{$adjacent}_post_join".

那么函数filter_adjacent 应作用于join和where子句,对current_filter 我能做到这一点。

下面是使用我的提示显示您的班级的方式:

class Site_Members_Taxonomy {

  const LANG = \'some_textdomain\';

  public $post_types = array( \'post\', \'page\', \'gallery\' );

  public $tax = \'membership\';

  public $tax_label;

  public function __construct() {
    $this->tax_label = __( \'Membership\', self::LANG );
    add_action( \'pre_get_posts\', array( $this, \'filter_query\' ) );
    add_filter( \'get_previous_post_where\', array( $this, \'filter_adjacent\' ) );
    add_filter( \'get_next_post_where\', array( $this, \'filter_adjacent\' ) );
    add_filter( \'get_previous_post_join\', array( $this, \'filter_adjacent\' ) );
    add_filter( \'get_next_post_join\', array( $this, \'filter_adjacent\' ) );
  }

  function get_term_to_exclude() {
    if (
      is_admin()
      || current_user_can (\'manage_options\')
      || current_user_can (\'view_level1_posts\')
    ) {
      return false;
    }
    $terms = array( \'level1\', \'level2\', \'level3\' );
    if( current_user_can ( \'view_level2_posts\' ) ) {
      $terms = array( \'level1\' );
    }
    if( current_user_can ( \'view_level3_posts\' ) ) {
      $terms = array( \'level1\', \'level2\' );
    }
    return $terms;
  }

  /**
   * Modify the query based on membership taxonomy
   */
  function filter_query( $query ) {
    $terms = $this->get_term_to_exclude();
    if ( ! $terms ) return;
    $tax_query = array(
      array(
        \'taxonomy\' => $this->tax,
        \'field\' => \'slug\',
        \'terms\' => $terms,
        \'operator\' => \'NOT IN\'
      )
    );
    set_query_var( \'tax_query\', $tax_query );
  }

  /**
   * Filter adjacent posts
   */
  function filter_adjacent( $clause ) {
    if ( substr_count( current_filter(), \'_post_join\' ) ) {
      if ( empty($clause) ) $clause = \'\';
      global $wpdb;
       $clause .=
        " INNER JOIN {$wpdb->term_relationships} trmship ON p.ID = trmship.object_id
        INNER JOIN {$wpdb->term_taxonomy} ttmship
        ON trmship.term_taxonomy_id = ttmship.term_taxonomy_id";
      return $clause;
    } elseif ( substr_count( current_filter(), \'_post_where\' ) ) {
      $excluded_term_slugs = $this->get_term_to_exclude();
      if ( ! $excluded_term_slugs ) return $clause;
      $excluded_terms = array();
      foreach ( $excluded_term_slugs as $slug ) {
        $t = get_term_by( \'slug\',  $slug, $this->tax );
        if ( ! $t || is_wp_error($t) ) continue;
        $excluded_terms[] = $t->term_id;
      }
      $excluded_terms = array_filter( array_map( \'intval\', $excluded_terms ) );
      if ( empty( $excluded_terms ) ) return $clause; 
      global $wpdb;
      $posts_in_ex_terms_sql = $wpdb->prepare(
        " AND ttmship.taxonomy = \'%s\'
        AND trmship.term_taxonomy_id NOT IN (" . implode( \',\', $excluded_terms ) . \')\',
        $this->tax
      );
      return $clause. $posts_in_ex_terms_sql;
    }
  }
}
我为分类表使用了不同的别名,这样即使在get_adjacent_post 任何条款都被传递给$excluded_terms 参数和/或$in_same_term 设置为true。

代码完全未经测试,请告诉我是否有效。。。

结束

相关推荐