Eine einzelne Abfrage
Ich habe ein bisschen mehr darüber nachgedacht und es besteht die Möglichkeit, dass Sie mit einer einzelnen / der Hauptabfrage arbeiten können. Oder mit anderen Worten: Sie benötigen keine zwei zusätzlichen Abfragen, wenn Sie mit der Standardabfrage arbeiten können. Und falls Sie nicht mit einer Standardabfrage arbeiten können, benötigen Sie nicht mehr als eine einzelne Abfrage, unabhängig davon, wie viele Schleifen Sie die Abfrage aufteilen möchten.
Voraussetzungen
Zuerst müssen Sie (wie in meiner anderen Antwort gezeigt) die erforderlichen Werte in einem pre_get_posts
Filter festlegen . Dort wirst du wahrscheinlich setzen posts_per_page
und cat
. Beispiel ohne den 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 ) );
Eine Basis bauen
Das nächste, was wir brauchen, ist ein kleines benutzerdefiniertes Plugin (oder functions.php
fügen Sie es einfach in Ihre Datei ein, wenn es Ihnen nichts ausmacht, es während Updates oder Themenänderungen zu verschieben):
<?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;
}
}
Dieses Plugin macht eines: Es verwendet die PHP SPL (Standard PHP Library) und ihre Schnittstellen und Iteratoren. Was wir jetzt haben, ist ein FilterIterator
, mit dem wir bequem Gegenstände aus unserer Schleife entfernen können. Es erweitert den PHP SPL Filter Iterator, sodass wir nicht alles einstellen müssen. Der Code ist gut kommentiert, aber hier sind einige Hinweise:
- Mit dieser
accept()
Methode können Kriterien definiert werden, die das Durchlaufen des Elements ermöglichen - oder auch nicht.
- Innerhalb dieser Methode verwenden wir
WP_Query::the_post()
, sodass Sie einfach jedes Vorlagen-Tag in Ihrer Vorlagendateischleife verwenden können.
- Außerdem überwachen wir die Schleife und spulen die Beiträge zurück, wenn wir das letzte Element erreichen. Dies ermöglicht es, eine unendliche Anzahl von Schleifen zu durchlaufen, ohne unsere Abfrage zurückzusetzen.
- Es gibt eine benutzerdefinierte Methode, die nicht Teil der
FilterIterator
Spezifikationen ist : deny()
. Diese Methode ist besonders praktisch, da sie nur unsere "Prozess oder nicht" -Statement enthält und wir sie in späteren Klassen leicht überschreiben können, ohne etwas anderes als WordPress-Vorlagen-Tags wissen zu müssen.
Wie schleife ich?
Mit diesem neuen Iterator brauchen wir if ( $customQuery->have_posts() )
und while ( $customQuery->have_posts() )
nicht mehr. Wir können mit einer einfachen foreach
Aussage gehen, da alle erforderlichen Prüfungen bereits für uns durchgeführt wurden. Beispiel:
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 );
Schließlich brauchen wir nichts weiter als eine Standardschleife foreach
. Wir können sogar the_post()
alle Vorlagen-Tags löschen und trotzdem verwenden. Das globale $post
Objekt bleibt immer synchron.
foreach ( $primaryQuery as $post )
{
var_dump( get_the_ID() );
}
Nebenschleifen
Das Schöne ist nun, dass jeder spätere Abfragefilter ganz einfach zu handhaben ist: Definieren deny()
Sie einfach die Methode und schon können Sie mit der nächsten Schleife beginnen. $this->current()
wird immer auf unseren aktuell geloopten Beitrag verweisen.
class NoThumbnailFilter extends ThumbnailFilter
{
public function deny()
{
return has_post_thumbnail( $this->current()->ID );
}
}
Da wir definiert haben, dass wir jetzt deny()
jeden Beitrag mit einer Miniaturansicht schleifen, können wir sofort alle Beiträge ohne Miniaturansicht schleifen:
foreach ( $secondaryQuery as $post )
{
var_dump( get_the_title( get_the_ID() ) );
}
Probier es aus.
Das folgende Test-Plugin ist als Gist auf GitHub verfügbar. Einfach hochladen und aktivieren. Es gibt die ID jedes geloopten Posts als Rückruf für die loop_start
Aktion aus / gibt sie aus. Dies bedeutet, dass abhängig von Ihrem Setup, der Anzahl der Beiträge und der Konfiguration möglicherweise einiges ausgegeben wird. Bitte fügen Sie einige Abbruchanweisungen hinzu und ändern Sie das var_dump()
s am Ende so, wie Sie es sehen möchten und wo Sie es sehen möchten. Es ist nur ein Proof of Concept.