Des options de tri pour vos pages d’archive et de taxonomie
Aujourd’hui, nous allons voir comment concevoir un système de filtre d’article, en front-office.
Il permettra aux utilisateurs qui visitent une page d’archive ou de taxonomie d’isoler uniquement les articles qui les intéresse, et de les trier selon leurs propres critères.
Je l’utilise relativement souvent sur les thèmes que je réalise, et particulièrement sur des sites autres que blogs.
Laissez vos utilisateurs filtrer vos contenus
Il y a plusieurs méthodes pour réaliser cela, mais celle qui va suivre à la particularité de ne pas dupliquer les urls. Elle ne créer pas de nouvelles ramifications dans la structure du site, et ne dilue pas le « jus » SEO de vos pages.
Et puis elle est simple à utiliser…
Tri d’articles par metadonnée
Pour illustrer la mise en place d’un tel système, je vais prendre pour exemple le site d’une agence immobilière.
Sur la page où sont listés les biens à vendre, il peut-être intéressant de laisser à l’utilisateur le choix :
d’afficher les maisons à vendre en fonction de leur prix
de montrer les annonces par ordre de parution
de les sortir par ordre croissant ou décroissant
On imagine que les annonces correspondent à un Custom Post Type, et que le prix de chaque bien y est enregistré en tant que meta-donnée. La date de parution, elle, renvoie nativement à la publication de l’article WordPress.
On va mettre en place notre système de tri en trois étapes :
créer un formulaire pour l’utilisateur
retenir ses préférences d’affichage dans une variable de session
puis modifier la requête en fonction de ses choix
Les codes qui vont suivre doivent être déposés dans le fichier functions.php de votre thème.
Un formulaire pour organiser l’affichage de vos contenus.
Pour permettre à l’internaute de choisir un mode d’affichage, nous allons concevoir un formulaire.
Vous allez probablement devoir le réutiliser à plusieurs endroits de votre thème. Il est donc préférable de le créer dans une fonction que nous appellerons là où il faut (dans la page d’archive, de taxonomie…).
Il n’est pas nécessaire de préciser l’action du formulaire ; lors de sa soumission, il se rechargera sur la même page.
function switcher_session() {
?>
<form method="post" class="switcher">
<!-- ici nous allons mettre les options -->
</form>
<?php
}
Il faut maintenant exécuter la fonction switcher_session() dans le template d’archive de notre custom post type, et éventuellement de taxonomie. Je vous suggère d’appeler fonction entre if( have_posts() ) et while( have_posts() ).
Si on visite la page, le formulaire y apparait maintenant.
Un fois qu’il sera validé, il faudra sauvegarder les informations quelque part. Le plus logique dans le cas présent est de les stocker dans la variable de session. Ainsi les informations seront isolées pour chaque utilisateur et persisteront tant qu’il ne ferme pas son navigateur.
Enregistrer les options dans la session
Pour créer et mettre à jour une variable de session, il faut lancer une fonction qui s’exécutera lors de l’initialisation de WordPress.
On utilise donc le hook init.
add_action( 'init', 'switch_session' );
function switch_session() {
// notre code ira ici
}
Il est important de s’arranger pour que les valeurs passées en post ne soient pas ajoutées telles quelles dans la variable. Simplement pour des raisons de sécurité…
WordPress à un comportement particulier avec les variables de session ; le code présenté aura besoin, dans certains cas normalement assez rares, d’être adapté.
À ce stade, les choix de l’utilisateur sont enregistrés. Par contre ils ne s’afficheront pas dans le formulaire qui vient de se recharger.
Il faut les récupérer via la session puis utiliser la fonction selected() de WordPress pour sélectionner l’option en cours.
Grâce au hook pre_get_posts, c’est quelque chose d’assez simple à faire.
Il faut y exécuter une fonction qui va filtrer les argument de WP_Query.
Tout d’abord on vérifie qu’il s’agit de la bonne requête à surcharger (page d’archive du post type ciblé, requête principale en front), puis on va chercher nos valeurs sauvegardées en session.
// L'overide de la requête
add_action( 'pre_get_posts', 'switch_output_order' );
function switch_output_order( $q ) {
// Si on est en front et qu'il s'agit de la requête principale de la page d'archive
if( ! is_admin() && $q->is_main_query() && is_post_type_archive( 'cpt' ) ) {
// tri par prix
if( 'price' == $_SESSION[ 'post-order-by' ] ) {
$q->set( 'meta_key', '_price' );
$q->set( 'orderby', 'meta_value_num');
}
/*
* Par défaut, WordPress tri par date, donc il n'y a pas besoin d'effectuer'
* un autre overide pour le tri par date ;-)
*
* Sauf si, par exemple, vous voulez trier selon une date
* autre que la publication de l'article...
*/
// Tri croissant ou décroissant
$q->set( 'order', $_SESSION[ 'post-order' ] );
}
La variable $q représente la WP_Query ; on utilise la méthode set() pour en redéfinir certaines parties.
Si la valeur de post-order-by est « price », alors on ajoute à la requête les conditions meta_key = _price (qui correspond à la metadonnée) et orderby = meta_value_num.
Si post-order-by est défini à date, alors nous n’avons rien à faire car WordPress tri les articles par date par défaut.
Puis on défini order selon la valeur de post-order.
Il n’y a pas besoin de tester nos variables de session, puisque l’on sait qu’elles ont été correctement définies lors de l’init.
Le code complet
Notre système de tri est maintenant pleinement fonctionnel 🙂
Re-voici le code dans son intégralité :
add_action( 'init', 'switch_session' );
function switch_session() {
// J'initialize la session
if( ! session_id() )
session_start();
// Si le switcher à été utilisé, on change la valeur
if( isset( $_POST[ 'post-order' ] ) ) {
$_SESSION[ 'post-order' ] = ( 'ASC' == $_POST['post-order'] ) ? 'ASC' : 'DESC';
}
if( isset( $_POST[ 'post-order-by' ] ) ) {
$_SESSION[ 'post-order-by' ] = ( 'price' == $_POST['post-order-by'] ) ? 'price' : 'date';
}
// S'il n'y a pas d'ordre de défini, on en met un par défaut
if( ! isset( $_SESSION[ 'post-order' ] ) )
$_SESSION[ 'post-order' ] = 'ASC';
if( ! isset( $_SESSION[ 'post-order-by' ] ) )
$_SESSION[ 'post-order-by' ] = 'price';
}
// L'overide de la requête
add_action( 'pre_get_posts', 'switch_output_order' );
function switch_output_order( $q ) {
// Si on est en front et qu'il s'agit de la requête principale de la page d'archive
if( ! is_admin() && $q->is_main_query() && is_post_type_archive( 'cpt' ) ) {
// tri par prix
if( 'price' == $_SESSION[ 'post-order-by' ] ) {
$q->set( 'meta_key', '_price' );
$q->set( 'orderby', 'meta_value_num');
}
/*
* Par défaut, WordPress tri par date, donc il n'y a pas besoin d'effectuer'
* un autre overide pour le tri par date ;-)
*
* Sauf si, par exemple, vous voulez trier selon une date
* autre que la publication de l'article...
*/
// Tri croissant ou décroissant
$q->set( 'order', $_SESSION[ 'post-order' ] );
}
// On retourne la requête
return $q;
}
// Le code du switcher
function switcher_session() {
$current_order = $_SESSION[ 'post-order' ];
$current_order_by = $_SESSION[ 'post-order-by' ];
?>
<form method="post" class="switcher">
<p><label for="post-order-by">Trier selon :</label>
<select id="post-order-by" name="post-order-by" onchange="this.form.submit()">
<option value="date" <?php selected( $current_order_by, 'date' ); ?>>la date</option>
<option value="price" <?php selected( $current_order_by, 'price' ); ?>>le prix</option>
</select></p>
<p><label for="post-order">Ordre de tri :</label>
<select id="post-order" name="post-order" onchange="this.form.submit()">
<option value="DESC" <?php selected( $current_order, 'DESC' ); ?>>Décroissant</option>
<option value="ASC" <?php selected( $current_order, 'ASC' ); ?>>Croissant</option>
</select></p>
</form>
<?php
}
Tout fonctionne, mais aurait pu aller beaucoup plus loin…
Filtrer les articles par terme de taxinomie
Reprenons notre exemple d’agence immobilière, et imaginons que l’on veuille filtrer les biens selon qu’ils soient des appartements, des villas, des maisons…
Il suffit simplement d’ajouter un select dans le formulaire, et d’y lister les termes de la taxonomie genre-bien (la taxonomie relative à nos type de biens).
Chaque bien de l’agence possède (ou non) certains équipements. Certains clients seront intéressés uniquement par les habitations qui comportent une piscine, une cuisine aménagée ou autre…
Ces différents équipements ont été entrés dans WordPress en tant que meta-donnés des hébergements.
Nous allons ajouter une checkbox « piscine » dans le formulaire :
Vu que la checkbox qui ne sera pas cochée ne sera pas soumise en post, il faut insérer un input hidden avec le même name juste avant, mais avec une valeur différente.
Ensuite on sauvegarde l’option dans une session.
//dans switch_session() on sauvegarde la valeur de post-piscine,
//on sinon on en défini une par défaut
if( isset( $_POST[ 'post-piscine' ] ) ) {
$_SESSION[ 'post-piscine' ] = ( 1 == $_POST[ 'post-piscine' ] ) ? true : false;
}
if( ! isset( $_SESSION[ 'post-piscine' ] ) )
$_SESSION[ 'post-piscine' ] = false;
Voilà, vous pouvez maintenant réaliser vos propres filtres d’article en front office.
Le gros avantage de cette méthode est qu’elle ne créer pas plusieurs pages avec des contenus quasi-similaires. C’est particulièrement intéressant au niveau de l’optimisation pour les moteurs de recherche.
Oui tout à fait, on peut s’en servir dans de nombreux contextes. Sur un site récent, je m’en suis servi pour laisser l’utilisateur choisir s’il était une entreprise ou un particulier. Les contenus restaient à peu de chose près identiques, seuls les descriptions de catégories changeaient… Il aurait été dommage de dupliquer tout le site 🙂
Pour le session_start(), il est indispensable sinon la variable de session ne fonctionne pas.
Par contre je ne me suis pas embêté ici avec le session_destroy()…
Ricardo, il y a 7 ans
Si je comprend bien, c’est le fait de retenir les préférences dans le session qui empêche la duplication?
En fait, il y a plusieurs façon de proposer des systèmes de tri en front-office.
La plupart de ces systèmes (dont les taxonomies WordPress, ou les archives datées) créent des pages avec des URLs différents et des contenus très similaires (mêmes articles et mêmes descriptions).
Alors qu’un système de session, lui, ne créer pas de nouvelles URLs. C’est juste ça.
J’avais testé avec un système de session de proposer sur une home des contenus selon un profil pré-déterminé, le moteur visitant celui par défaut.
En gros je chargeais les catégories selon les profils. Il me reste plus qu’à intégrer ces filtres et la personnalisation est complète et propre.
Avec ce code le filtre est généré à la volée, le moteur n’ayant pas de session (fin…) il y verra un seul et unique site et contenu. Dites si je me trompe !
Pierre, il y a 7 ans
Super article avec plein de références .. j’ai appris pas mal de truc !!
J’ai bien aimé le check :
( in_array( $_POST[ ‘post-genre’ ], wp_list_pluck( ‘slug’, $terms ) ) )
Un peu noob, mais j’aurais ajouté un wp_nonce_field dans le formulaire .. Bonne ou mauvaise idée ?
Autre question, y aurait-il un intérêt à passer les paramètres en paramètre WP ? En tout cas, j’ai cherché à le faire pour un cas perso .. sans succès !!
Merci , je suis content que cet article t’ai appris des trucs 😉
Le check de sécurité, c’est Julio de Boite a Web qui me l’a montré. Très pratique, et pas très long, j’aime bien aussi…
Pour le nonce field, ici je ne suis pas persuadé qu’il y en ai besoin : quel est le risque ? Une CSRF pour prendre le contrôle du tri des articles d’un internaute ? 😛
Mais après, oui, c’est possible.
On pourrai passer les paramètres à WP, mais dans des cas plus complexes, et cela sera le thème d’un futur article 🙂
Tout d’abord; merci beaucoup pour cet article ! Je suis débutante, mais j’apprends énormément grâce à ce genre d’article !
J’essayais de faire en sorte que l’utilisateur puisse sélectionner plusieurs checkbox de métadonnés à la fois pour la recherche. Pourriez-vous m’aiguiller vers une solution ?
Merci pour ce tutoriel. J’ai appris pas mal de choses techniques qui me manquaient jusque la 😉
Par contre, j’ai une petite question : je souhaiterais initialiser tous les paramètres appliqués d’une seule traite (plusieurs taxo filtrées) pour avoir une page clean à la demande même si les données s’effacent une fois le navigateur fermé. Comment puis-je procéder ?
Ce que j’aime est que cela peut servir dans d’autres contextes également.
En revanche toute la documentation que j’ai pu lire sur les sessions dans WordPress recommande cet ajout dans le hook init :
Il faudrait aussi un
session_destroy ();
sur les hookswp_logout
etwp_login
au cas où un utilisateur se logue avec différents identifiants.Pour le session_start(), il est indispensable sinon la variable de session ne fonctionne pas.
Par contre je ne me suis pas embêté ici avec le session_destroy()…
La plupart de ces systèmes (dont les taxonomies WordPress, ou les archives datées) créent des pages avec des URLs différents et des contenus très similaires (mêmes articles et mêmes descriptions).
Alors qu’un système de session, lui, ne créer pas de nouvelles URLs. C’est juste ça.
J’avais testé avec un système de session de proposer sur une home des contenus selon un profil pré-déterminé, le moteur visitant celui par défaut.
En gros je chargeais les catégories selon les profils. Il me reste plus qu’à intégrer ces filtres et la personnalisation est complète et propre.
Avec ce code le filtre est généré à la volée, le moteur n’ayant pas de session (fin…) il y verra un seul et unique site et contenu. Dites si je me trompe !
J’ai bien aimé le check :
( in_array( $_POST[ ‘post-genre’ ], wp_list_pluck( ‘slug’, $terms ) ) )
Un peu noob, mais j’aurais ajouté un wp_nonce_field dans le formulaire .. Bonne ou mauvaise idée ?
Autre question, y aurait-il un intérêt à passer les paramètres en paramètre WP ? En tout cas, j’ai cherché à le faire pour un cas perso .. sans succès !!
Le check de sécurité, c’est Julio de Boite a Web qui me l’a montré. Très pratique, et pas très long, j’aime bien aussi…
Pour le nonce field, ici je ne suis pas persuadé qu’il y en ai besoin : quel est le risque ? Une CSRF pour prendre le contrôle du tri des articles d’un internaute ? 😛
Mais après, oui, c’est possible.
On pourrai passer les paramètres à WP, mais dans des cas plus complexes, et cela sera le thème d’un futur article 🙂
J’essayais de faire en sorte que l’utilisateur puisse sélectionner plusieurs checkbox de métadonnés à la fois pour la recherche. Pourriez-vous m’aiguiller vers une solution ?
Merci !!!
$q->set( ‘orderby’, ‘meta_value_num’);
j’ai du zapper un truc..
Merci et bonne continuation
Par contre, j’ai une petite question : je souhaiterais initialiser tous les paramètres appliqués d’une seule traite (plusieurs taxo filtrées) pour avoir une page clean à la demande même si les données s’effacent une fois le navigateur fermé. Comment puis-je procéder ?