Développer un plugin pour WordPress
1 – Une lente introduction
4 juillet 2016.
Un peu de philosophie
Faire un plugin qui modifie l’aspect visuel d’une page sans compliquer pour autant la vie de ses utilisateurs, c’est bien. Faire en sorte que ce plugin ne transforme en rien la structure à laquelle il s’applique, c’est encore mieux.
Illustrons la chose avec un plugin hypothétique un peu neuneu qui permettrait d’un très bête clic de passer la première lettre d’un paragraphe en rouge. Pour obtenir ce triste résultat, la solution la plus triviale consisterait à insérer cette lettre dans un span doté d’un style=“color:red” puis à laisser WordPress enregistrer cette structure. Sauf que si l’administrateur retrouve ses esprits tout autant qu’un peu de bon gout et, ce faisant, désactive voire même supprime le plugin, les pages sur lesquelles ce dernier a été appliqué resteront en l’état avec leur désarmante lettre rouge.
La solution élégante s’avère un peu plus complexe mais pas tant. Il s’agit de donner au paragraphe un attribut data spécifique. Pour assurer la prévisualisation dans tinyMCE, on applique effectivement notre span stylé en rouge à la première lettre du paragraphe. Cependant, quand le rédacteur sauvegarde son article, on dégage prestement notre foutu span et on laisse WordPress enregistrer le contenu uniquement surchargé de notre attribut. Par la suite, quand un internaute plus curieux que les autres demande à consulter l’article en question, WordPress s’en va chercher le corps de notre post pour le lui présenter mais nous laisse alors le loisir d’en modifier le contenu avant de l’afficher. Chose que nous nous empressons de faire en réintroduisant notre délicieux span rouge.
Si le plugin est désactivé, le paragraphe conserve certes son attribut mais, le contenu du post n’étant pas traité, il conserve aussi son sobre aspect d’origine.
Par ailleurs, en cas de suppression du plugin, nous avons la possibilité de rechercher les pages qu’il a traité pour en effacer définitivement toutes les traces en supprimant l’attribut dédié.
Un peu de réflexion
Revenons à nos moutons et tentons vaille que vaille d’évaluer les obstacles par dessus lesquels nous allons devoir les entraîner à sauter…
L’intégration de la technique d’alignement exposée en préliminaire à TinyMCE et WordPress présente en effet quelques contraintes qu’il est essentiel de garder à l’esprit :
- Primo : nous devons nous débrouiller pour intégrer l’image dans un container de type block, genre une balise paragraphe <p>, mais il faut également veiller à ce qu’elle en soit la seule occupante, à l’exclusion de tout texte parasite. Voilà qui pose un épineux problème que nous ne pourrons surmonter sans déroger aux principes de bonne conception développés au cours de notre introduction philosophique. Le fait est qu’une image est couramment insérée dans le corps du texte (même si c’est généralement plutôt en début de bloc) et que cette architecture est proprement incompatible avec celle qui nous est nécessaire pour parvenir à l’alignement de nos rêves. Autrement dit, en fin politique que je ne suis pourtant pas, je m’assois derechef sur les règles que j’ai moi-même édictées il y a un instant et déclare sans vergogne aucune ou presque que nous allons bel et bien devoir altérer la structure html définie par le rédacteur (si tout ça vous rappelle quelque chose, c’est que vous n’êtes point encore affecté par le syndrome de la mémoire de poisson qui touche bon nombre de nos contemporains).
- Secundo : un blog WordPress recourt très souvent à une extension type lightbox (c’est d’ailleurs le cas du nôtre qui emploie featherlight que je ne saurais que trop vous recommander). Ce type de plugin procède à l’insertion de chaque image dans une ancre. Pour ne pas briser cet effet fort utile au demeurant, nous devrons donc nous assurer le cas échéant d’isoler non pas l’image seule mais l’image enserrée dans son lien.
Mais ce n’est pas tout…
Par définition, notre extension est destinée à aligner une image par rapport à un texte. Encore faut-il que texte il y ait…
D’où :
Règle 1 : notre plugin ne pourra s’appliquer à une image que si elle est immédiatement suivie d’un texte.
Par ailleurs, quand je dis texte, c’est texte (si ! si !). Pour des raisons tout à la fois esthétiques et techniques, nous devrons nous assurer que le texte sélectionné pour participer à l’alignement ne comprenne pas lui-même une ou plusieurs images.
D’où :
Règle 2 : les blocs de texte impliqués dans l’alignement ne peuvent contenir d’image.
Considérons maintenant la structure suivante :
1 2 3 4 5 6 7 8 9 |
<p> Bla bla bla bla <img src="monImage1.jpg"/> Bla bla bla bla <img src="monImage2.jpg"/> Bla bla bla bla </p> |
Pour appliquer notre extension à la première image, il nous faudrait non seulement l’isoler mais aussi rompre le paragraphe avant la seconde image pour disposer d’un bloc de texte obéissant à la règle 2. Nous obtiendrions alors quelque chose qui ressemblerait à ça :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<p> Bla bla bla bla </p> <!-- Première modification pour isoler l'image --> <p> <img src="monImage1.jpg"/> </p> <!-- Seconde modification pour disposer d'un bloc de texte dénué d'image --> <p> Bla bla bla bla </p> </p> <img src="monImage2.jpg"/> Bla bla bla bla </p> |
Une altération de la structure html initiale, passe encore mais deux, ça commence à faire sale…
D’où :
Règle 3 : notre plugin ne pourra pas s’appliquer à une image contenue dans un bloc contenant d’autres images à moins qu’elle ne soit la dernière image dudit bloc.
Enfin, il s’avère particulièrement complexe d’envisager l’application de notre mécanique à une image logée au sein d’une ligne de liste, que cette liste soit ordonnée ou non. Pour assurer un bon fonctionnement de la chose avec tinyMCE, il nous faudrait non seulement isoler l’image mais aussi scinder la liste au niveau de l’image, la deuxième partie de cette liste étant alors considérée comme un seul bloc de texte.
Autant dire que, pour ne point m’arracher le peu de cheveux qui me restent, j’édicte aussi derechef que royalement la quatrième règle que voici…
Règle 4 : notre plugin ne pourra pas s’appliquer à une image contenue dans un élément ligne.
Avant que de rendre notre plugin accessible, nous devrons donc nous assurer
- Que l’élément sélectionné est une image ne résidant pas dans un élément ligne.
- Qu’elle est la dernière image du bloc qui la contient.
- Que, dans la structure html résultant de son isolation, elle sera suivie d’au moins un bloc comprenant du texte mais pas d’image.
Enfin, le texte impliqué dans l’alignement comprendra au minimum le bloc de texte suivant l’image. Au maximum, il s’arrêtera avant le premier bloc contenant une image.
Les désirs d’Albert
Les contours de notre mission prenant forme, tentons maintenant de nous plier aux naturelles exigences d’Albert, un rédacteur lambda particulièrement perplexe face à notre proposition de plugin.
Cet aimable personnage a d’ores et déjà intégré une image dans son article et manifeste maintenant le désir aussi irrépressible que soudain de l’aligner avec quelques éléments de texte de son choix. Notre mission à nous consiste à lui rendre cette tâche a priori délicate aussi simple que possible. Néanmoins, nous aurons besoin qu’il y mette un peu du sien.
En premier lieu, il faut bien évidemment que ce monsieur daigne nous indiquer l’image en question en faisant l’effort de procéder à sa sélection. De notre côté et histoire de lui simplifier une vie fort compliquée par ailleurs, nous considérerons que le texte impliqué dans l’alignement sera constitué par défaut du premier block de texte qui suit l’image. Mais bon, faut pas nous leurrer : le gars a ses exigences et ne s’en laisse pas conter. Il y a donc fort à parier qu’il cède à la légitime tentation d’élargir le texte à d’autres paragraphes et qu’il veuille déterminer par lui-même comme un grand garçon qu’il est :
- Le pourcentage de la largeur de la page qui est réservée à l’image.
- La position de l’image par rapport au texte (gauche ou droite).
- Et pourquoi pas aussi les marges de l’image.
Comment allons-nous pouvoir l’aider ?
Tout d’abord, il sera judicieux de placer un bouton idoine dans la barre d’outil de l’éditeur. Ce bouton ne sera actif que si notre cher Albert sélectionne une image répondant aux règles 1, 3 et 4 définies précédemment.
Un clic sur ledit bouton provoquera l’ouverture d’un pop-up de paramétrage qui permettra à Albert d’effectuer tous les réglages qu’il peut souhaiter.
Par ailleurs, afin qu’il puisse le cas échéant modifier la présélection de texte opérée par nos petits soins, nous lui proposerons deux boutons : le premier portant le signe – lui permettra de diminuer la sélection de texte d’un bloc; le second, affublé du signe + assurera la fonction inverse en augmentant la sélection de texte d’un bloc. Bien évidemment, nous aurons à cœur de désactiver le bouton – dès lors qu’un seul bloc de texte sera sélectionné (règle 1) et de faire de même avec le bouton + lorsque tous les blocs de texte disponibles auront été inclus dans la sélection.
Enfin, notre interface ne saurait être complète sans un bouton OK et son pote Annuler.
Résumons :
- Albert sélectionne une image.
- Il clique sur notre bouton dans la barre d’outils.
- Il procède aux réglages de son choix.
- Il modifie ou pas la présélection de texte.
- Il valide ou annule.
Oui, mais que se passe-t-il lorsque Albert, subitement pris de remords, décide de modifier un alignement préalablement appliqué ?
Il s’en va derechef sélectionner l’image qui lui fait souci et clique sur le bouton de notre extension dans la barre d’outils de l’éditeur pour accéder au pop-up de paramétrages. Celui-ci doit en toute logique faire figurer les réglages d’ores et déjà affectés à l’image. Dans le même temps, nous devons assurer à titre indicatif la sélection du texte par rapport auquel se réalise l’alignement.
Et puisque Albert a tous les droits, il nous faut lui donner la possibilité d’annuler l’effet appliqué en rajoutant dans ce cas un bouton Supprimer en plus des deux boutons initiaux OK et Annuler.
Méthodologie
Voilà qui nous définit une première trame.
Nonobstant, en fin programmeur que vous êtes, vous vous doutez bien qu’elle risque fort de se trouver amendée maintes et maintes fois pour répondre aux exigences et contraintes que l’usage ne manquera pas de faire apparaître.
Avant que de nous lancer tête baissée et cœur vaillant dans l’écriture de cette fabuleuse interface, il serait plus que temps de nous demander comment nous allons procéder concrètement pour enregistrer les paramètres de l’image ainsi que les éléments de texte qui lui sont liés.
Pour faire court, mon idée mienne à moi est de doter l’image et chacun des blocs de texte associés d’un identifiant commun via un attribut data. Les caractéristiques propres à l’image (largeur, alignement gauche ou droite, marges) seront quant à elles stockées dans un attribut dédié.
Et pour tenter d’être aussi clair que possible, voici, à partir d’une configuration parmi les plus complexes auxquelles nous pourrions nous trouver confronter (une image ensachée dans un lien inséré dans un span lui même inclus dans un autre span et le tout dans un paragraphe), ce à quoi pourrait ressembler l’ensemble une fois passé entre nos petits doigts agiles :
Avant
1 2 3 4 5 6 7 8 |
<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent non dictum erat, a cursus est. Etiam vitae sem mollis, varius felis nec, ornare sapien. Vestibulum gravida justo quam, id convallis leo congue at. Vivamus varius, arcu id maximus lobortis, <span style="color:red">neque ipsum hendrerit magna, nec vehicula lacus tortor pellentesque purus. <span style="color:blue">Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; <a href="lien_vers_une_image"><img src="lien_vers_une_image" /></a>Sed convallis lorem purus, nec tincidunt tortor ultrices ac. Nulla tempor lectus ut gravida viverra.</span> Proin at erat quis arcu ultrices pellentesque. Nullam varius, velit id eleifend sodales, ligula metus posuere dui, sed rhoncus justo libero sed ante. Nullam et sollicitudin turpis. Cras elit nisi, tincidunt non mollis in, rhoncus ut diam. Proin volutpat tristique mattis. Nulla ullamcorper faucibus odio eget tincidunt</span>. Quisque magna lectus, hendrerit non velit vel, bibendum elementum lacus. Suspendisse tempus enim arcu, quis rhoncus tortor euismod nec. Maecenas in justo eu felis molestie tempor. </p> <p> Etiam auctor tincidunt quam vitae dictum. Quisque rutrum augue at neque rhoncus, eu pharetra massa vulputate. Vivamus pulvinar ultrices suscipit. Donec sit amet vehicula urna, vel congue ante. Duis massa nisi, rutrum vel venenatis eu, interdum a nunc. Duis hendrerit tincidunt dapibus. Integer nec sapien non odio convallis condimentum. Vestibulum eu purus nec odio placerat molestie. Vestibulum ultrices nunc fermentum velit fermentum eleifend. Etiam lacinia odio non malesuada mollis. Phasellus quis dictum ligula. </p> |
Après
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent non dictum erat, a cursus est. Etiam vitae sem mollis, varius felis nec, ornare sapien. Vestibulum gravida justo quam, id convallis leo congue at. Vivamus varius, arcu id maximus lobortis, <span style="color:red">neque ipsum hendrerit magna, nec vehicula lacus tortor pellentesque purus. <span style="color:blue">Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;</span></span> </p> <a href="lien_vers_une_image"><img src="lien_vers_une_image" data-text_floating_image="un_identifiant" data-text_floating_image-style="width:45%;clear:left;float:left;margin-right:20px;margin-left:0px"/></a> </p> <p data-text_floating_image="un_identifiant"> <span style="color:red"><span style="color:blue">Sed convallis lorem purus, nec tincidunt tortor ultrices ac. Nulla tempor lectus ut gravida viverra.</span> Proin at erat quis arcu ultrices pellentesque. Nullam varius, velit id eleifend sodales, ligula metus posuere dui, sed rhoncus justo libero sed ante. Nullam et sollicitudin turpis. Cras elit nisi, tincidunt non mollis in, rhoncus ut diam. Proin volutpat tristique mattis. Nulla ullamcorper faucibus odio eget tincidunt</span>. Quisque magna lectus, hendrerit non velit vel, bibendum elementum lacus. Suspendisse tempus enim arcu, quis rhoncus tortor euismod nec. Maecenas in justo eu felis molestie tempor. </p> <p> Etiam auctor tincidunt quam vitae dictum. Quisque rutrum augue at neque rhoncus, eu pharetra massa vulputate. Vivamus pulvinar ultrices suscipit. Donec sit amet vehicula urna, vel congue ante. Duis massa nisi, rutrum vel venenatis eu, interdum a nunc. Duis hendrerit tincidunt dapibus. Integer nec sapien non odio convallis condimentum. Vestibulum eu purus nec odio placerat molestie. Vestibulum ultrices nunc fermentum velit fermentum eleifend. Etiam lacinia odio non malesuada mollis. Phasellus quis dictum ligula. </p> |
Bon, je vous entends déjà marmonner que quand même c’est un peu léger tout ça, voire même carrément n’importe quoi foutage de … et comment qu’on fait alors pour caser l’élément élastique, hein?, et pis aussi comment qu’on fait s’il y a du texte après et même pas de clear:both pour en finir avec l’effet flottant, re-hein?
Et alors là moi je réponds : pas de panique ! Ne nous énervons pas ! Tout vient à point à qui sait attendre, petits scarabées !
Et que me voici une fois encore à radoter : afin d’alléger autant que possible la surcharge de syntaxe induite, nous allons nous débrouiller pour que l’essentiel du travail de mise en page soit effectué coté serveur par la mécanique php de notre plugin.
Et c’est donc à son niveau :
- que nous introduirons l’élément préventif stylé en clear:both ainsi que son compagnon élastique flottant;
- que nous affecterons les styles nécessaires au paragraphe container de l’image;
- et que nous rajouterons un block doté d’un clear:both assurant la clôture de notre effet.
Reste un point d’importance à considérer : WordPress a introduit une gestion responsive des images avec les attributs srcset et sizes. Pour profiter pleinement de ce progrès notable, il serait judicieux de pouvoir informer notre plugin de la largeur effectivement prévue par le thème du site pour les articles. Cette largeur, si elle est définie, est généralement spécifiée en pourcentage par rapport au body avec éventuellement en sus un maximum à ne pas dépasser (max-width).
Puisque nous en sommes à définir des options globales, il serait avisé de pouvoir spécifier le pourcentage, l’alignement (à gauche ou à droite) et les marges pris en compte par défaut par notre plugin.
Autant dire qu’il nous faut en plus de tout songer à concevoir une page de réglages des options globales de notre plugin.
Et puisque l’objectif ici est de faire un tour complet du problème, nous ne devrons pas nous priver d’internationaliser l’ensemble.
Ce petit tour d’horizon vous donne une idée de l’ampleur de la tâche. Je vais m’efforcer de détailler au mieux chacune des étapes mais il vous faudra néanmoins pour parvenir au but posséder quelques notions des langages employés, à savoir un joyeux mélange de php, d’html, de css et de javascript relevé au jQuery… Sans compter les subtilités des api de WordPress et TinyMCE.
Allez, en route pour une longue aventure…