Donner la possibilité aux visiteurs de choisir le critère de tri d’une liste

Nous présentons ici quelques boucles et astuces utiles pour permettre aux visiteurs d’un site web de modifier selon différents critères l’ordre de données présentées en liste. Plutôt qu’un produit fini à installer tel quel, nous proposons ici une boîte à outils dans laquelle il vous appartiendra de choisir ceux qui sont utiles et pertinents dans le cadre de votre projet.

Liminaire

Prérequis. Connaître le fonctionnement des boucles de SPIP et des critères de classement.

Compatibilité. La dernière version stable de SPIP (1.8.2.d) doit être installée : nous aurons en effet besoin du filtre parametre_url [1] introduit très récemment dans la distribution officielle (la version 1.8.2. ne suffit pas).

Objectif

Dans certains cas — assez rares [2] —, il est utile de permettre aux internautes de choisir eux-mêmes l’ordre d’affichage des données que vous leur proposez. L’exemple-type est celui des résultats d’une recherche interne au site où il est souvent intéressant de pouvoir trier les articles par pertinence, par date ou par date inverse. C’est cet exemple d’une page présentant les résultats d’une recherche que nous développons ici.

Pour le dire autrement — un petit dessin valant mieux qu’un long discours —, nous souhaitons arriver à quelque chose comme ceci: http://mag.spip.net/recherche.php?r... [3].

Le code

Venons-en tout de suite au fait. Voici le code que nous vous proposons d’ajouter dans votre squelette d’affichage des résultats d’une recherche. tel qu’écrit ci-dessous, ce code ne sera utilisable que dans ce cas bien précis (où un paramètre recherche est présent dans le contexte), mais il est facile de le modifier pour l’utiliser dans d’autres circonstances, ce qui pourra éventuellement faire l’objet d’un prolongement de cet article.

<!-- On n'affiche le formulaire de tri que si la boucle n'est pas vide -->
<BOUCLE_test(ARTICLES){recherche}> </BOUCLE_test>

<div class="boite_recherche">
<h3><:trier:>&nbsp;:</h3>

<form id="tri" action="#" method="get" name="tri">
<select size="1" name="choix_critere"
	onchange="if (options[selectedIndex].value) {
		location = options[selectedIndex].value;
	}">

<!-- Classement par pertinence -->
[(#ENV{tri}|?{
	<option value="[(#SELF|parametre_url{'tri',''}|parametre_url{'ordre',''})]"><:par_pertinence:></option>
,
	<option selected="selected" class="selected"><:par_pertinence:></option>

})]

<!-- Classement par date -->
[(#ENV{tri}|=={'date'}|?{
	[(#ENV{ordre}|=={'normal'}|?{
		<option value="[(#SELF|parametre_url{'tri','date'}|parametre_url{'ordre',''})]"><:par_ordre_antichronologique:><option>
		<option selected="selected" class="selected"><:par_ordre_chronologique:></option>

		,
		<option selected="selected" class="selected"><:par_ordre_antichronologique:></option>
		<option value="[(#SELF|parametre_url{'tri','date'}|parametre_url{'ordre','normal'})]"><:par_ordre_chronologique:></option>
	})]
	,
	<option value="[(#SELF|parametre_url{'tri','date'}|parametre_url{'ordre',''})]"><:par_ordre_antichronologique:></option>
	<option value="[(#SELF|parametre_url{'tri','date'}|parametre_url{'ordre','normal'})]"><:par_ordre_chronologique:></option>		
})]

<!-- Classement par date de modification -->
[(#ENV{tri}|=={'date_modif'}|?{
	<option selected="selected" class="selected"><:par_date_modif:></option>

	,
	<option value="[(#SELF|parametre_url{'tri','date_modif'}|parametre_url{'ordre',''})]"><:par_date_modif:></option>
})]

<!-- Classement par popularite -->
[(#ENV{tri}|=={'popularite'}|?{
	<option selected="selected" class="selected"><:par_popularite:></option>
	,
	<option value="[(#SELF|parametre_url{'tri','popularite'}|parametre_url{'ordre',''})]"><:par_popularite:></option>
	>})]

<!-- Classement par nb de visites -->
[(#ENV{tri}|=={'visites'}|?{
	<option selected="selected" class="selected"><:par_nombre_visiteurs:></option>

	,
	<option value="[(#SELF|parametre_url{'tri','visites'}|parametre_url{'ordre',''})]"><:par_nombre_visiteurs:></option>
})]
</select>
</form>
</div>

