WP_Query를 사용하여 카테고리 당 게시물 수가 제한된 여러 카테고리를 쿼리 하시겠습니까?


10

각 15 개의 게시물에 3 개의 카테고리가 있으며 각 카테고리에 대해 5 개의 첫 번째 게시물 만 가져 오는 DB에 한 번의 쿼리를하고 싶습니다. 어떻게 할 수 있습니까?

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

가능하지 않은 경우 상위 카테고리의 모든 게시물을 가져 와서 반복하거나 3 개의 다른 쿼리를 작성하는 것이 더 효율적인 이유는 무엇입니까?


주문 방법은 무엇입니까?
— MikeSchinkel

최근에 출판 .. 카테고리 A의 가장 최근 5 개, 카테고리 B의 가장 최근 것들 등
— Amit

좋아요, 아래 답변을보십시오
— MikeSchinkel

답변:


16

당신이 원하는 것은 가능하지만 가능할 때마다 피하고 싶은 SQL 을 파헤쳐 야 할 것입니다. 향후 잠재적 인 데이터베이스 구조 변경과 관련된 향후 호환성 문제를 최소화합니다.)

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 API를 사용하는 다른 옵션이 있습니까?

캐싱에 과도 API를 사용하는 것이 더 낫습니까?

귀하의 게시물이 자주 변경되지 않는다고 가정합니다. 3 개의 쿼리 적중을 주기적으로 수락 한 후 Transients API를 사용하여 결과를 캐시하면 어떻게 되나요? 유지 관리 가능한 코드와 뛰어난 성능을 얻을 수 있습니다. UNIONWordPress는 게시물 목록을 wp_options테이블의 한 레코드에 직렬화 된 배열로 저장하기 때문에 위 의 쿼리 보다 훨씬 좋습니다 .

다음 예제를 사용하여 test.php이를 테스트하기 위해 웹 사이트의 루트에 놓을 수 있습니다 .

<?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
과도 현상을 통한 캐싱은 사이트에 미치는 영향을 줄이는 좋은 방법입니다.
— hakre

1
@Transients 사용에 대한 좋은 아이디어.
— Chris_O

@ 마이크, 내가 당신의 대륙에 살고 있다면 나는 당신과 함께 수업을 들었을 것입니다! 다시 감사합니다!
— Amit

@Amit : LOL! :-)
— MikeSchinkel

1
과도를 무한정 저장 한 다음 save_post에서 플러시 할 수 있습니까? 좋은 예는 사본에서 (사용 edit_term 후크)있다
— helgatheviking

1

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 개의 게시물이 포함됩니다.


그게 db에 맞지 않습니까? 나는 당신이 1 명중 원인으로 그것을 할 수 있는지 알고 싶었습니다. 더 효율적이라고 생각했습니다.
— Amit

그게 db의 목적입니다. 데이터를 쿼리하십시오. db는 그런 것들을 위해 만들어졌습니다. 아마도 복잡한 SQL 쿼리를 실행하는 것보다 빠를 것입니다. 물건을 사용하는 것을 두려워하지 마십시오. 사이트가 고장난 경우 여기에보고하십시오.
— hakre

php.mysql / db의 효율성에 대해 잘 모릅니다 (더 읽기를 원할 것입니다).
— Amit

1
사실, 일반적으로 더 많을수록 더 적습니다. 그러나 먼저 시도하고 테스트하십시오. 소프트웨어가 "더 나빠질수록"최적화 가능성이 높아집니다. 결국 더 나은 소프트웨어를 더 빨리 작성하고 더 빠른 소프트웨어를 더 잘 작성할 수 있기 때문에 더 잘 배울 수 있습니다.
— hakre

0

단일 쿼리에서 각 범주에 대해 처음 다섯 개의 게시물을 얻는 방법을 모르겠습니다. 45 개의 게시물 만있는 경우 데이터베이스를 한 번 두드리고 각 범주에 대해 5 개의 게시물을 얻는 것이 가장 효율적인 방법 일 것입니다. 데이터베이스를 세 번 치고 결과를 결합하는 것은 나쁘지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.