Laisser un commentaire

WordPress starter theme pour les développeurs JS

On ne présente plus WordPress. CMS open source ultra populaire, je le perçois comme une sorte de framework. Je peux ainsi me concentrer sur l’expérience utilisateur : créer un thème sur-mesure de A à Z. Cependant, j’ai envie d’une expérience de développement moderne sans toutefois devoir utiliser tout l’écosystème PHP : bienvenue chez Steroids.

Le besoin

Chaque outil possède sa zone de confort. C’est à dire qu’il est approprié pour une tâche donnée. Je suis un développeur JavaScript, pour autant, je ne vais pas concevoir une solution full JS avec une API pour un simple blog comme celui-ci.

Je pourrais aussi utiliser un moteur de blog JS comme Ghost, mais son domaine de compétence est bien plus réduit : ce n’est que pour le blogging. Cela conviendrait donc pour ce blog, mais pas pour des sites plus complexes qui ont un besoin plus conséquent en fonctionalités, sans toutefois nécessiter un développement 100% sur mesure à partir d’un framework.

Pour un site e-commerce comme Alphapole par exemple, WordPress est parfait. Le plugin WooCommerce fournit la plupart des outils nécessaires au e-commerce, tout en étant extensible pour combler des besoins plus spécifiques. On ne ré-invente pas la roue et ça permet de se concentrer sur ce qui rend le site unique : son design et l’expérience utilisateur.

Le problème

Je l’ai dit, chaque outil a sa zone de confort. Le meilleur outil est souvent celui qui est le plus adapté à une situation. Néanmoins, le développeur aussi a sa zone de confort. Et le meilleur outil est celui que le développeur maîtrise parfaitement.

C’est l’évidence même, un outil maîtrisé, c’est une productivité accrue et moins de bugs. Bien entendu, comme dans tout domaine, il est bon de sortir de sa zone de confort : apprendre un nouveau paradigme de programmation, un nouveau langage etc. Cependant, un nouvel outil à chaque projet n’a aucun sens.

Si l’on résume, l’outil parfait est celui qui répond au besoin et que le développeur maîtrise. Bingo, WordPress is here. Des connaissances en HTML et CSS suffisent à créer un thème de A à Z. On passe le plus clair de son temps à gérer du HTML, du CSS et du JS lors de la création d’un thème WordPress et c’est justement ce qui convient parfaitement aux développeurs frontend.

Blank themes

Dès lors que l’on parle de sur-mesure, on pense aux blank themes. Ce sont des thèmes vierges qui fournissent une structure et des fonctions pour accélérer le démarrage.

Deux thèmes sont très populaires :

Sage et Roots embarquent beaucoup de choses et imposent un peu leur manière de faire. Je n’ai pas envie d’avoir à utiliser Composer, ni d’apprendre la syntaxe de Blade – le moteur de template du framework PHP Laravel – ni d’installer Vagrant sur ma machine simplement pour faire tourner un serveur web. Ça s’adresse à mon avis plutôt à des développeurs PHP.

J’ai envie de tester en local avec un simple Apache2/PHP ou le classique MAMP/XAMPP et je veux héberger mes sites sur mes propres serveurs avec une config aux petits oignons.

De son côté, _underscores est un peu trop simple. Il s’adresse au public le plus large possible. Mais pour un développeur JS, un ingénieur frontend ou un devops, il y a des habitudes et des outils desquels on a du mal à se défaire.

Si en plus, tout ça peut être géré avec un seul et même outil, de préférence un truc que j’utilise déjà, au hasard npm ou yarn, alors c’est l’apothéose.

Steroids : la solution

Steroids est donc mon starter theme pour WordPress. C’est à partir de cela que je conçois les sites pour lesquels WordPress est la réponse technique évidente. Côté PHP, c’est du WordPress pur et dur. On télécharge, on dézippe, un coup familier de npm install et roule ma poule.

Cela ne veut pas dire qu’aucune attention n’a été portée sur le code PHP. 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.

Côté front, c’est un peu plus cossu. On retrouve un environnement familier, efficace et performant :

