WP_Queryを使用して、カテゴリごとの投稿が制限された複数のカテゴリをクエリしますか?


10

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

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

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


それらをどのように注文しますか?
MikeSchinkel 2010

最近公開されました。カテゴリAの最新5、カテゴリBの最新のものなど
Amit

回答:


16

あなたが望むものは可能ですが、可能な限り回避したいSQLを掘り下げる必要があります(私はそれを知らないからではなく、私は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のヒアドキュメントを必ずそうで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 APIを使用する他のオプションがあるでしょうか?

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

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

次の例を使用して、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を使用してキャッシュを使用することをお勧めします。

お役に立てれば?


2
トランジェントを介したキャッシュは、サイトへの影響を軽減するのに適しています。
10

1
トランジェントの使用に関する@Mikeの素晴らしいアイデア。
Chris_O

@マイク、私があなたの大陸に住んでいたら、私はあなたと一緒に授業を受けたでしょう!再度、感謝します!
アミット

@アミット:笑!:-)
MikeSchinkel

1
一時的に無期限に保存してから、save_postでフラッシュすることもできますか?codexの良い例(edit_termフックを使用)があります
helgatheviking

1

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

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

$posts 現在、各カテゴリの最初の5つの投稿が含まれています。


それは3つのdbへのヒットではありませんか?1ヒットでできるかどうか知りたかったので、もっと効率的だと思いました。
2010

まあ、それはdbの目的ですよね?そこからデータをクエリします。dbはそのようなもののために作られています。おそらく、求めている複雑なSQLクエリを実行するよりも高速です。ものを使用することを恐れないでください。サイトが壊れた場合は、こちらから報告してください。
hakre 2010

mm ..わかりました。php/ mysql / dbの効率についてはあまり知りませんが(もっと読みたいと思います)、ヒット数が少ないほど良いと確信し、結果を自分で解析しました。
2010

1
まあ、確かに、一般的にはより多くはより多く、より少なくはより少ないです。ただし、最初にテストしてみてください。ソフトウェアが「より悪い」ほど、最適化の可能性が高くなります。最終的にあなたはより良いソフトウェアをより速くそしてより速くより良いソフトウェアを書くことになるので、そうすることでよりよく学ぶことができます。
10

0

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.