As postagens fixas excedem as postagens por limite de página

21

Estou usando pre_get_postspara ajustar o número de postagens exibidas na minha página inicial.

function lifelounge_query_adjust( $query ) {
    if ( is_home() ) {
        set_query_var( 'posts_per_page', 12 );
        return;
    }
}
add_filter( 'pre_get_posts', 'lifelounge_query_adjust' );

Mas estou com um problema com postagens persistentes. Basicamente, se eu tiver postagens aderentes, a consulta exibirá mais do que as 12 postagens especificadas, porque exibirá 12 mais postagens aderentes. É claro que eu poderia ignorar postagens adesivas:

function lifelounge_query_adjust( $query ) {
    if ( is_home() ) {
        set_query_var( 'posts_per_page', 1 );
        set_query_var( 'ignore_sticky_posts', 1 );
        return;
    }
}
add_filter( 'pre_get_posts', 'lifelounge_query_adjust' );

Mas não acho que isso seja ideal. Acho que as postagens fixas devem ser incluídas no limite de 12 postagens e não adicionadas ao limite. É isso que faz mais sentido para mim. Existe uma maneira de conseguir isso? Cometi um erro que valha a pena na cara?

Praticamente uma duplicata de: Postagens pegajosas e postagens por página, mas que foi estranhamente fechada por ser muito localizada. Discordo, obviamente, porque estou procurando uma resposta, mas também porque é uma questão de por que o WordPress não parece respeitar o posts_per_page limite se você estiver usando postagens fixas. Se você quiser 12 postagens por página, deverá receber 12, e não 13, o que você obteria se tivesse uma única postagem adesiva.

helgatheviking
fonte

Respostas:

12

Aqui está uma abordagem para contabilizar postagens aderentes, obtendo o número de postagens aderentes (se houver) e inclua isso no posts_per_pageparâmetro de cálculo :

add_action('pre_get_posts', 'ad_custom_query');
function ad_custom_query($query) {

    if ($query->is_main_query() && is_home()) {

        // set the number of posts per page
        $posts_per_page = 12;
        // get sticky posts array
        $sticky_posts = get_option( 'sticky_posts' );

        // if we have any sticky posts and we are at the first page
        if (is_array($sticky_posts) && !$query->is_paged()) {

            // counnt the number of sticky posts
            $sticky_count = count($sticky_posts);

            // and if the number of sticky posts is less than
            // the number we want to set:
            if ($sticky_count < $posts_per_page) {
                $query->set('posts_per_page', $posts_per_page - $sticky_count);

            // if the number of sticky posts is greater than or equal
            // the number of pages we want to set:
            } else {
                $query->set('posts_per_page', 1);
            }

        // fallback in case we have no sticky posts
        // and we are not on the first page
        } else {
            $query->set('posts_per_page', $posts_per_page);
        }
    }
}

Editar

No caso em que o número de postagens por página que desejamos definir seja menor ou igual ao número de postagens fixas, defini a posts_per_pagecomo uma e isso resultará em 13 ou mais postagens $sticky_count + 1(neste caso) apenas no primeiro página (as páginas subsequentes terão 12 postagens). Talvez esteja tudo bem, já que esse caso é raro e o +1 na primeira página pode não ser tão significativo.

Isso ocorre porque o Wordpress exibirá todas as postagens adesivas primeiro e em uma página (a primeira página), mesmo que sua contagem seja maior que o posts_per_pageparâmetro, portanto, posts_per_pageneste caso , definimos o valor mínimo possível 1, pois 0valores negativos serão desativados o posts_per_pageparâmetro e que fará com que o Wordpress exiba todas as postagens na primeira página.

Ahmad M
fonte
Ótimo!! Eu acho que você precisa mudar $sticky_count + (12 - $sticky_count)para 12- $sticky_countembora. Por exemplo, se eu tiver 1 adesivo, sua matemática ainda funcionará para 12 e, em seguida, o WP adicionará o post para 13. Ah, e se if ($sticky_count > $posts_per_page)definirmos como 12, isso não significa que mostraremos mais de 24?
helgatheviking
@helgatheviking: você está certo. Eu sempre cometo erros tão bobos, os cálculos nunca foram tão interessantes para mim. E sim, isso resultaria em 24 postagens. Atualizei o código para explicar isso e adicionei um cheque para o número da página. Isso funciona bem, mas agora haverá um caso em $posts_per_pageque será igual a $sticky_count, e aqui defino o parâmetro posts_per_page como 1, e que acho que será bom, pois esse caso talvez seja raro e estará apenas na primeira página ( $sticky_count + 1)
Ahmad H
Obrigado pela edição! Penso que esta é a melhor solução que podemos encontrar utilizando mensagens adesivas. Eu acho que posso eventualmente classificar por uma meta-chave simples para saber se um post é destaque ou não. Isso se comporta mais normalmente pelo meu entendimento.
helgatheviking
isso falhará como uma solução se as postagens adesivas fizerem parte da posts_per_page originalmente desejada. O número total de postagens será reduzido, mas as postagens fixas não enviarão esse número novamente, pois fazem parte da data normal definida.
Andrew Killen
3

