一个单独的查询
再仔细考虑一下,就有可能使用一个单独的/主查询。或者换句话说:当您可以使用默认查询时,不需要另外两个查询。如果无法使用默认查询,则无论要拆分多少个循环,都只需要一个查询。
先决条件
首先,您需要在
pre_get_posts
滤器你很可能就在这里
posts_per_page
和
cat
. 示例中没有
pre_get_posts
-过滤器:
$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 (Standard PHP Library) 及其接口和迭代器。我们现在得到的是
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() ) );
}
对其进行测试以下内容
test plugin 作为GitHub上的Gist提供。只需上传并激活即可。它将每个循环帖子的ID作为回调输出/转储到
loop_start
行动这意味着根据您的设置、帖子数量和配置,可能会得到相当多的输出。请添加一些中止语句并更改
var_dump()
在你想看的内容和你想看的地方的末尾。这只是概念的证明。