Crayon de mots pour un article Un crayon pour un groupe de mots

, par Matthieu Marcillaud

Pour les besoins d’un projet en SPIP 3 (utilisant spipr-dist), nous voulions sélectionner les mots clés attribués à un article depuis l’interface publique de SPIP, de façon rapide via les crayons, et cela pour plusieurs groupes de mots clés.

La problématique est assez proche de l’article « Un crayon listant des liaisons », mais actualisé pour SPIP 3 et avec quelques subtilités. Vous aurez tout intérêt à le relire si vous vous intéressez aux crayons. Nous ferons également ici un plugin pour pouvoir réutiliser la chose un peu plus simplement.

Problématique

Comme indiqué, nous devons pouvoir éditer ici des liaisons entre les mots clés d’un certain groupe et un article. Ce n’est pas, donc, la fonction première des crayons qui permettent, sans rien faire d’autre, d’éditer un champ d’une ligne d’une table connue.

Ici, il nous faut éditer des liaisons entre une ligne d’une table connue (un article dans notre cas) et une autre table (des mots d’un certain groupe), ce qui concrètement revient à remplir ou modifier la table SQL spip_mots_liens. Pour cela, nous créerons des fonctions et squelettes spécifiques pour gérer notre crayon.

Créer le plugin

Un plugin très sommaire peut être créé pour commencer. Ce n’est évidemment pas obligatoire car ce que nous construisons pourrait être mis en partie dans config/mes_options.php et en partie dans le répertoire squelettes.

Pour ce faire, le plus rapide est de créer avec la Fabrique un plugin minimal, ayant un fichier d’option.

Dépendance à Crayons

Pour fonctionner, nous aurons besoin de la version 1.17 minimum de crayons, qui permet ce dont nous aurons besoin sans afficher de notices PHP [1].

On ajoute donc dans paquet.xml la dépendance :

  1. <necessite nom="crayons" compatibilite="[1.17.0;]" />

Dépendance à Chosen

On ajoute ensuite une dépendance au plugin Chosen qui permettra d’améliorer l’interface de sélection des mots clés dans notre crayon. Cette dépendance n’est pas réellement obligatoire, le crayon fonctionnerait sans.

  1. <necessite nom="chosen" compatibilite="[1.0.5;]" />

Une fois le plugin chosen actif, il faut le configurer pour indiquer qu’il doit s’activer dans l’espace public, et sur les select.chosen :

PNG - 17.6 ko
Configuration possible de Chosen

Il ne reste plus qu’à créer les fichiers et fonctions de travail.

Inclusion de travail

Dans un premier temps, nous créons une inclusion – qu’il suffira de charger dans une colonne de navigation par exemple – qui affichera les mots clés des groupes de mots que nous aurons choisis pour un article donné.

L’inclusion est appelé ici inclure/selection_mots_article_colonne.html et comporte le simple code suivant, qui liste les mots d’un article et groupe donné :

  1. <BOUCLE_groupe(GROUPES_MOTS){id_groupe}>
  2. <div class="liste mots groupe#ID_GROUPE">
  3. <h2 class="h2">#TITRE</h2>
  4. <ul class="liste-items">
  5. <BOUCLE_mots(MOTS) {id_groupe} {id_article} {par num titre, titre}>
  6. <li class="item"><a href="#URL_MOT" rel="tag">#TITRE</a></li>
  7. </BOUCLE_mots>
  8. <li class="item"><:crayonsmots:aucun_mot_present:></li>
  9. <//B_mots>
  10. </ul>
  11. </div>
  12. </BOUCLE_groupe>

Télécharger

Pour tester, nous surchargeons un fichier de spipr-dist (extra/article.html) dans notre dossier squelettes, et ajoutons, dans la boucle article l’inclusion avec les groupes de mots clés désirés, par exemple avec ce code :

  1. <BOUCLE_extra2_article(ARTICLES){id_article}>
  2. <INCLURE{fond=inclure/selection_mots_article_colonne,
  3. id_article, id_groupe=1} />
  4. <INCLURE{fond=inclure/selection_mots_article_colonne,
  5. id_article, id_groupe=2} />
  6. <INCLURE{fond=inclure/selection_mots_article_colonne,
  7. id_article, id_groupe=3} />
  8. [...]
  9. </BOUCLE_extra2_article>

Télécharger

À partir de maintenant, en allant sur un article dans l’espace public, nous pouvons voir, en colonne les groupes de mots choisis (ici d’identifiant 1, 2 et 3), et les mots qui y sont associés (ou non).

PNG - 11.9 ko
Exemple de colonne avec les mots
Sur ce site de test, les titre des mots clés n’ont pas beaucoup de sens !

Commencer les crayons

Nous ajoutons alors de quoi afficher un crayon sur notre sélection en modifiant l’inclusion. Nous ajoutons la balise #EDIT sur la ligne :

  1. <div class="liste mots groupe#ID_GROUPE">

