Una sola consulta
Pensé en esto un poco más y existe la posibilidad de que pueda ir con una sola / la consulta principal. O en otras palabras: no es necesario realizar dos consultas adicionales cuando puede trabajar con la predeterminada. Y en caso de que no pueda trabajar con una predeterminada, no necesitará más de una consulta, sin importar cuántos bucles desee dividir la consulta.
Prerrequisitos
Primero debe establecer (como se muestra en mi otra respuesta) los valores necesarios dentro de un pre_get_posts
filtro. Allí probablemente establecerás posts_per_page
y cat
. Ejemplo sin el pre_get_posts
-Filtro:
$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 ) );
Construyendo una base
Lo siguiente que necesitamos es un pequeño complemento personalizado (o simplemente póngalo en su functions.php
archivo si no le importa moverlo durante las actualizaciones o cambios 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 complemento hace una cosa: utiliza PHP SPL (Biblioteca PHP estándar) y sus interfaces e iteradores. Lo que ahora tenemos es un FilterIterator
que nos permite eliminar convenientemente elementos de nuestro bucle. Extiende el iterador de filtro PHP SPL para que no tengamos que configurar todo. El código está bien comentado, pero aquí hay algunas notas:
- El
accept()
método permite definir criterios que permiten recorrer el ítem, o no.
- Dentro de ese método que usamos
WP_Query::the_post()
, puede simplemente usar cada etiqueta de plantilla en su bucle de archivos de plantilla.
- Y también estamos monitoreando el ciclo y rebobinando las publicaciones cuando llegamos al último elemento. Esto permite recorrer una cantidad infinita de bucles sin restablecer nuestra consulta.
- Hay un método personalizado que no es parte de las
FilterIterator
especificaciones: deny()
. Este método es especialmente conveniente ya que contiene solo nuestra declaración "proceso o no" y podemos sobrescribirlo fácilmente en clases posteriores sin necesidad de saber nada aparte de las etiquetas de plantilla de WordPress.
¿Cómo hacer un bucle?
Con este nuevo iterador, que no necesitamos if ( $customQuery->have_posts() )
y while ( $customQuery->have_posts() )
más. Podemos ir con una foreach
declaración simple ya que todas las verificaciones necesarias ya están hechas para nosotros. Ejemplo:
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, no necesitamos nada más que un foreach
bucle predeterminado . Incluso podemos soltar the_post()
y seguir usando todas las etiquetas de plantilla. El $post
objeto global siempre permanecerá sincronizado.
foreach ( $primaryQuery as $post )
{
var_dump( get_the_ID() );
}
Bucles subsidiarios
Ahora lo bueno es que cada filtro de consulta posterior es bastante fácil de manejar: simplemente defina el deny()
método y estará listo para su próximo ciclo. $this->current()
siempre apuntará a nuestra publicación en bucle actual.
class NoThumbnailFilter extends ThumbnailFilter
{
public function deny()
{
return has_post_thumbnail( $this->current()->ID );
}
}
Como definimos que ahora hacemos un deny()
bucle en cada publicación que tiene una miniatura, podemos instantáneamente hacer un bucle en todas las publicaciones sin una miniatura:
foreach ( $secondaryQuery as $post )
{
var_dump( get_the_title( get_the_ID() ) );
}
Pruébalo.
El siguiente complemento de prueba está disponible como Gist en GitHub. Simplemente cárguelo y actívelo. Produce / vuelca la ID de cada publicación en bucle como devolución de llamada en la loop_start
acción. Esto significa que podría obtener bastante salida dependiendo de su configuración, número de publicaciones y configuración. Agregue algunas declaraciones de cancelación y modifique el var_dump()
s al final de lo que desea ver y dónde desea verlo. Es solo una prueba de concepto.