web-dev-qa-db-ja.com

カテゴリ除外とメタ後の「ホワイトリスト」を使用したカスタムクエリ

私は2つのウィジェットを持っています、一つはNewsを示し、もう一つはNewsを除くすべてを示します(二番目のウィジェットと呼びます)ブログ)ブログ部分は現在正しく機能しています。

ニュース投稿は、1に設定されたカスタム投稿メタIn the Newsを持つin-the-news ORに分類されます。すべての投稿がカスタム投稿メタを定義するわけではないことに注意することは重要です。

私が直面している主な問題は、投稿が何らかの方法で分類されているかどうかに基づいて投稿メタを比較する必要があることです。

少なくともニュースについては、この動作のためにカスタムデータベースクエリを実行する必要があるかもしれません。カスタムクエリを実行してそれをに変換することは可能ですか?標準のWP_Queryオブジェクト


私が試したこと

ニュースを検索します。

問題:カテゴリ75内のin-the-news = 1を持つ投稿のみを表示します。

目的の結果:in-the-newsの値にかかわらず、カテゴリ75からのすべての投稿と、in-the-news = 1を持つカテゴリ外からの追加の投稿を表示します。

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' => '',
    ),
  )
));

これがブログのクエリです。

このクエリは正しく機能しているようで、カテゴリ75以外のすべての投稿を表示し、投稿をin-the-news = 1で非表示にします。

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' => '',
    ),
  )
));

溶液

素晴らしい例を示してくれたs_ha_dumのおかげで、これが私が使っている最後のクエリです。ここでのロジックは、投稿IDの配列に対してカスタムのMySQLクエリを実行し、次に返されたIDを使用して標準のWP_Queryを実行することです。

注:ここのロジックは、元の投稿よりも少し複雑です。基本的に、私たちはもともと "News"と "Blog"を持っていました。しかし今、私たちには「リスク」もあります。また、in-the-newsポストメタはshow-in-blogに変更されました。私はそれがばかげていると思うとしても私は他の誰かがこれまでのところその推論を理解することをこれまで理解することができません(しかしクライアントはそれを望んでいるので、それで!)

これが "Blog"ウィジェットに対する私の質問です。 「ニュース」エリアには少しバリエーションがあります。クエリをクリーンアップできるかどうかわかりません。同じクエリ内で非常に多くのSELECTを実行するのは悪い考えかどうかもわかりません。

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

カスタムクエリを実行してそれを標準のWP_Queryオブジェクトに変換することは可能ですか?

はい。あなたは何かをすることができます...

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

2番目のクエリは最初のクエリの結果の順序を保持します。

WP_Queryや他の関数で最初の問い合わせをすることはできないと確信しています。論理は複雑すぎます。 WP_QueryがサポートしていないJOINまたはWHERE節が必要です。残念ながら、SQLと書くことは、カテゴリを取得するためだけにも複雑になります。

クエリを完全に手書きすることはもちろん最初の選択肢です。 SQLを手書きせずにできることは、次のようになります。

$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'));

それは3つのクエリ(痛い)であり、あなたがそれについて心配しているならば順序は問題になるかもしれません。

もう1つの選択肢は、2つのフィルタを介してクエリを変更することです。 WP_Query引数はin-the-news = 1部分を扱います。

$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' => '=',
    )
  )
));

カテゴリコンポーネントを省略し、my_variableという名前の追加の非公式パラメータを渡していることに注意してください。 このような追加の変数を渡すことが設計上のものであるかどうかはわかりませんので、それが非公式な動作になる可能性があることに注意してください。追加するために使用します。 2つのフィルタを使用して、カテゴリコンポーネントをクエリに追加します。

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

それは十分にテストされたことにはほど遠いです、しかし私が試みるときそれは働いているようです。それでも、これらのことを正しく理解するのは難しい場合があります。おそらく私はミスを犯しました。ほとんどテストされていません。おそらくバグがあります。買い手責任負担。返金なし。

2
s_ha_dum