Qui devient :

  1. <div class="liste mots groupe#ID_GROUPE #EDIT{mots_article-#ID_ARTICLE}">

Il faut noter la subtilité ici avec #EDIT{mots_article-#ID_ARTICLE} : habituellement, on ne passe aucun identifiant à ce genre de balise, #EDIT retrouvant l’objet et l’identifiant de la boucle parente. Cependant ici nous avons dans la boucle parente le groupe et son identifiant, mais ce n’est pas suffisant pour connaître l’article de la liaison. On transmet donc – en fourbant – cet identifiant d’article, que l’on pourra ensuite récupérer dans les fonctions spécifiques du crayon.

Indiquer comment récupérer les valeurs du champ

Pour calculer la signature du champ, calculé à partir des données présentes dans celui-ci – ici une liste de mots clés —, il nous faut créer une fonction spécifique. On l’ajoute dans le fichier d’options du plugin :

  1. function valeur_champ_mots_article($table, $ids, $champ) {
  2. return valeur_champ_mots_objet($table, $ids, $champ);
  3. }

Télécharger

En prévision de proposer d’autres objets (pourquoi pas les mots liés à des auteurs), notre fonction spécifique appelle une fonction plus générique :

  1. function valeur_champ_mots_objet($table, $ids, $champ) {
  2. list($id_objet, $id_groupe) = explode('-', $ids);
  3. list(, $objet) = explode('_', $champ);
  4.  
  5. $valeurs = sql_allfetsel("m.id_mot", "spip_mots AS m, spip_mots_liens AS ml", array(
  6. "m.id_groupe=" . sql_quote($id_groupe),
  7. "m.id_mot = ml.id_mot",
  8. "ml.id_objet=".sql_quote($id_objet),
  9. "ml.objet=".sql_quote($objet)
  10. ));
  11. $valeurs = array_map('array_shift', $valeurs);
  12.  
  13. return $valeurs;
  14. }

Télécharger

Il y a des subtilités ici.

  • d’une part le champ $ids contient du texte, tel que « 348-2 » où le premier nombre est l’identifiant de l’article, le second du groupe. On sépare en 2 pour récupérer ces 2 nombres. [2]
  • d’autre part on récupère le type d’objet dans le nom du contrôleur, sous entendant que nos contrôleurs s’appellent « mots_T » où T est le type d’objet, tel qu’ici « mots_article ».

Ces astuces permettent d’avoir un code assez générique et réutilisable.

Le code HTML du contrôleur

