it-swarm.com.de

Benutzerdefinierte Abfrage mit Kategorieausschluss und Post-Meta-Whitelist

Ich habe zwei Widgets, eines zeigt News während das andere alles außer News zeigt (wir nennen das zweite Blog ). Der Blog-Teil funktioniert derzeit ordnungsgemäß.

Die Nachrichtenbeiträge sind entweder als In the News OR mit dem benutzerdefinierten Post-Meta in-the-news (1) kategorisiert. Es ist wichtig zu beachten, dass nicht für alle Beiträge das benutzerdefinierte Post-Meta definiert wird.

Das Hauptproblem, mit dem ich konfrontiert bin, ist, dass ich Post-Meta vergleichen muss, basierend darauf, ob der Post auf die eine oder andere Weise kategorisiert ist.

Möglicherweise muss ich eine benutzerdefinierte Datenbankabfrage für dieses Verhalten ausführen, zumindest für die Nachrichten. Ist es möglich, eine benutzerdefinierte Abfrage durchzuführen und in ein Standard-WP_Query-Objekt zu konvertieren?


Was ich probiert habe

Abfrage für News .

Problem: Zeigt nur Beiträge innerhalb der Kategorie 75, die in-the-news = 1 haben.

Gewünschtes Ergebnis: Zeige alle Beiträge der Kategorie 75 unabhängig vom Wert von in-the-news und alle zusätzlichen Beiträge von außerhalb der Kategorie, die in-the-news = 1 haben.

query_posts(array(
  'ignore_sticky_posts' => true,
  'posts_per_page' => 3,
  'cat' => "75", // Only posts within category 75 (News)

  // Including posts tagged to show "In the News"
  'meta_query' => array(
    'relation' => 'OR',
    array(
      'key' => 'in-the-news',
      'value' => '1',
      'compare' => '=',
    ),
    array( 
      'key' => 'in-the-news',
      'compare' => 'NOT EXISTS',
      'value' => '',
    ),
  )
));

Hier ist die Abfrage für den Blog :

Diese Abfrage funktioniert anscheinend ordnungsgemäß. Sie zeigt alle Posts außerhalb der Kategorie 75 an und blendet Posts mit in-the-news = 1 aus.

query_posts(array(
  'ignore_sticky_posts' => true,
  'posts_per_page' => 3,
  'cat' => "-75", // All posts EXCLUDING those in category 75 (News)

  'meta_query' => array(
    'relation' => 'OR',
    array(
      'key' => 'in-the-news',
      'value' => '0',
      'compare' => '=',
    ),
    array( 
      'key' => 'in-the-news',
      'compare' => 'NOT EXISTS',
      'value' => '',
    ),
  )
));

Lösung

Dank s_ha_dum für die tollen Beispiele ist hier die letzte Abfrage, die ich verwende. Die Logik hier ist, dass wir eine benutzerdefinierte MySQL-Abfrage für ein Array von Post-IDs durchführen und dann eine Standard-WP_Query unter Verwendung der zurückgegebenen IDs durchführen.

Hinweis: Die Logik hier war etwas komplizierter als der ursprüngliche Beitrag. Grundsätzlich hatten wir ursprünglich "News" und "Blog". Jetzt haben wir aber auch "Risiko". Außerdem wurde das Post-Meta von in-the-news in show-in-blog geändert, da wir die Funktionalität umkehren. Ich kann nicht erwarten, dass irgendjemand sonst jemals die Gründe dafür versteht, denn selbst ich finde es lächerlich (Aber der Kunde will es, also sei es!)

Hier ist meine Abfrage für das Widget "Blog". Für den Bereich "News" werden geringfügige Abweichungen vorgenommen. Ich bin nicht sicher, ob die Abfrage bereinigt werden könnte. Ich bin mir auch nicht sicher, ob es eine schlechte Idee ist, so viele SELECTs in derselben Abfrage durchzuführen.

global $wpdb;

$query = // Splitting the SQL query to it's own code block for syntax highlighting!

  SELECT `ID`
  FROM {$wpdb->posts} posts
  WHERE (

    /* Exclude posts in News (94) 
       Ignore show-in-blog option for News here, 
       as News is displayed on the same page */
    94 NOT IN ( 
      SELECT `term_taxonomy_id` 
      FROM {$wpdb->term_relationships}
      WHERE `object_id` = posts.`ID`
    )

    AND

    /* Exclude posts in Risk (96), 
       But show Risk posts that have the postmeta "show-in-blog" */
    (

      96 NOT IN ( 
        SELECT `term_taxonomy_id` 
        FROM {$wpdb->term_relationships}
        WHERE `object_id` = posts.`ID`
      )
      OR
      (
        96 IN ( 
          SELECT `term_taxonomy_id` 
          FROM {$wpdb->term_relationships}
          WHERE `object_id` = posts.`ID`
        )
        AND
        1 IN (
          SELECT `meta_value` 
          FROM {$wpdb->postmeta}
          WHERE 
          `meta_key` = 'show-in-blog'
          AND `post_id` = posts.`ID`
        )
      ) /* OR */

    ) /* AND */

  ) /* WHERE */

  ORDER BY `post_date` DESC;

