单个查询
再多考虑一下,您就有可能进行单个/主查询。换句话说:当您可以使用默认查询时,不需要另外两个查询。而且,如果您无法使用默认查询,则无论您想拆分查询多少个循环,都不需要一个查询。
先决条件
首先,您需要在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;
}
}
这个插件做一件事:它利用了PHP SPL(标准PHP库)及其接口和迭代器。现在我们得到的是一个FilterIterator
允许我们方便地从循环中删除项目的对象。它扩展了PHP SPL筛选器迭代器,因此我们无需设置所有内容。该代码的注释很好,但是这里有一些注意事项:
- 该
accept()
方法允许定义允许循环或不允许循环的条件。
- 在该方法内,我们使用
WP_Query::the_post()
,因此您可以简单地使用模板文件循环中的每个模板标记。
- 当到达最后一个项目时,我们还监视循环并回绕帖子。这允许循环通过无数个循环,而无需重置查询。
- 有一种自定义方法不属于
FilterIterator
规范:deny()
。这种方法特别方便,因为它仅包含“ process or not”语句,并且我们可以在以后的类中轻松覆盖它,而无需了解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,以使其符合您的期望以及在何处可以看到。这只是概念的证明。