Créer des balises personnalisées pour SPIP - Les balises statiques

Cet article est la traduction libre d’un article de Thomas Sutton publié sur son blog passingcuriosity en novembre 2008 (article original).

Intéressons-nous à deux des types d’éléments offerts par le language utilisé dans les squelettes de SPIP :

  • les boucles (qui déterminent les objets desquels seront extraites les données)
  • les balises (qui retournent les données particulières).

La syntaxe extrêmement simple de ces balises, pour la plupart notées #BALISE, masque leur puissance, leur flexibilité et la simplicité avec laquelle il est possible de les utiliser pour étendre SPIP en lui ajoutant de nouvelle fonctionnalités ou en l’interfaçant avec d’autres applications PHP.

Dans cet article, nous allons décrire comment créer nos propres balises statiques SPIP.
Avant de lire cet article, vous devez être familier avec SPIP, ses squelettes et la programmation en PHP.

Une balise SPIP est utilisée pour retourner une valeur.

  • La plupart des balises tirent cette valeur du contexte dans lequel elles sont appelées : le titre de l’article « courant », ou le logo de la brève « courante » par exemple.
  • Certaines retournent des valeurs globales comme le nom du site, ou la version du logiciel.
  • D’autres encore permettent aux utilisateurs d’interagir avec le site (par exemple #LOGIN_PUBLIC qui affiche un formulaire de connexion et en lance le processus).
  • Quelques-unes enfin (comme #SET et #GET) offrent les possibilités d’un langage de programmation et l’on pourrait ne voir leur capacité à afficher des valeurs que comme un effet secondaire.

Toutes ces possibilité sont offertes en utilisant une même syntaxe, relativement simple, et un même mécanisme.

Les balises peuvent être rangées dans deux groupes en fonction de leur comportement :

  • les balises statiques sont celles qui retournent une valeur statique, qui ne changera pas d’une évaluation à l’autre. Le titre d’un article, par exemple, n’a pas nécessairement besoin d’être différent d’une page à l’autre ; il peut l’être, certes, mais pas nécessairement.
  • Les balises dynamiques sont celles qui génèrent des valeurs dynamiques qui, elles, doivent nécessairement changer entre les différents appels ; la date et l’heure, par exemple.

les balises statiques

Les balises statiques génèrent un contenu « statique » ; c’est à dire une valeur qui ne devrait pas changer sur une période donnée.
Cela signifie que SPIP peut évaluer une balise statique une fois, en cacher le résultat et le réutiliser plus tard à l’occasion de demandes ultérieures.

Une balise (désormais dans cet article nous utiliserons « balise » pour « balise statique ») renvoie à une fonction [1] portant un nom particulier : le nom de la balise accolé au préfixe « balise_ ».
Par exemple, une balise nommée #TRUC sera exécutée par une fonction appelée function balise_TRUC().
Ces fonctions, comme un grand nombre de celles utilisées par SPIP, peuvent être surchargées par des plugins, ou d’autres fichiers spécifiques au site. En effet, quand il voit une balise #TRUC, SPIP va d’abord rechercher la fonction balise_TRUC puis, s’il ne la trouve pas, la fonction balise_TRUC_dist puis, enfin, considèrera que la dite balise n’existe pas.

Mais commençons par un exemple trivial : la balise #BONJOUR_VOUS.
Cette balise affichera tout simplement la phrase : « Bonjour tout le monde ! » (Pour utiliser ce code, il suffit de copier la fonction dans votre fichier mes_fonctions.php de votre installation SPIP) :
<?php

function balise_BONJOUR_VOUS ($p) {
  
$p->code "'Bonjour tout le monde !'";
  return 
$p;
}

?>

Comme vous pouvez le voir il y a quelques détails en plus du nom ; à savoir : ce $p quelque chose.
Ce paramètre $p de la fonction qui met en œuvre la balise est une référence au nœud de l’arbre de syntaxe abstraite correspondant pour cette balise. Ce paramètre $p contient toutes les informations que SPIP possède sur la balise : les filtres qui lui sont passés, les parenthèses qui l’entourent, le contexte, etc. Tout ce qui manque, c’est la valeur elle-même, et c’est là que notre fonction entre en scène.
Une fois que SPIP a analysé les squelettes et manipulé tout ce qu’il peut, il appelle donc la fonction associée à chaque balise pour remplir les trous.

Il y a un grand nombre de champs dans l’objet Champ (la classe est définie dans
ecrire/public/interfaces.php mais sa lecture n’est pas particulièrement
édifiante), et la plupart sont peu documentés :

type la chaîne de caractères décrivant le type de nœud AST. Devrait être « champ » pour les balises.
nom_champ le nom de la balise sans le « # »
nom_boucle le nom de la boucle. Les balises n’étant pas des boucles, il sera donc vide dans notre exemple.
avant la liste des nœuds précédents qui sont subordonnés à celui-ci.
apres la liste des nœuds suivants subordonnés à celui-ci.
etoile la balise appelée par « #BONJOUR_VOUS* » renverrait un résultat brut, sa valeur n’étant pas sécurisée pour un affichage HTML.
param la liste des paramètres et des filtres associés à l’appel de la balise. C’est un peu compliqué.
fonctions semblable à param mais structuré différemment.
id_boucle le nom de la boucle au sein de laquelle apparait la balise.
boucles le tableau des nœuds AST pour les boucles du squelette.
type_requete aucune idée. [2]
code le code PHP, qui, lors de eval()d, génère la valeur de la balise.
interdire_scripts autorise ou non l’interprétation de "scripts". [3]
descr le tableau des valeurs décrivant le nœud AST, le fichier dont il est issu, etc.
ligne le numéro de la ligne d’où la balise est appelée dans le squelette.

Exemple :
si l’on remplaçait le contenu de squelettes-dist/sommaire.html par :
[d'abord (#BONJOUR_VOUS{arg1}|strtoupper) ensuite]
cela devrait se traduire par l’AST suivant, transmis donc à la fonction balise_BONJOUR_VOUS :

type => "champ"
nom_champ => "BONJOUR_VOUS"
avant => le (ou les) nœud pour "d’abord", ...
apres => le (ou les) nœud pour "ensuite", ...
etoile =>
param => [

0 => "arg1" est là, ...

1 => "strtoupper" est là, ...

]

fonctions => [

0 => arg1" est aussi ici, ...

1 => strtoupper" est aussi ici, ...

]

Heureusement, vous pouvez ignorer la quasi-totalité de ceci.

La fonction interprete_argument_balise

Cette fonction (détaillée ici) est particulièrement utile :
interprete_argument_balise(1, $p) retourne le premier argument du nœud AST $p.

Avec ce que nous avons décrit jusqu’ici, nous en savons assez pour écrire notre balise #BONJOUR qui affichera le message « Bonjour nom » s’il y a un nom (#BONJOUR{Marcel}) et « Bonjour le monde ! » sinon (code à placer dans mes_fonctions.php ) :
<?php

function  balise_BONJOUR ($p) {
  
$name interprete_argument_balise (1$p);
  if (!
$name) {
    
$name "le monde !";
  }
  
$p->code "'Bonjour '.$name ";
  return 
$p;
}

?>

Comme il y a bien des raisons d’écrire ses propres balises statiques, il faut être assuré (comme pour tout le reste, d’ailleurs) qu’elles prendront bien en charge les traductions, surtout si vous envisagez de distribuer votre travail.

  • Cela est relativement facile à l’aide de la fonction _T (voir le détail ici) et des fichiers de langue.
  • Tout comme il est aisé d’obtenir des données à partir d’une boucle (titres d’article, identifiants de rubriques, etc) avec la fonction champ_sql (voir le détail ici).

Pour encore plus d’exemples, n’hésitez pas à jeter un œil sur le code de certaines des balises de SPIP dans le fichier ecrire/public/balises.php.
Et si vous regardez attentivement le code source de SPIP, vous verrez que beaucoup de balises ne tirent pas leur résultat du mécanisme détaillé ci-dessus, mais l’extraient des colonnes de même nom de la base de données.
Si vous modifiez ou complétez votre base de données vous pourrez ainsi en tirer parti.

Notes

[1En un sens, ce n’est pas tout à fait vrai : la fonction, pour cette balise, ne fait qu’utiliser un nœud de l’arbre de syntaxe abstraite (AST), dont les éléments seront ensuite traités par SPIP pour générer la balise.

[2pour une balise, contient le plus souvent le nom de la table sur laquelle porte la boucle englobant cette balise ; pour une boucle : le nom de la table [ajout du traducteur].

[3en désactivant les fonctions de désinfection de spip appliquées sur le contenu de la balise [ajout du traducteur].