Wie kann ich eine Kategorie-Landingpage gefolgt von Postseiten erstellen?

9

Ich versuche, in meinem Thema eine Kategorievorlage zu erstellen, die statischen Inhalt anzeigt, wenn sich der Benutzer auf der ersten Seite des Archivs befindet, und dann die Beiträge in der Kategorie auf den folgenden Seiten anzuzeigen. Ich versuche im Grunde, das Verhalten der Kategorie auf Wired.com zu replizieren, wobei http://www.wired.com/category/design eine Zielseite ist, während / category / design / page / 1 eine umgekehrte chronologische Liste von Posts wie Ihnen anzeigt würde auf ein Kategoriearchiv erwarten.

Der Schlüssel hier ist, dass ich auf der ersten Seite keine Beiträge aus dem Kategoriearchiv anzeige. Daher benötige ich die nächste Seite, um mit dem ersten Beitrag zu beginnen. Ich habe dies zuerst mit Offset und manueller Paginierung versucht, indem ich den Offset der Abfrage auf 0 gesetzt habe, wenn die 'paged'-Abfrage var 2 war. Der Offset wird jedoch ignoriert, wenn er auf Null gesetzt ist. Das Beste, was ich tun kann, ist, den Offset auf zu setzen 1 und beginnen Sie mit dem zweiten Beitrag in der Kategorie.

Folgendes habe ich zu functions.php hinzugefügt:

add_action('pre_get_posts', 'category_query_offset', 1 );
function category_query_offset(&$query) {
  // Before anything else, make sure this is the right query
  if (!$query->is_category('news')) {
    return;
  }

  // Next, determine how many posts per page
  $ppp = get_option('posts_per_page');

  //Next, detect and handle pagination
  if ($query->is_paged) {
    // Manually determine page query offset
    $page_offset = (($query->query_vars['paged']-1) * $ppp) - $ppp;
    // Apply adjust page offset
    $query->set('offset', $page_offset );
  }
}

Was besser wäre und was Wired anscheinend tut, ist die Verwendung der Standardpaginierung, damit die Beiträge auf Seite 1 beginnen, aber eine Seite 0 für den statischen Inhalt einfügen. Hypothetisch scheint dies möglich zu sein, indem der statische Inhalt angezeigt wird, wenn 'paged' 0 ist, und die erste Seite von Posts angezeigt wird, wenn 'paged' 1 ist. Das Problem ist, dass 'paged' niemals 1 ist, weil Wordpress 'paged' setzt 'auf Null, wenn der Benutzer die erste Seite anfordert. Das bedeutet, dass 'paged' sowohl für / category / news / page / 1 als auch für / category / news 0 ist.

Gibt es eine Möglichkeit zu überprüfen, ob der Benutzer / category / news / page / 1 im Gegensatz zu / category / news angefordert hat? Wenn dies nicht der Fall ist, gibt es eine Möglichkeit, alle Beiträge in der Kategorie ab Seite 2 anzuzeigen?

Willcwelch
quelle

Antworten:

7

Dies ist eine ziemlich interessante Frage ( die ich speziell für Ihren Ansatz und Ihre Forschung positiv bewertet habe ). Der große Curveball hier ist die erste Seite der Abfrage:

  • Sie können die Abfrage nicht so einstellen, dass 0Beiträge auf der ersten Seite zurückgegeben werden

  • Wenn Sie den Seiteninhalt jeder Seite um eine Seite nach oben verschieben, verlieren Sie die letzte Seite, da die Abfrage immer noch nur die gleiche Anzahl von Posts enthält, sodass die $max_num_pagesEigenschaft immer noch dieselbe bleibt

Wir müssen die WP_QueryKlasse irgendwie " austricksen " , um unsere Beiträge korrekt mit dem Versatz einer Seite zurückzugeben und auch die richtige Anzahl von Seiten zu erhalten, um die letzte Seite in der Abfrage nicht zu verlieren

