Como posso criar uma página de destino da categoria seguida por páginas de postagens?

9

Estou tentando criar um modelo de categoria no meu tema que exibirá conteúdo estático se o usuário estiver na primeira página do arquivo e, em seguida, exibirá as postagens na categoria nas páginas seguintes. Basicamente, estou tentando replicar o comportamento da categoria no Wired.com, onde http://www.wired.com/category/design é uma página de destino, enquanto / category / design / page / 1 mostra uma lista cronológica inversa de postagens como você esperaria em um arquivo de categorias.

A chave aqui é que eu não estou mostrando nenhuma postagem do arquivo de categorias na primeira página, então preciso da próxima página para começar com a primeira postagem. Eu tentei fazer isso usando o deslocamento e a paginação manual definindo o deslocamento da consulta como 0 se a consulta 'paginada' var fosse 2. Mas o deslocamento é ignorado quando definido como zero, então o melhor que posso fazer é definir o deslocamento como 1 e comece com o segundo post na categoria.

Isto é o que eu adicionei ao 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 );
  }
}

O que seria melhor e o que parece com fio , é usar a paginação padrão para que as postagens comecem na página 1, mas insira uma página 0 para o conteúdo estático. Hipoteticamente, isso parece possível, exibindo o conteúdo estático se 'paginado' for 0 e exibindo a primeira página de postagens se 'paginado' for 1. O problema é que 'paginado' nunca é 1 porque o Wordpress define 'paginado 'a zero quando o usuário solicita a primeira página. Isso significa que 'paginado' é 0 para ambos / categoria / notícias / página / 1 e / categoria / notícias.

Existe uma maneira de verificar se o usuário solicitou / categoria / notícias / página / 1 em oposição a / categoria / notícias? Caso contrário, existe uma maneira de exibir todas as postagens na categoria, começando na página 2?

willcwelch
fonte

Respostas:

7

Essa é uma pergunta bastante interessante ( que eu votei, especialmente por sua abordagem e pesquisa ). A grande curva aqui é a primeira página da consulta:

  • Você não pode definir a consulta para retornar 0postagens na primeira página

  • Ao mover o conteúdo da página de uma página para outra em uma página, você perderá a última página, pois a consulta ainda terá apenas a mesma quantidade de postagens, para que a $max_num_pagespropriedade permaneça a mesma

De alguma forma, precisaremos "enganar" a WP_Queryclasse para retornar nossas postagens corretamente com o deslocamento de uma página e também obter o número correto de páginas para não perder a última página na consulta

Vamos analisar a ideia a seguir e tentar colocar tudo em código. Antes de fazermos, gostaria de fazer algumas anotações aqui

ANOTAÇÕES IMPORTANTES:

  • Tudo não foi testado, portanto pode ser um bug. Certifique-se de testar isso localmente com a depuração ativada

  • O código requer pelo menos PHP 5.3, qualquer versão abaixo de 5.3 causará um erro fatal. Observe que, se ainda estiver usando alguma versão abaixo do PHP 5.5, você já deve ter atualizado há muito tempo

  • Modifique e abuse do código como achar melhor para atender às suas necessidades exatas

A IDEIA DO LÂMPADA:

O QUE NÓS PRECISAMOS

Para que tudo funcione, precisamos do seguinte:

  • O número da página atual sendo visualizada

  • A posts_per_pageopção definida nas configurações de leitura

  • personalizadas offset

  • Modifique a $found_postspropriedade da consulta para corrigir a $max_num_pagespropriedade

Paginação se WP_Queryresume a algumas linhas de código muito simples

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

O que basicamente acontece, quando um deslocamento é definido explicitamente, o pagedparâmetro é ignorado. O primeiro parâmetro da LIMITcláusula SQL é recalculado do deslocamento e será o número de postagens a serem ignoradas na consulta SQL gerada.

Da sua pergunta, aparentemente ao definir offsetcomo 0, a consulta de deslocamento falha, o que é estranho, pois a verificação a seguir deve retornar true

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

0é um número válido e deve retornar verdadeiro. Se isso não ocorrer na sua instalação, você deve depurar o problema

Para voltar ao problema em questão, usaremos o mesmo tipo de lógica para calcular e definir nosso deslocamento para obter a postagem 1 na página 2 e a partir daí paginar a consulta. Para a primeira página, não alteraremos nada; portanto, as postagens que deveriam estar na página 1 ainda estarão na página normalmente, apenas precisaríamos "ocultá-las" mais tarde para não exibi-las na página 1 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 );
        }
    }
});

Você deve ver as mesmas postagens da página 1 na página 2. Como afirmei anteriormente, se isso não acontecer, is_numeric( 0 )está retornando false (o que não deveria ) ou você tem outra pre_get_postsação que também está tentando definir um deslocamento ou você estão usando os posts_*filtros de cláusula ( mais especificamente, o post_limitsfiltro ). Isso seria algo que você precisaria depurar sozinho.