Le contrôleur affiche le formulaire de saisie. Son code, placé dans le fichier controleurs/mots_article.html de notre plugin est le suivant :

  1. #CACHE{0}
  2.  
  3. #SET{ids,#ENV{id_groupes_mot}|explode{-}}
  4. #SET{id_groupe,#GET{ids/1}}
  5. #SET{id_article,#GET{ids/0}}
  6. #SET{name,#ENV{name_#ENV{crayon_modele}}}
  7.  
  8. <BOUCLE_groupe(GROUPES_MOTS){id_groupe=#GET{id_groupe}}>
  9. #SET{mots,#ARRAY}
  10. <BOUCLE_mots_actifs(MOTS){id_groupe}{id_article=#GET{id_article}}>
  11. #SET{mots,#GET{mots}|push{#ID_MOT}}
  12. </BOUCLE_mots_actifs>
  13. <ul>
  14. <li>
  15. <label for="#GET{name}">#TITRE</label>
  16. <select name='#GET{name}\[\]' class='crayon-active chosen' multiple='multiple' id="#GET{name}" style="width:[(#ENV{largeur}|moins{40})]px">
  17. <BOUCLE_mots(MOTS){id_groupe}{par num titre, titre}>
  18. <option value="#ID_MOT" [(#ID_MOT|in_array{#GET{mots}}|oui) selected="selected"]>
  19. #TITRE
  20. </option>
  21. </BOUCLE_mots>
  22. </select>
  23. </li>
  24. </ul>
  25. </BOUCLE_groupe>

Télécharger

De la même façon que dans le code PHP précédent, on doit retrouver l’identifiant de l’article et l’identifiant du groupe transmis, en utilisant le filtre explode.

Le reste est un formulaire pour crayons assez standard. Il faut faire attention à bien récupérer le name attendu pour ce champ, indiquer que c’est un champ multiple. Nous forçons aussi une largeur sur le sélecteur pour qu’il prenne à peu près toute la largeur disponible.

En cliquant le crayon, nous avons maintenant son contrôleur (le formulaire) qui s’affiche.

PNG - 9.9 ko
Contrôleur ouvert
Le crayon a été cliqué et affiche les mots clés actifs. En cliquant la zone blanche, la liste des mots clés possibles s’ouvre, permettant d’en sélectionner de nouveaux.

Les traitements à enregistrer

Les traitements se passent dans la fonction de révision. De même que pour les valeurs du champ, on passe par une fonction plus générique et par l’API d’édition de liens de SPIP 3. Cela peut s’écrire ainsi :

  1. function mots_article_revision($ids, $colonnes, $type_objet) {
  2. return mots_objet_revision($ids, $colonnes, $type_objet, 'mots_article');
  3. }
  4.  
  5. function mots_objet_revision($ids, $colonnes, $type_objet, $champ = '') {
  6.  
  7. if (!$champ) return false;
  8.  
  9. list($id_objet, $id_groupe) = explode('-', $ids);
  10. list(, $type_liaison) = explode('_', $champ);
  11.  
  12. // actuellement en bdd
  13. $old = valeur_champ_mots_objet($type_objet, $ids, $champ);
  14. // ceux qu'on veut maintenant
  15. $new = explode(',', $colonnes[$champ]);
  16. // les mots à supprimer
  17. $del = array_diff($old, $new);
  18. // les mots à ajouter
  19. $add = array_diff($new, $old);
  20.  
  21. include_spip('action/editer_liens');
  22. if ($del) {
  23. objet_dissocier(array('mot'=>$del), array($type_liaison => $id_objet));
  24. }
  25. if ($add) {
  26. objet_associer(array('mot'=>$add), array($type_liaison => $id_objet));
  27. }
  28.  
  29. return true;
  30. }

Télécharger

Le code HTML de la vue (affichage des nouvelles valeurs)

La vue est très simple et reprend en grande partie, dans le fichier vues/mots_article.html, notre première inclusion :

  1. #SET{ids,#ENV{id_groupes_mot}|explode{-}}
  2. #SET{id_groupe,#GET{ids/1}}
  3. #SET{id_article,#GET{ids/0}}
  4.  
  5. <BOUCLE_groupe(GROUPES_MOTS){id_groupe=#GET{id_groupe}}>
  6. <div class="liste mots groupe#ID_GROUPE">
  7. <h2 class="h2">#TITRE</h2>
  8. <ul class="liste-items">
  9. <BOUCLE_mots(MOTS) {id_groupe} {id_article=#GET{id_article}} {par num titre, titre}>
  10. <li class="item"><a href="#URL_MOT" rel="tag">#TITRE</a></li>
  11. </BOUCLE_mots>
  12. <li class="item"><:crayonsmots:aucun_mot_present:></li>
  13. <//B_mots>
  14. </ul>
  15. </div>
  16. </BOUCLE_groupe>

Télécharger

À ce stade, le crayon est entièrement fonctionnel.

Bonus pour le centre de page

Nous avions surtout besoin de pouvoir éditer quelques groupes de mots dans la partie centrale de la page. Il y a dans le plugin un autre crayon « tags_article » et une autre inclusion « selection_mots_article_grille » qui peut afficher plusieurs groupes de mots sur la grille 12 colonnes de bootstrap, par exemple avec :

  1. <h2>Tous les groupes</h2>
  2. <INCLURE{fond=inclure/selection_mots_article_grille, id_article, colonnes=4} />
  3.  
  4. <h2>Autre sélection précise</h2>
  5. <INCLURE{fond=inclure/selection_mots_article_grille, id_article, groupes=#LISTE{2,3}, colonnes=6} />

Télécharger

Ce qui donne cet affichage :

PNG - 14.6 ko
Mots au centre de la page
Présentation légèrement différente, d’où un nouvelle vue et un autre nom pour le crayon.

Notes

[2Cela vient du fait que nous avons ajouté l’identifiant de l’article à la balise #EDIT (la fameuse fourberie). Cette balise crée une classe CSS avec le nom de la table (groupes_mots), le texte transmis à la balise #EDIT (mots_article-248), précédé et suivi par un signe - puis suivi de l’identifiant de la table (le id_groupe), soit au total la classe CSS « groupes_mot-mots_article-348-2 » dans notre exemple.

Crayons attend 3 données séparées par des - : la table, le champ, l’identifiant. Tout signe - supplémentaire est mis dans l’identifiant, considérant que c’est une donnée particulière. Nativement dans crayons ces nommages complexes – qui ajoutent des moins en plus ! – servent pour crayonner les champs des tables ayant des clés primaires composées, tel que les tables de liens. Ils ont été introduits en révision r46818. Ici nous en détournons l’usage.

Coup de pouce

Pour me maintenir en éveil et en pleine forme physique et mentale, vous pouvez me faire le cadeau d'un jus de fruit pressé.

En plus de m'hydrater, de m'offrir une alimentation saine crudivore et frugivore, cela peut aussi me motiver à produire d'autres documentations ou peut-être à prendre des vacances ! :)

Vous pouvez également me « Flattrer » si vous utilisez le service en ligne très malin Flattr de microdonations qui permet d'allouer un budget mensuel à des créateurs de contenu. Votre budget est partagé chaque mois entre toutes les personnes que vous avez flattées ce mois là.