On profite de Rollup afin de pouvoir utiliser les modules ESM et CommonJS. Rollup permet de bundler les modules JavaScript tout en profitant du tree shaking.

En outre, on peut faire deux builds adaptés à deux cibles navigateurs. 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.

Utilisation

Comme je l’ai dit, j’aime avoir quelque chose d’assez standard côté PHP et je n’ai pas envie de m’embêter à apprendre 50 outils que je n’utilise pas déjà. Cependant, j’aime avoir un workflow très épuré. La CLI, c’est la vie et si je peux tout mettre en place en une ligne de commande, c’est un sacré gain de temps.

Installation

J’utilise Apache et PHP nativement fournis avec macOS. Cela me permet une grande flexibilité dans les configurations de mes différents projets. Sachez aussi qu’il est tout à fait possible d’utiliser directement le serveur web de PHP. wp-cli permet même de lancer le serveur en une seule commande : php wp-cli server.

En ce qui concerne l’installation de WordPress à proprement parler, j’ai une fonction dans mon .bash_profile qui me permet, en une seule commande :

J’utilise root en tant qu’utilisateur en développement. Je précise néanmoins que ce n’est valable que lors du développement en local. En production, chaque site doit avoir son propre utilisateur. Les droits sont alors les suivants :

# droits classiques
GRANT ALL PRIVILEGES ON `base_du_site`.* TO 'user'@'localhost';

# droits plus restreints
# risque de ne pas fonctionner via la web interface pour des upgrades de versions majeures (ALTER TABLE…)
GRANT SELECT, UPDATE, DELETE ON `base_du_site`.* TO 'user'@'localhost';

Voyons donc le contenu de ce script.

installWordpress() {
    if [[ $1 ==  "" || $2 == "" || $3 = "" || $4 == "" || $5 == "" || $6 == "" ]]
    then
        echo "installWordpress <dbname> <title> <url> <admin_user> <admin_passd> <admin_email>"
        return
    fi

    mysql -u root -e "CREATE DATABASE $1 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" \
    && mkdir wordpress && cd wordpress \
    && wget https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar \
    && php wp-cli.phar core download --locale=fr_FR \
    && php wp-cli.phar config create --dbname=$1 --dbuser=root --dbpass="" --dbhost=127.0.0.1 --dbcharset=utf8mb4 --dbcollate=utf8mb4_general_ci \
    && php wp-cli.phar core install --title="$2" --url="$3" --admin_user="$4" --admin_password="$5" --admin_email=$6 \
    && php wp-cli.phar theme install https://github.com/Buzut/steroids/archive/master.zip --activate \
    && php wp-cli.phar theme uninstall `ls wp-content/themes/ | grep -v steroids | grep -v index.php | xargs` \
    && cd .. && chmod -R 775 wordpress \
    && sudo chown -R buzut:_www wordpress
}

Vous pouvez modifier cette config pour vos propres besoins. Notamment, l’utilisateur et le mot de passe de la base de données et les droits et l’utilisateur nécessaires pour qu’Apache puisse correctement faire son travail (lignes 12 à 14). Les réglages des droits, groupes et propriétaires dépendent de la configuration de votre environnement.

Vous pouvez également lancer la commande sans utiliser la fonction, simplement en remplaçant les variables $1 à $6 par leurs valeurs respectives et en collant la commande dans votre terminal (de la ligne 8 à la ligne 19).

Vous êtes aussi tout à fait libre de télécharger le thème manuellement, de le dézipper et de le placer dans le répertoire des thèmes du WordPress que vous aurez préalablement récupéré sur le site officiel.

Une fois que c’est fait, vous n’avez plus qu’à vous concentrer sur votre thème ! Rendez-vous donc dans wp-content/themes/steroids/ et commencez à développer. Vous pouvez faire un lien symbolique si ça vous ennuie d’aller chercher le thème au fond de l’arborescence du site.

En terme d’usage, une fois à la racine du thème, après le classique npm install ; npm run watch permet de recompiler le code à la volée ; npm run build s’occupe de build pour la prod et voilà. Il faudra juste installer Gzip et Brotli si vous ne les avez pas déjà.

