編集3 - G.M.の提案に従って改訂。コードはエラーなしで実行されますが、それでも隣接する投稿フィルターはフィルタリングされません。変更はコードのコメントに記載され、現在の質問は投稿の下部に示されます。
編集2 - 下のG.M.のコード提案を反映しています。変更されたjoin/whereフィルター関数がどこに行くべきかについて混乱しているので、私はmu-pluginコード構造の詳細を追加しました。
編集1 - 下記のKaiserのコメントを反映、例を示しています。また、どのコードが投稿をフィルター処理しているのか間違っていました。質問はMembersプラグインに関連していません。
私はmu-pluginが私のWPクエリをフィルタリングしているので、インデックスループでは訪問者は読むことができる投稿しか見ることができません。これは、投稿の作成者に、各投稿に複数レベルのメンバーシップ分類を割り当てる機能を提供することで実現します。
最も低い(公の)レベルでは、投稿に添付される会員分類はありません。
これがmu-pluginのクエリフィルタです。
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()
がフィルタを取得できないため、訪問者はにアクセスできないreadにアクセスできません。これらの記事へのリンクをフィルタリングして、実際に読むことができる次の記事へのリンクのみを表示します。
私は基本的にget_adjacent_post()で上記のクエリフィルタを使いたいのです。
Link-template.phpの WPコアTrac (および以下にリンクされている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フィルタ
私はG.M.の答えで提案されているJOIN/WHEREを次のように書き換えてみました。彼が言うように、それはwp-core関数に非常に密接に基づいており、trとttは異なる名前を与えられ、除外された用語は関数に直接渡されます。
この機能は現在サイト上でアクティブになっており、エラーをスローしませんが、隣接する投稿のクエリも正しくフィルタリングしていません。
現在の質問:以下の関数filter_adjacentで$ excluded_termsをスラッグから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;
}
}
まず、除外する用語を返す関数を使用することをお勧めします。 「pre_get_posts」フィルターおよび隣接する投稿フィルター。
そう:
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
句ができないはWHERE
なしでフィルタリングし、WHERE
は失敗JOIN
で定義されていないテーブル名を使用しているため、joinメソッドおよびwhereメソッドが存在しない場合、ただし、joinとwhere methodが存在します。
コアでは、除外用語のフィルターは'WHERE'
とJOIN
の両方を介して行われます。実際には、#1183行目で次のように表示されます。
"WHERE p.post_date $op %s AND p.post_type = %s
AND p.post_status = 'publish' $posts_in_ex_terms_sql"
#1154行目のif ( ! empty( $excluded_terms ) ) {
ステートメント内
および#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";
$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
が空でない場合にコアで使用されるコードをコピーできると思います...コアで機能する場合は、あなたにも機能するはずです。
したがって、"get_{$adjacent}_post_where"
フィルターand"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に設定されている場合でも、フィルターが機能するように、分類テーブルに別のエイリアスを使用しました。
コードは完全にテストされていません。動作するかどうかを教えてください...