Một truy vấn duy nhất
Nghĩ về điều này nhiều hơn một chút và có một cơ hội mà bạn có thể đi với một truy vấn duy nhất / chính. Hay nói cách khác: Không cần hai truy vấn bổ sung khi bạn có thể làm việc với truy vấn mặc định. Và trong trường hợp bạn không thể làm việc với một mặc định, bạn sẽ không cần nhiều hơn một truy vấn duy nhất cho dù bạn muốn chia bao nhiêu vòng truy vấn.
Điều kiện tiên quyết
Trước tiên, bạn cần đặt (như thể hiện trong câu trả lời khác của tôi) các giá trị cần thiết bên trong pre_get_posts
bộ lọc. Có khả năng bạn sẽ thiết lập posts_per_page
và cat
. Ví dụ không có pre_get_posts
-Filter:
$catID = 1;
$catQuery = new WP_Query( array(
'posts_per_page' => -1,
'cat' => $catID,
) );
// Add a headline:
printf( '<h1>%s</h1>', number_format_i18n( $catQuery->found_posts )
.__( " Posts filed under ", 'YourTextdomain' )
.get_cat_name( $catID ) );
Xây dựng căn cứ
Điều tiếp theo chúng tôi cần là một plugin tùy chỉnh nhỏ (hoặc chỉ đưa nó vào functions.php
tệp của bạn nếu bạn không ngại di chuyển nó trong khi cập nhật hoặc thay đổi chủ đề):
<?php
/**
* Plugin Name: (#130009) Merge Two Queries
* Description: "Merges" two queries by using a <code>RecursiveFilterIterator</code> to divide one main query into two queries
* Plugin URl: http://wordpress.stackexchange.com/questions/130009/how-to-merge-two-queries-together
*/
class ThumbnailFilter extends FilterIterator implements Countable
{
private $wp_query;
private $allowed;
private $counter = 0;
public function __construct( Iterator $iterator, WP_Query $wp_query )
{
NULL === $this->wp_query AND $this->wp_query = $wp_query;
// Save some processing time by saving it once
NULL === $this->allowed
AND $this->allowed = $this->wp_query->have_posts();
parent::__construct( $iterator );
}
public function accept()
{
if (
! $this->allowed
OR ! $this->current() instanceof WP_Post
)
return FALSE;
// Switch index, Setup post data, etc.
$this->wp_query->the_post();
// Last WP_Post reached: Setup WP_Query for next loop
$this->wp_query->current_post === $this->wp_query->query_vars['posts_per_page'] -1
AND $this->wp_query->rewind_posts();
// Doesn't meet criteria? Abort.
if ( $this->deny() )
return FALSE;
$this->counter++;
return TRUE;
}
public function deny()
{
return ! has_post_thumbnail( $this->current()->ID );
}
public function count()
{
return $this->counter;
}
}
Plugin này thực hiện một điều: Nó sử dụng PHP SPL (Thư viện PHP chuẩn) và các Giao diện và Trình lặp của nó. Những gì chúng ta có bây giờ là một FilterIterator
thứ cho phép chúng ta thuận tiện loại bỏ các mục khỏi vòng lặp của chúng ta. Nó mở rộng Bộ lặp Bộ lọc SPL PHP để chúng ta không phải thiết lập mọi thứ. Mã được nhận xét tốt, nhưng đây là một số lưu ý:
- Các
accept()
phương pháp cho phép xác định tiêu chí cho phép lặp mục - hay không.
- Bên trong phương pháp đó chúng tôi sử dụng
WP_Query::the_post()
, vì vậy bạn chỉ cần sử dụng mọi thẻ mẫu trong vòng lặp tệp mẫu của mình.
- Và chúng tôi cũng đang theo dõi vòng lặp và tua lại các bài đăng khi chúng tôi đến mục cuối cùng. Điều này cho phép lặp lại một số lượng vòng lặp vô hạn mà không cần đặt lại truy vấn của chúng tôi.
- Có một phương pháp tùy chỉnh không phải là một phần của
FilterIterator
thông số kỹ thuật : deny()
. Phương pháp này đặc biệt thuận tiện vì nó chỉ chứa "quá trình hoặc không" của chúng tôi và chúng tôi có thể dễ dàng ghi đè lên nó trong các lớp sau mà không cần biết gì ngoài các thẻ mẫu WordPress.
Làm thế nào để lặp?
Với Iterator mới này, chúng ta không cần if ( $customQuery->have_posts() )
và while ( $customQuery->have_posts() )
nữa. Chúng tôi có thể đi với một foreach
tuyên bố đơn giản vì tất cả các kiểm tra cần thiết đã được thực hiện cho chúng tôi. Thí dụ:
global $wp_query;
// First we need an ArrayObject made out of the actual posts
$arrayObj = new ArrayObject( $wp_query->get_posts() );
// Then we need to throw it into our new custom Filter Iterator
// We pass the $wp_query object in as second argument to keep track with it
$primaryQuery = new ThumbnailFilter( $arrayObj->getIterator(), $wp_query );
Cuối cùng, chúng ta không cần gì hơn một foreach
vòng lặp mặc định . Chúng tôi thậm chí có thể thả the_post()
và vẫn sử dụng tất cả các thẻ mẫu. Các $post
đối tượng toàn cầu sẽ luôn luôn đồng bộ.
foreach ( $primaryQuery as $post )
{
var_dump( get_the_ID() );
}
Các công ty con
Bây giờ, điều tuyệt vời là mọi bộ lọc truy vấn sau này khá dễ xử lý: Chỉ cần xác định deny()
phương thức và bạn đã sẵn sàng cho vòng lặp tiếp theo của mình. $this->current()
sẽ luôn luôn trỏ đến bài viết hiện đang lặp của chúng tôi.
class NoThumbnailFilter extends ThumbnailFilter
{
public function deny()
{
return has_post_thumbnail( $this->current()->ID );
}
}
Như chúng tôi đã xác định rằng bây giờ chúng tôi deny()
lặp mỗi bài đăng có hình thu nhỏ, sau đó chúng tôi có thể lập tức lặp lại tất cả các bài đăng mà không cần hình thu nhỏ:
foreach ( $secondaryQuery as $post )
{
var_dump( get_the_title( get_the_ID() ) );
}
Kiểm tra nó
Plugin kiểm tra sau đây có sẵn dưới dạng Gist trên GitHub. Đơn giản chỉ cần tải lên và kích hoạt nó. Nó xuất / bỏ ID của mỗi bài đăng được lặp lại dưới dạng gọi lại trên loop_start
hành động. Điều này có nghĩa là có thể nhận được đầu ra khá ít tùy thuộc vào thiết lập, số lượng bài đăng và cấu hình của bạn. Vui lòng thêm một số tuyên bố hủy bỏ và thay đổi var_dump()
s ở cuối thành những gì bạn muốn xem và nơi bạn muốn xem nó. Nó chỉ là một bằng chứng về khái niệm.