Ausschließen oder Einschließen von Kategorie-IDs in WP_Query

Ich habe ein WordPress-Setup, das mehr als 300 Kategorien hat.

Jetzt muss ich etwas Flexibilität geben, um die Kategorien zu wählen. In diesem Fall habe ich zunächst alle Kategorien vorbelegt. Wenn jemand eine Kategorie ausschließen muss, kann er diese abwählen.

Jetzt ist das Problem, das ich gegenüberstelle, wie man genaue Ergebnisse entsprechend der Kategorienauswahl gibt.

Meine erste Herangehensweise war einfach, alle Abwählen Kategorien wie unten auszuschließen,

zB: 10,11,12 Kategorien ausschließen

$args = array( 'category__not_in' => array('10','11','12') ); 

Sagen wir, ich habe einen Posten, der unter category 12 & 13 angekreuzt wurde. Von oben genannten Code werde ich diesen Beitrag nicht erhalten, da er Beiträge in der category 12 . Aber idealerweise sollte es in den Ergebnissen sein, da category 13 nicht abgewählt wurde.

Als Lösung konnte ich die Option 'category__in' mit allen ausgewählten Kategorie-IDs verwenden. Aber meine Sorge ist, dass die Liste sogar sehr lang sein würde – obwohl es programmatisch kommt, bin ich mir über den wp_query Overhead nicht sicher, da ich mehr als 300 Kategorien habe.

Jeder hat eine bessere Idee, wie man dieses Problem lösen kann.

Solutions Collecting From Web of "Ausschließen oder Einschließen von Kategorie-IDs in WP_Query"

Wie Sie wahrscheinlich wissen, sind Kategorien Taxonomien. Wenn Sie die Argumente wie category__in , wird eine Steueranfrage zu Ihrer WP_Query() . Deine Situation wäre also etwa so:

 $args = array( 'post_type' => 'post', 'tax_query' => array( 'relation' => 'AND', array( 'taxonomy' => 'category', 'field' => 'term_id', 'terms' => array( 12 ), 'operator' => 'IN', ), array( 'taxonomy' => 'category', 'field' => 'term_id', 'terms' => array( 11, 12, 13 ), 'operator' => 'NOT IN', ), ), ); $query = new WP_Query( $args ); 

Ich denke hier nicht an performancesprobleme. Dies ist wahrscheinlich die einzige Lösung, wenn Sie die Posts nicht direkt mit einer SQL-Abfrage aus der database abfragen wollen (Dies könnte die Performance ein wenig verbessern).

Nehmen wir an, wir haben 4 Beiträge und 4 Kategorien.

 +----+--------+ | ID | Post | +----+--------+ | 1 | Test 1 | | 2 | Test 2 | | 3 | Test 3 | | 4 | Test 4 | +----+--------+ +----+------------+ | ID | Category | +----+------------+ | 1 | Category 1 | | 2 | Category 2 | | 3 | Category 3 | | 4 | Category 4 | +----+------------+ +--------+------------------------+ | Post | Category | +--------+------------------------+ | Test 1 | Category 1, Category 2 | | Test 2 | Category 2 | | Test 3 | Category 3 | | Test 4 | Category 4 | +--------+------------------------+ 

Wenn ich Ihre Frage richtig verstanden habe, möchten Sie den Test 1 Post mit dem Parameter category__not_in abrufen. Argumente für Ihre Abfrage sehen folgendermaßen aus:

 $args = array( 'category__not_in' => array(2, 3, 4) ); 

Das Problem mit category__not_in ist, dass es NOT IN SELECT SQL-Abfrage erzeugt.

 SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND (wp_posts.ID NOT IN ( SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id IN (2, 3, 4) )) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10 

NOT IN SELECT schließt alle Beiträge einschließlich Test 1 . Wenn nur dieses SQL JOIN anstelle von NOT IN SELECT dies funktionieren.

 SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) WHERE 1=1 AND (wp_term_relationships.term_taxonomy_id NOT IN (2, 3, 4)) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10 