Schauen wir uns die folgende Idee an und versuchen wir, alles in Code zu setzen. Bevor wir dies tun, möchte ich hier jedoch einige Anmerkungen machen

WICHTIGE NOTIZEN:

  • Alles ist ungetestet, daher könnte es fehlerhaft sein. Stellen Sie sicher, dass Sie dies lokal mit aktiviertem Debug testen

  • Der Code erfordert mindestens PHP 5.3. Jede Version unter 5.3 verursacht einen schwerwiegenden Fehler. Hinweis: Wenn Sie noch eine Version unter PHP 5.5 verwenden, sollten Sie bereits vor langer Zeit ein Upgrade durchgeführt haben

  • Ändern und missbrauchen Sie den Code nach Ihren Wünschen

DIE GLÜHBIRNEN-IDEE:

WAS WIR BRAUCHEN

Damit alles funktioniert, benötigen wir Folgendes:

  • Die aktuell angezeigte Seitenzahl

  • Die in den posts_per_pageLeseeinstellungen festgelegte Option

  • Benutzerdefiniert offset

  • Ändern Sie die $found_postsEigenschaft der Abfrage, um die $max_num_pagesEigenschaft zu korrigieren

Die Paginierung besteht WP_Queryaus sehr einfachen Codezeilen

if ( empty($q['nopaging']) && !$this->is_singular ) {
    $page = absint($q['paged']);
    if ( !$page )
        $page = 1;
    // If 'offset' is provided, it takes precedence over 'paged'.
    if ( isset( $q['offset'] ) && is_numeric( $q['offset'] ) ) {
        $q['offset'] = absint( $q['offset'] );
        $pgstrt = $q['offset'] . ', ';
    } else {
        $pgstrt = absint( ( $page - 1 ) * $q['posts_per_page'] ) . ', ';
    }
    $limits = 'LIMIT ' . $pgstrt . $q['posts_per_page'];
}

Was im Grunde passiert, sobald ein Offset explizit gesetzt ist, wird der pagedParameter ignoriert. Der erste Parameter der SQL- LIMITKlausel wird aus dem Offset neu berechnet und gibt die Anzahl der Beiträge an, die in der generierten SQL-Abfrage übersprungen werden sollen.

Aus Ihrer Frage geht hervor , dass die Offset-Abfrage anscheinend beim Setzen offsetauf 0fehlschlägt, was seltsam ist, da die folgende Prüfung true zurückgeben sollte

if ( isset( $q['offset'] ) && is_numeric( $q['offset'] ) )

0ist eine gültige Zahl und sollte true zurückgeben. Wenn dies bei Ihrer Installation nicht der Fall ist, sollten Sie das Problem beheben

Um auf das vorliegende Problem zurückzukommen, verwenden wir dieselbe Logik, um unseren Offset zu berechnen und festzulegen, um Post 1 auf Seite 2 zu erhalten und von dort aus die Abfrage zu paginieren. Für die erste Seite werden wir nichts ändern, sodass die Beiträge, von denen angenommen wird, dass sie sich auf Seite 1 befinden, weiterhin wie gewohnt auf der Seite sind. Wir müssten sie später nur "ausblenden", damit wir sie nicht auf der Seite anzeigen 1

add_action( 'pre_get_posts', function ( $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $current_page = $q->get( 'paged' ); // Get the current page number
        // We will only need to run this from page 2 onwards
        if ( $current_page != 0 ) { // You can also use if ( is_paged() ) {
            // Get the amount of posts per page
            $posts_per_page = get_option( 'posts_per_page' );
            // Recalculate our offset
            $offset = ( ( $current_page - 1) * $posts_per_page ) - $posts_per_page; // This should work on page 2 where it returns 0

            // Set our offset
            $q->set( 'offset', $offset );
        }
    }
});

