Abfrage mehrere Post-Typen mit jeweils eigenen Meta-Abfrage

Ich habe 2 Post-Typen: sagen wir products und product_variations . Ich möchte in der Lage sein, die Abfrage über pre_get_posts zu modifizieren, um alle Produkte mit meta_keys "_visible" = "true" und "_available" = "true" UND alle product_variations mit meta_key "_featured" = "true" .

Die product_variations haben nicht die Meta_Schlüssel "_visible"/"_available" und umgekehrt, also liefert eine direkte AND Meta-Abfrage keine Ergebnisse. OR Beziehung ist auch nicht ganz richtig, da zwei Felder für einen Posttyp AND verknüpft sind AND dann mit dem anderen OR verknüpft sind.

Um das etwas visueller zu machen, weil ich gerade erkannt habe, wie komplex es ist, aufzuschreiben:

 **product** _visible = true _available = true **product_variation** _featured = true 

Ist dies über Abfrageargumente möglich?
Ist das möglich über posts_where ?
Muss ich eine separate Abfrage ausführen und dann die Ergebnisse irgendwie zusammenführen?

Solutions Collecting From Web of "Abfrage mehrere Post-Typen mit jeweils eigenen Meta-Abfrage"

Ist dies über Abfrageargumente möglich?

Ich denke nicht.

Ist das möglich über 'posts_where' ?

Es ist wahrscheinlich möglich, einige 'posts_*' Filter zu verwenden, nicht nur mit 'posts_where' . Oder vielleicht mit 'posts_request' Filter, um die Abfrage vollständig zu überdecken.

Muss ich eine separate Abfrage ausführen und dann die Ergebnisse irgendwie zusammenführen?

Das wäre die einfachste Wahl, die am einfachsten anzupassen wäre, z. B. wäre es einfach, ein Limit für Produkte und ein anderes Limit für Produktvariationen zu verwenden.

Darüber hinaus ist dieser Ansatz nicht notwendigerweise der schlechteste auf der performancesseite, da nicht immer 2 Abfragen langsamer sind als ein einzelner, wenn letzterer sehr komplex ist.

Die vierte Alternative wäre ein vollständig benutzerdefiniertes SQL. Eine (vage getestete) Abfrage, die den Trick machen könnte, ist folgende:

 $products_and_variations = $wpdb->get_results(" SELECT * FROM ( SELECT products.* FROM {$wpdb->posts} products LEFT JOIN {$wpdb->postmeta} meta1 ON meta1.post_id = products.ID LEFT JOIN {$wpdb->postmeta} meta2 ON meta2.post_id = products.ID WHERE products.post_type = 'product' AND products.post_status = 'publish' AND (meta1.meta_key = '_visible' AND meta1.meta_value = '1') AND (meta2.meta_key = '_available' AND meta2.meta_value = '1') GROUP BY products.ID UNION SELECT variations.* FROM {$wpdb->posts} variations LEFT JOIN {$wpdb->postmeta} meta3 ON meta3.post_id = variations.ID WHERE variations.post_type = 'product_variation' AND variations.post_status = 'publish' AND (meta3.meta_key = '_featured' AND meta3.meta_value = '1') GROUP BY variations.ID ) posts ORDER BY post_date DESC LIMIT 0, 100 "); 

Sie können feststellen:

  • wie komplex es ist
  • Wie ist es möglich, ein Limit für Produkte und ein anderes Limit für Variationen zu verwenden: Es ist nur möglich, die zusammengeführten Ergebnisse zu begrenzen.

Bevor ich etwas so verwenden würde, würde ich seine performance testen, indem ich sie mit dem 2-Abfragen-Ansatz vergleiche, und nur die benutzerdefinierte Abfrage verwenden, wenn es nennenswerte performancesverbesserungen gibt.

Hier ist ein weiterer Ansatz mit pre_get_posts .

  • Verwenden Sie get_posts() (x2-Abfragen), um alle Post-IDs jedes Post-Typs gemäß seinen Anforderungen get_posts() . Fügen Sie den Abfrageargumenten den 'fields' => 'ids' ( 'fields' => 'ids' ) hinzu, um nur die Post-IDs zu holen, da dies das ist, was wir brauchen, sonst nichts. Dies wird die performance drastisch verbessern und wird nicht so schwer auf Ressourcen sein. Sie erhalten also zwei Arrays mit Post-IDs

  • Sie müssen nun die beiden Arrays mit array_merge() , um ein “super” array_merge() zu erstellen, das alle Post-IDs enthält

  • Sie würden in diesem Fall das Speichern in einem Transient und das Leeren des Transienten überprüfen, wenn ein Post aktualisiert, verworfen, nicht übertragen oder veröffentlicht wird. Dadurch wird sichergestellt, dass die performance Ihrer Website nicht umfasst ist.

  • Jetzt, da Sie ein Array von IDs haben, die Ihren Anforderungen entsprechen, können Sie dieses Array von Post-IDs post__in an post__in in pre_get_posts

Beispiel ( und ungetestet, da dies nur eine Illustration ist. Leider habe ich keine Zeit für eine korrekte Codierung )

 function get_all_special_posts() { /* * This is here were you would want to introduce your transient */ $args1 = [ 'post_type' => 'post_type_1', 'fields' => 'ids', 'nopaging' => true, 'meta_query' => [[ /*Your specific custom fields */ ]] ]; $query1 = get_posts( $args1 ); $args2 = [ 'post_type' => 'post_type_2', 'fields' => 'ids', 'nopaging' => true, 'meta_query' => [[ /*Your specific custom fields */ ]] ]; $query2 = get_posts( $args2 ); $post_ids = array_merge( $query1, $query2 ); /* * Set your transient here, you would want to store $post_ids in the transient */ return $post_ids; } 

Denken Sie daran, eine function zu erstellen, die Ihre Transienten nach der Veröffentlichung, dem Papierkorb, dem Extrahieren und der Aktualisierung löscht. Schauen Sie sich transition_post_status dafür an. Sehr vielseitiger Haken. Verwenden Sie $post->post_type um nur auf Ihre beiden gewünschten $post->post_type zu zielen

 add_action( 'pre_get_posts', function ( $q ) { if ( !is_admin() && $q->is_main_query() && $q->is_home() ) { $q->set( 'post__in', get_all_special_posts() ); } }); 

Nur um zu bemerken, würde ich zuerst überprüfen, ob get_all_special_posts() tatsächlich ein gültiges Array hat und dass es nicht leer ist, bevor es an post__in