Home » wordpress » Filtrer ses articles et ajouter un bouton « loadmore »
Filtrer ses articles et ajouter un bouton « loadmore »
Comment créer un filtre et un bouton ajax load more pour vos articles ?
Aujourd’hui on va voir comment créer un système de filtre (classification) pour les articles, et ajouter une navigation ajax grâce à un bouton load more.
Les sources
Le code s’inspire très largement de l’excellent tuto de rudrastyh, sauf que nous on ne va pas utiliser le même système de filtres. Dans son tutoriel, rudrastyh utilise des champs select qu’il relie entre eux. Dans notre exemple, on va partir sur des checkbox ou boutons radios, stylisés en bouton. Pour une simple liste en ul>li, le code sera le même.
Je me suis également appuyé sur le tuto d’Alicia ramirez, qui en fait une utilisation plus simple en utilisant isotope.js.
On va partir ici d’un cadre relativement simple, celui des articles classiques de wordpress.
Un affichage original
On va en plus permettre un affichage original de nos articles, avec un système en colonnes, qui se reproduira à chaque filtrage .
Voici donc le résultat auquel on veut parvenir :
L’originalité de mon exemple, c’est qu’au clic sur n’importe lequel des filtres, la présentation des vignettes d’articles sera la même, avec toujours en premier, une vignette de 12 colonnes, ensuite 6, puis 4.
Ce dont on va avoir besoin :
Des articles. Cela paraît évident, donc il faut créer des articles pour que le système fonctionne.
Des catégories : liez vos articles à des catégories, les boutons des filtres représentent justement vos catégories.
Une grille en colonne, j’utilise ici une grille flexbox originale que vous pouvez trouver ici.
La structure de base
Je repars ici de mon exemple précédent, auquel je rajoute le système de filtres. Je suis dans ma page blog, donc dans mon fichier index.php ou home.php.
); $query = new WP_Query( $args ); ?> <?php if ( $query->have_posts() ) : $count = (int)0;?> <div id="cc_posts_wrap" class="flex-row"> <?php while ( $query->have_posts() ) : $count++; $query->the_post(); if($count == 1){ // Si c'est le premier article de la liste, entour le d'une clase 12 colonnes $span = 'flex-col-xs-12'; } if($count == 2 || $count == 3){// Si c'est le deuxième et troisième article de la liste, entour le d'une clase 6 colonnes $span = 'flex-col-sm-6';
} if($count > 3){ // sinon pour tous les suivants, répartis les en 3 colonnes $span = 'flex-col-sm-4';
} //If its not 3 or higher, increase the count $termsArray = get_the_terms($post->ID, "category"); $termsString =""; foreach ( $termsArray as $term ) { $termsString .= $term->slug; } ?> <div class="<?php echo $termsString .' ' . $span ;?> item"> <article id="post-<?php the_ID(); ?>" <?php post_class();?>> <div class="post-featured-thumbnail"> <?php if ( has_post_thumbnail() ) { if($count == 1){ the_post_thumbnail('blog_featured'); }else{ the_post_thumbnail(); } }
Le système de filtres est assez simple, c’est un code que l’on peut retrouver un peu partout, notamment sur stackoverflow, puisque tout le monde se base sur les mêmes tutoriels, celui d’Alicia Ramirez par exemple ! C’est évidemment à personnaliser en fonction de ses besoins.
C’est donc un simple formulaire, contenant un bouton radio « all » censé réinitialiser la recherche ou le filtrage. Ensuite dans une boucle on crée autant de boutons radios qu’il y a de catégories, et pour chacune d’entre elle, on récupère l’id, le nom ou le slug.
Il faut faire très attention aux noms données aux éléments : Choisissez des noms précis et gardez-les, il faut avoir un peu de rigueur là-dessus car on va les retrouver un peu partout dans le système :
l’ID du formulaire : id= »post_filters »
le nom de nos boutons radio : name= »category_filters »
la valeur du champ caché pour envoyer le formulaire: value= »ccfilter »
L’article en lui-même
La boucle principale va donc nous ramener nos articles. Ici, comme précisé au début, j’affiche grâce à un compteur que j’incrémente, une disposition en colonne, comme sur l’image. Le code est propre à mon projet, à vous de styliser ça à votre façon !
L’essentiel, c’est que l’article soit disposé dans un conteneur, ici je lui donne l’ID: id= »cc_posts_wrap ». Le système de filtres, ainsi que le bouton load more sont donc à l’extérieur de ce conteneur.
Le bouton load-more
Enfin, tout à la fin on place notre bouton load more
<?php global $wp_query; if ( $wp_query->max_num_pages > 1 ) : echo '<div class="loadmore_block"><div id="cc_loadmore">Voir plus d\'articles</div></div>';
Le moteur des filtres et bu bouton ajax
Voici tout le code à insérer dans functions.php
/*FUNCTION FILTER AND AJAX LOAD MORE*/ add_action( 'wp_enqueue_scripts', 'cc_script_and_styles'); function cc_script_and_styles() { if ( is_home() || is_category() || is_archive()) { global $wp_query; wp_register_script( 'cc_scripts', get_stylesheet_directory_uri() . '/js/script.js', array('jquery') ); wp_localize_script( 'cc_scripts', 'cc_loadmore_params', array( 'ajaxurl' => site_url() . '/wp-admin/admin-ajax.php', // WordPress AJAX 'posts' => json_encode( $wp_query->query_vars ), // everything about your loop is here 'current_page' => $wp_query->query_vars['paged'] ? $wp_query->query_vars['paged'] : 1, 'max_page' => $wp_query->max_num_pages ) );
wp_enqueue_script( 'cc_scripts' ); } } /*AJAX LOAD MORE AND FILTERS*/ add_action('wp_ajax_loadmorebutton', 'cc_loadmore_ajax_handler'); add_action('wp_ajax_nopriv_loadmorebutton', 'cc_loadmore_ajax_handler');
add_action( 'wp_enqueue_scripts', 'cc_script_and_styles'); function cc_script_and_styles() { if ( is_home() || is_category() || is_archive()) { global $wp_query; wp_register_script( 'cc_scripts', get_stylesheet_directory_uri() . '/js/script.js', array('jquery') ); wp_localize_script( 'cc_scripts', 'cc_loadmore_params', array( 'ajaxurl' => site_url() . '/wp-admin/admin-ajax.php', // WordPress AJAX 'posts' => json_encode( $wp_query->query_vars ), // everything about your loop is here 'current_page' => $wp_query->query_vars['paged'] ? $wp_query->query_vars['paged'] : 1, 'max_page' => $wp_query->max_num_pages ) );
wp_enqueue_script( 'cc_scripts' ); } }
/*AJAX LOAD MORE AND FILTERS*/ add_action('wp_ajax_loadmorebutton', 'cc_loadmore_ajax_handler'); add_action('wp_ajax_nopriv_loadmorebutton', 'cc_loadmore_ajax_handler');
Dans notre fonction wp_enqueue_script, on fait appel à un premier fichier js qui va contenir tout le code nécessaire au bon fonctionnement du système de filtre et du rechargement ajax des articles. On voit ca juste après.
Puis on charge le fichier ‘admin-ajax.php‘ intégré par défaut dans wordpress.
Vous pouvez voir que j’entoure l’appel au script d’une condition :
if ( is_home() || is_category() || is_archive()) {...}
Comme j’utilise ce système aussi pour des custom post type, je limite ici l’appel des scripts au blog, aux catégories et aux archives puisque j’utilise ce même script pour mes catégories et mes archives. Comme l’appel au script ajax est différent pour les custom post type, j’évite ainsi une interférence entre les deux.
2-Ajax load more button
Les deux lignes de codes qui suivent nous servent à créer nos actions ajax. Les premières serviront au bouton ajax load more, et plus bas dans le code, on va retrouver la même chose mais cette fois pour les filtres ajax.
Dans notre add_action et pour faire fonctionner notre ajax, les deux « mots clés » wp_ajax_ » et « wp_ajax_nopriv_ » sont obligatoires, et ils doivent être suivis du nom de votre action.
Pour le bouton load_more, je leur donne un nom significatif « loadmorebutton« . Le nom donné en deuxième argument : « cc_loadmore_ajax_handler » est le nom de la fonction située juste en dessous.
Comme on le voit, cette fonction « function cc_loadmore_ajax_handler(){ } » contient une boucle pour afficher mes articles. Ici, je n’ai pas besoin de reproduire l’affichage avec différentes tailles de colonnes. Comme les articles doivent s’afficher à la suite, je souhaite plutôt conserver un affichage homogène avec les derniers articles. Ils s’afficheront donc normalement, c’est à dire en 3 colonnes.
Filters functions
Ensuite vient le code pour le filtrage des articles.
Ici, on retrouve les deux mots clés obligatoires, suivi du nom de mes actions :
Le nom de l’action donné ici: « ccfilter« , doit être le même que celui de la valeur de mon champs caché dans le formulaire de filtrage, souvenez-vous.
<!-- required hidden field for admin-ajax.php --> <input type="hidden" name="action" value="ccfilter" />
Comme à chaque clic sur un bouton de filtrage la page devra « effacer les articles » pour afficher ceux d’une autre catégorie, je souhaite conserver mon affichage original montré dans l’image. La boucle est donc exactement la même que dans mon fichier index.php (ou home.php)
Pour le bouton « all », c’est assez simple en fait, on crée un boucle sans distinction de catégorie :
On ramène toutes les catégories, avec get_terms suivi du nom de la taxonomie qui est ici category (système classique de wordpress). On aurait aussi pu faire un simple get_categories().
Vous pouvez vous référer à l’article cité ou aller sur php.net pour comprendre l’utilité des fonctions ob_start();ob_end_clean(); et ob_get_contents();
Les fonctions js
Dans notre fonction wp_enqueue_script, on a vu qu’on faisait appel à un fichier js
Il va donc falloir créer ce fichier. Donnez-lui le nom que vous voulez, bien sûr le même que dans cette fonction wp_register_script().
Et voici donc tout le code à insérer dans le fichier js
jQuery(function($){
/* LOAD MORE FUNCTION ON FORMATION ARCHIVE PAGE */ $('#cc_loadmore').click(function(){
$.ajax({ url : cc_loadmore_params.ajaxurl, // AJAX handler data : { 'action': 'loadmorebutton', // le paramètre pour admin-ajax.php 'query': cc_loadmore_params.posts, // le paramètre de la loop utilisée par wp_localize_script() 'page' : cc_loadmore_params.current_page // la page en cours }, type : 'POST', beforeSend : function ( xhr ) { $('#cc_loadmore').text('Recherche...'); // mettre ici let exte de son choix pour le chargement des articles }, success : function( posts ){ if( posts ) {
$('#cc_loadmore').text( 'Voir plus d\'articles' ); $('#cc_posts_wrap').append( posts ); // on "append" les articles supplémentaires cc_loadmore_params.current_page++;
if ( cc_loadmore_params.current_page == cc_loadmore_params.max_page ) $('#cc_loadmore').hide(); // on cache le bouton s'il n'y a plus d'articles
} else { $('#cc_loadmore').hide(); // s'il n'y a rien à afficher on cache le bouton } } }); return false; }); /* FILTERING FUNCTION ON FORMATION ARCHIVE PAGE */ $('#post_filters').change(function(){
$.ajax({ url : cc_loadmore_params.ajaxurl, data : $('#post_filters').serialize(), // form data dataType : 'json', // on utilise le format json pour passer directement côté serveur type : 'POST',
success : function( data ){
cc_loadmore_params.current_page = 1;
cc_loadmore_params.posts = data.posts;
cc_loadmore_params.max_page = data.max_page;
$('#cc_posts_wrap').html(data.content);
if ( data.max_page < 2 ) { $('#cc_loadmore').hide(); } else { $('#cc_loadmore').show(); } } }); // return folse pour ne pas envoyer le formulaire return false;
}); });
Comme on le voit ici , on retrouve les différents noms donnés à nos élements :
#cc_loadmore c’est l’ID de notre bouton ajax load more dans notre fichier index.php ou home.php.
‘action’: ‘loadmorebutton’, c’est donc le nom de notre action ajax,
cc_loadmore_params c’est le nom donné en argument à notre fonction wp_localize_script()
#cc_posts_wrap c’est le nom de notre conteneur principal, dans notre fichier index.php ou home.php.
#post_filters, c’est l’ID de notre formulaire de filtrage.
Utiliser le même système pour ses pages d’archives
Pour aller plus loin, vous pouvez aussi faire fonctionner votre bouton ajax load more dans vos pages d’archives.
Je mets ici tout le code d’une page archive, dans laquelle j’intègre ce bouton. C’est le même css finalement que dans la page blog, et on utilise le même appel au script js. J’utilise donc la fonction function cc_loadmore_ajax_handler(){} et la boucle contenue à l’intérieur
<?php endwhile;?> </div> <!-- end isotope-list --> <?php global $wp_query; // you can remove this line if everything works for you if ( $wp_query->max_num_pages > 1 ) : echo '<div class="loadmore_block"><div id="cc_loadmore">Voir plus d\'articles</div></div>'; // you can use <a> as well endif; else : get_template_part( 'template-parts/content', 'none' );
Dans un prochain article, on va voir comment pousser encore plus loin et faisant la même chose avec les custom post type.
Recommandations :
Si malgré tout ce code vous ne parvenez pas à faire marcher le bouton loadmore en ajax ou le système de filtres, je vous invite à consulter les nombreux commentaires sur les pages suivantes : loadmore, filters, ajax et filtres, load more et pagination. De nombreux internautes posent des questions et d’autres y répondent. Vous devriez y trouver des pistes !
Si vous rencontrez un problème lors de l’affichage des articles, notamment au niveau du nombre de posts affichés, changez le paramètre « posts_per_page » et modifiez également les options dans le backoffice de wordpress dans Réglages / Lecture.