Oberhalb von SQL wird nur Test 1 Post zurückgegeben. Wir können einen kleinen Trick machen, um eine solche Abfrage mit der WP_Query-class zu erstellen. Anstatt den Parameter category__not_in , ersetzen Sie ihn durch den Parameter category__in und fügen post_where Filter post_where , wodurch SQL direkt für unseren Zweck modifiziert wird.

 function wp_286618_get_posts() { $query = new WP_Query( array( 'post_type' => 'post', 'category__in' => array( 2, 3, 4 ) // Use `category__in` to force JOIN SQL query. ) ); return $query->get_posts(); } function wp_286618_replace_in_operator($where, $object) { $search = 'term_taxonomy_id IN'; // Search IN operator created by `category__in` parameter. $replace = 'term_taxonomy_id NOT IN'; // Replace IN operator to NOT IN $where = str_replace($search, $replace, $where); return $where; } add_filter( 'posts_where', 'wp_286618_replace_in_operator', 10, 2 ); // Add filter to replace IN operator $posts = wp_286618_get_posts(); // Will return only Test 1 post remove_filter( 'posts_where', 'wp_286618_replace_in_operator', 10, 2 ); // Remove filter to not affect other queries 

Der Vorteil dieser Lösung gegenüber anderen ist, dass ich keine anderen Kategorien ID kennen muss, und es wird Ihre Post-Schleife sauber halten.

Warum tippst du alle Kategorien vor? Ist es nicht einfacher, alle Ergebnisse anzuzeigen und gleichzeitig die Kategorien nicht angekreuzt zu haben? Wenn der Benutzer dann ein paar auswählt (wer wird 300 Kategorien auswählen?), Können Sie eine Abfrage mit category__in ausführen.

Ich bin mir nicht sicher, aber ich denke, Sie können dies nicht mit dem Standardverhalten / Optionen von WP_Query . Also vielleicht eine Arbeit um eine function zu implementieren, die diesen Test für Sie nach der Auswahl aller Beiträge tun wird.

Der Nachteil dieser Methode ist natürlich, dass Sie zuerst alle Beiträge auswählen und dann filtern müssen, aber es kann eine Lösung für Ihr Problem sein. So können Sie so etwas machen:

 < ?php function test_categorie($cats,$ex_cats) { $test = false; //we consider that this post is excluded until we found a category that doesn't belong to the array foreach ($cats as $cat){ if(!in_array(intval($cat->term_id),$ex_cats)) { $test = true; //We can exit the loop as this post have at least one category not excluded so we can consider it break; } } return $test; } //Define the excluded categorie here $exclude_cat = array(11,12,13); $args = array( 'posts_per_page' => -1, 'post_type' => 'post', ); $the_query = new WP_Query($args ); if ( $the_query->have_posts() ) : while ( $the_query->have_posts() ) : $the_query->the_post(); //we do our test, if(false) we don't consider the post and we continue to the next if(!test_categorie(get_the_category(),$exclude_cat)) continue; /* Add you code here */ endwhile; wp_reset_postdata(); endif; ?> 

Ich denke, ich würde performancesproblem (en) angehen, wenn und wenn sie auftauchen, aber wenn Sie wirklich betroffen sind, microtime das langsame Abfrageprotokoll von MySQL und verwenden Sie microtime zu verfolgen, wie lange diese bestimmte Abfrage / Hydration dauert. Um Ihre Frage zu beantworten, wäre eine einfache Lösung array_diff zu verwenden. Beispielsweise:

 $notIn = [10, 11, 12]; $in = [11]; $args = array( 'category__not_in' => array_diff($notIn, $in) ); 

Probier diese. Ich schätze das ist ein bisschen dreckig, aber es funktioniert für mich gut!

  $skills = get_user_meta($curr_id , 'designer_skills'); $skills = array_map('intval', explode(',' , $skills[0])); $args = array( 'numberposts' => -1, 'post_type' => 'project', 'meta_query' => array( 'relation' => 'AND', array( 'key' => 'status', 'compare' => '=', 'value' => 'open' ), array( 'key' => 'payment_status', 'compare' => '=', 'value' => true ) ) ); $posts = get_posts( $args ); if ($posts) { $count = 0; foreach ($posts as $project) { if (in_array(get_the_terms( $project->ID, 'projects')[0] -> term_id , $skills)){ //implement your own code here } } }