Filter get_adjacent_post () für private Beiträge, wie man JOIN / WHERE ändert?

Edit 3 – überarbeitet nach den Vorschlägen von GM. Der Code wird zwar errorsfrei ausgeführt, aber der Filter des angrenzenden Posts filtert immer noch nicht. Änderungen in Code-Kommentaren, aktuelle Frage am Ende des Posts notiert.

Edit 2 – spiegelt den unten stehenden Codevorschlag von GM wider. Ich bin verwirrt darüber, wo die modifizierte Join / Where-Filter-function gehen sollte, also fügte ich mehr von der Mu-Plugin-Code-Struktur hinzu.

Edit 1 – reflektiert den Kommentar von Kaiser unten, Beispiele zur Verfügung gestellt. Außerdem habe ich mich geirrt, welcher Code meine Beiträge gefiltert hat. Die Frage bezieht sich nicht auf das Mitglieder-Plugin.

Ich habe ein mu-Plugin, das meine WP-Abfrage filtert, so dass ein Besucher in der Indexschleife nur Beiträge sieht, die er lesen kann. Dies wird dadurch erreicht, dass Postautoren die Möglichkeit erhalten, für jeden Beitrag eine mehrstufige Mitgliedschaftstaxonomie zu vergeben.

Auf der niedrigsten (öffentlichen) Ebene ist keine Mitgliedschaftstaxonomie mit der Post verbunden.

Hier ist der Abfragefilter im 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. 

So weit, ist es gut. Dieser Filter funktioniert großartig.

Das Problem ist, dass in der Einzelpostansicht next_post_link() und previous_post_link() den Filter nicht erhalten, sodass Besucher zu Beiträgen navigieren können, die sie nicht lesen können. Ich möchte die Links zu diesen Posts filtern, um den Link nur zum nächsten Post zu zeigen, den sie tatsächlich lesen können.

Ich würde im Grunde gerne den obigen Abfragefilter auf get_adjacent_post () verwenden.

In WP core trac für link-template.php (sowie in dem next_post_link() verlinkten Beitrag von Kaiser) fand ich, dass next_post_link() , get_next_post() und get_adjacent_post() die angrenzende Post-Abfrage über die folgenden Filter ausführen:

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

REWRITE JOIN / WHERE FILTER

Ich versuchte das folgende Neuschreiben von JOIN / WHERE, das in GMs Antwort vorgeschlagen wurde. Wie er sagt, basiert es sehr genau auf der wp-core-function, wobei tr und tt unterschiedliche Namen haben und die ausgeschlossenen Terme direkt an die function übergeben werden.

Diese function ist derzeit auf der Site aktiv und wirft keine Fehler, die Posts werden jedoch nicht korrekt gefiltert.

Aktuelle Frage: Wenn ich $ exclude_terms von Slugs zu IDs in der function filter_adjacent unten konvertiere , baue ich das Array korrekt? Wie kann ich die ausgeschlossenen Begriffe protokollieren und herausfinden, was vor sich geht?

  // 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; } } 

Solutions Collecting From Web of "Filter get_adjacent_post () für private Beiträge, wie man JOIN / WHERE ändert?"

Als erstes schlage ich vor, dass Sie eine function verwenden, um die auszuschließenden Begriffe zurückzugeben, die Ihnen helfen werden, sie an verschiedenen Stellen zu erhalten, ohne Code wiederholen zu müssen, zB im ‘pre_get_posts’-Filter und den angrenzenden Postfiltern.

Damit:

 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; } 

Ich habe Kommentare aus Gründen der Einfachheit entfernt, aber Sie Code ist gut kommentiert und meins wird von dort übernommen. Ich habe gerade den Check für Admins bei Function Top aufgegeben.

Danach kann im Allgemeinen speacking die JOIN Klausel nichts ohne WHERE filtern, und WHERE schlägt fehl, wenn ein Tabellenname nicht in JOIN definiert ist. JOIN existiert keine Join-Methode und keine Where-Methode , sondern eine Join-Where-Methode .

Im core erfolgt der Filter für ausgeschlossene Begriffe sowohl über 'WHERE' als auch über JOIN , tatsächlich können Sie in Zeile 1183 sehen:

 "WHERE p.post_date $op %s AND p.post_type = %s AND p.post_status = 'publish' $posts_in_ex_terms_sql" 

innerhalb der if ( ! empty( $excluded_terms ) ) { statement in Zeile # 1154

und auf Linie # 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"; 

Die $posts_in_ex_terms_sql wird auf folgende Weise auf Zeile # 1173 gesetzt:

 $posts_in_ex_terms_sql = $wpdb->prepare( " AND tt.taxonomy = %s AND tt.term_id NOT IN (" . implode( $excluded_terms, ',' ) . ')', $taxonomy ); 

Ich denke, dass du einfach Code kopieren kannst, der von core benutzt wird, wenn $excluded_terms nicht leer ist … wenn es für Core funktioniert, sollte es auch für dich funktionieren.

So können Sie den "get_{$adjacent}_post_where" Filter "get_{$adjacent}_post_join" "get_{$adjacent}_post_where" und "get_{$adjacent}_post_join" .

Die function filter_adjacent sollte also auf die filter_adjacent und filter_adjacent Klausel filter_adjacent werden. Eine einfache Überprüfung von current_filter kann den Trick filter_adjacent .

So sollte Ihre class mit meinen Tipps erscheinen:

 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; } } } 

Ich habe auf diese Weise einen anderen Alias ​​für Taxonomie-Tabellen verwendet. Der Filter funktioniert, selbst wenn get_adjacent_post aufgerufen wird, werden alle Bedingungen für $in_same_term und / oder $in_same_term wird auf true gesetzt.

Code ist komplett ungetestet, lass es mich wissen, wenn es funktioniert …