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.