<!-- Il ne reste plus qu a afficher les resultats en fonction des criteres chosis -->
<?php if("[(#ENV{ordre})]"=="normal") { ?>

	<BOUCLE_trier(ARTICLES){recherche}{par #ENV{tri},points}{0,25}{id_rubrique !IN 13}>
	<div class="bloc">
		[(#POINTS|etoiles)]
		<INCLURE(item.inc.php){id_article}{recherche}{mode='detail'}>

	</div>
	</BOUCLE_trier>

<?php } else { ?>

	<BOUCLE_trier2(ARTICLES){recherche}{!par #ENV{tri},points}{0,25}{id_rubrique !IN 13}>
	<div class="bloc">
		[(#POINTS|etoiles)]
		<INCLURE(item.inc.php){id_article}{recherche}{mode='detail'}>
	</div>
	</BOUCLE_trier2>

<?php } ?>

</B_test>
<p><:aucun_article:></p>
<//B_test>

Quelques explications

-  Un usage intensif est fait de la balise #ENV [4], qui nous permet de récupérer la valeur d’un paramètre passé en url et de générer le tri adéquat en fonction de ce paramètre. Pratiquement, nous utilisons deux paramètres: tri et ordre. Combinés, ces deux paramètres devraient théoriquement nous permettre de générer dix cas de figure différents (chacun des cinq critères de tri utilisés ici pouvant être classés par ordre normal ou par ordre inverse). Nous avons cependant volontairement réduit ces possibilités à six, en estimant que le seul cas où un classement par ordre croissant des valeurs est pertinents est l’ordre chronologique (il n’est pas intéressant de trier une liste en commençant par le moins populaire, le moins visité ou le moins pertinent). Ceci n’étant qu’un exemple, il vous sera facile d’adapter le concept à vos propres besoins.

-  Nous utilisons abondamment les potentialités du filtres “?” , seule structure conditionnelle explicite du langage SPIP.

-  Le passage d’un mode de tri à un autre s’effectue grâce à une ligne de javascript dans le menu de type select qui est mis en place. Il est possible de remplacer ce menu par des simples liens html en supprimant les balises <select> ... </select> et en remplaçant simpement par <option value="..."> par <a href="..."> (et </option> par </a>).

-  Etant donné que nous utilisons la méthode «GET» pour transmettre les données de notre formulaire, une url différente est appelée pour chaque tri différent. Cela nous permet de ne pas avoir à nous soucier du cache de SPIP et au contraire d’en profiter pleinement. Un nouvel enregistrement dans le cache est en effet généré pour chaque url différent appelé.

-  Le filtre parametre_url permet de modifier l’url courant (#SELF) pour en modifier un des paramètres. Ceci nous évite de perturber d’autres fonctionnalités du site qui peuvent dépendre d’autres paramètres de l’url. Nous devons donc éviter de perturber ces autres paramètres comme nous le ferions en nous contentants de regénérer une url à partir des seuls paramètres utilisés dans le présent cadre.

-  Nous n’échappons pas à l’utilisation d’un peu de php, car il n’est actuellement pas possible de faire dépendre une boucle d’une structure conditionnelle et parce qu’il n’est pas encore possible de définir l’ordre du tri par une variable d’environnement. Des formules alambiquées utilisant des inclusions permettent dans certains cas de contourner le problème mais nous avons préféré privilégier la lisibilité du code.

-  Notez, dans les boucles d’affichage de la liste, la structure {par #ENV{tri},points}, qui utilise deux critères de tri sucessifs, ce qui n’est pas spécialement la méthode la plus intuitive. Elle est cependant inévitable car si nous avions écrit {par #ENV{tri,points}}, qui trie par points si tri n’est pas défini dans l’environnement — ce qui est a priori plus logique —, nous aurions butté sur une limitation du compilateur (points n’étant pas une donnée directement issue de la base de données, mais une pseudo-colonne, calculée par SPIP).

-  Pour l’affichage des informations relatives aux articles recherches (titre, introduction, métadonnées,...), nous faisons ici appel à un fichier inclus item.inc.php/html, ce qui évite de dupliquer ce morceau de code [5]. A toutes fins utiles, en voici le code:

<BOUCLE_item(ARTICLES){id_article}>
<div dir="#LANG_DIR" style="text-align: #LANG_LEFT;">
[<div class="rubrique">(#SURTITRE)</div>]
<h2><a href="#URL_ARTICLE" [title="(#DESCRIPTIF|textebrut|entites_html)"]>#TITRE</a></h2>
<div class="reference"><?php
$tous_auteurs = trim(auteur_et_auteur('<BOUCLE_signature(AUTEURS){id_article}{par nom}{nom!==^@}{", "}><a href="#URL_AUTEUR">[(#NOM|prenom|texte_script) ][<span class="nom">(#NOM|nom|texte_script)</span>]</a></BOUCLE_signature>','<:et:>'));
if ($tous_auteurs) echo "<:par_auteur:> ".$tous_auteurs.", "; ?>[(#DATE|affdate)]
[(#ENV{mode}|=={'detail'}|?{
	<br/>
	[<:mise_a_jour:> (#DATE_MODIF|affdate) | ]
	[(#POPULARITE_ABSOLUE) <:visiteurs_par_jour:> | ]
	[(#VISITES) <:total_visiteurs:>]
,''})]
</div>

[<a href="#URL_ARTICLE" class="bloc">(#INTRODUCTION|couper{#ENV{couper,300}})</a>]
</div>
</BOUCLE_item>

Bien sûr, vous pouvez aisément remplacer cette inclusion par l’affichage des données normales attendues (#TITRE, #INTRODUCTION, #DATE,...)

Gestion des inclusions

Si vous jouez avec des inclusions [6] et surtout si le code proposé ici se trouve lui-même dans un fichier inclus, n’oubliez pas de faire passer les paramètres nécessaires aux squelettes inclus, de la façon suivante :

<INCLURE(squelette_inclus.inc.php){critere1}{critere2}>

Concrètement, dans le cas présent, une inclusion prendra probablement la forme suivante :

<INCLURE(listing.inc.php) {tri} {ordre} {recherche}>

Les paramètres transmis dans l’URL de la page seront alors passés dans le fichier inclus où ils pourront être utilisés.

Fichiers de langue

Avant de terminer, nous n’oublierons pas de compléter nos fichiers de langue [7] avec les chaînes utilisées, dont voici la version française:

'mise_a_jour_le' => 'Mise &agrave; jour',
'nombre_de_visiteurs' => 'Nombre de visiteurs',
'par_date' => 'Par date',
'par_date_modif' => 'Par date de modification',
'par_nombre_visiteurs' => 'Par le nombre de visiteurs',
'par_ordre_antichronologique' => 'Par ordre antichronologique',
'par_ordre_chronologique' => 'Par ordre chronologique',
'par_pertinence' => 'Par pertinence',
'par_popularite' => 'Par popularit&eacute;',
'publie_le' => 'Publi&eacute; le',
'trier' => 'Trier',

Si votre site est monolingue et que vous ne souhaitez pas profiter de la centralisation des chaînes verbales qu’offre le module de gestion des langues, vous pouvez sans dommage vous passer de cette étape et remplacer les balises linguistique dans le code source que nous proposons par leur traduction.

Aller plus loin

-  Concernant la gestion de tris avancés, vous consulterez utilement l’article Définir le type de tri d’une rubrique avec des mots-clés.

-  L’article Trier les résultats d’une boucle par ordre alphabétique des auteurs examine le cas particulier (non pris en compte ici) du tri d’une liste d’articles par les noms des auteurs.

Footnotes

[1Voir à ce sujet la page Le filtre parametre_url.

[2On peut lourdement insister sur ce point: certains webmestres ont la fâcheuse tendance de vouloir transformer leur site en quelque chose qui ressemble plus à un cockpit d’avion qu’à l’interface légère, pertinente et ergonomique (votre sobre et dépouillée) qu’attend l’internaute normalement constitué.

[3Le squelette de cette page se trouve à l’adresse http://mag.spip.net/layout/recherche.html.

[4Voir à ce sujet la page http://www.spip.net/fr_article1902.html.

[5Par ailleurs, dans l’exemple donné, celui de SPIP Mag’, ce squelette item.inc.html est utilisé dans d’autres squelettes (sommaire, rubriques,...), ce qui permet de centraliser en un seul point la gestion de l’affichage des descriptifs d’article.

[7Lire à ce sujet la page de la documentation officielle consacrée à l’internationalisation des squelettes et plus particulièrement son paragraphe 1. Méthode des fichiers de langue.

updated on 5 December 2006

Discussion

5 discussions

  • Salut,
    Lorsque je choisis “ordre chronologique” comme critère de tri et que j’ouvre à nouveau le menu déroulant, une ligne blanche figure dans celui-ci juste au-dessus de “ordre chronologique” et décale tout vers le bas. Est-ce que quelqu’un eu ce problème et l’a résolu ?
    Merci

    Reply to this message

  • 1

    Bonjour à tous,

    Je souhaiterais savoir comment faire afficher ces fameuses petites étoiles lors du résultat d’une recherche avec SPIP 1.9.2. Faut-il créer un script additionnel?

    Merci tout le monde !

    • J’avais trouvé ce filtre quelque part (et il fonctionne):

      function etoiles($texte) {
              $point = $texte;
              $texte = "";
              $star="<img src=\"squelettes/images/etoile.png\">";
              if ($point > 2) {
                      $texte= $star;
              }
              if ($point > 6) {
                      $texte= $star."&nbsp;".$star ;
              }
              if ($point > 8) {
                      $texte= $star."&nbsp;".$star."&nbsp;".$star ;
              }
              if ($point > 12) {
                      $texte= $star."&nbsp;".$star."&nbsp;".$star."&nbsp;".$star ;
              }
              if ($point > 20) {
                      $texte= $star."&nbsp;".$star."&nbsp;".$star."&nbsp;".$star."&nbsp;".$star ;
              }
      
      return $texte;
      }

      avec [(#POINTS|etoiles)] dans le squelette....

    Reply to this message

  • 3

    Bonjour, et féllicitations pour cette contrib.

    Malheureusement je suis sonfronté à un probleme.
    Il me semble avoir fait tout ce qu’il fallait cependant j’ai cette erreur:

    Fatal error: Call to undefined function: auteur_et_auteur() in c:\program files\easyphp\www\beespip\inc-public.php3(20) : eval()’d code on line 6

    Que dois-je faire?
    Merci

    • Bon je crois qu’en fait ca vient du code de item.inc
      j’ai donc viré cette ligne:
      $tous_auteurs = trim(auteur_et_auteur(’[(#NOM|prenom|texte_script) ][(#NOM|nom|texte_script)]’,’<:et:>’));

      et cela semble marché! meme si la disposition des étoiles et le texte en francais est assez étrange.

      Mais merci, je vais m’en sortir à présent!

    • Voici ce que j’ai trouvé incorrect chez moi:
      Il manque des mots a public-fr.php:
      -  mise_a_jour
      -  visiteurs_par_jour
      -  total_visiteurs

      D’autre part la fonction pour afficher les étoiles n’avait pas les bonnes valeurs chez moi (je parle de celle donnée en commentaires):
      voici ce que ca donne chez moi maintenant:

      // Affiche des jolies zetoiles dans le moteur de recherche
      // A appeler avec la balise #POINTS : [(#POINTS|etoiles)]
      function etoiles($points) {
              $retour = '5';
              if ($points < 2600) $retour = '4';
              if ($points < 1600) $retour = '3';
      
              if ($points < 800) $retour = '2';
              if ($points < 500) $retour = '1';
      
              if ($points < 200) $retour = '1';
              
      return '<img src="images-interface/stars/etoiles_'.$retour.'.png" border="0" alt="'.$points.'">';
      }

      images-interface/stars/ étant le répertoire dans lequel j’ai mis les zolies nimages :)

      En revanche, moi qui ne met jamais de Surtitre, les étoiles apparaissent au dessus du titre! ca fait un peu bizarre.
      J’ai beau essayer je n’arrive pas a appeller le fonction “etoiles” avec les Points de la page item.inc.php; donc impossible de mettre les étoiles a coté de Visiteurs par jour | Visiteurs total...
      Dommage.
      Si vous avez une astuce faite le moi savoir.

    • Voici donc cette contrib mise en place sur mon site:

    Reply to this message

  • 1

    cette contrib est exactement ce que je cherche mais je n’ai pas le filtre “etoile”... peux tu y remédier...

    Merci d’avance...

    • Salut,

      Voici le filtre «étoiles» que j’utilise:

      // Affiche des jolies zetoiles dans le moteur de recherche
      // A appeler avec la balise #POINTS : [(#POINTS|etoiles)]
      function etoiles($points) {
              $retour = '5';
              if ($points < 26) $retour = '4';
              if ($points < 16) $retour = '3';
              if ($points < 08) $retour = '2';
              if ($points < 05) $retour = '1';
              if ($points < 02) $retour = '1';
              return '<img src="/'.$GLOBALS['dossier_squelettes'].'/img/etoiles_'.$retour.'.png" border="0" alt="'.$points.'">';
      }

      Tu dois affecter la variable $GLOBALS['dossier_squelettes'] (par défaut, mets juste squelettes) et récupérer les 6 images nommées etoiles(0|1|2|3|4|5|6).png (par exemple ici), ou les créer toi-même puis les placer dans le répertoire qui va bien.

      Le résultat est assez joli.

      FS

      PS : Cette idée ne vient pas de moi; je l’ai reprise (et adaptée) depuis une contrib ou un post sur une liste, mais je ne retrouve pas la source et je ne me rappelle plus du nom de l’auteur.

    Reply to this message

  • Bon c’est une super contrib, visiblement elle ne plaît à personne, car pas un seul retour !

    Je l’utilise (enfin une version plus simplifié) sur mon blog, et pour le squelette BliP.

    Et elle marche très bien !!!

    FONCEZ !

    Reply to this message

Comment on this article

Who are you?
  • [Log in]

To show your avatar with your message, register it first on gravatar.com (free et painless) and don’t forget to indicate your Email addresse here.

Enter your comment here

This form accepts SPIP shortcuts {{bold}} {italic} -*list [text->url] <quote> <code> and HTML code <q> <del> <ins>. To create paragraphs, just leave empty lines.

Add a document

Follow the comments: RSS 2.0 | Atom