web-dev-qa-db-ja.com

WP_Queryを使用してカテゴリごとの投稿数を制限して複数のカテゴリをクエリする

15の投稿ごとに3つのカテゴリがありますが、各カテゴリに対して最初の投稿を5つだけ持っているデータベースに対して1つのクエリを実行したいのですが、どうすればよいでしょうか。

$q = new WP_Query(array( 'post__in' => array(2,4,8), 'posts_per_page' => **FIRST_5_OF_EACH_CAT** ));

それが不可能な場合、何がより効率的ですか?親カテゴリのすべての投稿を取得してそれらをループするか、3つの異なるクエリを作成する?

10
Amit

あなたが望むものは可能ですが、可能であればいつでも避けたいSQLを掘り下げる必要があります(私はそれを知らないからではなく、私はm高度なSQL開発者。ただし、WordPressのでは、可能な限りAPIを使用するため、将来に関連する将来の互換性の問題を最小限に抑えたい潜在的なデータベース構造の変更。)

UNION演算子を使用したSQLは可能性です

SQLを使用するには、クエリでUNION演算子を使用します。カテゴリスラグが"category-1""category-1"、および"category-3"であると仮定すると、次のようになります。

SELECT * FROM wp_posts WHERE ID IN (
  SELECT tr.object_id
  FROM wp_terms t 
  INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
  INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
  WHERE tt.taxonomy='category' AND t.slug='category-1'
  LIMIT 5

  UNION

  SELECT tr.object_id
  FROM wp_terms t 
  INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
  INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
  WHERE tt.taxonomy='category' AND t.slug='category-2'
  LIMIT 5

  UNION

  SELECT tr.object_id
  FROM wp_terms t 
  INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
  INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
  WHERE tt.taxonomy='category' AND t.slug='category-3'
  LIMIT 5
)

posts_joinフィルターでSQL UNIONを使用できます

上記を使用して、単に直接呼び出しを行うか、posts_joinフィルターフックを使用することができます次のように。 PHP heredoc を使用していることに注意してください。したがって、SQL;が左にフラッシュされることを確認してください。また、グローバル変数を使用して、配列内のカテゴリスラッグをリストすることにより、フックの外側でカテゴリを定義できるようにしました。このコードをプラグインまたはテーマのfunctions.phpファイルに配置できます。

<?php
global $top_5_for_each_category_join;
$top_5_for_each_category_join = array('category-1','category-2','category-3');
add_filter('posts_join','top_5_for_each_category_join',10,2);
function top_5_for_each_category_join($join,$query) {
  global $top_5_for_each_category_join;
  $unioned_selects = array();
  foreach($top_5_for_each_category_join as $category) {
    $unioned_selects[] =<<<SQL
SELECT object_id
FROM wp_terms t
INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
WHERE tt.taxonomy='category' AND t.slug='{$category}'
LIMIT 5
SQL;
  }
  $unioned_selects = implode("\n\nUNION\n\n",$unioned_selects);
  return $join . " INNER JOIN ($unioned_selects) categories ON wp_posts.ID=categories.object_id " ;
}

しかし、副作用があります

もちろん、posts_joinのようなクエリ変更フックを使用すると、常にクエリに対してグローバルに動作するという副作用が生じるため、通常は、必要なときにのみ使用するifで変更をラップする必要がありますテストするのは難しい場合があります。

代わりに最適化に焦点を当てますか?

しかし、私はあなたの質問が懸念していると思います最適化についての詳細、トップ5の3回のクエリを行うことができるということよりも正しいですか?その場合、WordPress AP​​Iを使用する他のオプションがありますか?

キャッシュにTransients APIを使用した方が良いですか?

あなたの投稿はそれほど頻繁には変わらないと思いますか? 3つのクエリヒットを定期的に受け入れ、 Transients API を使用して結果をキャッシュするとどうなりますか?保守可能なコードと優れたパフォーマンスが得られます。 WordPressは投稿のリストをwp_optionsテーブルの1つのレコードにシリアル化された配列として保存するため、上記のUNIONクエリよりもかなり優れています。

次の例を使用し、test.phpとしてWebサイトのルートにドロップして、これをテストできます。

<?php

$timeout = 4; // 4 hours
$categories = array('category-1','category-2','category-3');

include "wp-load.php";
$category_posts = get_transient('top5_posts_per_category');
if (!is_array($category_posts) || count($category_posts)==0) {
  echo "Hello Every {$timeout} hours!";
  $category_posts = array();
  foreach($categories as $category) {
    $posts = get_posts("post_type=post&numberposts=5&taxonomy=category&term={$category}");
    foreach($posts as $post) {
      $category_posts[$post->ID] = $post;
    }
  }
  set_transient('top5_posts_per_category',$category_posts,60*60*$timeout);
}
header('Content-Type:text/plain');
print_r($category_posts);

概要

はい、SQL UNIONクエリとposts_joinフィルターフックを使用して要求したことを実行できますが、Transients API代わりに。

お役に立てれば?

15
MikeSchinkel

WP_Query() First X For Each Catのようなものをサポートしていません WP_Query()の代わりにget_posts()をあなたの各カテゴリに使うことができます。

<?php
$posts      = array():
$categories = array(2,4,8);
foreach($categories as $cat) {
  $posts[] = get_posts('numberposts=5&offset=1&category='.$cat);
}
?>

$postsに各カテゴリの最初の5つの投稿が含まれるようになりました。

1
hakre

1回のクエリで各カテゴリの最初の5つの投稿を取得する方法がわかりません。 45件の投稿しかない場合は、データベースを1回クリックして各カテゴリの5件の投稿を取得するのが最も効率的な方法です。データベースを3回押して結果を組み合わせるのは悪いことではありません。

0
Bernard Chen