Sie sollten dieselben Beiträge von Seite 1 auf Seite 2 sehen. Wie bereits erwähnt, wird in diesem Fall entweder is_numeric( 0 )false zurückgegeben ( was nicht der Fall sein sollte ) oder Sie haben eine andere pre_get_postsAktion, die ebenfalls versucht, einen Offset festzulegen, oder Sie verwenden die posts_*Klauselfilter ( genauer gesagt den post_limitsFilter ). Dies wäre etwas, das Sie selbst debuggen müssten.

Das nächste Problem ist die Korrektur der Paginierung, da Sie, wie bereits erwähnt, nur eine kurze Seite haben. Dazu müssen wir den Wert von get_option( 'posts_per_page' )zur Anzahl der in der Abfrage gefundenen Beiträge hinzufügen, da wir die Abfrage um diesen Betrag versetzen. Auf diese Weise erweitern wir 1die $max_num_pagesImmobilie effektiv .

add_action( 'found_posts', function ( $found_posts, $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $found_posts = $found_posts + get_option( 'posts_per_page');
    }
}, 10, 2 );

Dies sollte alles außer der ersten Seite sortieren.

JETZT ZUSAMMEN ( und speziell für @ialocin - Yellow Submarine )

Das sollte alles gehen functions.php

add_action( 'pre_get_posts', function ( $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $current_page = $q->get( 'paged' ); // Get the current page number
        // We will only need to run this from page 2 onwards
        if ( $current_page != 0 ) { // You can also use if ( is_paged() ) {
            // Get the amount of posts per page
            $posts_per_page = get_option( 'posts_per_page' );
            // Recalculate our offset
            $offset = ( ( $current_page - 1) * $posts_per_page ) - $posts_per_page; // This should work on page 2 where it returns 0

            // Set our offset
            $q->set( 'offset', $offset );
        }
    }
});

add_filter( 'found_posts', function ( $found_posts, $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $found_posts = $found_posts + get_option( 'posts_per_page');
    }
    return $found_posts;
}, 10, 2 );

OPTIONEN DER ERSTEN SEITE

Hier gibt es einige Optionen:

OPTION 1

Ich würde mich höchstwahrscheinlich für diese Option entscheiden. Was Sie hier tun möchten, ist ein category-news.php( falls Sie dies noch nicht getan haben ) zu erstellen . Dies ist die Vorlage, die verwendet wird, wenn die newsKategorie angezeigt wird. Diese Vorlage wird sehr einfach sein

Beispiel

<?php
get_header()

if ( !is_paged() ) { // This is the first page
    get_template_part( 'news', 'special' );
} else { // This is not the first page
    get_template_part( 'news', 'loop' );
}

get_sidebar();
get_footer();

Wie Sie sehen können, habe ich zwei Vorlagenteile news-special.phpund news-loop.php. Die Grundlagen der beiden benutzerdefinierten Vorlagen sind nun:

  • news-special.php-> Dieser Vorlagenteil ist alles, was Sie auf der ersten Seite anzeigen möchten. Fügen Sie hier alle Ihre benutzerdefinierten statischen Informationen hinzu. Achten Sie darauf, die Schleife in dieser Vorlage nicht aufzurufen, da hierdurch die Beiträge der ersten Seite angezeigt werden.

  • news-loop.php-> Dies ist die Vorlage, in der wir die Schleife aufrufen. Dieser Abschnitt sieht ungefähr so ​​aus:

    global $wp_query;
    while ( have_posts() ) {
    the_post();
    
        // Your template tags and markup
    
    }

OPTION 2

Erstellen Sie eine separate Vorlage mit Ihrem statischen Inhalt und verwenden Sie einfach den category_templateFilter, um diese Vorlage zu verwenden, wenn wir die erste Seite der newsKategorie anzeigen . Stellen Sie außerdem sicher, dass Sie die Standardschleife in dieser Vorlage nicht aufrufen. Stellen Sie außerdem sicher, dass Ihre Namenskonvention hier nicht mit Vorlagennamen innerhalb der Vorlagenhierarchie kollidiert

Ich hoffe das ist nützlich. Fühlen Sie sich frei, Kommentare mit Bedenken zu hinterlassen

