Uma única consulta
Pensei um pouco mais sobre isso e há uma chance de você ir com uma única consulta / a principal. Ou, em outras palavras: Não há necessidade de duas consultas adicionais quando você pode trabalhar com a padrão. E, caso você não consiga trabalhar com uma padrão, não precisará de mais do que uma única consulta, independentemente de quantos ciclos desejar dividir.
Pré-requisitos
Primeiro, você precisa definir (como mostrado na minha outra resposta) os valores necessários dentro de um pre_get_posts
filtro. Lá você provavelmente definirá posts_per_page
e cat
. Exemplo sem o 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 ) );
Construindo uma base
A próxima coisa que precisamos é de um pequeno plug-in personalizado (ou apenas o coloque no seu functions.php
arquivo, se você não se importar em movê-lo durante atualizações ou alterações de 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;
}
}
Este plugin faz uma coisa: utiliza o PHP SPL (Standard PHP Library) e suas interfaces e iteradores. O que temos agora é um FilterIterator
que nos permite remover convenientemente itens do nosso loop. Ele estende o Iterador de Filtro PHP SPL para que não tenhamos que definir tudo. O código está bem comentado, mas aqui estão algumas notas:
- O
accept()
método permite definir critérios que permitem o loop do item - ou não.
- Dentro desse método que usamos
WP_Query::the_post()
, você pode simplesmente usar todas as tags de modelo no loop de arquivos de modelo.
- E também estamos monitorando o loop e rebobinando as postagens quando atingimos o último item. Isso permite percorrer uma quantidade infinita de loops sem redefinir nossa consulta.
- Há um método personalizado que não faz parte das
FilterIterator
especificações: deny()
. Esse método é especialmente conveniente, pois contém apenas nossa declaração de "processo ou não" e podemos substituí-lo facilmente em classes posteriores sem precisar saber nada além das tags de modelo do WordPress.
Como fazer um loop?
Com esta nova Iterator, nós não precisamos if ( $customQuery->have_posts() )
e while ( $customQuery->have_posts() )
mais. Podemos usar uma foreach
declaração simples , pois todas as verificações necessárias já foram feitas para nós. Exemplo:
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 );
Finalmente, não precisamos de nada além de um foreach
loop padrão . Podemos até soltar the_post()
e ainda usar todas as tags de modelo. O $post
objeto global sempre permanecerá sincronizado.
foreach ( $primaryQuery as $post )
{
var_dump( get_the_ID() );
}
Loops subsidiários
Agora, o mais interessante é que todo filtro de consulta posterior é bastante fácil de manipular: basta definir o deny()
método e você estará pronto para o próximo ciclo. $this->current()
sempre apontará para nossa postagem em loop no momento.
class NoThumbnailFilter extends ThumbnailFilter
{
public function deny()
{
return has_post_thumbnail( $this->current()->ID );
}
}
Como definimos que agora fazemos o deny()
loop de todas as postagens que têm uma miniatura, podemos fazer um loop instantâneo de todas as postagens sem uma miniatura:
foreach ( $secondaryQuery as $post )
{
var_dump( get_the_title( get_the_ID() ) );
}
Teste-o.
O seguinte plugin de teste está disponível como Gist no GitHub. Basta fazer o upload e ativá-lo. Ele gera / despeja o ID de cada postagem em loop como retorno de chamada na loop_start
ação. Isso significa que você pode obter um pouco de saída, dependendo da sua instalação, número de posts e configuração. Por favor, adicione algumas instruções de cancelamento e altere os var_dump()
s no final do que você deseja ver e onde deseja vê-lo. É apenas uma prova de conceito.