Mon Premier Projet d’Extension WordPress PHP | La Suite !

Cela fait maintenant quelques semaines que je peaufine mon extension WordPress Za Pep, et j’ai énormément appris. J’ai notamment mis en place une nouvelle architecture, un panneau de gestion des paramètres, un système d’authentification à deux facteurs, une gestion des erreurs, une gestion du cache, un système de log et des tests avec PHPUnit. Voyons tout cela ensemble.

Architecture

Za Pep est né d’un besoin simple : établir une communication efficace entre WordPress, wpForo et Zapier. Initialement concentré dans un fichier principal avec quelques classes pour plus de clarté, cela m’a permis de valider le “Proof of concept”. Cependant, pour aller plus loin dans le projet, il est nécessaire d’appliquer les bonnes pratiques de développement, ce qui implique notamment une bonne architecture.

Si l’on regarde d’un peu plus près notre environnement, l’on est dans un sous-programme d’une application Web WordPress qui elle même possède une API native qui communique avec sa base de données qui se trouve sur le même serveur et Za Pep est une API qui possède aussi une partie front.

Mon approche repose sur un modèle hybride, combinant le pattern MVC et l’architecture par couches. Cette stratégie devrait apporter la flexibilité, la maintenabilité et la scalabilité souhaitée.

Arborescence du projet

za-pep/

├── assets/ # Ressources statiques
│ ├── css/ # Feuilles de style
│ └── js/ # Scripts JavaScript

├── bin/ # Scripts utilitaires

├── logs/ # Fichiers de logs
│ └── za-pep.log # Log principal du plugin

├── src/ # Code source principal
│ ├── classes/ # Classes utilitaires
│ │ ├── ApiKeyManager.php
│ │ ├── JwtManager.php
│ │ ├── LogManager.php
│ │ └── WpManager.php
│ │
│ ├── controllers/ # Contrôleurs de logique métier
│ │ ├── ZapierController.php
│ │ └── WordPressController.php
│ │
│ ├── exceptions/ # Gestion des exceptions personnalisées
│ │ └── ZaPepException.php
│ │
│ ├── functions/ # Fonctions utilitaires
│ │ └── cron.php
│ │
│ ├── middlewares/ # Middlewares de traitement
│ │ ├── AuthMiddleware.php
│ │ └── ValidatorMiddleware.php
│ │
│ ├── routes/ # Définition des routes
│ │ ├── ZapierRoutes.php
│ │ └── WordPressRoutes.php
│ │
│ ├── services/ # Services métiers
│ │ ├── AuthService.php
│ │ └── DataService.php
│ │
│ ├── views/ # Vues ou templates (si nécessaire)
│ │
│ ├── Router.php # Routeur principal
│ └── ZaPepPlugin.php # Classe principale du plugin

├── tests/ # Tests unitaires
│ ├── bootstrap.php # Configuration des tests
│ ├── ExampleTest.php # Test exemple
│ └── middlewares/ # Tests spécifiques aux middlewares
│ ├── AuthMiddlewareTest.php
│ └── ValidatorMiddlewareTest.php

├── vendor/ # Dépendances Composer

├── .gitignore # Fichier d’exclusion Git
├── .gitlab-ci.yml # Configuration CI/CD
├── composer.json # Définition des dépendances
├── composer.lock # Verrouillage des versions de dépendances
├── phpunit.xml # Configuration PHPUnit
├── README.md # Documentation du projet
└── za-pep.php # Fichier principal du plugin

Authentification

Clé API

Dans l’ancienne version, j’avais déjà appliqué une clé API à donner dans les requêtes envoyées à mes endpoints de façon à autoriser l’exécution. On retrouve donc ce système, avec en plus un chiffrement de la clé stockée dans la base de données. Une clé aléatoire de 24 caractères est proposée par le programme, mais il est possible de la personnaliser.

Clé de sécurité

JWT

L’outil de Zapier permet d’envoyer des requêtes à WordPress en y ajoutant un jeton d’authentification (JWT). Za Pep vérifie que ce JWT n’est pas altéré et peut ainsi s’assurer qu’il provient bien de Zapier, identifier l’utilisateur WordPress connecté à Zapier et vérifier si son rôle est administrateur. Pour cela, j’ai implémenté un middleware qui s’intègre facilement à tous les endpoints ouverts aux requêtes Zapier.

Endpoint

Gestion des erreurs

Une erreur critique dans une extension peut avoir des conséquences directes sur le site en bloquant son accès. Il est donc essentiel d’anticiper toutes les possibilités d’erreurs et d’informer l’utilisateur de manière claire si une erreur survient, afin d’éviter qu’une erreur du plugin ne soit bloquante. C’est dans ce sens que j’ai implémenté une gestion des erreurs qui explore un maximum de scénarios et retourne des informations pertinentes à l’utilisateur.

Message d’erreur

Gestion du cache

WordPress utilise un système de cache pour optimiser les performances du site. Le cache des membres du forum wpForo est un résumé de toutes les variables d’un utilisateur, stockées dans des métadonnées avec les données sérialisées. Lorsque WordPress a besoin de données d’un utilisateur pour l’affichage ou d’autres opérations, il va chercher les informations en priorité dans cette métadonnée, chargée au démarrage de WordPress. Cela signifie que lorsque Za Pep modifie une donnée d’un utilisateur dans la base de données, WordPress ne la voit pas si les métadonnées de l’utilisateur n’ont pas été synchronisées.

Une solution native à wpForo consiste à cliquer sur le bouton “Supprimer tous les caches” du tableau de bord du forum, ce qui appelle la méthode “reset_all_caches()” de wpForo. Cela met à jour toutes les métadonnées des caches avec les données de la base. Cependant, cette méthode nécessite de retrouver le bouton dans une page surchargée d’informations et est coûteuse en termes de performances.

Supprimer tous les caches

Une alternative que j’ai implémentée est de créer un bouton dans le panneau de Za Pep qui supprime uniquement le cache des membres en utilisant la fonction de wpForo “WPF()->member->clear_db_cache();”. Cette solution est un peu plus performante que la précédente, mais il est possible de faire encore mieux.

Nettoyage du cache des membres

Après des investigations pour comprendre où aboutissent les méthodes reset_all_caches et clear_db_cache, j’ai découvert où les données modifiées dans la base utilisateur se cachent dans les métadonnées de WordPress. Le résultat de ces investigations m’a permis d’implémenter une fonction qui modifie parallèlement les données de la table utilisateur et les métadonnées correspondantes. Cela synchronise avec précision les données stockées et affichées sur le site de manière invisible pour l’utilisateur et peu coûteuse en termes de performances.

Métadonnées

Logs

J’ai développer une classe au pattern singleton qui permet de logger tous les actions faites avec Za Pep et les erreurs dans un fichier, l’administrateur du site peu les consulter en téléchargeant le fichier.

Fichier de logs

Environnement de développement

Pour être plus efficace, j’ai installé un serveur WAMP local contenant une application WordPress. Afin de recevoir les requêtes de Zapier, j’ai mis en place un tunnel sécurisé avec Ngrok. (En savoir plus sur Ngrok : Créez facilement un tunnel pour vos applications locales)

Illustration Ngrok de www.cachem.fr

Cela a demandé quelques efforts pour mettre en place cet environnement de développement, mais cela s’est avéré très pratique pour voir l’avancement en direct et pour le débogage du code.

Exemple d’erreur fatale dans WordPress

Tests PHPUnit

Les tests unitaires sont importants dans un projet. Cela m’a demandé beaucoup d’efforts pour y arriver. Même si PHPUnit est un bon framework pour créer et exécuter des tests, j’ai dû réécrire mes fonctions pour les rendre testables, intégrer une installation allégée de WordPress dans le scope des tests, jouer avec les compatibilités des dépendances et, bien sûr, implémenter des tests pertinents. J’ai beaucoup appris lors de cette phase du projet, mais j’ai dû faire preuve de beaucoup de courage et de persévérance pour parvenir à faire passer mes tests.

Tests PHPUnit

Dupliquer les articles

Sur cette nouvelle version de mon projet, je suis cette fois-ci parti d’un tutoriel qui explique les bases d’une extension WordPress. Même si les exemples donnés sont éloignés de mon sujet, cela m’a permis d’acquérir des bases solides pour redémarrer mon projet. Néanmoins, dans ce tutoriel, j’ai appris à implémenter une fonctionnalité qui permet de dupliquer un article, et c’est tellement pratique que je me demande pourquoi ce n’est pas natif à WordPress. Je l’ai donc gardée ^^.

Fonctionnalité Dupliquer

Téléversement

Pour l’utilisateur final, il faut fournir une archive Zip du projet qui peut être téléversée sur son site WordPress. Cela paraît simple, mais c’est en fait très délicat, car c’est le moment clé où l’on met toute la fiabilité du programme en jeu.

Mes premiers essais furent désastreux, car ce qui fonctionne en local ne fonctionne pas forcément sur un serveur distant. Cela ne fonctionnait pas, et il n’y avait pas de messages du débogueur. Les seuls indices étaient WordPress qui partait en erreur 404 ou qui refusait le fichier en le considérant comme un virus, ou au mieux un refus d’activation pour cause d’erreur fatale.

Après quelques recherches infructueuses et de multiples essais hasardeux ratés, je n’ai jamais été aussi proche d’abandonner. Après tout, je ne me destine pas à devenir un spécialiste en PHP ni WordPress, c’était juste un défi, un challenge… Puis, après quelques jours de pause, je n’arrivais pas à me débarrasser de l’idée que je m’étais arrêté devant la ligne d’arrivée. Alors, je m’y suis remis avec une approche pas à pas. Je suis donc reparti d’un projet vierge pour y ajouter des petits bouts de code de mon projet, afin de voir chaque détail qui ne passait pas le test du téléversement, puis appliquer des corrections sur mon projet principal, pour finalement obtenir une version qui s’installe et fonctionne parfaitement sur tous les environnements.

Ajouter extension

En conclusion, je suis satisfait du niveau de qualité que j’ai pu atteindre en partant d’un seul cas pratique dont une entreprise aurait pu avoir besoin. Je vois encore beaucoup d’axes d’amélioration, comme dans l’architecture ou l’aspect DevOps, en automatisant les tests et la branche de téléversement grâce aux outils d’intégration (CI/CD) de GitLab.

Cependant, la version actuelle remplit parfaitement sa fonction et le coût de l’améliorer à ce stade n’apporterait aucune plus-value. Par contre, le jour où il sera nécessaire d’y apporter de nouvelles fonctionnalités ou simplement de faire des ajustements dus à des dépendances devenues obsolètes, il faudra appliquer le principe du “camp scout” : laisser le camp plus propre que lorsqu’on y est arrivé. C’est-à-dire que si je suis amené à faire des modifications dans une partie du code, j’en profiterai pour y appliquer en même temps des améliorations selon les bons principes de développement. Cela permettra d’améliorer la maintenabilité du code tout en enrichissant ses fonctionnalités et en augmentant sa sophistication.

Voilà, j’espère vous avoir intéressé avec ce projet et vous avoir donné envie de sortir de votre zone de confort dans vos propres projets. Pour ma part, je suis très heureux de cette expérience et, même si je me suis éloigné un temps de mon objectif de devenir expert en technologie Angular, je suis sûr que ce voyage dans une technologie qui paraît très lointaine me permettra de devenir meilleur dans mon domaine. À bientôt !

Liens

Lien vers le dépôt GitLab du projet

Scroll to Top