BEARBEITEN

Dank des OP gibt es einen bestimmten Fehler in der WP_QueryKlasse. Überprüfen Sie das Trac-Ticket Nr. 34060 . Der Code, den ich gepostet habe, stammt aus Wordpress v4.4 und der Fehler wurde in dieser Version behoben.

Ich bin zum Quellcode von Version 4.3 zurückgekehrt, wo der Fehler liegt, und ich kann bestätigen, dass dieser 0ignoriert wird, wenn er als Wert festgelegt wird, offsetda der Code einfach prüft, ob der offsetParameter ist empty. 0wird in PHP als leer genommen. Ich bin nicht sicher, ob dieses Verhalten (Fehler) nur in Version 4.3 oder in allen vorherigen Versionen gefunden wurde (laut Ticket ist dieser Fehler in Version 4.3), aber es gibt einen Patch für diesen Fehler, den Sie überprüfen können draußen im Trac-Ticket. Wie gesagt, dieser Fehler wurde definitiv in Version 4.4 behoben

Pieter Goosen
quelle
2
Vielen Dank für Ihre ausführliche Antwort. Dies ist eigentlich so ziemlich das, was ich in meinem ersten Versuch implementiert habe. Das Problem war, dass das Setzen von 'Offset' auf 0 nicht funktionierte. Es stellte sich heraus, dass es sich tatsächlich um einen Fehler im WordPress Core core.trac.wordpress.org/ticket/34060 handelte . Durch das Patchen hat alles funktioniert. Das einzige, was Ihrem Code fehlt, ist return $found_posts;nach der if-Anweisung in der Aktion found_posts. Vielen Dank!
Willcwelch
Vielen Dank für Ihr positives Feedback. Ich bin in Version 4.3 des Quellcodes zurückgekehrt query.phpund 0werde ignoriert, da die Prüfung hier leer ist und 0als leer angesehen wird. Der Code in meiner Antwort ist der Update-Code, der mit v4.4 geliefert wird, sodass ich bestätigen kann, dass der Fehler in 4.4 behoben ist. Ich werde meine Antwort entsprechend aktualisieren. Zu dem found_postsThema, guter Fang, es ist eigentlich ein Filter und sollte zurückgegeben werden. Viel Spaß
Pieter Goosen
haha, danke :) und für all die, die sich fragen, warum ... eins, zwei, drei, vier, kann ich noch ein bisschen mehr haben ... der eigentliche Link zum Song jetzt alle zusammen
Nicolai
@ialocin hahaha, ich werde mich an diesen erinnern ;-)
Pieter Goosen
1
es ist ziemlich eingängig :) aber kein Wunder, denn es ist so ziemlich wie ein Kinderlied geschrieben
Nicolai
0

Aktualisieren:

add_action('pre_get_posts', 'category_query_offset', 1 );
function category_query_offset($query) {
 // Before anything else, make sure this is the right query
 if (!$query->is_category('news')) {
    return;
 }

 // Next, determine paged
 $ppp = get_option('paged');
}
// Next, handle paged
if($ppp > 1){
    $query->set('paged', $ppp-1);
}

Versuchen Sie etwas wie

$paged = ( get_query_var('paged') ) ? get_query_var('paged')-1 : 1;
$args = array (
    'paged' => $paged,
);
Kika
quelle
Ich habe meine Erklärung für die Funktionsweise der Variablen "Paged" korrigiert. Es sieht so aus, als würden Sie versuchen, jede Seitenzahl um 1 zu senken. Wenn Sie also Seite 2 anfordern, erhalten Sie Seite 1. Das Problem besteht darin, dass bei der Abfrage von Seite 1 'paged' auf 0 gesetzt wird. Außerdem get_query_var () sollte anstelle von get_option für 'paged' verwendet werden. Wenn dieser Fix ausgeführt wird, wird die Abfrage bei jeder Änderung erneut wiederholt, bis 'paged' für eine Seitenanforderung 0 ist.
Willcwelch