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?


10

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?


Làm thế nào để bạn muốn chúng được đặt hàng?
MikeSchinkel

được xuất bản gần đây .. vì vậy gần đây nhất là 5 loại A, gần đây nhất là loại B, v.v.
Amit

Được rồi, xem câu trả lời của tôi dưới đây
MikeSchinkel

Câu trả lời:


16

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ì trong 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 một UNIONtoán tử là một khả năng

Để sử dụng SQL những gì bạn cần là một UNIONnhà điều hành trong truy vấn của bạn, một cái gì đó như thế này giả sử sên loại của bạn "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 posts_joinBộ lọc

Sử dụng ở trên, bạn có thể thực hiện cuộc gọi trực tiếp hoặc bạn có thể sử dụng posts_joinmóc lọc như sau; lưu ý Tôi đang sử dụng một heredoc PHP vì vậy hãy chắc chắn rằng SQL;nó đang bị bỏ lạ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 trong một plugin hoặc trong functions.phptệp chủ đề của bạn :

<?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, sử dụng các móc sửa đổi truy vấn như posts_joinluôn luôn mời các hiệu ứng phụ trong đó chúng tác động toàn cầu lên các truy vấn và do đó bạn thường cần phải sửa đổi các sửa đổi của mình trong một ifchỉ sử dụng nó khi cần thiết 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à về tối ưu hóa hơn là có thể 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 API Transents ? 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 UNIONtruy vấn ở 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 wp_optionsbảng.

Bạn có thể lấy ví dụ sau và thả vào thư mục gốc của trang web 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 UNIONtruy vấn SQL và posts_joinhook bộ lọc mà bạn có thể cung cấp tốt hơn bằng cách sử dụng bộ đệm ẩn với API Transents thay thế.

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


2
Bộ nhớ đệm thông qua quá độ là một điều tốt đẹp để giảm tác động trên trang web.
hakre

1
@Mike ý tưởng tuyệt vời về việc sử dụng Transents.
Chris_O

@ Giống như, nếu tôi sống ở lục địa của bạn, tôi sẽ tham gia các lớp học với bạn! cảm ơn lần nữa
Amit

@ Nhận: LOL! :-)
MikeSchinkel

1
bạn cũng có thể lưu tạm thời vô thời hạn và sau đó xóa nó trên save_post? có một ví dụ hay (sử dụng edit_term hook) trong codex
helgatheviking 27/212

1

WP_Query()không hỗ trợ thứ gì đó như First X For Each Cat . Thay vì WP_Query()bạn có thể sử dụng get_posts()trên 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 bây giờ chứa năm bài viết đầu tiên cho mỗi thể loại.


không phải là 3 lần truy cập vào db? Tôi muốn biết liệu bạn có thể làm điều đó trong 1 lần không vì tôi nghĩ nó hiệu quả hơn.
Amit

Vâng, đó là những gì db dành cho, phải không? truy vấn dữ liệu từ nó. db được tạo ra cho những thứ đó. nó có thể nhanh hơn sau đó chạy một truy vấn sql phức tạp mà bạn yêu cầu. đừng sợ sử dụng các công cụ. nếu nó phá vỡ trang web của bạn, báo cáo nó ở đây.
hakre

mm .. hiểu rồi, tôi không biết nhiều về hiệu quả của php / mysql / db (muốn đọc thêm), chắc chắn rằng ít lượt truy cập sẽ tốt hơn và sau đó tự phân tích kết quả.
Amit

1
tốt, đúng, nói chung là nhiều hơn và ít hơn là ít hơn. Nhưng hãy thử và kiểm tra trước. Phần mềm của bạn càng "tệ" thì càng có tiềm năng tối ưu hóa. Vì vậy, học tốt hơn bằng cách làm, bởi vì cuối cùng bạn sẽ viết phần mềm tốt hơn nhanh hơn và viết phần mềm nhanh hơn tốt hơn.
hakre

0

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 chưa bao giờ 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.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.