Come posso creare una landing page di categoria seguita da pagine di post?


9

Sto cercando di creare un modello di categoria nel mio tema che visualizzi il contenuto statico se l'utente si trova nella prima pagina dell'archivio e quindi visualizzi i post nella categoria nelle pagine seguenti. Sto fondamentalmente cercando di replicare il comportamento della categoria su Wired.com dove http://www.wired.com/category/design è una landing page mentre / category / design / page / 1 mostra un elenco cronologico inverso di post come te si aspetterebbe da un archivio di categoria.

La chiave qui è che non sto mostrando alcun post dall'archivio categoria sulla prima pagina, quindi ho bisogno della pagina successiva per iniziare con il primo post. Per prima cosa ho provato a farlo usando offset e impaginazione manuale impostando l'offset della query su 0 se la query 'paged' var era 2. Ma l'offset viene ignorato quando è impostato su zero, quindi il meglio che posso fare è impostare l'offset su 1 e inizia con il secondo post nella categoria.

Questo è ciò che ho aggiunto a Functions.php:

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 );
  }
}

Cosa sarebbe meglio, e ciò che sembra Wired , è usare l'impaginazione predefinita in modo che i post inizino a pagina 1, ma inserire una pagina 0 per il contenuto statico. Ipoteticamente, sembra che sarebbe possibile visualizzando il contenuto statico se "paginato" è 0 e visualizzando la prima pagina di post se "paginato" è 1. Il problema è che "impaginato" non è mai 1 perché Wordpress imposta "impaginato" 'a zero quando l'utente richiede la prima pagina. Ciò significa che "impaginato" è 0 sia per / categoria / notizie / pagina / 1 e / categoria / notizie.

C'è un modo per verificare se l'utente ha richiesto / categoria / notizie / pagina / 1 rispetto a / categoria / notizie? In caso contrario, c'è un modo per visualizzare tutti i post nella categoria a partire da pagina 2?

Risposte:


7

Questa è una domanda piuttosto interessante ( che ho votato, specialmente per il tuo approccio e ricerca ). La curva grande qui è la prima pagina della query:

  • Non è possibile impostare la query per restituire 0post nella prima pagina

  • Spostando il contenuto della pagina di ogni pagina in alto di una pagina, perderai l'ultima pagina in quanto la query avrà ancora solo la stessa quantità di post, quindi la $max_num_pagesproprietà rimarrà sempre la stessa

Dovremo in qualche modo "ingannare" la WP_Queryclasse per restituire i nostri post in modo corretto con l'offset di una pagina e anche ottenere il numero corretto di pagine per non perdere l'ultima pagina nella query

Vediamo la seguente idea e proviamo a mettere tutto nel codice. Prima di farlo, vorrei tuttavia sollevare alcune note qui

NOTE IMPORTANTI:

  • Tutto non è testato, quindi potrebbe essere difettoso. Assicurati di testarlo localmente con il debug attivato

  • Il codice richiede almeno PHP 5.3, qualsiasi versione precedente alla 5.3 causerà un errore fatale. Nota, se stai ancora utilizzando una versione inferiore a PHP 5.5, dovresti aver già aggiornato molto tempo fa

  • Modifica e abusa del codice secondo le tue esigenze

L'IDEA DELLA LAMPADINA:

COSA ABBIAMO BISOGNO

Per far funzionare tutto, avremo bisogno di quanto segue:

  • Il numero di pagina corrente visualizzato

  • L' posts_per_pageopzione impostata nelle impostazioni di lettura

  • costume offset

  • Modificare la $found_postsproprietà della query per correggere la $max_num_pagesproprietà

L'impaginazione WP_Queryscende in poche righe di codice molto semplici

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'];
}

Ciò che accade sostanzialmente, una volta impostato esplicitamente un offset, il pagedparametro viene ignorato. Il primo parametro della LIMITclausola SQL viene ricalcolato dall'offset e sarà il numero di post da saltare nella query SQL generata.

Dalla tua domanda, apparentemente quando impostato offsetsu 0, la query offset non riesce, il che è strano, poiché il seguente controllo dovrebbe restituire vero

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

0è un numero valido e dovrebbe restituire vero. In caso contrario, è necessario eseguire il debug del problema

Per tornare al problema in questione, utilizzeremo lo stesso tipo di logica per calcolare e impostare il nostro offset per ottenere il post 1 a pagina 2 e da lì impaginare la query. Per la prima pagina, non modificheremo nulla, quindi i post che si suppone siano nella pagina 1 saranno ancora nella pagina come al solito, dovremmo solo "nasconderli" in seguito in modo da non visualizzarli sulla pagina 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 );
        }
    }
});

Dovresti vedere gli stessi post da pagina 1 a pagina 2. Come ho detto in precedenza, se ciò non accade, o is_numeric( 0 )sta restituendo false ( cosa che non dovrebbe ) o hai un'altra pre_get_postsazione che sta anche cercando di impostare un offset o tu stanno usando i posts_*filtri della clausola ( più specificamente, il post_limitsfiltro ). Questo sarebbe qualcosa di cui dovresti eseguire il debug da solo.

