Satu permintaan
Pikirkan hal ini sedikit lebih dan ada kemungkinan Anda bisa pergi dengan satu / permintaan utama. Atau dengan kata lain: Tidak perlu dua kueri tambahan saat Anda bisa bekerja dengan yang default. Dan jika Anda tidak dapat bekerja dengan yang default, Anda tidak akan membutuhkan lebih dari satu permintaan, tidak peduli berapa banyak loop yang ingin Anda pisahkan.
Prasyarat
Pertama, Anda perlu mengatur (seperti yang ditunjukkan dalam jawaban saya yang lain) nilai yang dibutuhkan di dalam pre_get_posts
filter. Di sana Anda mungkin akan mengatur posts_per_page
dan cat
. Contoh tanpa 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 ) );
Membangun basis
Hal berikutnya yang kami butuhkan adalah plugin khusus berukuran kecil (atau masukkan saja ke functions.php
file Anda jika Anda tidak keberatan memindahkannya selama pembaruan atau perubahan tema):
<?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 ini melakukan satu hal: Menggunakan PHP SPL (Perpustakaan PHP Standar) dan Antarmuka dan Iterator-nya. Apa yang sekarang kami dapatkan adalah FilterIterator
yang memungkinkan kami untuk dengan mudah menghapus item dari loop kami. Ini memperluas PHP SPL Filter Iterator sehingga kita tidak perlu mengatur semuanya. Kode ini dikomentari dengan baik, tetapi ada beberapa catatan:
- The
accept()
Metode memungkinkan untuk menentukan kriteria yang memungkinkan perulangan item - atau tidak.
- Di dalam metode itu kami gunakan
WP_Query::the_post()
, jadi Anda bisa menggunakan setiap tag templat di loop file templat Anda.
- Dan kami juga memonitor loop dan memundurkan posting ketika kami mencapai item terakhir. Ini memungkinkan untuk mengulang melalui jumlah loop yang tak terbatas tanpa mengatur ulang kueri kami.
- Ada satu metode kustom yang bukan bagian dari
FilterIterator
spesifikasi: deny()
. Metode ini sangat nyaman karena hanya berisi "proses atau tidak" pernyataan kami dan kami dapat dengan mudah menimpanya di kelas berikutnya tanpa perlu tahu apa pun selain dari tag template WordPress.
Bagaimana cara mengulang?
Dengan Iterator baru ini, kita tidak perlu if ( $customQuery->have_posts() )
dan while ( $customQuery->have_posts() )
lagi. Kita dapat pergi dengan foreach
pernyataan sederhana karena semua pemeriksaan yang diperlukan sudah dilakukan untuk kita. Contoh:
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 );
Akhirnya kita membutuhkan tidak lebih dari foreach
loop default . Kami bahkan dapat menjatuhkan the_post()
dan masih menggunakan semua tag templat. $post
Objek global akan selalu tetap sinkron.
foreach ( $primaryQuery as $post )
{
var_dump( get_the_ID() );
}
Loop anak perusahaan
Sekarang yang menyenangkan adalah bahwa setiap filter kueri selanjutnya cukup mudah ditangani: Cukup tentukan deny()
metode dan Anda siap untuk melanjutkan ke loop berikutnya. $this->current()
akan selalu menunjuk ke pos kami yang sekarang di-loop.
class NoThumbnailFilter extends ThumbnailFilter
{
public function deny()
{
return has_post_thumbnail( $this->current()->ID );
}
}
Seperti yang telah kami definisikan bahwa sekarang kami deny()
memutarkan setiap posting yang memiliki thumbnail, kami kemudian dapat secara otomatis mengulang semua posting tanpa thumbnail:
foreach ( $secondaryQuery as $post )
{
var_dump( get_the_title( get_the_ID() ) );
}
Menguji.
Plugin tes berikut tersedia sebagai Gist di GitHub. Cukup unggah dan aktifkan. Ini output / kesedihan ID dari setiap posting diulang sebagai callback pada loop_start
tindakan. Ini berarti bahwa mungkin mendapatkan sedikit keluaran tergantung pada pengaturan Anda, jumlah posting dan konfigurasi. Harap tambahkan beberapa pernyataan batalkan dan ubah huruf var_dump()
s di bagian akhir menjadi apa yang ingin Anda lihat dan di mana Anda ingin melihatnya. Itu hanya bukti konsep.