Bon, je vais être honnête avec vous : gérer un projet WordPress avec du code qui part dans tous les sens et des déploiements à la main, c’est le cauchemar assuré. Heureusement, on peut transformer tout ça en workflow professionnel grâce à Composer et GitHub Actions ! Dans cet article, je vous montre comment j’ai mis en place une chaîne de déploiement automatisée qui teste, build et déploie mes sites WordPress comme un chef.
Architecture d’un projet WordPress avec Composer
Quand on commence à travailler sérieusement avec WordPress, on se rend vite compte que l’installation classique via l’admin ou le téléchargement direct a ses limites. C’est là que Composer entre en jeu ! Cette approche moderne transforme complètement la façon dont on structure et maintient nos projets WordPress.
Structure moderne des dossiers
Fini le temps où tout était mélangé dans le dossier racine ! Avec Composer, on adopte une architecture plus propre et professionnelle :
mon-projet/
├── web/
│ ├── wp/ # WordPress core
│ ├── wp-content/
│ │ ├── themes/
│ │ ├── plugins/
│ │ └── uploads/
│ ├── wp-config.php
│ └── index.php
├── vendor/ # Dépendances Composer
├── composer.json
├── composer.lock
└── .gitignore
Cette structure sépare clairement le code WordPress (web/wp/) de notre configuration personnalisée. Le dossier web/ devient notre document root, tandis que les fichiers sensibles (comme composer.json) restent inaccessibles depuis le navigateur. C’est un énorme plus pour la sécurité !
Configuration du composer.json
Le fichier composer.json est le cœur de notre architecture. Voici un template complet que j’utilise régulièrement :
{
"name": "mon-agence/mon-projet",
"type": "project",
"require": {
"php": ">=7.4",
"johnpbloch/wordpress-core": "^6.0",
"johnpbloch/wordpress-core-installer": "^2.0",
"wpackagist-plugin/advanced-custom-fields": "*",
"wpackagist-plugin/yoast-seo": "*",
"wpackagist-theme/twentytwentythree": "*"
},
"require-dev": {
"phpunit/phpunit": "^9.0",
"wp-coding-standards/wpcs": "^2.3"
},
"repositories": [
{
"type": "composer",
"url": "https://wpackagist.org"
}
],
"extra": {
"wordpress-install-dir": "web/wp",
"installer-paths": {
"web/wp-content/plugins/{$name}/": ["type:wordpress-plugin"],
"web/wp-content/themes/{$name}/": ["type:wordpress-theme"]
}
},
"autoload": {
"psr-4": {
"MonProjet\\": "src/"
}
}
}
La clé repositories permet d’accéder à WPackagist, qui mirror tous les plugins et thèmes du répertoire WordPress. Les installer-paths définissent où installer chaque type de package. Plutôt pratique, non ?
Gestion des dépendances WordPress
Avec cette approche, WordPress devient une simple dépendance comme une autre ! Plus besoin de télécharger manuellement le core ou les plugins. Un simple composer install et tout est en place.
Pour ajouter un plugin, par exemple :
composer require wpackagist-plugin/contact-form-7
Pour mettre à jour WordPress :
composer update johnpbloch/wordpress-core
Les avantages sont énormes : versionning précis (fini les « quelle version j’avais déjà ? »), sécurité renforcée (les fichiers sensibles ne sont pas exposés), et maintenance simplifiée. Quand votre collègue récupère le projet, il fait juste composer install et boom, l’environnement est identique au vôtre. Plus d’excuses du type « ça marche chez moi » !
Gestion des plugins et thèmes via Composer
Maintenant qu’on a configuré notre projet WordPress avec Composer, on peut enfin gérer nos plugins et thèmes comme de vraies dépendances. Et croyez-moi, une fois qu’on a goûté à cette approche, difficile de revenir en arrière !
Le secret ? Utiliser wpackagist.org, un repository qui transforme automatiquement les plugins et thèmes du répertoire WordPress.org en packages Composer. C’est génial, car on peut installer n’importe quel plugin gratuit avec une simple commande.
Prenons un exemple concret. Pour installer Yoast SEO, au lieu de passer par l’interface WordPress, on fait ça :
composer require wpackagist-plugin/wordpress-seo
Pour un thème comme Twenty Twenty-Four :
composer require wpackagist-theme/twentytwentyfour
La différence entre require et require-dev ? C’est simple : require pour les dépendances nécessaires en production (vos plugins actifs), require-dev pour les outils de développement uniquement.
Je mets souvent Query Monitor en require-dev :
composer require --dev wpackagist-plugin/query-monitor
Comme ça, mes environnements de production restent propres.
Bon, parlons maintenant des plugins premium (ACF Pro, Gravity Forms, etc.). C’est là que ça se complique un peu. Ces plugins ne sont pas sur wpackagist, donc plusieurs solutions :
- Repository privé : Créer votre propre repository Composer
- Packages locaux : Déposer les .zip dans un dossier
packages/ - Services tiers : Utiliser des solutions comme Composer Packages ou WP Pusher
Pour ACF Pro, je configure souvent un repository privé dans mon composer.json :
{
"repositories": [
{
"type": "composer",
"url": "https://connect.advancedcustomfields.com/v2/plugins"
}
],
"require": {
"wpengine/advanced-custom-fields-pro": "^6.0"
}
}
Pour les thèmes custom, deux approches : soit vous les versionnez dans un repository Git séparé (recommandé), soit vous les gérez localement. Dans le premier cas :
{
"repositories": [
{
"type": "vcs",
"url": "git@github.com:votre-compte/votre-theme.git"
}
]
}
Les commandes de base ? composer install pour installer exactement ce qui est défini dans le composer.lock (parfait pour la production), composer update pour mettre à jour selon les contraintes définies.
Attention avec composer update : ça peut casser des choses ! Mieux vaut spécifier le package :
composer update wpackagist-plugin/wordpress-seo
Pour les versions, utilisez les contraintes Composer. ^5.0 accepte 5.x mais pas 6.0, ~5.2 accepte 5.2.x mais pas 5.3. Pour des plugins critiques, je fixe parfois la version exacte : "5.2.1" (mais c’est plus rigide pour les mises à jour de sécurité).
Un conseil : testez toujours vos mises à jour sur un environnement de staging avant la production. WordPress, c’est parfois capricieux !
Configuration GitHub Actions pour CI/CD
Alors là, on entre dans le vif du sujet ! GitHub Actions, c’est vraiment un game changer pour automatiser tout le processus de déploiement WordPress. J’ai mis du temps à m’y mettre (je restais sur du FTP manuel comme un sauvage), mais une fois qu’on a goûté à l’automatisation… impossible de revenir en arrière.
Workflow de base pour WordPress
Voici un template complet que j’utilise depuis des mois sur mes projets. Ce fichier va dans .github/workflows/deploy.yml :
name: WordPress CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
extensions: mysql, zip, gd
tools: composer
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install Composer dependencies
run: composer install --no-dev --optimize-autoloader
- name: Install NPM dependencies
run: npm ci
Ce workflow se déclenche sur les pushs vers main et develop, plus les pull requests. C’est exactement ce qu’on veut : tester avant de merger, déployer automatiquement en production.
Variables d’environnement et secrets
Bon, parlons sécurité. Les secrets GitHub, c’est VITAL. Dans Settings > Secrets and variables > Actions, j’ajoute toujours :
SSH_PRIVATE_KEY: ma clé SSH pour accéder au serveurSSH_HOST: l’adresse de mon serveurSSH_USER: le nom d’utilisateur SSHDB_PASSWORD: mot de passe de la base de donnéesWP_ENV: l’environnement (staging, production)
Pour les utiliser dans le workflow :
- name: Deploy to server
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_USER: ${{ secrets.SSH_USER }}
run: |
echo "$SSH_PRIVATE_KEY" | tr -d '\r' > /tmp/deploy_key
chmod 600 /tmp/deploy_key
rsync -avz --delete -e "ssh -i /tmp/deploy_key -o StrictHostKeyChecking=no" \
--exclude='.git' --exclude='node_modules' ./ $SSH_USER@$SSH_HOST:/var/www/html/
Attention : ne JAMAIS commiter de secrets dans le code. J’ai vu trop de projets compromis à cause de ça…
Tests de qualité de code
Les tests, c’est là que GitHub Actions devient vraiment puissant. Voici ma config PHPStan et PHPCS :
- name: Run PHPStan analysis
run: ./vendor/bin/phpstan analyse --no-progress
- name: Run PHPCS coding standards
run: ./vendor/bin/phpcs --standard=WordPress-Core wp-content/themes/mon-theme/
- name: Run PHPUnit tests
run: ./vendor/bin/phpunit
env:
WP_TESTS_DB_NAME: wordpress_test
WP_TESTS_DB_USER: root
WP_TESTS_DB_PASS: ''
J’ajoute aussi un setup MySQL pour les tests d’intégration :
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: ''
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: wordpress_test
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
Si les tests échouent, le déploiement s’arrête. C’est exactement ce qu’on veut !
Build et préparation des assets
Pour les assets CSS/JS, j’utilise cette approche (avec webpack dans mon cas) :
- name: Build production assets
run: |
npm run build:production
- name: Optimize images
run: npm run imagemin
- name: Create deployment archive
run: |
tar -czf wordpress-build.tar.gz \
--exclude='node_modules' \
--exclude='.git' \
--exclude='src' \
--exclude='tests' \
.
Je sépare les environnements avec des conditions :
deploy-staging:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/develop'
# ... étapes de déploiement staging
deploy-production:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
# ... étapes de déploiement production
Et voilà ! Avec cette config, chaque push déclenche les tests, et si tout passe, le déploiement se fait automatiquement. Plus de stress, plus d’erreurs humaines. C’est du bonheur !
Tests automatisés et monitoring
Une fois votre workflow GitHub Actions en place, il est temps de passer aux choses sérieuses : s’assurer que votre code WordPress fonctionne correctement avant le déploiement. Et croyez-moi, après avoir déployé quelques bugs en production (oui, ça m’est arrivé !), vous comprendrez vite l’importance d’une stratégie de tests solide.
Intégration PHPUnit
PHPUnit reste l’outil de référence pour les tests unitaires en PHP, et WordPress ne fait pas exception. La configuration est relativement simple : on ajoute PHPUnit dans notre composer.json et on configure un fichier phpunit.xml adapté à WordPress.
"require-dev": {
"phpunit/phpunit": "^9.0",
"wp-cli/wp-cli-bundle": "^2.5"
}
Pour tester vos fonctions custom et vos hooks, la clé c’est de bien isoler la logique métier. Par exemple, si vous avez développé une fonction qui calcule des prix avec des remises :
public function testCalculateDiscount() {
$price = 100;
$discount = 20;
$result = calculate_discount($price, $discount);
$this->assertEquals(80, $result);
}
Attention cependant : tester des hooks WordPress nécessite souvent de mocker l’environnement WP. C’est là que les outils comme WP_Mock deviennent indispensables pour simuler les fonctions WordPress sans charger tout le core.
Tests fonctionnels avec Behat
Behat, c’est le complément parfait de PHPUnit. Là où PHPUnit teste vos fonctions individuellement, Behat teste le comportement global de votre site depuis la perspective de l’utilisateur. Et franchement, c’est bluffant de voir des scénarios écrits en langage naturel !
Voici un exemple de scénario Behat pour tester un formulaire de contact :
Feature: Contact form
Scenario: Submit contact form
Given I am on "/contact"
When I fill in "name" with "John Doe"
And I fill in "email" with "john@example.com"
And I press "Send"
Then I should see "Message sent successfully"
L’avantage ? Même votre client peut comprendre ce qui est testé. Pour WordPress, on utilise généralement Mink avec un driver comme Selenium pour automatiser un vrai navigateur. C’est un peu plus lourd à configurer, mais ça teste vraiment l’expérience utilisateur complète.
Déploiement staging et production
Bon, maintenant que vos tests passent, il faut déployer ! Et là, on a plusieurs écoles. Personnellement, j’utilise souvent rsync pour sa simplicité, mais Deployer PHP est une excellente alternative pour des déploiements plus sophistiqués.
Voici un exemple de script de déploiement avec rsync dans votre GitHub Action :
- name: Deploy to staging
run: |
rsync -avz --delete \
--exclude-from='.deployignore' \
./ user@staging-server:/var/www/html/
Le fichier .deployignore est crucial : il évite de synchroniser les fichiers de développement (.git, tests/, node_modules/, etc.). Et surtout, déployez TOUJOURS d’abord en staging ! J’ai vu trop de projets où on déployait directement en production… jusqu’au jour où ça casse tout.
Stratégies de rollback
Et quand ça casse malgré tous vos tests ? Il faut pouvoir revenir en arrière rapidement. Ma stratégie favorite : utiliser des tags Git avec des sauvegardes automatiques de la base de données.
Avant chaque déploiement, on crée un backup :
#!/bin/bash
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mysqldump -u $DB_USER -p$DB_PASS $DB_NAME > backup_$TIMESTAMP.sql
tar -czf files_backup_$TIMESTAMP.tar.gz wp-content/uploads/
Pour le rollback, on garde les 5 dernières versions déployées. Si la version courante pose problème, on revient simplement à la précédente avec git checkout et on restaure le backup correspondant.
Côté monitoring, New Relic reste une valeur sûre pour surveiller les performances, tandis que Sentry excelle pour traquer les erreurs PHP. L’intégration est simple : quelques lignes dans wp-config.php et vous avez une visibilité complète sur ce qui se passe en production. Et croyez-moi, ça change la vie quand vous devez investiguer un bug signalé par un utilisateur !