Há um problema se as postagens adesivas estiverem na primeira página.

A solução é diminuir a contagem de postagens fixas das postagens fixas que fazem parte da primeira página.

function fix_posts_per_page_with_sticky_posts( $query ) {

    if ( $query->is_main_query() ) {

        // set the number of posts per page
        $posts_per_page = 12;

        // get sticky posts array
        $sticky_posts = get_option( 'sticky_posts' );

        // get queried post ids array
        $ids = array();
        $args = array(
            'post_type' => 'post',
            'post_per_page' => $posts_per_page,
            'paged' => 1
        );

        $posts = get_posts( $args );

        foreach ( $posts as $post ) {
            $ids[] = $post->ID;
        }

        // if we have any sticky posts and we are at the first page
        if ( is_array( $sticky_posts ) && ! $query->is_paged() ) {

            // count the number of sticky posts
            $sticky_count = count( $sticky_posts );

            foreach ( $sticky_posts as $sticky_post ) {
                if ( in_array( $sticky_post, $ids ) ) {
                    // decrement sticky posts count if the sticky post in on the page
                    $sticky_count--;
                }
            }

            // and if the number of sticky posts is less than
            // the number we want to set:
            if ( $sticky_count < $posts_per_page ) {
                $query->set( 'posts_per_page', $posts_per_page - $sticky_count );

            // if the number of sticky posts is greater than or equal
            // the number of pages we want to set:
            } else {
                $query->set( 'posts_per_page', 1 );
            }

        // fallback in case we have no sticky posts
        // and we are not on the first page
        } else {
            $query->set( 'posts_per_page', $posts_per_page );
        }
    }
}
add_action( 'pre_get_posts', 'fix_posts_per_page_with_sticky_posts'  );

Eu espero que isso ajude

csag
fonte
1
Tem certeza de que não há uma solução mais fácil e rápida para isso? Dica: Você sabe a quantidade de mensagens pegajosas e as mensagens por página ...
kaiser
Eu não encontrei melhor até agora .. Esta é mais uma correção para algo que deveria estar no núcleo WP na minha opinião
CSAG
Se isso fosse essencial, outros cenários não funcionariam.
Kaiser
Este é um bug conhecido e está sendo rastreado em core.trac.wordpress.org/ticket/27282
Will.
A solução de Ahmad M do @kaiser não leva em conta postagens que apareceriam na primeira página, independentemente do seu estado. Isso pode resultar em poucas postagens aparecendo na primeira página (WordPress v4.9.7). Essa resposta é melhor porque explica isso.
27418 Jacob Budin
0

Limpei as duas respostas acima em uma para que ele não carregue WP_Query desnecessário, corrige se o adesivo estiver na primeira página e reduza o tempo para processar as informações com um código mais rápido e limpo.

function modify_main_query( $query ) {
   if ( ( $query->is_home() || is_front_page() ) && $query->is_main_query() ) {
         // set the number of posts per page
        $posts_per_page = 12;
        // get sticky posts array
        $sticky_posts = get_option( 'sticky_posts' );
        // if we have any sticky posts and we are at the first page
        if (is_array($sticky_posts) && !$query->is_paged()) {
            // make a second query to make sure the sticky posts will still work 
            // correctly when on the first page
            // Only reply with the ID's as that is all that is needed
            $args = [
                'post_type' => 'post',
                'post_per_page' => $posts_per_page,
                'paged' => 1,
                'fields' => 'ids'
            ];
            // Array flip to reduce the time taken by 
            // using isset and not in_array
            $posts = array_flip( get_posts( $args ) );

            // count the number of sticky posts
            $sticky_count = count($sticky_posts);

            // loop the posts from the 2nd query to see if the ID's of the sticky posts
            // sit inside it.
            foreach ( $sticky_posts as $sticky_post ) {
                if(isset($posts[$sticky_post])){
                    $sticky_count--;
                }
            }
            // and if the number of sticky posts is less than
            // the number we want to set:
            if ($sticky_count < $posts_per_page) {
               $query->set('posts_per_page', $posts_per_page - $sticky_count);
            } else {
                // if the number of sticky posts is greater than or equal
                // the number of pages we want to set:
                $query->set('posts_per_page', 1);
            }
        // fallback in case we have no sticky posts
        // and we are not on the first page
        } else {
            $query->set('posts_per_page', $posts_per_page);
        }
    } 
}

add_action( "pre_get_posts", 'modify_main_query' );
Andrew Killen
fonte