A próxima questão é corrigir a paginação, porque, como afirmei anteriormente, você terá uma página curta. Para isso, precisaremos adicionar o valor da get_option( 'posts_per_page' )quantidade de postagens encontradas na consulta, pois estamos compensando a consulta por essa quantidade. ao fazer isso, estamos adicionando efetivamente 1à $max_num_pagespropriedade.

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

Isso deve classificar tudo, exceto a primeira página.

TODOS JUNTOS AGORA ( e especialmente para @ialocin - Submarino Amarelo )

Tudo isso deve entrar em 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 );

OPÇÕES DA PRIMEIRA PÁGINA

Existem algumas opções aqui:

OPÇÃO 1

Eu provavelmente iria por esta opção. O que você gostaria de fazer aqui é criar um category-news.php( se ainda não o fez ). Este será o modelo que será usado sempre que a newscategoria for exibida. Este modelo será muito simples

Exemplo

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

Como você pode ver, incluí duas partes do modelo news-special.phpe news-loop.php. Agora, o básico dos dois modelos personalizados são:

  • news-special.php-> Esta parte do modelo será o que você deseja exibir na primeira página. Adicione todas as suas informações estáticas personalizadas aqui. Tenha muito cuidado para não chamar o loop neste modelo, pois isso exibirá as postagens da primeira página.

  • news-loop.php-> Este é o modelo em que chamaremos o loop. Esta seção será mais ou menos assim:

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

OPÇÃO 2

Crie um modelo separado com seu conteúdo estático e simplesmente use o category_templatefiltro para usá-lo quando visualizarmos a primeira página da newscategoria. Além disso, certifique-se de não chamar o loop padrão neste modelo. Além disso, verifique se a sua convenção de nomenclatura aqui não colide com nomes de modelos na hierarquia de modelos

Espero que isso seja útil. Sinta-se livre para deixar comentários com preocupações

EDITAR

Graças ao OP, há um erro definido na WP_Queryclasse, verifique o bilhete trac # 34060 . O código que publiquei é do Wordpress v4.4, e o bug foi corrigido nesta versão.

Voltei ao código fonte da v4.3, onde está o erro, e posso confirmar que 0é ignorado quando definido como valor, offsetpois o código simplesmente verifica se o offsetparâmetro está empty. 0é considerado vazio no PHP. Não tenho certeza se esse comportamento (bug) é encontrado apenas na v4.3 ou em todas as versões anteriores (de acordo com o ticket, esse bug está na v4.3), mas há um patch para esse bug que você pode verificar no bilhete trac. Como eu disse, esse bug foi definitivamente corrigido na v4.4

Pieter Goosen
fonte
2
Obrigado pela sua resposta detalhada. Isso é realmente o que eu implementei na minha primeira tentativa. O problema era que a configuração de 'deslocamento' para 0 não estava funcionando. Acontece que na verdade foi um bug no núcleo do WordPress core.trac.wordpress.org/ticket/34060 . A aplicação de patches fez tudo funcionar. A única coisa que falta no seu código é return $found_posts;após a instrução if na ação found_posts. Obrigado!
willcwelch
Obrigado pelo seu feedback positivo. Voltei para o código fonte da versão 4.3 query.phpe, sim, 0será ignorado porque a verificação aqui é vazia e 0é considerada vazia. O código na minha resposta é o código de atualização fornecido com a v4.4, para que eu possa confirmar que o bug foi corrigido na 4.4. Vou atualizar minha resposta de acordo. Na found_postsquestão, boa captura, na verdade é um filtro e deve ser devolvido. Desfrute
Pieter Goosen
haha, obrigado :) e por tudo o que está se perguntando por que ... um, dois, três, quatro, posso ter um pouco mais ... o link atual da música agora todos juntos
Nicolai
@ialocin hahaha, eu vou lembrar este ;-)
Pieter Goosen
1
é bastante catchy :) mas não admira, porque ele é muito bonito escrito como uma canção crianças
Nicolai
0

Atualizar:

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

Tente algo como

$paged = ( get_query_var('paged') ) ? get_query_var('paged')-1 : 1;
$args = array (
    'paged' => $paged,
);
Kika
fonte
Corrigi minha explicação de como a variável 'paginada' funciona. Parece que o que você está tentando fazer é diminuir cada número de página em 1; portanto, uma solicitação para a página 2 fornece a página 1. O problema é que, quando a página 1 é consultada, 'paginado' é definido como 0. Além disso, get_query_var () deve ser usado em vez de get_option para 'paginado'. Com essa correção, quando é executada, toda vez que a consulta é alterada, ele volta a repetir até que 'paginado' seja 0 para qualquer solicitação de página.
willcwelch