En outre, j’ai à cœur de ne pas utiliser jQuery par défaut. Sérieusement, servir plus de 80k de code pour modifier trois bouts de DOM, c’est contraire aux bonnes mœurs, j’utilise ƒlightDOM pour ça.

Babel se chargera de build pour les navigateurs plus anciens et le CSS sera automatiquement préfixé. 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 ou de nouveaux modules CSS. Ainsi, si vous voulez utiliser fetch ou IntersectionObserver, à vous de fournir les polyfills nécessaires. Il en va de même pour Flexbox ou les grilles CSS.

Il arrive qu’en local, les fonctions de mise à jour de WordPress échouent et demandent un accès FTP. Une ligne dans le wp-config.php suffit bien souvent à régler le problème : define('FS_METHOD','direct');.

Deploy

Beaucoup reprochent à WordPress d’être fastidieux à transférer de sa machine locale au serveur. Il n’en est rien. C’est simplement que les personnes en question n’ont pas les bons outils. Nous avons la CLI de WordPress et j’ai parlé plus haut d’Ansible.

J’utilise Ansible car cet outil a une place de choix dans mon processus devops. Capable de gérer une VM comme une ferme de serveurs, il peut changer votre vie. J’ai écrit à son sujet pour une prise en main rapide et pour en tirer le maximum de puissance.

Voyons mon exemple de playbook Ansible qui s’occupe de tout en une seule commande. Je le place en général à côté du répertoire racine wordpress/ et j’ai pour habitude de l’appeler deploy.yml.

---
- hosts: "monserveur"

  vars:
    themeName: steroids

    devPath: wordpress
    devDomain: http://local.monsite.com

    prodPath: /var/www/monsite
    prodDomain: https://monsite.com

    webUser: www-data
    adminUser: root

  tasks:
    - name: Build site
      command: npm run build
      args:
        chdir: "{{ devPath }}/wp-content/themes/{{ themeName }}/"
      delegate_to: localhost

    - name: Dump database
      command: php wp-cli.phar db export --add-drop-table dump.sql
      args:
        chdir: "{{ devPath }}"
      delegate_to: localhost

    - name: Sync local to distant
      synchronize:
        src: "{{ devPath }}"
        dest: "{{ prodPath }}"
        partial: yes
        delete: yes
        rsync_opts:
          - "--exclude=.git"
          - "--exclude=.DS_Store"
          - "--exclude=node_modules"
          - "--exclude=wp-config.php"
          - "--copy-links"

    - name: Replace wp-config by wp-config for prod
      command: mv wp-config.php.prod wp-config.php
      args:
        chdir: "{{ prodPath }}"

    - name: Set directories rights
      file:
        path: "{{ prodPath }}"
        owner: "{{ adminUser }}"
        group: "{{ adminUser }}"
        recurse: yes

    - name: Set wp-content rights
      file:
        path: "{{ prodPath }}/wp-content"
        owner: "{{ webUser }}"
        group: "{{ webUser }}"
        recurse: yes

    - name: Set theme rights
      file:
        path: "{{ prodPath }}/wp-content/themes/{{ themeName }}"
        owner: "{{ adminUser }}"
        group: "{{ adminUser }}"
        mode: 0755
        recurse: yes

    - name: Finer grained rights
      shell: "{{ item }}"
      loop:
        - find {{ prodPath }} -type d -exec chmod 755 {} \;
        - find {{ prodPath }} type f -exec chmod 644 {} \;

    - name: Import database & re-configure it for remote url
      command: php wp-cli.phar {{ item }}
      loop:
        - db import dump.sql
        - search-replace '{{ devDomain }}' '{{ prodDomain }}'
      args:
        chdir: "{{ prodPath }}"
      become: true
      become_user: "{{ webUser }}"

