単一のクエリ
これについてもう少し考えてみてください。単一またはメインのクエリで実行できる可能性があります。または言い換えると、デフォルトのクエリで作業できる場合、追加の2つのクエリは必要ありません。また、デフォルトのクエリを使用できない場合は、クエリを分割するループの数に関係なく、クエリは1つしか必要ありません。
前提条件
最初に、(他の回答で示されているように)pre_get_posts
フィルター内に必要な値を設定する必要があります。そこにあなたはおそらく設定posts_per_page
しcat
ます。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 ) );
基地の建設
次に必要なのは、小さなカスタムプラグインです(またはfunctions.php
、更新やテーマの変更中に移動してもかまわない場合は、ファイルに挿入します)。
<?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;
}
}
このプラグインは1つのことを行います。それは、PHP SPL(標準PHPライブラリー)とそのインターフェースおよびイテレーターを利用します。これでFilterIterator
、ループからアイテムを簡単に削除できるようになりました。PHP SPL Filter Iteratorを拡張するため、すべてを設定する必要はありません。コードはよくコメントされていますが、ここにいくつかのメモがあります:
- この
accept()
メソッドでは、アイテムのループを許可する基準を定義できます。
- そのメソッド内ではを使用
WP_Query::the_post()
しているため、テンプレートファイルループ内のすべてのテンプレートタグを使用できます。
- また、ループを監視し、最後のアイテムに到達したときに投稿を巻き戻します。これにより、クエリをリセットすることなく、無限ループをループできます。
FilterIterator
仕様に含まれていないカスタムメソッドが1つありますdeny()
。このメソッドは、「プロセスオアノット」ステートメントのみを含み、WordPressテンプレートタグ以外は何も知らなくても、後のクラスで簡単に上書きできるため、特に便利です。
ループするには?
この新しいイテレーターを使用するif ( $customQuery->have_posts() )
と、while ( $customQuery->have_posts() )
もう必要ありません。foreach
必要なすべてのチェックがすでに行われているため、簡単なステートメントで進むことができます。例:
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 );
最後に、デフォルトのforeach
ループだけが必要です。the_post()
すべてのテンプレートタグをドロップして使用することもできます。グローバル$post
オブジェクトは常に同期されます。
foreach ( $primaryQuery as $post )
{
var_dump( get_the_ID() );
}
補助ループ
これでいいのは、後のクエリフィルターの処理が非常に簡単になるdeny()
ことです。メソッドを定義するだけで、次のループに進む準備が整います。$this->current()
常に現在ループしている投稿をポイントします。
class NoThumbnailFilter extends ThumbnailFilter
{
public function deny()
{
return has_post_thumbnail( $this->current()->ID );
}
}
deny()
サムネイルのあるすべての投稿をループするように定義したので、サムネイルのないすべての投稿を即座にループできます。
foreach ( $secondaryQuery as $post )
{
var_dump( get_the_title( get_the_ID() ) );
}
試して。
次のテストプラグインはGitHubのGistとして入手できます。アップロードしてアクティブ化するだけです。ループされたすべての投稿のIDをloop_start
アクションのコールバックとして出力/ダンプします。つまり、設定、投稿の数、設定によっては、かなりの出力が得られる可能性があります。いくつかの中止ステートメントを追加var_dump()
し、最後のsを、見たいものと見たい場所に変更してください。これは単なる概念実証です。