it-swarm-vi.tech

Sử dụng WP_Query để truy vấn nhiều danh mục với số lượng bài viết giới hạn cho mỗi danh mục?

Tôi có 3 danh mục với mỗi 15 bài đăng, tôi muốn thực hiện MỘT truy vấn tới db chỉ mang lại 5 bài đăng đầu tiên cho mỗi danh mục, tôi phải làm thế nào?

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

Trong trường hợp không thể, điều gì hiệu quả hơn, nhận tất cả các bài đăng cho danh mục chính và lặp qua chúng hoặc tạo 3 truy vấn khác nhau?

10
Amit

Những gì bạn muốn là có thể nhưng sẽ yêu cầu bạn đào sâu vào SQL mà tôi muốn tránh bất cứ khi nào có thể (không phải vì tôi không biết, tôi là nhà phát triển SQL nâng cao, nhưng vì in WordPress bạn muốn sử dụng API bất cứ khi nào có thể để giảm thiểu các vấn đề tương thích trong tương lai liên quan đến thay đổi cấu trúc cơ sở dữ liệu tiềm năng trong tương lai.)

SQL với toán tử UNION là một khả năng

Để sử dụng SQL, thứ bạn cần là toán tử UNION trong truy vấn của bạn, một cái gì đó giống như giả sử các sên danh mục của bạn là "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
)

Bạn có thể sử dụng SQL UNION với Bộ lọc posts_join

Sử dụng ở trên, bạn có thể chỉ cần thực hiện cuộc gọi trực tiếp hoặc bạn có thể sử dụng móc lọc posts_joinnhư sau; lưu ý Tôi đang sử dụng a PHP heredoc vì vậy hãy chắc chắn SQL; bị trượt sang trái. Cũng lưu ý rằng tôi đã sử dụng một var toàn cục để cho phép bạn xác định các danh mục bên ngoài hook bằng cách liệt kê các sên danh mục trong một mảng. Bạn có thể đặt mã này vào một plugin hoặc trong tệp functions.php của chủ đề:

<?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 " ;
}

Nhưng có thể có tác dụng phụ

Tất nhiên, bằng cách sử dụng các móc sửa đổi truy vấn như posts_join luôn mời các hiệu ứng phụ trong đó chúng hành động toàn cầu đối với các truy vấn và do đó bạn thường cần bọc các sửa đổi của mình trong một if chỉ sử dụng nó khi cần và tiêu chí nào để kiểm tra có thể khó khăn.

Tập trung vào tối ưu hóa thay thế?

Tuy nhiên, tôi cho rằng câu hỏi của bạn quan tâm là nhiều hơn về tối ưu hóa hơn là về khả năng thực hiện truy vấn 5 lần 3 hàng đầu, phải không? Nếu đó là trường hợp thì có lẽ có các tùy chọn khác sử dụng API WordPress?

Sử dụng API tạm thời tốt hơn cho bộ nhớ đệm?

Tôi cho rằng bài viết của bạn sẽ không thay đổi thường xuyên, đúng không? Điều gì xảy ra nếu bạn chấp nhận ba (3) truy vấn được truy cập định kỳ và sau đó lưu trữ kết quả bằng cách sử dụng API khách hàng ? Bạn sẽ nhận được mã duy trì và hiệu suất tuyệt vời; tốt hơn một chút so với truy vấn UNION ở trên vì WordPress sẽ lưu trữ danh sách các bài đăng dưới dạng một mảng được tuần tự hóa trong một bản ghi của bảng wp_options.

Bạn có thể lấy ví dụ sau và thả vào thư mục gốc của trang web của bạn dưới dạng test.php để kiểm tra điều này:

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

Tóm lược

Mặc dù có, bạn có thể thực hiện những gì bạn đã yêu cầu khi sử dụng truy vấn SQL UNION và hook bộ lọc posts_join, bạn có thể cung cấp tốt hơn bằng cách sử dụng bộ đệm ẩn vớiAPI tạm thờithay vào đó.

Hi vọng điêu nay co ich?

15
MikeSchinkel

WP_Query() không hỗ trợ một cái gì đó như Đầu tiên X cho mỗi con mèo . Thay vì WP_Query(), bạn có thể sử dụng get_posts() cho mỗi danh mục của mình, có thể nói ba lần:

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

$posts hiện chứa năm bài đăng đầu tiên cho mỗi danh mục.

1
hakre

Tôi không biết cách nào để có được năm bài đăng đầu tiên cho mỗi danh mục trong một truy vấn duy nhất. Nếu bạn đã từng chỉ có 45 bài đăng, thì hãy nhấn cơ sở dữ liệu một lần và nhận năm bài đăng của bạn cho mỗi danh mục có lẽ là cách tiếp cận hiệu quả nhất. Đánh vào cơ sở dữ liệu ba lần và kết hợp các kết quả không phải là một điều xấu.

0
Bernard Chen