$args = array(
  // Only include IDs returned by the above query
  'post__in' => $wpdb->get_col( $query ),
  'posts_per_page' => 10,
);

$wp_query = new WP_Query( $args );

get_template_part('loop', 'frontpage');
1
Radley Sustaire

Ist es möglich, eine benutzerdefinierte Abfrage durchzuführen und in ein Standard-WP_Query-Objekt zu konvertieren?

Ja. Sie können etwas tun wie ...

$post_ids = $wpdb->get_col("SELECT ID FROM {$wpdb->posts} WHERE ....");
$posts_qry = new WP_Query(array('post__in'=> $posts_ids,'orderby' => 'post__in'));

Die zweite Abfrage behält die Reihenfolge der Ergebnisse der ersten bei.

Ich bin mir ziemlich sicher, dass Sie diese erste Abfrage nicht mit WP_Query oder einer anderen Funktion durchführen können. Die Logik ist zu kompliziert. Sie benötigen eine JOIN- oder eine WHERE-Klausel, die WP_Query nicht unterstützt. Leider wird es auch kompliziert sein, diese SQL zu schreiben, nur um die Kategorie zu erhalten.

Die Abfrage vollständig von Hand zu schreiben, ist natürlich Ihre erste Option. Das Beste, was ich tun kann, ohne eine SQL von Hand zu schreiben, wäre:

$post_ids = new WP_Query(array(
  'fields' => 'ids',
  'ignore_sticky_posts' => true,
  'posts_per_page' => 3,
  'cat' => "75", // Only posts within category 75 (News)
));

$post_ids_2 = new WP_Query(array(
  'fields' => 'ids',
  'ignore_sticky_posts' => true,
  'posts_per_page' => 3,
  'post__not_in' => $post_ids->posts,
  'meta_query' => array(
    array(
      'key' => '_edit_lock',
      'value' => '0',
      'compare' => '=',
    ),
  )
));
$post_ids = $post_ids->posts + $post_ids_2->posts;
$posts_qry = new WP_Query(array('post__in'=> $posts_ids,'orderby' => 'post__in'));

Das sind 3 Fragen (autsch) und die Bestellung könnte ein Problem sein, wenn Sie sich darüber Sorgen machen.

Sie können die Abfrage auch über einige Filter ändern. Die WP_Query-Argumente behandeln den in-the-news = 1-Teil.

$post_ids_v3 = new WP_Query(array(
  'ignore_sticky_posts' => true,
  'posts_per_page' => 20,
  'my_variable' => true,
  // Including posts tagged to show "In the News"
  'meta_query' => array(
    array(
      'key' => 'in-the-news',
      'value' => '1',
      'compare' => '=',
    )
  )
));

Beachten Sie, dass Sie Ihre Kategoriekomponente weglassen und einen zusätzlichen inoffiziellen Parameter mit dem Namen my_variable übergeben. Ich weiß nicht, ob die Übergabe zusätzlicher Variablen so beabsichtigt ist, also sei dir bewusst, dass dies inoffizielles Verhalten sein kann. Damit fügen Sie Ihre Kategoriekomponente mit zwei Filtern in die Abfrage ein.

function posts_join_wpse_98652($join,$qry) {
  global $wpdb;
  if (true === $qry->get('my_variable')) {
    $join .= " JOIN {$wpdb->term_relationships} ON ({$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id)";
  }
  return $join;
}
add_filter('posts_join','posts_join_wpse_98652',1,2);

function posts_where_wpse_98652($where,$qry) {
  global $wpdb;
  if (true === $qry->get('my_variable')) {
    $where .= " OR {$wpdb->term_relationships}.term_taxonomy_id IN (75)";
  }
  return $where;
}
add_filter('posts_where','posts_where_wpse_98652',1,2);

Das ist nicht mal annähernd gut getestet, aber es scheint zu funktionieren, wenn ich es versuche. Trotzdem kann es schwierig sein, diese Dinge richtig zu machen. Vielleicht habe ich einen Fehler gemacht. Kaum getestet. Möglicherweise fehlerhaft. Vorbehalt Emptor. Keine Rückerstattung.

2
s_ha_dum