Avec ce playbook, une fois votre hébergement configuré, plus que quatre étapes vous séparent de la mise en prod :

  1. créer un fichier wp-config.php.prod avec les paramètres de la prod,
  2. renseigner les variables dans vars,
  3. remplacer monserveur par le nom du serveur correspondant,
  4. exécuter ansible-playbook deploy.yml.

Cela nécessite évidemment que votre hébergement soit disponible via ssh. Enfin, Ansible est bien entendu optionel. Cependant, si vous êtes devops et que vous l’utilisez déjà pour d’autres projets et pour la gestion de vos serveurs, c’est juste un régal. À titre d’exemple, Grafikart présente une méthode assez similaire mais qui utilise make.

Notez que l’option "--copy-links" de rsync permet de remplacer les liens symboliques par leurs contenus. C’est fort utile et peut vous éviter un débug pénible, notamment si vous avez suivi mon conseil et avez placé le répertoire du thème hors de l’arborescence de WordPress.

Enfin, vous noterez peut-être que j’accorde un soin tout particulier au paramétrage des droits et utilisateurs des fichiers et dossiers. C’est le dernier rempart contre la compromission d’un site WordPress. On autorise donc le strict minimum.

Ainsi, si vous n’avez pas besoin d’autoriser les modifications via l’éditeur de WordPress directement du code de votre thème, autant en restreindre l’écriture. Pour un petit rappel sur le fonctionnement des droits et utilisateurs de Linux, n’hésitez pas à lire mon article sur le sujet. Si vous désirez en savoir plus sur les besoins en droits de WordPress pour la base de données et les fichiers, vous pouvez consulter la documentation officielle [en].

Retouches

Le deploy utilisé précédemment remplace totalement le WordPress déjà présent sur le serveur – s’il y en a déjà un, le créé sinon – par ce que vous avez en local. C’est pratique lors du premier deploy ou si vous avez effectés de grosses modifications en local.

Cependant, il est courant que l’on ne veuille modifier que le thème alors que le base de données du WordPress distant aura différée de la base de développement utilisée en local. C’est d’ailleurs le cas le plus courant : seules des modifications du thème ont été effectués et l’on souhaite simplement les répercuter en live.

Cette fois, on reste avec nos outils de dev, j’utilise tout simplement npm.

"scripts": {
  …
  "deploy": "npm run build && rsync -rv --exclude=.git --exclude=.DS_Store --exclude=node_modules --exclude=*.less . alpha:/var/www/mon-site/wp-content/themes/mon-theme/ --delete",
  …
}

Et le tour est joué ! On profite tout simplement de la puissance de rsync pour synchroniser le répertoire local du thème avec le répertoire sur le serveur. On prend soin d’exclure .git, le dossier node_modules les fichiers .less (ou .sass si on est utilisateur de Sass) et .\_DS\_Store si on est sur Mac.

Par ailleurs, on demande ici à rsync de supprimer les fichiers périmés avec l’option --delete. Cela évite que de vieux fichiers soient conservés sur le serveur. Si vous voulez tout de même les laisser, libre à vous d’effacer cette option.

Conclusion

Je présente les problèmes régulièrement rencontrés face à un besoin et les solutions qui sont pour moi les plus adaptées. Chaque pièce peut être utilisée indépendamment des autres. Ansible n’est en rien spécifique à WordPress et mon thème peut tout à fait s’utiliser plus manuellement avec une installation classique sans CLI et sans scripting.

D’ailleurs, Steroids est sur GitHub. Il n’attend que vous pour réaliser un site unique et performant. N’hésitez pas l’améliorer, l’étendre, le modifier. Le fork et les PR sont là pour ça !

Si vous souhaitez une architecture plus avancée et plus orientée PHP, voici un article décivant un workflow avec Bedrock et Composer.

N’hésitez pas à me faire part de vos avis, besoins ou retour d’expérience via les commentaires. Bon dev !

Commentaires

Rejoignez la discussion !

Vous pouvez utiliser Markdown pour les liens [ancre de lien](url), la mise en *italique* et en **gras**. Enfin pour le code, vous pouvez utiliser la syntaxe `inline` et la syntaxe bloc

```
ceci est un bloc
de code
```