Das Problem
Standardmäßig verwendet WordPress in einem bestimmten Kontext die Hauptabfrage, um die Paginierung zu bestimmen. Das Hauptabfrageobjekt wird im $wp_query
globalen Objekt gespeichert , das auch zur Ausgabe der Hauptabfrageschleife verwendet wird:
if ( have_posts() ) : while ( have_posts() ) : the_post();
Wenn Sie eine benutzerdefinierte Abfrage verwenden , erstellen Sie ein völlig separates Abfrageobjekt:
$custom_query = new WP_Query( $custom_query_args );
Und diese Abfrage wird über eine völlig separate Schleife ausgegeben:
if ( $custom_query->have_posts() ) :
while ( $custom_query->have_posts() ) :
$custom_query->the_post();
Aber Paginierung Template - Tags, einschließlich previous_posts_link()
, next_posts_link()
, posts_nav_link()
, und paginate_links()
, stützen ihre Ausgabe auf dem Haupt-Abfrageobjekt , $wp_query
. Diese Hauptabfrage kann paginiert sein oder nicht. Wenn der aktuelle Kontext beispielsweise eine benutzerdefinierte Seitenvorlage ist, besteht das $wp_query
Hauptobjekt nur aus einem einzelnen Beitrag - dem der ID der Seite, der die benutzerdefinierte Seitenvorlage zugewiesen ist.
Wenn es sich bei dem aktuellen Kontext um einen Archivindex handelt, kann der Hauptindex $wp_query
aus genügend Beiträgen bestehen, um eine Paginierung zu verursachen. Dies führt zum nächsten Teil des Problems: Für das $wp_query
Hauptobjekt übergibt WordPress paged
der Abfrage einen Parameter auf der Grundlage der paged
URL-Abfragevariable. Wenn die Abfrage abgerufen wird, wird dieser paged
Parameter verwendet, um zu bestimmen, welche Gruppe von paginierten Posts zurückgegeben werden soll. Wenn auf einen angezeigten Paginierungslink geklickt und die nächste Seite geladen wird, kann Ihre benutzerdefinierte Abfrage nicht feststellen, ob sich die Paginierung geändert hat .
Die Lösung
Übergeben des richtigen Seitenparameters an die benutzerdefinierte Abfrage
Angenommen, die benutzerdefinierte Abfrage verwendet ein args-Array:
$custom_query_args = array(
// Custom query parameters go here
);
Sie müssen den richtigen paged
Parameter an das Array übergeben. Sie können dies tun , indem das Abrufen der URL - Abfragevariable verwendet , um die aktuelle Seite zu bestimmen, über get_query_var()
:
get_query_var( 'paged' );
Sie können diesen Parameter dann an Ihr benutzerdefiniertes query args-Array anhängen:
$custom_query_args['paged'] = get_query_var( 'paged' )
? get_query_var( 'paged' )
: 1;
Hinweis: Wenn Ihre Seite ist eine statische Titelseite , achten Sie darauf zu verwenden , page
anstatt paged
als eine statische Titelseite verwendet page
und nicht paged
. Dies ist, was Sie für eine statische Titelseite haben sollten
$custom_query_args['paged'] = get_query_var( 'page' )
? get_query_var( 'page' )
: 1;
Wenn die benutzerdefinierte Abfrage abgerufen wird, wird der richtige Satz von paginierten Beiträgen zurückgegeben.
Verwenden eines benutzerdefinierten Abfrageobjekts für Paginierungsfunktionen
Damit die Paginierungsfunktionen die richtige Ausgabe liefern - dh vorherige / nächste / Seitenlinks relativ zur benutzerdefinierten Abfrage - muss WordPress gezwungen werden, die benutzerdefinierte Abfrage zu erkennen. Dies erfordert einen kleinen "Hack": Ersetzen des $wp_query
Hauptobjekts durch das benutzerdefinierte Abfrageobjekt $custom_query
:
Hacken Sie das Hauptabfrageobjekt
- Sichern Sie das Hauptabfrageobjekt:
$temp_query = $wp_query
- Setzen Sie das Hauptabfrageobjekt auf Null:
$wp_query = NULL;
Tauschen Sie die benutzerdefinierte Abfrage in das Hauptabfrageobjekt aus: $wp_query = $custom_query;
$temp_query = $wp_query;
$wp_query = NULL;
$wp_query = $custom_query;
Dieser "Hack" muss durchgeführt werden, bevor Paginierungsfunktionen aufgerufen werden
Setzen Sie das Hauptabfrageobjekt zurück
Nachdem die Paginierungsfunktionen ausgegeben wurden, setzen Sie das Hauptabfrageobjekt zurück:
$wp_query = NULL;
$wp_query = $temp_query;
Korrekturen der Paginierungsfunktion
Die previous_posts_link()
Funktion arbeitet normal, unabhängig von der Paginierung. Sie ermittelt lediglich die aktuelle Seite und gibt dann den Link für aus page - 1
. Für next_posts_link()
die ordnungsgemäße Ausgabe ist jedoch ein Fix erforderlich . Dies liegt daran, dass next_posts_link()
der max_num_pages
Parameter verwendet wird:
<?php next_posts_link( $label , $max_pages ); ?>
Wie bei anderen Abfrageparametern wird die Funktion standardmäßig max_num_pages
für das $wp_query
Hauptobjekt verwendet. Um zu erzwingen next_posts_link()
, dass das $custom_query
Objekt berücksichtigt wird, müssen Sie das max_num_pages
an die Funktion übergeben. Sie können diesen Wert aus dem $custom_query
Objekt abrufen $custom_query->max_num_pages
:
<?php next_posts_link( 'Older Posts' , $custom_query->max_num_pages ); ?>
Alles zusammen
Das Folgende ist ein grundlegendes Konstrukt einer benutzerdefinierten Abfrageschleife mit ordnungsgemäß funktionierenden Paginierungsfunktionen:
// Define custom query parameters
$custom_query_args = array( /* Parameters go here */ );
// Get current page and append to custom query parameters array
$custom_query_args['paged'] = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
// Instantiate custom query
$custom_query = new WP_Query( $custom_query_args );
// Pagination fix
$temp_query = $wp_query;
$wp_query = NULL;
$wp_query = $custom_query;
// Output custom query loop
if ( $custom_query->have_posts() ) :
while ( $custom_query->have_posts() ) :
$custom_query->the_post();
// Loop output goes here
endwhile;
endif;
// Reset postdata
wp_reset_postdata();
// Custom query loop pagination
previous_posts_link( 'Older Posts' );
next_posts_link( 'Newer Posts', $custom_query->max_num_pages );
// Reset main query object
$wp_query = NULL;
$wp_query = $temp_query;
Nachtrag: Was ist damit query_posts()
?
query_posts()
für Sekundärschleifen
Wenn Sie query_posts()
eine benutzerdefinierte Schleife ausgeben, anstatt ein separates Objekt für die benutzerdefinierte Abfrage über zu instanziieren WP_Query()
, _doing_it_wrong()
treten mehrere Probleme auf (nicht zuletzt Paginierungsprobleme). Der erste Schritt zur Behebung dieser Probleme besteht darin, die missbräuchliche Verwendung von query_posts()
in einen ordnungsgemäßen WP_Query()
Anruf umzuwandeln .
Verwenden Sie, query_posts()
um die Hauptschleife zu ändern
Wenn Sie lediglich die Parameter für die Hauptschleifenabfrage ändern möchten, z. B. die Beiträge pro Seite ändern oder eine Kategorie ausschließen möchten, sind Sie möglicherweise versucht, diese zu verwenden query_posts()
. Aber du solltest es trotzdem nicht. Wenn Sie query_posts()
, Sie Wordpress zwingen, ersetzen das Hauptabfrageobjekt. (WordPress führt tatsächlich eine zweite Abfrage durch und überschreibt sie $wp_query
.) Das Problem ist jedoch, dass diese Ersetzung zu spät durchgeführt wird, um die Paginierung zu aktualisieren.
Die Lösung besteht darin , die Hauptabfrage zu filtern, bevor Beiträge über den pre_get_posts
Hook abgerufen werden .
Anstatt dies der Kategorie-Vorlagendatei ( category.php
) hinzuzufügen :
query_posts( array(
'posts_per_page' => 5
) );
Fügen Sie Folgendes hinzu zu functions.php
:
function wpse120407_pre_get_posts( $query ) {
// Test for category archive index
// and ensure that the query is the main query
// and not a secondary query (such as a nav menu
// or recent posts widget output, etc.
if ( is_category() && $query->is_main_query() ) {
// Modify posts per page
$query->set( 'posts_per_page', 5 );
}
}
add_action( 'pre_get_posts', 'wpse120407_pre_get_posts' );
Anstatt dies zur Index-Vorlagendatei für Blog-Posts hinzuzufügen ( home.php
):
query_posts( array(
'cat' => '-5'
) );
Fügen Sie Folgendes hinzu zu functions.php
:
function wpse120407_pre_get_posts( $query ) {
// Test for main blog posts index
// and ensure that the query is the main query
// and not a secondary query (such as a nav menu
// or recent posts widget output, etc.
if ( is_home() && $query->is_main_query() ) {
// Exclude category ID 5
$query->set( 'category__not_in', array( 5 ) );
}
}
add_action( 'pre_get_posts', 'wpse120407_pre_get_posts' );
Auf diese Weise verwendet WordPress das bereits geänderte $wp_query
Objekt zur Bestimmung der Paginierung, ohne dass eine Vorlagenänderung erforderlich ist.
Wann soll welche Funktion verwendet werden?
Forschung diese Frage und Antwort und diese Frage und Antwort zu verstehen , wie und wann zu verwenden WP_Query
, pre_get_posts
und query_posts()
.
paged
Version nicht aktualisiert wurde (obv etwas mit der Administration zu tun hat). ajax.php environment) also habe ich folgendes hinzugefügt:global $paged; $paged = $custom_query_args['paged'];
und es hat funktioniert :)Ich benutze diesen Code für eine benutzerdefinierte Schleife mit Paginierung:
Quelle:
quelle
Genial wie immer Chip. Betrachten Sie als Ergänzung dazu die Situation, in der Sie eine globale Seitenvorlage verwenden, die an eine Seite für einen "Intro-Text" angehängt ist, und auf die eine Unterabfrage folgt, die ausgelagert werden soll.
Wenn Sie, wie oben erwähnt, paginate_links () mit den meisten Standardeinstellungen verwenden (und davon ausgehen, dass Sie ziemlich eingeschaltete Permalinks haben), werden Ihre Paginierungslinks standardmäßig verwendet,
mysite.ca/page-slug/page/#
die zwar ansprechend sind, aber404
Fehler auslösen, da WordPress nichts über diese bestimmte URL-Struktur weiß und dies auch tatsächlich tut Suchen Sie nach einer untergeordneten Seite von "page", die ein untergeordnetes Element von "page-slug" ist.Der Trick dabei ist, eine raffinierte Umschreiberegel einzufügen, die nur für diesen bestimmten "Pseudo-Archivseite" -Seiten-Slug gilt, der die
/page/#/
Struktur akzeptiert und sie in eine Abfragezeichenfolge umschreibt, die WordPress verstehen kann, nämlichmysite.ca/?pagename=page-slug&paged=#
. Beachten Siepagename
undpaged
nichtname
undpage
(was mich buchstäblich Stunden der Trauer verursachte und diese Antwort hier motivierte!).Hier ist die Weiterleitungsregel:
Denken Sie beim Ändern der Umschreiberegeln daran, Ihre Permalinks zu leeren, indem Sie im Admin-Backend auf Einstellungen> Permalinks klicken.
Wenn Sie mehrere Seiten haben, die sich auf diese Weise verhalten (z. B. wenn Sie mit mehreren benutzerdefinierten Beitragstypen arbeiten), möchten Sie möglicherweise nicht für jeden Seitenblock eine neue Umschreiberegel erstellen. Wir können einen allgemeineren regulären Ausdruck schreiben, der für jeden von Ihnen identifizierten Seitenblock funktioniert.
Ein Ansatz ist unten:
Nachteile / Vorbehalte
Ein Nachteil dieses Ansatzes, der mich ein wenig in den Mund kotzen lässt, ist die harte Kodierung der Seitenschnecke. Wenn ein Administrator jemals den Seitenbuckel dieser Pseudo-Archiv-Seite ändert, wird getoastet - die Umschreiberegel stimmt nicht mehr überein und Sie erhalten die gefürchtete 404.
Ich bin nicht sicher, ob ich mir eine Problemumgehung für diese Methode vorstellen kann, aber es wäre schön, wenn die globale Seitenvorlage die Regel zum Umschreiben auslösen würde. Eines Tages werde ich vielleicht noch einmal auf diese Antwort zurückkommen, wenn niemand anders diese bestimmte Nuss geknackt hat.
quelle
_wp_page_template
, und dann weitere Regeln zum Umschreiben und Löschen hinzufügen.Großartige Antwort Der erstellte Chip muss heute geändert werden.
Seit einiger Zeit haben wir eine
$wp_the_query
Variable, die gleich der$wp_query
globalen sein sollte, unmittelbar nachdem die Hauptabfrage ausgeführt wurde.Dies ist der Teil aus der Antwort des Chips:
wird nicht mehr benötigt. Wir können diesen Teil beim Erstellen der temporären Variablen vergessen.
Jetzt können wir anrufen:
oder noch besser können wir anrufen:
Alles andere, was Chip umrissen hat, bleibt. Nach diesem Query-Reset-Teil können Sie die Paginierungsfunktionen aufrufen, die
f($wp_query)
von$wp_query
global abhängen .Um die Paginierungsmechanik weiter zu verbessern und der
query_posts
Funktion mehr Freiheit zu geben, habe ich diese mögliche Verbesserung geschaffen:https://core.trac.wordpress.org/ticket/39483
quelle
quelle