Le WordPress d'aujourd'hui, décodé pour les développeurs

Headless & API

Programmation d’un festival de cinéma exposée par une route paginée par curseur

Comment paginer une programmation qui change plusieurs fois par jour sans que les séances ne se dédoublent ou ne disparaissent d'une page à l'autre côté front.

Par WordPress Développement • 5 novembre 2022 • 4 min de lecture • Aucun commentaire
Programmation d'un festival de cinéma exposée par une route paginée par curseur

Une séance annulée entre le chargement de la page deux et celui de la page trois d’une programmation suffit à tout dérégler. Sur une pagination classique par numéro de page, la conséquence est fâcheuse : tous les résultats situés après la séance supprimée se décalent d’un rang, ce qui peut faire apparaître deux fois la même séance à l’écran, ou en faire disparaître une autre sans que l’utilisateur comprenne pourquoi.

Le contexte

Un festival de cinéma de taille moyenne publie sa programmation via un site headless, avec des séances ajoutées, déplacées ou annulées jusqu’à une douzaine de fois par jour pendant la période du festival, selon les disponibilités de salle ou les décisions de dernière minute des équipes de programmation. Le front affiche cette programmation sous forme de liste défilante, chargée par lots de vingt séances, avec un bouton « charger plus » qui déclenche l’appel suivant.

Pourquoi la pagination par page échoue ici

La pagination classique de l’API REST de WordPress, avec les paramètres page et per_page, s’appuie sur un décalage numérique : la page trois correspond aux résultats 41 à 60, quel que soit ce que contiennent réellement ces rangs au moment de la requête. Si une séance est supprimée entre le chargement de la page deux et celui de la page trois, l’ensemble des rangs suivants se décale d’une position, et la séance qui occupait le rang 41 au moment du premier appel n’est plus celle qui l’occupe au moment du second. Le front, qui suppose une continuité entre les pages successives, affiche alors des doublons ou saute des séances sans aucun moyen de le détecter.

La pagination par curseur

L'essentiel à retenir : La pagination par numéro de page déplace les résultats quand le contenu bouge ; Un curseur basé sur un identifiant stable évite ce décalage ; before et after remplacent page dans la logique de requête

Plutôt que de désigner une position numérique dans la liste, la pagination par curseur désigne un point de repère stable — ici, l’identifiant de la dernière séance affichée — et demande au serveur tout ce qui vient après ce repère précis, indépendamment de ce qui a pu changer avant lui :

register_rest_route( 'festival/v1', '/seances', array(
    'methods'  => 'GET',
    'callback' => function( WP_REST_Request $request ) {
        $apres = (int) $request->get_param( 'after' );
        $limite = 20;

        $requete = new WP_Query( array(
            'post_type'      => 'seance',
            'posts_per_page' => $limite,
            'orderby'        => 'ID',
            'order'          => 'ASC',
            'post_status'    => 'publish',
        ) );

        // Filtre effectif : ne garder que les identifiants strictement supérieurs au curseur
        add_filter( 'posts_where', function( $where ) use ( $apres ) {
            global $wpdb;
            if ( $apres ) {
                $where .= $wpdb->prepare( " AND {$wpdb->posts}.ID > %d", $apres );
            }
            return $where;
        } );

        $seances = $requete->posts;
        $dernier = end( $seances );

        return new WP_REST_Response( array(
            'seances'      => $seances,
            'curseur_apres' => $dernier ? $dernier->ID : null,
        ) );
    },
) );

Chaque réponse renvoie, en plus des séances elles-mêmes, le curseur à utiliser pour la requête suivante : l’identifiant de la dernière séance transmise. Le front n’a plus besoin de connaître un numéro de page ; il se contente de transmettre ce curseur reçu à l’appel précédent, garantissant que la continuité de la liste ne dépend jamais d’une position numérique susceptible de bouger entre deux requêtes.

Ce que ce choix a changé concrètement

  • Une séance supprimée entre deux appels n’affecte plus le contenu des pages déjà chargées ni celui des pages suivantes
  • Une nouvelle séance ajoutée après le curseur courant apparaît naturellement lors du prochain chargement, sans décalage à gérer
  • Le front peut mettre en cache localement chaque lot déjà reçu sans craindre qu’il devienne incohérent avec les lots suivants

Une limite assumée

Ce mécanisme ne permet pas de sauter directement à une page arbitraire, comme le ferait une pagination numérotée classique. Un curseur ne fonctionne que de façon séquentielle, dans un seul sens à la fois. Pour ce projet, cette limite était acceptable : l’interface propose un défilement continu plutôt que des numéros de page cliquables, un choix cohérent avec la nature évolutive de la programmation.

En résumé

Une programmation qui change plusieurs fois par jour ne se prête pas bien à une pagination numérotée, qui suppose implicitement une liste stable entre deux requêtes. Un curseur basé sur un identifiant stable, transmis d’une réponse à la requête suivante, évite les doublons et les séances manquantes que la pagination classique aurait inévitablement produits sur un contenu aussi mouvant.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi