Chapitre 6 sur 20
Framework WordPress
Afin d’accélérer le développement et d’éviter de recommencer depuis zéro pour chaque projet, il existe des frameworks et des starter themes. Un blank theme ou starter theme est un thème vierge fournissant une structure et des fonctions pour accélérer – bootstraper dans le jardon – le démarrage. Un framework va en général plus loin avec une approche globale ne se limitant pas au thème.
Les principales options
Une fois n’est pas coutume, plusieurs options s’offrent à nous. _underscores est le blank theme proposé par l’équipe derrière WordPress. Il s’adresse au public le plus large possible et de ce fait, est extrêmement simple. Cependant, pour un vrai développeur, il y a des habitudes et des outils desquels on a du mal à se défaire.
Diamétralement opposé au premier, Sage fait partie de l’écosystème Roots, un ensemble d’outils dédiés au développement WordPress. Celui-ci est bien plus complet, destiné aux développeurs PHP et embarque un nombre important d’outils. Néanmoins, il impose sa manière de faire : on n’a pas forcément envie d’apprendre la syntaxe de Blade – le moteur de template du framework PHP Laravel – ni d’installer Vagrant sur sa machine simplement pour faire tourner un serveur web.
Il faut également mentionner WordPlate qui est une solution assez populaire. Inspiré de Laravel, WordPlate se veut comme une surcouche à WordPress dont il gère totalement le cycle de vie. De la même manière que Roots, WordPlate impose également sa manière de faire : Blade, Webpack, suppression de la gestion des plugins via l’interface web…
Voici venu Steroids 💪
Steroids, de la même manière que WordPlate, est un framework WordPress. Il gère en effet le cycle de vie du CMS, par opposition à un simple thème qui n’en est qu’une dépendance.
On n’a pas à télécharger WordPress d’un côté, le thème de l’autre, placer le tout dans le bon répertoire et s’assurer que l’on commit simplement quelques fichiers du projet. Avec Steroids, on profite d’une gestion intégrée complète.
WordPress as a dependency
Pour tout projet d’envergure, WordPress comporte trop de parties mouvantes et hors de contrôle du développeur : update du core, des thèmes et des plugins toutes les 10 minutes. À chaque update, les comportements peuvent changer, la compatibilité avec votre code peut casser.
Cela nuit à la qualité et à la maintenabilité du projet. Lorsque l’on adopte une vraie approche devops avec WordPress, il faut adopter les pratiques modernes comme on le ferait avec tous les frameworks et langages récents : les dépendances sont gérées par le package manager du langage.
Le projet est ainsi facilement réplicable (autres développeurs, serveurs…) et on a la main sur la gestion de toutes les dépendances. Le code métier dirige le projet, WordPress, toutes les librairies externes et les plugins sont des dépendances de votre projet. Le projet dicte quoi installer, quand le mettre à jour et quelle version il requiert.
Bien que tout soit géré à travers Composer, le package manager de PHP, on passe quand même le plus clair de son temps dans le thème. Commençons donc par ce qui nous intéresse.
Le thème est clean et on s’y retrouve facilement. Le code est dûment commenté, les fichiers de fonctions sont bien organisés et pensés pour être étendus. De nombreuses fonctions sont activées par défaut et d’autres sont prêtes à être activées en décommentant simplement la ligne correspondante.
On reste cependant sur une syntaxe simple et classique, sans importer la dernière syntaxe à la mode issue du SuperFramework™ du moment. L’idée est que l’on s’adresse à tous les développeurs, dont une partie n’est pas experte en PHP et n’a pas forcément envie de l’être.
Je ne suis pas un expert
PHP n’est pas mon langage de prédilection et je l’assume totalement. J’ai pour ambition de l’utiliser pour faire des projets avec du code propre, fiable et facilement maintenable, accessible aux développeurs frontend ou spécialisés dans d’autres langages.
Je ne suis pas cependant expert en PHP et n’ai aucunement l’intention de le devenir. WordPress est justement la réponse aux projets qui ne nécessitent pas 100% de développement backend sur mesure dans le langage et le framework que l’on maîtrise de A à Z.
L’idée est de se concentrer sur le front pour l’expérience utilisateur et laisser WordPress gérer le reste. On utilise donc PHP pour le templating et le code métier de manière simple et efficace. Comme déjà expliqué, si le projet est extrêmement complexe avec énormément de code métier, c’est peut-être un cas où il faut songer à d’autres outils plus bas niveau.
Utilisation de Composer
Composer n’est pas plus difficile à utiliser qu’un autre package manager et la doc officielle est extrêmement claire.
Cependant, l’outil est conçu pour gérer les bibliothèques PHP. Les plugins WordPress doivent être installés dans le bon répertoire afin que WordPress les détecte. Par ailleurs, les plugins référencés sur WordPress ne sont pas présents dans Packagist, le dépôt officiel de Composer.
Tout problème a sa solution. Pour trouver les plugins, il existe un dépôt spécifique à WordPress : WPackagist. De plus, pour placer les plugins dans le bon répertoire, il suffit de spécifier quelques règles dans le composer.json.
Problem solved! Il reste un dernier détail : les plugins premium. Si vous utilisez des plugins payants, ils ne sont en général pas disponible au téléchargement via le répertoire des plugins de WordPress, et par conséquent, ne se trouvent pas dans WPackagist. Rien de bloquant cependant. Nous verrons dans un prochain chapitre comment surpasser cette limitation.
Frontend
Côté front, c’est plus cossu. On retrouve un environnement familier, efficace et performant :
- Code splitting pour le JS et le CSS ;
- Le JS est bundlé, tree shaké, minifié et compressé ;
- Les styles sont minifiés et compressés également ;
- Le JavaScript est automatiquement adapté en fonction de la cible navigateur via Babel (deux builds différents pour deux cibles navigateur) ;
- Le CSS est également préfixé en fonction de la cible navigateur.
On profite de Rollup afin de pouvoir utiliser les modules ESM et CommonJS. Rollup permet de bundler les modules JavaScript tout en permettant le tree shaking.
En outre, avec deux builds adaptés à deux cibles navigateur, on peut ainsi profiter d’un build léger pour les navigateurs récents tout en ayant une compatibilité maximum pour les navigateurs plus anciens. Tout cela est expliqué en détails dans mon article sur Rollup.
#WebPerf et Web Vitals
Tree Shaking et bundling sont dorénavant un classique de la performance web. Steroids va beaucoup plus loin. C’est le seul framework WordPress à permettre le dynamic loading des scripts et des styles !
En quoi cela consiste-t-il ? Vous ne chargez que les parties du code nécessaires sur les pages que vous utilisez. Ainsi :
- les CSS du blog ne surchargent pas inutilement les pages produit,
- le JavaScript utilisé sur les comptes client ne ralentit pas le tunnel d’achat avec du code inutile !
Le dynamic loading vous permet donc d’améliorer l’expérience utilisateur et les Core Web Vitals, indispensable à un bon référencement.
Installation & usage
Il y a quelques prérequis, vous avez besoin de :
- PHP,
- MySQL,
- Composer,
- Node.js et npm.
Sans surprise, je pense que côté PHP & MySQL vous êtes déjà all good. Concernant Node.js et npm, ils sont disponibles via la plupart des gestionnaires de paquets système (apt, homebrew, chocolatey). Il existe également des binaires pour le plupart des systèmes. Direction le site officiel pour plus d’infos.
Concernant Composer, il est également disponibles via les gestionnaires de paquets natifs mais on peut aussi simplement l’installer localement.
# Sur Debian et dérivés
apt install composer
# macOS avec bhomebrew
brew install composer
# Windows avec Chocolatey
choco install composer
# En local, à la racine du projet, quel que soit le système
curl -sS https://getcomposer.org/installer | php
Une fois cela fait, la magie opère, Composer s’occupe de tout.
# Dans le cas de Composer installé sur le système
composer create-project buzut/steroids my-new-project
# Dans le cas où Composer est installé localement
php composer.phar create-project buzut/steroids my-new-project
Et voilà ! Vous avez un nouveau répertoire qui contiendra tout votre projet. Le versionning s’effectue ici depuis la racine du projet, mais on ignore toutes les dépendances. Seuls sont commités les fichiers nécessaires à la réplication du projet.
*NB : si vous avez téléchargé Composer localement, déplacez-le à la racine du projet.
L’étape suivante est évidemment de configurer la base de données. Une fois que vous l’avez créée, tout se configure depuis la racine dans le fichier .env
.
Dotenv
Le fichier .env
, aussi appellé dotenv dans la langue de Shakespeare, est un standard de l’industrie logicielle (pas seulement en PHP). On y définit des variables d’environnement (d’où son nom “env”) accessibles partout dans le code.
Ces fichiers ne sont jamais versionnés pour deux raisons :
- ils contiennent souvent des données sensibles (clefs d’API et autres identifiants),
- les valeurs changent selon l’environnement (dev, prod…).
La plupart du temps, sur le serveur (et dans les environnement Cloud), les valeurs sont directement chargées en mémoire sans passer par un fichier. Cela simplifie énormément les déploiements.
En dernier lieu, cette pratique nous permet de commiter le wp-config.php
et donc de savoir ce qui y est déclaré, indépendamment des valeurs. Dans la même logique, on commit en général un .env.example
afin de documenter les valeurs attendues dans le Dotenv.
Une fois votre .env
complété, on lance WordPress. Ici, chacun ses préférences : Mamp, Xamp, Wamp… Personellement, je trouve que rien ne vaut la simplicité du serveur de développement intégré à PHP.
# Depuis la racine du projet
php -S localhost:8080 -t public
Évidemment, libre à vous de changer le port. Par ailleurs, comme il est rapidement fastidieux de taper cette commande à chaque fois, j’ai intégré un script qui s’en charge pour nous.
Pensez à le rendre exécutable si ce n’est pas le cas chmod +x startserver.sh
. Dès lors, un simple ./startserver.sh
démarre le serveur PHP et vous accédez à WordPress sur l’url localhost:8080
dans votre navigateur. Pour les développeurs JavaScript, c’est très similaire à ce à quoi nous sommes habitués avec tous les frameworks front.
On se rend ensuite dans le répertoire du thème (wp-content/themes/steroids/
), un coup familier de npm install
pour installer les dépendances et npm run watch
permettra de recompiler le code à la volée tandis que npm run build
s’occupe de build pour la prod et voilà, prêt à coder !
Il existe de nombreuses options dont l’activation/désactivation s’effectue par un simple flag dans le fichier .env
. Certaines sont activées par défaut, d’autres non. Jetez-y un œil. Par ailleurs, pour profiter du livereload, pensez à définir la constante IS_DEV
à true
.
CSS et JS
C’est la raison d’être de Steroids, pouvoir utiliser du CSS et JS modernes ! Vos styles seront bien entendu compilés en CSS et pré-fixés pour les deux dernières versions des navigateurs courants (vous pouvez modifier cela dans le package.json
). Quand vous lancez un npm run build
, les styles sont minifiés tandis qu’ils intègrent un sourcemap quand vous lancez un watch
.
Côté JS, on est sur une stack moderne. Le point d’entrée est scripts/main.js
et vous pouvez évidemment utilisez les modules ESM. Babel se chargera de build pour les navigateurs plus anciens. Cependant, gardez à l’esprit qu’il n’y a pas de système de polyfill automatique si vous utilisez des API du DOM très récentes. Ainsi, si vous voulez utiliser fetch
ou IntersectionObserver
, à vous de fournir les polyfills nécessaires (si vous souhaitez supporter de vieux navigateurs).
Dans la même logique, les nouveaux modules CSS ne reçoivent pas de polyfill non plus. Par exemple, Flexbox ou les grilles CSS s’afficheront mal dans les vieux navigateurs si vous n’apportez pas de polyfill ou de fallback… Who cares dirons certains !
jQuery or not
Actuellement, WordPress ajoute jQuery par défaut (ça changera peut-être). Cette décision est liée à la place centrale qu’a eu jQuery dans le développement web. De ce fait, de très nombreux plugins en dépendent encore (dont un certain nombre de plugins officiels).
Le thème permet de ne pas charger jQuery par défaut et de remplacer la version jQuery de WordPress par une version plus moderne et légère. Dans ce cas, jQuery ne sera chargé que lorsqu’un plugin le requiert (seulement sur les pages où il est nécessaire). Pour ce faire, direction le config.php
et les options OVERRIDE_JQUERY
& UNLOAD_JQUERY
.
Votre code ne devra pas dépendre de jQuery. Afin de m’en afranchir tout en conservant une syntaxe consise et fonctionnelle, j’ai créé ƒlightDom.
Dynamic styles
Étant donnée que Steroids permet de charger les styles de manière dynamique, la structure du répertoire styles/
est la suivante :
utils.less
regroupe les helpers. On importera ce fichier en haut de chaque fichier ayant besoin d’utiliser les fonctions helpers.critical.less
concerne les styles qui seront immédiatement chargés sur toutes les pages. On utilise donc ce fichier pour importer les fichiers de styles à appliquer sur toutes les pages (header, typographie…).lazy.less
concerne les styles qui seront chargés sur toutes les pages de manières asynchrone. On l’utilise de ce fait pour les fichiers de styls à appliquer partout mais qui peuvent tolérer d’attendre le pageload pour être chargés : styles under the fold (footer…).
Les fichiers importés par critical.less
ou lazy.less
sont respectivement dans critical/
et lazy/
. Étant donné que utils.less
est importé par critical et lazy, vous n’aurez pas besoin d’explicitement l’importer dans les fichiers de critical/
et lazy/
pour en utiliser les fonctions.
Le troisième répertoire, nommé routes/
, contient tous les fichiers qui seront appliqués de manière conditionnelle.
Vous pouvez bien entendu créer des sous-répertoires pour organiser vos fichiers. Cependant, les fichiers contenus dans les sous-répertoires sont compilés seulement s’ils sont importés par des fichiers du répertoire parent (critical.less
, lazy.less
ou routes/*.less
).
Enfin, pour définir quels styles seront importés sur tel ou tel template, on passe le ou les slugs du fichier de style à charger sous forme de tableau, en second paramètre de la fonction get_header
: get_header(null, ['slug'])
.
Par exemple, supposons que nous ayons besoin de charger styles/routes/blog.less
sur notre page des articles de blog. Le template responsable des articles de blog est le single.php
, le fichier commencera donc comme cela :
<?php
defined('ABSPATH') || exit;
get_header(null, ['blog']);
Supposons maintenant que nous voulions également charger les styles des commentaires, lesquels sont aussi utilisés sur les fiches produits. Voici ce que l’on ferait.
<?php
defined('ABSPATH') || exit;
get_header(null, ['blog', 'comments']);
On réalise cependant que les commentaires sont en bas de page et que le fichier contient beaucoup de styles. On suppose que l’on peut sans problème charger se fichier de manière asynchrone. Aucun problème.
<?php
defined('ABSPATH') || exit;
get_header(null, [['name' => 'blog', 'lazy' => false], ['name' => 'comments', 'lazy' => true]]);
Nous avons donc un chargement immédiat des styles de blog.less
et un chargement asynchrone de comments.less
.
Tree shaking et Code splitting
Le tree sharking consiste à l’élimination du code non utilisé. Ainsi, lorsque vous importez un module via import
, les parties du code qui ne sont pas utiliées sont éliminés du bundle final.
Le code spliting consiste quant à lui à diviser le code en plusieurs parties plus petites. De cette manière, on ne charge que le nécessaire, de manière dynamique, lorsque l’on en a besoin.
Pour profiter du tree chaking, vous n’avez rien à faire. Pour le code splitting, le router de Steroids va vous aider, mais il faut quand même organiser votre code en plusieurs fichiers. Par exemple, vous avez du code à destination de la homepage et du blog. Vous le placez donc dans des fichiers home
et blog
dans le répertoire js/routes/
.
Vous initialisez le router dans main.js
et lui indiquez quels fichiers il doit charger lorsque la balise body
possède telle ou telle classe (en fonction des pages et templates utilisés).
import router from './router'; // le routeur est un module que l'on charge
function domready(callback) { … }
// C'est plus safe de l'appeler lorsque le DOM est prêt
// Sinon, il faudra de nouveau le vérifier dans chacun des modules dynamiques
domready(() => {
router({
home: 'home', // importe ./routes/home.js quand body possède la classe "home"
slider: 'home' // importe aussi ./routes/slider.js sur la home
blog: ['blog', 'single-post'], // importe ./routes/blog.js quand body possède l'une des classe "blog" ou "single-post"
})
.then(() => console.log('Modules chargés 🎉'))
.catch(console.error);
});
Le router s’appuie sur les dynamic imports afin de proposer le code splitting. De ce fait, il est très largement compatible avec les navigateurs raisonablement récents.
Pour les navigateurs plus anciens, ils ne bénéficieront pas du code splitting mais tout fonctionnera normalement.
Exécuter WordPress
Vous avez installé WordPress et le thème, vous commencez à développer, vous voudriez très certainement voir plus en détails les différentes options pour faire tourner WordPress en local. On en parle en détails dans le prochain chapitre !
Commentaires
Rejoignez la discussion !