web-dev-qa-db-fra.com

Pagination/défilement infini avec WP_Query et plusieurs boucles

J'ai besoin que la page principale de mon site comporte 3 colonnes: - la première contenant les 5 messages les plus consultés; - la seconde avec les 5 prochains posts les plus visités; - Le troisième avec les messages les plus récents.

Je ne veux pas que les publications ne soient jamais répétées dans la même colonne ou dans une autre, je me sers donc de wp_query pour obtenir les publications que je veux, dans le nombre que je veux. Voici ce qui se passe lorsque je charge la deuxième page, en utilisant une pagination simple ou un défilement infini:

  • La première boucle charge les 5 à 10 messages les plus consultés, qui étaient déjà affichés lors du premier passage de la deuxième boucle;
  • La deuxième boucle charge les 5 prochains articles les plus consultés, dont certains ont déjà été chargés sur la troisième boucle lors de sa première utilisation;
  • La troisième boucle charge les articles les plus récents et n’a pas été chargée dans la première ou la deuxième boucle.

Pendant que je charge encore les pages suivantes, les boucles chargent les publications respectives jusqu'à ce que toutes les publications de la troisième boucle soient publiées, puis aucune publication ne soit dans la deuxième boucle et toutes les publications soient chargées dans la première boucle.

Voici le code que j'utilise:

<div id="content">

<div class="recentColumn">
<div class="columnContent">

<?

$hotArgs =  array(
    'post__not_in' => $loaded,
    'meta_key' => 'wpb_post_views_count', // Pega o número de visitas do post.
    'orderby' => 'meta_value_num', // Ordena do mais visitado para o menos visitado.
    'posts_per_page' => '2',
    'paged' => $paged
    );
$hot = new WP_Query( $hotArgs );


if ($hot->have_posts()) : while ($hot->have_posts()) : $hot->the_post();
$loaded[] = $post->ID;
?>

<div class="articleContent">
<article class="recent" role="article">

    <a href="<?php the_permalink();?>" title="<?php the_title();?>"><?php the_category();?>

    <header>
    <h1><a href="<?php the_permalink(); ?>" title="<?php the_title();?>"><?php the_title(); ?></a></h1>
    <?php the_excerpt(); ?>
    </header>

</article>
</div>

<?php endwhile; endif; ?>

</div>
</div>




<div class="popularColumn">
<div class="columnContent">

<?
$nextArgs =  array(
    'post__not_in' => $loaded,
    'meta_key' => 'wpb_post_views_count', // Pega o número de visitas do post.
    'orderby' => 'meta_value_num', // Ordena do mais visitado para o menos visitado.
    'posts_per_page' => '3',
    'paged' => $paged
    );
 $next = new WP_Query( $nextArgs );

if ($next->have_posts()) : while ($next->have_posts()) : $next->the_post();
$loaded[] = $post->ID; 
?>

<div class="articleContent">
<article class="popular" role="article">
        <a href="<?php the_permalink();?>" title="<?php the_title();?>"><?php the_category();?>

        <header>
        <h1><a href="<?php the_permalink(); ?>" title="<?php the_title();?>"><?php the_title(); ?></a></h1>
        </header>

</article>
</div>

<?php endwhile; endif; ?>

</div>
</div> 



<div class="randomColumn">
<div class="columnContent">

<?  
$recentsArgs =  array(
    'post__not_in' => $loaded,
    'posts_per_page' => '3',
    'paged' => $paged
    );
 $recents = new WP_Query( $recentsArgs );

if ($recents->have_posts()) : while ($recents->have_posts()) : $recents->the_post();
$loaded[] = $post->ID;
?>


<div class="articleContent">
<article class="random" role="article">
        <header>
        <h1><a href="<?php the_permalink(); ?>" title="<?php the_title();?>"><?php the_title(); ?></a></h1>
        </header>

</article>
</div>

<?php endwhile; endif; ?>

</div>
</div>

Je pense que la solution pourrait être d’utiliser une session php ou une variable qui stocke l’identifiant des posts déjà chargés et de vérifier dans les boucles si les posts ont été chargés ou non avant de continuer. J'ai essayé de faire ça mais ça n'a pas marché. J'ai trop peu de compétences sur php, et peut-être que quelqu'un pourrait avoir une meilleure idée de la façon de le faire fonctionner.

J'apprécie toute aide. Merci.

3
João Luiz Felde

Cela ne résoudra peut-être pas votre problème, mais cela vous aidera ultérieurement à créer des requêtes personnalisées. Paginer plus d'une requête peut devenir extrêmement délicat. Par défaut, la pagination de construction dans Wordpress ne dispose pas de cette logique pour paginer plusieurs requêtes. Vous devrez exécuter plusieurs requêtes et les fusionner d'une manière ou d'une autre.

OK, maintenant à ce que je voudrais souligner. Vous devriez consulter WP_Query dans le codex pour voir comment créer correctement une requête personnalisée. Votre problème ici est que vous exécutez trois requêtes personnalisées sans en réinitialiser aucune. Cela cassera toute autre requête qui suit la précédente

Il est de la plus haute importance de réinitialiser chaque requête personnalisée que vous créez. Vous DOVE TO faire cela. Vous pouvez le faire en appelant simplement wp_reset_postdata(); après chaque requête pour restaurer la variable $post. Regardez les exemples dans les liens fournis

1
Pieter Goosen

Vous pouvez recréer le tableau $loaded à partir de la base de données:

$hot_ppp = 3;
$next_ppp = 3;
$recents_ppp = 3;

if ( $paged > 1 ) {
    $prev_hot_next_loaded = $wpdb->get_col( $wpdb->prepare(
        'SELECT ID FROM ' . $wpdb->posts . ' p JOIN ' . $wpdb->postmeta . ' pm ON pm.post_id = p.ID AND pm.meta_key = %s'
        . ' WHERE p.post_type = %s AND p.post_status = %s ORDER BY pm.meta_value+0 DESC LIMIT %d',
        'wpb_post_views_count', 'post', 'publish', ( $hot_ppp + $next_ppp ) * ( $paged - 1 )
    ) );
    $prev_recents_loaded = $wpdb->get_col( $wpdb->prepare(
        'SELECT ID FROM ' . $wpdb->posts . ' WHERE ID NOT IN (' . implode(',', $prev_hot_next_loaded ) . ')'
        . ' AND post_type = %s AND post_status = %s ORDER BY post_date DESC LIMIT %d',
        'post', 'publish', $recents_ppp * ( $paged - 1 )
    ) );

    $loaded = $prev_hot_next_loaded + $prev_recents_loaded;
}
0
bonger