Il prossimo numero è correggere l'impaginazione, perché come ho già detto in precedenza, sarai una pagina breve. Per questo, dovremo aggiungere il valore get_option( 'posts_per_page' )alla quantità di post trovati nella query poiché stiamo compensando la query di tale importo. facendo ciò, stiamo effettivamente aggiungendo 1alla $max_num_pagesproprietà.

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 );

Questo dovrebbe ordinare tutto, tranne la prima pagina.

TUTTI INSIEME ADESSO ( e specialmente per @ialocin - Yellow Submarine )

Questo dovrebbe andare tutto in 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 );

OPZIONI PRIMA PAGINA

Ci sono alcune opzioni qui:

OPZIONE 1

Molto probabilmente sceglierei questa opzione. Quello che vorresti fare qui è creare un category-news.php( se non l'hai ancora fatto ). Questo sarà il modello che verrà utilizzato ogni volta che newsviene visualizzata la categoria. Questo modello sarà molto semplice

Esempio

<?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();

Come puoi vedere, ho incluso due parti di modello news-special.phpe news-loop.php. Ora, le basi dei due modelli personalizzati sono:

  • news-special.php-> Questa parte del modello sarà quella che vorresti visualizzare sulla prima pagina. Aggiungi qui tutte le tue informazioni statiche personalizzate. Fai molta attenzione a non chiamare il ciclo in questo modello in quanto ciò visualizzerebbe i post della prima pagina.

  • news-loop.php-> Questo è il modello in cui invocheremo il ciclo. Questa sezione sarà simile a questa:

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

OPZIONE 2

Crea un modello separato con il tuo contenuto statico e usa semplicemente il category_templatefiltro per usare questo modello quando visualizziamo la prima pagina della newscategoria. Inoltre, assicurarsi di non richiamare il ciclo predefinito in questo modello. Inoltre, assicurati che la convenzione di denominazione qui non entri in conflitto con i nomi dei modelli all'interno della gerarchia dei modelli

Spero sia utile. Sentiti libero di lasciare commenti con preoccupazioni

MODIFICARE

Grazie all'OP, c'è un bug definito nella WP_Queryclasse, controlla il ticket trac # 34060 . Il codice che ho pubblicato proviene da Wordpress v4.4 e il bug è stato corretto in questa versione.

Sono tornato al codice sorgente di v4.3, dove si trova il bug, e posso confermare che 0viene ignorato quando impostato come valore su offsetcome il codice controlla semplicemente se il offsetparametro è empty. 0viene considerato vuoto in PHP. Non sono sicuro se questo comportamento (bug) si trova solo nella v4.3 o in tutte le versioni precedenti (in base al ticket, questo bug è nella v4.3), ma esiste una patch per questo bug che puoi controllare fuori nel biglietto del trac. Come ho detto, questo bug è stato risolto definitivamente in v4.4


2
Grazie per la tua risposta dettagliata. Questo è praticamente ciò che ho implementato nel mio primo tentativo. Il problema era che l'impostazione 'offset' su 0 non funzionava. Si è scoperto che in realtà era un bug nel core.trac.wordpress.org/ticket/34060 di WordPress Core . Patch che ha fatto funzionare tutto. L'unica cosa che manca al codice è return $found_posts;dopo l'istruzione if nell'azione found_posts. Grazie!
willcwelch,

Grazie per il tuo feedback positivo. Sono tornato alla versione 4.3 del codice sorgente query.phpe, sì, 0verrà ignorato perché il segno di spunta qui è vuoto e 0viene considerato vuoto. Il codice nella mia risposta è il codice di aggiornamento fornito con v4.4, quindi posso confermare che il bug è stato corretto in 4.4. Aggiornerò la mia risposta di conseguenza. Sulla found_postsquestione, buona cattura, in realtà è un filtro e dovrebbe essere restituito. Divertiti
Pieter Goosen il

ahah, grazie :) e per tutto ciò che si chiede perché ... uno, due, tre, quattro, posso avere un po 'di più ... l'effettivo collegamento alla canzone tutti insieme ora
Nicolai,

@ialocin hahaha, ricorderò questo ;-)
Pieter Goosen il

1
è piuttosto accattivante :) ma non c'è da stupirsi, perché è praticamente scritto come una canzone per bambini
Nicolai,

0

Aggiornare:

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);
}

Prova qualcosa del genere

$paged = ( get_query_var('paged') ) ? get_query_var('paged')-1 : 1;
$args = array (
    'paged' => $paged,
);

Ho corretto la mia spiegazione su come funziona la variabile 'paged'. Sembra che quello che stai cercando di fare sia abbassare ogni numero di pagina di 1, quindi una richiesta per pagina 2 ti dà la pagina 1. Il problema è che quando la pagina 1 viene interrogata, 'paged' è impostato su 0. Inoltre, get_query_var () dovrebbe essere usato al posto di get_option per 'paged'. Con tale correzione, quando viene eseguita, ogni volta che la query viene modificata, si ripete fino a quando 'paginato' è 0 per qualsiasi richiesta di pagina.
Willcwelch,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.