Catégories
Informatique & Dev

Maintenir WordPress avec Git entre local et production

Maintenir WordPress avec Git

Pourquoi utiliser Git pour maintenir WordPress ?

WordPress reste l’un des systèmes de gestion de contenu les plus utilisés au monde, mais sa méthode traditionnelle de maintenance n’a presque pas changé :
on met à jour depuis l’interface d’administration, on installe des plugins, on ajoute du code dans un thème enfant, et on croise les doigts pour que tout se passe bien.

Cette approche fonctionne pour un blog personnel, mais dès qu’un site devient un peu plus complexe ou qu’on souhaite travailler proprement — en séparant un environnement de développement d’un environnement de production — les limites apparaissent très vite :

  • pas d’historique clair des changements,
  • impossible de tester une mise à jour avant de l’appliquer en production,
  • difficulté à revenir en arrière,
  • fichiers modifiés directement sur le serveur,
  • risques d’erreurs humaines,
  • sauvegardes parfois insuffisantes ou incomplètes.

Aujourd’hui, même sur un hébergement mutualisé, il est possible — et conseillé — d’adopter des pratiques beaucoup plus professionnelles.
Git, associé à une stack locale (ici Lando), transforme complètement la manière de maintenir un site WordPress :

  • on travaille localement sans risque,
  • on teste les mises à jour avant de les appliquer,
  • chaque modification est tracée,
  • on déploie proprement via Git plutôt qu’en FTP,
  • et on sécurise durablement son site sans dépendre uniquement des sauvegardes automatiques de l’hébergeur.

Ce workflow modernisé permet d’aborder WordPress non plus comme un simple CMS “à cliquer”, mais comme un véritable projet de développement où :

  • le code est versionné,
  • la configuration est centralisée,
  • les environnements sont distincts,
  • et les déploiements sont reproductibles.

L’objectif de cet article est de montrer, étape par étape, comment structurer et maintenir un site WordPress grâce à Git, en synchronisant un environnement local et un environnement de production — même sur un hébergement mutualisé.

Nous verrons notamment :

  • ce qu’il faut (et ne faut pas) versionner,
  • comment organiser le projet,
  • comment maintenir un workflow propre entre local et production,
  • comment déployer des changements en toute sécurité,
  • comment s’appuyer sur Composer et WP-CLI quand c’est utile,
  • tout en restant compatible avec un usage WordPress classique.

Ce guide s’adresse donc aux utilisateurs WordPress avancés, développeurs ou administrateurs techniques, qui souhaitent professionnaliser leur manière de travailler sans pour autant basculer dans une architecture trop complexe ou inaccessible.

Dans cet article, voici les principaux points abordés :

Dépôt GitHub compagnon

Pour compléter cet article, j’ai mis en ligne un dépôt GitHub volontairement minimal.
Il ne s’agit pas d’un projet WordPress prêt à l’emploi, mais d’un support technique :

  • un .gitignore issu d’un site réel en production
  • quelques notes opérationnelles
  • un point d’entrée durable entre GitHub et cet article

👉 Le dépôt sert à héberger ce qui a plus de sens dans Git que dans un article.

🔗 https://github.com/manooweb/wordpress-git-workflow

L’article reste la référence pour la démarche et le raisonnement global.

🧰 1. Prérequis techniques

Avant de mettre en place un workflow Git entre votre environnement local et votre hébergement, il est essentiel de poser quelques bases.
Nous n’entrons pas ici dans l’installation détaillée de chaque outil : chacun possède une documentation claire et largement disponible.

L’objectif est simplement de s’assurer que vous disposez des outils indispensables pour suivre ce guide, effectuer vos déploiements, et maintenir WordPress de manière fiable et reproductible.

Ces prérequis sont volontairement orientés “bonne pratique” : ils reflètent un workflow réellement utilisable sur un site WordPress de production — pas un environnement de test ou de démonstration.

🔧 Outils nécessaires


1. Git

Git est au cœur de ce workflow.
Vous en aurez besoin :

  • en local, pour versionner les changements que vous faites sur votre thème, plugins, ou configuration,
  • et sur l’hébergement, pour mettre à jour votre site via un simple git pull.

Important : votre hébergeur doit proposer Git en SSH.

o2switch, Infomaniak, OVH mutualisé, Ionos (offre linux + SSH)

2. Une stack locale WordPress

Travailler proprement nécessite un environnement local fiable.
Dans ce guide, nous utiliserons Lando car :

  • une stack PHP/MariaDB prête à l’emploi,
  • il intègre composer et WP-CLI dans la recette pour WordPress
  • Il gère SSL nativement
  • il permet de très facilement ajouter de l’outillage (phpMyAdmin, mailpit, etc.)
  • il permet de reproduire facilement la configuration du serveur (Redis, Memcached),

Mais vous pouvez utiliser ce que vous voulez (LocalWP, Docker, LAMP, MAMP, WAMP etc.).

3. Accès SSH à l’hébergement

Indispensable pour :

  • lancer git pull directement sur la production,
  • exécuter des commandes WP-CLI en cas de besoin (désactiver un plugin, réparer la base…),
  • lancer composer si nécessaire,
  • faire un minimum d’administration.

Sans SSH → pas de workflow Git viable..

4. WP-CLI

Très pratique pour :

  • désactiver un plugin cassé (wp plugin deactivate)
  • effectuer un search-replace propre
  • vider le cache
  • forcer une mise à jour DB (wp core update-db)

Non indispensable à chaque étape du workflow, mais essentiel en cas :

  • d’erreur fatale,
  • d’urgence,
  • de migration.

La plupart des hébergeurs qui proposent de l’hébergement spécifiquement pour WordPress l’intègrent par défaut.
( o2switch par exemple)

5. Composer

Utilisé exclusivement pour :

  • charger phpdotenv,
  • gérer des dépendances PHP dans votre projet WordPress,
  • optimiser l’autoload sur le serveur.

Composer doit être installé localement et présent sur l’hébergement.
( o2switch par exemple)

6. Un éditeur de code moderne

Pour travailler efficacement localement sur le code de votre site.

Exemples :

  • VS Code
  • PhpStorm
  • Sublime Text
  • etc.

7. Une compréhension minimale de ce qu’on versionne dans Git

Il n’est pas nécessaire d’être expert Git, mais indispensable de comprendre :

  • ce que vous ajoutez au dépôt,
  • ce que vous ignorez,
  • pourquoi certains fichiers ne doivent jamais être versionnés,
  • pourquoi certains doivent impérativement l’être.

La section 3 de ce guide détaillera ce point.

En résumé

Pour suivre ce guide, vous avez besoin :

  • d’un Git fonctionnel local + hébergement
  • d’une stack locale WordPress (Lando conseillé)
  • d’un accès SSH sur la production
  • de WP-CLI
  • de Composer
  • d’un éditeur moderne
  • et d’une compréhension minimale de ce qu’on met (ou pas) dans Git.

🗂️ 2. Structure Git recommandée pour un projet WordPress

Avant de parler de workflow, il est important de savoir comment votre projet est structuré :
où se trouve le code, où se trouve la configuration, où commence réellement le dépôt Git.

L’idée est de séparer :

  • un dossier projet, qui contient tout ce qui entoure le site (config Lando, fichier .env, etc.) ;
  • un webroot, qui correspond à la racine publique de votre site (là où pointe le domaine) et qui sert aussi de racine du dépôt Git.

Cette structure vous permet :

  • d’avoir un code identique entre local et production ;
  • de garder les secrets et certains fichiers de configuration en dehors de la zone publique ;
  • de maîtriser exactement ce qui est versionné… et ce qui ne l’est pas (détaillé en section 3).

2.1 Vue d’ensemble : arborescence du projet

Voici l’arborescence de base que nous allons utiliser :

project-root/
├── .env                 ← fichier d’environnement (non versionné, hors webroot)
├── .env.production      ← copie de sauvegarde de la config de prod (optionnelle, non versionnée)
├── .lando.yml           ← configuration Lando (environnement local)
└── webroot/             ← racine publique du site ET racine du dépôt Git
    ├── .git/            ← dépôt Git
    ├── .gitignore       ← règles d’ignorance Git
    ├── composer.json    ← dépendances PHP du projet (versionné)
    ├── wp-config.php    ← configuration WordPress (commune local / prod)
    ├── env-loader.php   ← chargement de .env via phpdotenv
    ├── wp-admin/
    ├── wp-includes/
    ├── wp-content/
    │   ├── plugins/     ← plugins (versionnés)
    │   ├── mu-plugins/  ← must-use plugins (versionnés)
    │   ├── themes/      ← thèmes (versionnés)
    │   ├── uploads/     ← médias (NON versionnés)
    │   └── cache/       ← caches divers (NON versionnés)
    ├── vendor/          ← dépendances Composer générées (NON versionné)
    └── index.php, etc.

Quelques points importants à retenir :

  • le dépôt Git est initialisé dans webroot/ (git init lancé dans ce dossier) ;
  • le fichier .gitignore se trouve donc dans webroot/ ;
  • le fichier .env est au niveau project-root/ → il n’est pas dans le dépôt, il n’est pas accessible en HTTP ;
  • composer.json est versionné dans webroot/ pour pouvoir exécuter composer install sur l’hébergement ;
  • vendor/ n’est pas versionné : il est régénéré à partir de composer.json ;
  • tout le code WordPress (core, thèmes, plugins, mu-plugins) est suivi par Git.

2.2 Dépôt Git : le cœur du workflow

Dans ce guide, le code de référence de votre site est celui du dépôt Git, pas celui de la production.

Concrètement :

  • vous travaillez en local sur le code contenu dans webroot/ (thèmes, plugins, core, etc.) ;
  • vous commitez vos modifications (mise à jour d’un plugin, changement dans un thème, ajout d’un mu-plugin…) ;
  • vous poussez vers votre remote (GitHub, GitLab, etc.) ;
  • vous mettez à jour la production via git pull depuis ce même dépôt.

Les mises à jour WordPress (core et plugins) ne sont donc pas des opérations “magiques” en production, mais deviennent :

  1. mises à jour en local (via l’admin ou WP-CLI),
  2. tests en local,
  3. commit des fichiers modifiés,
  4. déploiement via Git sur l’hébergement.

💡 Idée clé
La production ne doit jamais être la “source de vérité” du code.
C’est le dépôt Git (et donc votre environnement local) qui fait foi.
On ne commit jamais depuis la production : on y déploie uniquement ce qui a été testé et validé en local.
Il peut y avoir les mises à jour automatiques sur la production; elles créeront un déphasage avec le dépôt Git mais une fois que vous aurez fait les vérifications en local et valider les modifications, vous pourrez parfaitement venir écrasez la production à partir du dépôt Git.

La manière dont vous ignorez certains fichiers (uploads, caches, vendor, etc.) sera détaillée dans la section 3, avec un .gitignore complet.

2.3 Composer, vendor/ et fichiers composer.*

Nous utiliserons Composer pour gérer les dépendances PHP (comme vlucas/phpdotenv) directement dans le webroot.

Les choix retenus dans ce workflow sont :

  • composer.json est versionné dans webroot/ ;
  • composer.lock n’est pas versionné : il est régénéré lorsque nécessaire et vous ne faites jamais de composer update en production ;
  • vendor/ est exclu du dépôt (généré localement et sur l’hébergement avec composer install) ;
  • le dossier vendor/ est protégé en HTTP via .htaccess (voir section sécurité).

En pratique :

  • en local, vous faites composer install après un clone ou un pull ;
  • sur l’hébergement, vous faites également composer install (ou composer install --no-dev --optimize-autoloader) après un git pull, si une dépendance a été ajoutée ou modifiée.

2.4 Où interviennent .env et env-loader.php ?

Pour que votre code soit strictement identique entre local et production tout en ayant des paramètres différents (base de données, URL, etc.), la configuration passe par un fichier .env commun et un chargeur dédié :

  • le fichier .env est situé dans project-root/ (hors webroot, non versionné) ;
  • son contenu est différent en local et en production (identifiants, URLs…) mais son nom reste le même ;
  • vous pouvez conserver une copie de sauvegarde .env.production (toujours hors webroot et non versionnée) pour la configuration réelle de la production ;
  • le fichier env-loader.php (dans webroot/) se charge de lire ce .env via phpdotenv dès le chargement de WordPress, et d’exposer les valeurs à wp-config.php.

Cette approche garantit :

  • un seul code source pour tous les environnements ;
  • des secrets jamais versionnés ;
  • un même wp-config.php pour local et production, entièrement piloté par les variables d’environnement.

Les détails d’implémentation de env-loader.php, de l’intégration dans wp-config.php et des règles .htaccess associées seront expliqués plus loin — l’important ici est de visualiser où se trouvent les fichiers et qui est responsable de quoi dans l’arborescence.

📦 3. Ce qu’il faut versionner / ne pas versionner

Avant d’aller plus loin dans le workflow Git entre local et production, il est indispensable de bien définir ce qui doit être présent dans le dépôt — et ce qui ne doit surtout pas l’être.
L’objectif n’est pas d’apprendre Git, mais de clarifier les règles essentielles pour maintenir un projet WordPress propre, reproductible et cohérent entre vos environnements.

Les sous-sections suivantes décrivent précisément quels fichiers doivent être versionnés, lesquels doivent être ignorés, et pourquoi.

3.1. Les fichiers et dossiers à versionner

Pour assurer une maintenance fiable du site, le code source doit être synchronisé entre local et production.
Le dépôt Git doit donc contenir :

Le cœur WordPress (wp-admin + wp-includes+fichiers à la racine)

Même si WordPress est mis à jour automatiquement sur la production, c’est la version présente dans votre dépôt Git qui fait foi.

Les mises à jour automatiques en production peuvent créer un décalage temporaire, mais :
une fois la mise à jour testée et validée en local, vous pourrez la confirmer dans Git et déployer proprement, en écrasant la version du serveur.

C’est la logique du workflow :
la production reflète le dépôt Git, pas l’inverse.

Le dossier wp-content/themes

Inclut votre thème enfant, vos thèmes custom, et tout code spécifique.

Les thèmes tiers se traitent de la même manière que le core :
→ mise à jour en local → validation → commit → déploiement.

Le dossier wp-content/plugins

Tous les plugins doivent être versionnés, qu’ils soient :

  • gratuits,
  • premium,
  • propres à votre site.

Les mises à jour automatiques ne posent pas de problème :
→ elles créent simplement un déphasage temporaire avant votre prochain déploiement Git.

Le dossier wp-content/mu-plugins

Les MU-plugins étant souvent critiques, ils doivent impérativement être synchronisés via Git.

Le fichier wp-config.php (incluant env-loader.php)

C’est un fichier fondamental du projet.
Il doit rester strictement identique entre local et production, et donc être versionné.

Pour information

Historiquement, wp-config.php ne devait jamais être versionné car il contenait les mots de passe et réglages propres à chaque environnement.
Dans ce workflow, le fichier ne contient plus aucune donnée sensible : tout est externalisé dans un fichier .env chargé via env-loader.php.
wp-config.php redevient ainsi un fichier de configuration “structurelle”, identique entre local et production — et parfaitement compatible avec un dépôt Git.

3.2. Les fichiers et dossiers à ne pas versionner

Certaines données :

  • sont volumineuses,
  • sont générées automatiquement,
  • dépendent d’un environnement,

→ elles n’ont rien à faire dans Git.

🚫 wp-content/uploads

Les médias doivent être synchronisés par un autre moyen (rsync, SSH, plugin de migration), mais jamais versionnés.

🚫 Caches, transients, sessions

wp-content/cache/
wp-content/litespeed/
wp-content/wflogs/
wp-content/_wp_generated/

🚫 Backups de base de données

*.sql
*.sql.gz
*.sql.zip

🚫 Fichiers journaux ou temporaires

*.log
*.tmp

🚫 Le dossier vendor/ à la racine du webroot

Ce dossier doit être régénéré via Composer :

composer install --no-dev --optimize-autoloader

Les vendor/ internes aux plugins ou au core WordPress ne doivent pas être ignorés :
→ ils font partie de leur code.

🚫 Les fichiers .env

Ils ne sont pas dans le webroot, et donc déjà hors périmètre du dépôt.
La règle dans .gitignore sert uniquement à éviter une copie accidentelle dans le mauvais dossier.

🚫 Le fichier wp-config-sample.php

Une fois votre installation ce fichier d’example n’a plus aucun intérêt et ne doit pas être conservé dans votre dépôt git.
A chaque mise à jour de WordPress, ce fichier va réapparaître et il est donc utile de l’ignorer pour qu’il ne soit pas conservé dans le depôt git et par conséquence être livré sur l’hébergement de votre site en production.

3.3. Ignorer globalement les fichiers système / éditeur

Certains fichiers ne concernent que votre poste de travail : fichiers système (Linux, macOS, Windows), fichiers temporaires, répertoires d’IDE, etc.
Ils n’ont aucune raison d’apparaître dans un dépôt Git, mais il est préférable de ne pas polluer le .gitignore du projet avec ces règles personnelles.

Git permet de définir un fichier .gitignore global, utilisé sur tous vos dépôts :

git config --global core.excludesfile ~/.gitignore

Créez le fichier dans le dossier de votre profil utilisateur.
Vous pouvez ensuite y ajouter les fichiers spécifiques à votre environnement :

# Fichiers système
.DS_Store
Thumbs.db

# IDE
.vscode/
.idea/

# Éditeurs / swaps
*.swp

Cela permet de garder le .gitignore du projet strictement dédié à WordPress, tout en évitant que les fichiers locaux à votre machine ne soient ajoutés par erreur.

🔐 4. Intégrer env-loader.php dans wp-config.php + sécurité .htaccess

Jusqu’ici, le workflow s’appuie sur une idée clé :
le dépôt Git contient tout le code, mais aucune donnée sensible.

Pour que cela fonctionne réellement, il faut :

  • sortir les identifiants de base de données et autres secrets du wp-config.php ;
  • les placer dans un fichier .env situé en dehors du webroot ;
  • charger ce fichier via un petit bootstrap : env-loader.php ;
  • protéger ce bootstrap et les dossiers sensibles (vendor/, composer.json, etc.) côté HTTP.

Cette section montre pas à pas comment mettre en place ce mécanisme.

4.1. Rappel : où sont placés .env et env-loader.php ?

L’arborescence cible est la suivante :

project-root/
│
├── .env              ← configuration (local ou production), hors webroot, non versionné
│
└── webroot/          ← racine WordPress (dépôt Git)
    ├── wp-config.php
    ├── env-loader.php
    ├── vendor/       ← dépendances Composer (phpdotenv, etc.)
    ├── composer.json
    ├── wp-content/
    │   ├── plugins/
    │   ├── themes/
    │   └── mu-plugins/
    └── ...

.env contient les secrets (BDD, clés diverses…)

  • env-loader.php se trouve dans le webroot, aux côtés de wp-config.php
  • vendor/ se trouve également dans le webroot, mais est ignoré par Git et protégé côté HTTP

Le but est que wp-config.php ne contienne plus aucun secret, et puisse donc être versionné sans risque.

4.2. Structure de env-loader.php

env-loader.php joue trois rôles :

  1. Charger l’autoloader Composer (vendor/autoload.php)
  2. Charger le fichier .env via phpdotenv
  3. Gérer les erreurs de manière propre (dev vs prod)

Voici une version type :

<?php
defined( 'ABSPATH' ) || exit;

/**
 * Environment variables bootstrap using vlucas/phpdotenv.
 *
 * This block is intended to be placed at the very top of wp-config.php,
 * before any WordPress constants are defined.
 *
 * It loads environment variables from a file located OUTSIDE the webroot.
 * Example structure:
 *
 *   project-root/
 *     .env     <-- environment file
 *     webroot/
 *       wp-config.php
 *       vendor/
 */

/**
 * Determines whether the current environment is considered a development environment.
 *
 * You can customize this logic according to your own setup (hostname, IP, env var, etc.).
 *
 * @since 1.0.0
 *
 * @return bool True if this is a development environment, false otherwise.
 */
function env_is_dev(): bool {
	return ( ! empty( $_SERVER['LANDO'] ) || getenv( 'LANDO' ) );
}

/**
 * Handles configuration errors in a clean, predictable manner.
 *
 * - Logs the detailed error message (server-side only).
 * - Displays a verbose message in development.
 * - Displays a neutral HTTP 500 error in production.
 *
 * @since 1.0.0
 *
 * @param string $public_message Message shown to end users (must be neutral).
 * @param string $log_message    Detailed message stored in server error logs.
 *
 * @return void
 */
function env_config_fail( string $public_message, string $log_message ): void {
	$is_dev = env_is_dev();

	// Log internal error message.
	error_log( '[ENV ERROR] ' . $log_message ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log

	if ( $is_dev ) {
		// Verbose output in development environments.
		if ( ! headers_sent() ) {
			header( 'Content-Type: text/html; charset=utf-8' );
		}

		echo '<h1>Environment configuration error</h1>';
		echo '<p>' . esc_html( $log_message ) . '</p>';
		exit;
	}

	// Neutral output in production.
	if ( ! headers_sent() ) {
		header( 'HTTP/1.1 500 Internal Server Error' );
		header( 'Content-Type: text/plain; charset=utf-8' );
	}

	echo $public_message;
	exit;
}

// The project root is assumed to be one level above the webroot.
$project_root = dirname( __DIR__ );

// Single source of truth: environment file name.
$env_file_name = '.env';

// Environment file located outside the webroot.
$env_file = $project_root . '/' . $env_file_name;

// Composer autoloader located inside the webroot's vendor directory.
$autoload = __DIR__ . '/vendor/autoload.php';

/**
 * 1. Ensure Composer autoloader exists.
 */
if ( ! file_exists( $autoload ) ) {
	env_config_fail(
		'Internal error. Please try again later.',
		'Composer autoloader not found: ' . $autoload
	);
}

require_once $autoload;

/**
 * 2. Ensure Dotenv is available.
 */
if ( ! class_exists( \Dotenv\Dotenv::class ) ) {
	env_config_fail(
		'Internal error. Please try again later.',
		'Dotenv class "\\Dotenv\\Dotenv" is not available. Verify Composer dependencies.'
	);
}

/**
 * 3. Ensure the environment file exists.
 */
if ( ! file_exists( $env_file ) ) {
	env_config_fail(
		'Configuration error. Please contact the site administrator.',
		'Environment file missing: ' . $env_file
	);
}

/**
 * 4. Load environment variables and validate required keys.
 */
try {
	// Load the specifically named environment file (e.g. .env).
	$dotenv = \Dotenv\Dotenv::createImmutable( $project_root, $env_file_name );
	$dotenv->safeLoad();

	// Define required environment variables.
	$dotenv->required(
		array(
			'DB_NAME',
			'DB_USER',
			'DB_PASSWORD',
			'DB_HOST',
		)
	)->notEmpty();

} catch ( \Throwable $e ) {
	env_config_fail(
		'Internal error. Please try again later.',
		$e->getMessage()
	);
}

/**
 * Retrieves an environment variable with an optional default value.
 *
 * Example:
 *   define( 'DB_NAME', env( 'DB_NAME', 'wordpress' ) );
 *
 * @since 1.0.0
 *
 * @param string $key     Environment variable name.
 * @param mixed  $default Default value if variable is not set.
 *
 * @return mixed The environment variable value or the default.
 */
if ( ! function_exists( 'env' ) ) {
	function env( string $key, mixed $default = null ): mixed {
		return isset( $_ENV[ $key ] ) ? $_ENV[ $key ] : $default;
	}
}

/**
 * Retrieves an environment variable as a boolean.
 *
 * Accepted truthy values (case-insensitive):
 *   "1", "true", "on", "yes"
 *
 * Accepted falsy values (case-insensitive):
 *   "0", "false", "off", "no", ""
 *
 * Any other non-null value will return the default.
 *
 * Example:
 *   define( 'WP_DEBUG', env_bool( 'WP_DEBUG', false ) );
 *
 * @since 1.0.0
 *
 * @param string $key     Environment variable name.
 * @param bool   $default Default value if variable is not set or invalid.
 *
 * @return bool The boolean value of the environment variable or the default.
 */
if ( ! function_exists( 'env_bool' ) ) {
	function env_bool( string $key, bool $default = false ): bool {
		$value = env( $key, null );

		if ( null === $value ) {
			return $default;
		}

		if ( is_bool( $value ) ) {
			return $value;
		}

		$value = strtolower( (string) $value );

		$truthy = array( '1', 'true', 'on', 'yes' );
		$falsy  = array( '0', 'false', 'off', 'no', '' );

		if ( in_array( $value, $truthy, true ) ) {
			return true;
		}

		if ( in_array( $value, $falsy, true ) ) {
			return false;
		}

		return $default;
	}
}

À adapter uniquement si nécessaire (nom du fichier .env, logique de détection dev, etc.).

4.3. Intégration minimale dans wp-config.php

Une fois env-loader.php en place, l’intégration dans wp-config.php est volontairement minimale :

<?php

require_once __DIR__ . '/env-loader.php';
define( 'WP_ENVIRONMENT_TYPE', env( 'WP_ENVIRONMENT_TYPE', 'production' ) );

define( 'DB_NAME',     env( 'DB_NAME', 'wordpress' ) );
define( 'DB_USER',     env( 'DB_USER', 'wordpress' ) );
define( 'DB_PASSWORD', env( 'DB_PASSWORD', 'wordpress' ) );
define( 'DB_HOST',     env( 'DB_HOST', 'localhost' ) );

Ici :

  • les identifiants de base de données ne se trouvent plus dans le fichier ;
  • ils sont lus depuis le .env via la fonction env() ;
  • wp-config.php peut donc être versionné sereinement.

4.4. Protéger env-loader.php des accès directs

Même si env-loader.php ne contient pas de secrets, il est préférable qu’il ne soit jamais exécuté directement via une URL.

La protection de base est déjà en place avec :

defined( 'ABSPATH' ) || exit;
  • si le fichier est appelé par WordPress (via wp-config.php) → ABSPATH est défini → exécution normale ;
  • si quelqu’un appelle /env-loader.php directement → ABSPATH n’est pas défini → exit immédiat.

En complément, il est possible d’ajouter une règle .htaccess au niveau du webroot :

<Files env-loader.php>
    Require all denied
</Files>

Ce n’est pas obligatoire, mais cela ajoute une barrière HTTP supplémentaire.

4.5. Protéger vendor/ et les fichiers Composer

Le dossier vendor/ ne doit pas être accessible en HTTP :
il contient du code tiers, des métadonnées (installed.json), etc., qui n’ont aucune raison d’être exposés.

Il peut être également judicieux de protéger le dépôt Git local (.git/) ou tout autre fichier ou dossier caché (commençant par un .)

Dans le .htaccess à la racine du WordPress, on peut ajouter :

# Bloquer le vendor du webroot
<IfModule mod_rewrite.c>
    RewriteEngine On

    # Bloquer fichiers et dossiers cachés
    RewriteRule (^|/)\..+ - [F]

    # vendor/ à la racine du site (dépendances du projet)
    RewriteRule ^vendor/ - [F,L]

    # vendor/ dans les plugins
    RewriteRule ^wp-content/plugins/[^/]+/vendor/ - [F,L]

    # (optionnel) vendor/ dans les mu-plugins
    RewriteRule ^wp-content/mu-plugins/[^/]+/vendor/ - [F,L]

    # (optionnel) vendor/ dans les thèmes
    RewriteRule ^wp-content/themes/[^/]+/vendor/ - [F,L]
</IfModule>

Et pour les fichiers composer.json / composer.lock (où qu’ils se trouvent) :

# Bloquer composer.json / composer.lock partout
<FilesMatch "^composer\.(json|lock)$">
    <IfModule mod_authz_core.c>
        Require all denied
    </IfModule>
    <IfModule !mod_authz_core.c>
        Order allow,deny
        Deny from all
    </IfModule>
</FilesMatch>

Le code continue de fonctionner normalement côté PHP, mais plus aucun fichier sensible lié à Composer n’est exposé en HTTP.

4.6. Protéger les fichiers .env en cas d’erreur humaine

Dans le workflow présenté, le fichier .env est toujours au-dessus du webroot.
Il n’est donc pas accessible en HTTP, et n’a pas besoin de protection spécifique.

Cependant, pour se prémunir d’une erreur de copie manuelle (ex. : .env posé par mégarde dans le webroot), il est possible d’ajouter une règle défensive :

# Par sécurité, si un .env se retrouve dans le webroot
<Files ".env">
    Require all denied
</Files>
<Files ".env.*">
    Require all denied
</Files>

Cela ne change rien dans le cas normal (le fichier reste en dehors du webroot), mais évite une exposition accidentelle.

Pour information

Certains hébergeurs sécurisent déjà l’accès aux fichiers composer, .env, etc. mais on ne prend jamais trop de précaution en le faisant soit même.

4.7. Pour aller plus loin

Une fois env-loader.php en place, vous pouvez aller bien au-delà d’une simple gestion des accès à la base de données.

Les exemples suivants montrent différentes manières d’adapter WordPress selon l’environnement, afin que chacun puisse s’en inspirer et façonner une configuration parfaitement alignée avec ses propres besoins.

4.7.1. Constantes WordPress dépendantes de l’environnement

Certaines constantes doivent être différentes selon que l’on se trouve en local ou en production.
Grâce à WP_ENVIRONMENT_TYPE et env-loader.php, ces valeurs peuvent être externalisées dans le fichier .env, ce qui évite de modifier wp-config.php.

Les cas les plus courants concernent les réglages de débogage :

  • WP_DEBUG
  • WP_DEBUG_LOG
  • WP_DEBUG_DISPLAY
  • SCRIPT_DEBUG
  • WP_ENVIRONMENT_TYPE (standard WordPress : local, development, staging, production)

Avec les helpers env() et env_bool(), la déclaration dans wp-config.php reste simple et propre :

define( 'WP_DEBUG', env_bool( 'WP_DEBUG', false ) );
define( 'WP_DEBUG_LOG', env_bool( 'WP_DEBUG_LOG', false ) );
define( 'WP_DEBUG_DISPLAY', env_bool( 'WP_DEBUG_DISPLAY', false ) );
define( 'SCRIPT_DEBUG', env_bool( 'SCRIPT_DEBUG', false ) );
define( 'WP_ENVIRONMENT_TYPE', env( 'WP_ENVIRONMENT_TYPE', 'production' ) );

Les valeurs sont ensuite définies dans .env, ce qui permet d’adapter finement le comportement du site sans jamais modifier wp-config.php.

4.7.2. Sécuriser les valeurs sensibles et les clés d’authentification

Certaines constantes WordPress contiennent des informations sensibles ou essentielles à la sécurité.
Grâce à env-loader.php, elles peuvent être externalisées dans .env pour éviter qu’elles apparaissent en clair dans wp-config.php.

C’est notamment le cas :

  • de COOKIEHASH, utilisé dans plusieurs mécanismes internes ;
  • de WP_CACHE_KEY_SALT, qui doit être unique pour isoler votre environnement ;
  • des clés et SALT WordPress (AUTH_KEY, LOGGED_IN_SALT, etc.), si vous choisissez de les externaliser.

L’avantage :
✔ pas d’information sensible dans le fichier versionné
✔ possibilité d’utiliser des valeurs différentes entre local et production
✔ un wp-config.php propre et stable dans Git

Exemple d’intégration :

define( 'COOKIEHASH', md5( env( 'COOKIE_HASH' ) ) );

define( 'WP_CACHE_KEY_SALT', env( 'WP_CACHE_KEY_SALT' ) );

// Exemple si l’on souhaite externaliser les clés WordPress
define( 'AUTH_KEY',         env( 'AUTH_KEY', '' ) );
define( 'SECURE_AUTH_KEY',  env( 'SECURE_AUTH_KEY', '' ) );
define( 'LOGGED_IN_KEY',    env( 'LOGGED_IN_KEY', '' ) );
define( 'NONCE_KEY',        env( 'NONCE_KEY', '' ) );
define( 'AUTH_SALT',        env( 'AUTH_SALT', '' ) );
define( 'SECURE_AUTH_SALT', env( 'SECURE_AUTH_SALT', '' ) );
define( 'LOGGED_IN_SALT',   env( 'LOGGED_IN_SALT', '' ) );
define( 'NONCE_SALT',       env( 'NONCE_SALT', '' ) );

Ainsi, les valeurs réellement sensibles se trouvent uniquement dans vos fichiers .env, hors webroot, et jamais dans le dépôt Git.

4.7.3. Interaction avec les plugins de sécurité

Certains plugins de sécurité — comme SecuPress — peuvent modifier automatiquement le fichier wp-config.php pour ajouter ou réécrire des constantes.

Dans un workflow Git où wp-config.php est versionné, cette approche pose deux problèmes :

  • cela crée des différences non souhaitées entre local et production ;
  • certaines constantes doivent être différentes selon l’environnement (URLs, debug…).

Avec l’usage de .env et env-loader.php, on adopte une méthode bien plus fiable :

  • wp-config.php reste propre, stable et versionné ;
  • toutes les constantes sensibles ou dépendantes de l’environnement sont déportées dans .env ;
  • le plugin détecte les constantes déjà définies et n’écrase plus rien.

Ainsi, vous laissez d’abord le plugin générer ses constantes, puis vous externalisez celles qui doivent varier selon l’environnement.

Exemple 1 — Les constantes de debug générées par SecuPress

SecuPress peut injecter ceci dans wp-config.php :

# BEGIN SecuPress debugging
define( 'WP_DEBUG', false );
# END SecuPress

# BEGIN SecuPress Correct Constants Values
define( 'WP_DEBUG_DISPLAY',  false ); // Added by SecuPress.
# END SecuPress

Avec le workflow .env, vous remplacez simplement par :

# BEGIN SecuPress debugging
define( 'WP_DEBUG', env_bool( 'WP_DEBUG' ) );
# END SecuPress

# BEGIN SecuPress Correct Constants Values
define( 'WP_DEBUG_DISPLAY',  env_bool( 'WP_DEBUG_DISPLAY' ) ); // Added by SecuPress.
# END SecuPress

Dans .env local:

WP_DEBUG=true
WP_DEBUG_DISPLAY=false

Dans .env production :

WP_DEBUG=false
WP_DEBUG_DISPLAY=false

Le plugin ne réécrit plus rien et la configuration reste propre.

Attention

Les constantes WP_DEBUG et WP_DEBUG_DISPLAY vues également en §4.7.1 susceptible d’être ajouté manuellement ne doivent pas faire doublon avec celles ajoutés par SecuPress.
SecuPress ne les ajoutera que si elles ne sont pas présentes. Sinon il les modifie.

Exemple 2 — WP_SITEURL et WP_HOME

SecuPress peut également injecter :

# BEGIN SecuPress locations
define( 'RELOCATE', false );
define( 'WP_HOME', 'https://monsite.com' );
define( 'WP_SITEURL', 'https://monsite.com' );
# END SecuPress

Or ces constantes doivent être radicalement différentes entre local et production.

Grâce à .env :

# BEGIN SecuPress locations
define( 'RELOCATE', false );
define( 'WP_SITEURL', env( 'WP_SITEURL' ) );
define( 'WP_HOME', env( 'WP_HOME' ) );
# END SecuPress

Dans .env local:

WP_HOME="https://monsite.lndo.site"
WP_SITEURL="https://monsite.lndo.site"

Dans .env production :

WP_HOME="https://monsite.fr"
WP_SITEURL="https://monsite.fr"

Résultat :

  • SecuPress fonctionne parfaitement,
  • aucune modification intempestive du fichier versionné,
  • les environnements local/prod sont parfaitement isolés,
  • aucun risque de casser le site en définissant une mauvaise URL.

4.7.4. Configurations serveur : Redis

La configuration de Redis peut elle aussi être entièrement externalisée dans .env.

Exemples de variables :

WP_REDIS_SCHEME=tcp
WP_REDIS_HOST=redis
WP_REDIS_PORT=6379
WP_REDIS_DATABASE=1
WP_REDIS_TIMEOUT=1
WP_REDIS_READ_TIMEOUT=1
WP_REDIS_PATH=
WP_REDIS_PASSWORD=

Et dans wp-config.php :

define( 'WP_REDIS_SCHEME', env( 'WP_REDIS_SCHEME', 'tcp' ) );
define( 'WP_REDIS_HOST', env( 'WP_REDIS_HOST', '127.0.0.1' ) );
define( 'WP_REDIS_PORT', (int) env( 'WP_REDIS_PORT', 6379 ) );
define( 'WP_REDIS_DATABASE', (int) env( 'WP_REDIS_DATABASE', '1' ) );
define( 'WP_REDIS_TIMEOUT', (int) env( 'WP_REDIS_TIMEOUT', '1' ) );
define( 'WP_REDIS_READ_TIMEOUT', (int) env( 'WP_REDIS_READ_TIMEOUT', '1' ) );
define( 'WP_REDIS_PATH', env( 'WP_REDIS_PATH', null ) );
define( 'WP_REDIS_PASSWORD', env( 'WP_REDIS_PASSWORD', null ) );

Ainsi :

  • la production peut utiliser un socket Unix, un mot de passe Redis, ou une configuration optimisée ;
  • le local utilise simplement les valeurs fournies par Lando ;
  • le fichier wp-config.php reste identique, propre, et entièrement versionné ;
  • aucune différence de logique n’existe entre local et production : seules les valeurs changent via .env.

4.7.5. Exemples complets de .env local et .env production

Exemple .env local (Lando / développement)

DB_NAME=wordpress
DB_USER=wordpress
DB_PASSWORD=wordpress
DB_HOST=database

WP_SITEURL=https://monsite.lndo.site
WP_HOME=https://monsite.lndo.site

COOKIE_HASH=moncookieuniquedev

WP_ENVIRONMENT_TYPE=development

WP_DEBUG=true
WP_DEBUG_LOG=true
WP_DEBUG_DISPLAY=false

WP_REDIS_SCHEME=tcp
WP_REDIS_HOST=redis
WP_REDIS_PORT=6379
WP_REDIS_DATABASE=1
WP_REDIS_TIMEOUT=1
WP_REDIS_READ_TIMEOUT=1
WP_REDIS_PATH=
WP_REDIS_PASSWORD=

Exemple .env production

DB_NAME=prod_xxx
DB_USER=prod_xxx
DB_PASSWORD=********
DB_HOST=localhost

WP_SITEURL=https://monsite.com
WP_HOME=https://monsite.com

COOKIE_HASH=moncookieuniqueprod

WP_ENVIRONMENT_TYPE=production

WP_DEBUG=false
WP_DEBUG_LOG=false
WP_DEBUG_DISPLAY=false

WP_REDIS_SCHEME=unix
WP_REDIS_HOST=127.0.0.1
WP_REDIS_PORT=0
WP_REDIS_DATABASE=1
WP_REDIS_TIMEOUT=1
WP_REDIS_READ_TIMEOUT=1
WP_REDIS_PATH=/home/USER/redis/redis.sock
WP_REDIS_PASSWORD=********

En résumé

Pour que la configuration basée sur .env soit correctement intégrée au workflow Git :

  • env-loader.php charge les variables d’environnement depuis un fichier .env situé hors webroot ;
  • wp-config.php ne contient plus de secrets et peut être versionné sereinement ;
  • env-loader.php est protégé à la fois par defined( 'ABSPATH' ) || exit; et, si souhaité, par une règle .htaccess ;
  • le dossier vendor/ et les fichiers composer.* sont inaccessibles en HTTP, tout en restant utilisables par PHP ;
  • une règle défensive peut bloquer tout fichier .env qui se retrouverait par erreur dans le webroot.

🚀 5. Workflow complet : développement local → Git → production

Le cœur de ce guide repose sur un workflow clair, reproductible et sans surprise entre votre environnement local (Lando) et votre hébergement (o2switch, OVH, Infomaniak, IONOS…).

Cette section décrit le cycle complet, depuis la création du dépôt jusqu’au déploiement propre en production.

5.1. Initialiser le dépôt Git local et le dépôt central

On suppose à ce stade que :

  • votre stack locale (Lando, Docker, autre) est opérationnelle,
  • WordPress fonctionne déjà en local dans le dossier webroot/ (installation neuve ou site existant migré).

Pour information

Que ce soit un nouveau projet WordPress ou un site récupéré par FTP ou sauvegarde, la logique d’initialisation Git reste la même.

1️⃣ Créer le dépôt distant (GitHub, GitLab, Forge, etc.)

Sur votre forge Git préférée (GitHub, GitLab, Bitbucket, dépôt privé…), créez un dépôt vide :

  • sans README automatique,
  • sans .gitignore généré par l’interface,
  • sans modèle WordPress pré-rempli.

L’objectif : que ce soit votre projet qui fasse foi, pas un squelette imposé.

2️⃣ Initialiser le dépôt Git dans le webroot local

Dans votre environnement local, placez-vous dans le dossier webroot/ de votre projet (là où se trouve wp-config.php) :

cd /chemin/vers/project-root/webroot
git init

Ajoutez ensuite votre .gitignore (défini dans la section précédente) si ce n’est pas déjà fait, ainsi que les fichiers de configuration propres au projet.

3️⃣ Faire le premier commit

On ajoute tout ce qui doit être versionné (core WordPress, wp-content, configuration, etc.) :

git add .
git commit -m "Initial commit: base WordPress + configuration projet"

À ce stade :

  • votre dépôt local contient la version de référence du site,
  • les fichiers ignorés (wp-content/uploads, backups SQL, cache, etc.) ne sont pas intégrés.

4️⃣ Lier le dépôt local au dépôt distant

Ajoutez le dépôt distant comme remote :

git remote add origin git@github.com:mon-user/mon-projet.git
# ou avec une URL HTTPS si vous préférez

Vous pouvez vérifier :

git remote -v

5️⃣ Pousser la branche principale

Enfin, envoyez votre code vers le dépôt central :

git branch -M main
git push -u origin main

Votre projet WordPress est maintenant :

  • versionné proprement,
  • centralisé dans un dépôt Git distant,
  • prêt à être synchronisé avec votre hébergement (section suivante).

Pour un site existant récupéré par FTP ou via une sauvegarde :

  • placez tous les fichiers dans webroot/,
  • ajustez wp-config.php pour utiliser .env + env-loader.php,
  • puis appliquez exactement les mêmes étapes d’initialisation Git que ci-dessus.

5.2. Développer localement : thèmes, plugins, configuration

Une fois votre environnement local opérationnel et le dépôt Git initialisé, vous pouvez commencer à travailler sereinement sur votre site WordPress.

En local, vous allez pouvoir :

  • ajouter ou modifier du code dans votre thème enfant ;
  • développer ou maintenir des plugins personnalisés ;
  • gérer vos mu-plugins ;
  • tester des optimisations ou des modifications de configuration ;
  • mettre à jour le cœur WordPress ;
  • mettre à jour votre thème parent ;
  • mettre à jour les extensions ;
  • mettre à jour les traductions ;
  • tester des évolutions majeures sans impact sur la production.

Ce travail se fait sans risque, puisque rien n’est déployé tant que vous ne faites pas de git push.

1️⃣ Organisation recommandée pour le développement

  • Travaillez dans un thème enfant lorsque vous ajustez un thème tiers.
  • Placez votre code maison dans :
    • wp-content/mu-plugins/ pour les fonctionnalités critiques,
    • wp-content/plugins/ si vous préférez des modules indépendants,
    • wp-content/themes/votre-theme-enfant/ pour la partie visuelle.
  • Testez régulièrement :
    • les pages clés,
    • les formulaires,
    • les performances,
    • le cache et cache objet (Redis).

2️⃣ Composer et dépendances PHP

Si votre projet utilise phpdotenv — ce qui devrait être le cas si vous avez suivi les § 4.1 à 4.6 — ou d’autres dépendances PHP :

  • Installez-les avec :
lando composer install
  • Ne versionnez pas le dossier vendor/ local : il sera régénéré sur la production.

3️⃣ WP-CLI comme outil de développement

WP-CLI facilite de nombreuses tâches :

lando wp plugin update --all
lando wp theme update --all
lando wp core update
lando wp core update-db

Idéal pour appliquer rapidement les mises à jour locales avant de les valider dans Git.

4️⃣ L’importance des tests avant commit

À chaque modification significative :

  • rechargez le site,
  • videz le cache et le cache objet si nécessaire
lando wp cache flush
  • vérifiez les erreurs éventuelles en consultant wp-content/debug.log si vous avez activé WP_DEBUG_LOG par exemple.

5.3. Déployer en production via Git

Que votre site soit neuf ou déjà en place, le déploiement suit toujours le même principe :

👉 le code vient du dépôt Git — jamais l’inverse.
👉 la production doit refléter exactement ce qui a été validé en local.

Très important

Avant toute opération, assurez-vous que :

  • le fichier .env de production (hors webroot) est bien présent,
  • il contient la configuration correcte de la production,
  • vous en avez une copie locale au cas où.
    Le déploiement écrasera toujours les fichiers du site.
  • le fichier wp-config.php sera écrasé par la référence dans le dépôt Git

Selon votre situation, deux scénarios possibles :

🟦 Cas 1 — Nouveau site

Votre projet n’existe pas encore sur le serveur.
Vous allez simplement cloner votre dépôt Git vide puis déployer votre premier commit.

1. Se connecter à l’hébergement en ssh

ssh user@votre-serveur

2. Se placer dans le répertoire webroot
(ex : public_html ou un sous-dossier dédié, abitrairement appelé webroot ici pour coller à l’environnement local)

cd webroot

3. Cloner votre dépôt Git

git clone https://github.com/mon-user/mon-projet.git .

4. Installer les dépendances PHP

composer install --no-dev --optimize-autoloader

5. Importer la base de données sauvegarde de votre base de données locale

En supposant que vous avez au préalable :

  • fait un export avant en local avec lando wp db export local.sql
  • transférer ce fichier en FTP sur votre hébergement
  • créer la base de données sur votre hébergement
wp db import local.sql

6. Search-replace des URLs dans la base de données

wp search-replace "https://monsite.lndo.site" "https://monsite.com" --all-tables

7. Vider la cache

wp cache flush

8. Tester votre site

Votre site devrait être opérationnel : la production est parfaitement alignée avec le dépôt Git et votre site en local.

🟧 Cas 2 — Site existant que l’on met sous Git

C’est le cas le plus fréquent :
vous avez un site WordPress déjà installé et fonctionnel sur votre hébergement, mais vous voulez désormais qu’il soit maintenu via Git.

L’objectif est simple :

➡️ remplacer totalement les fichiers du serveur par ceux du dépôt Git
➡️ sans manipulations complexes, sans conflits

Le moyen le plus sûr et le plus propre :

1. Se connecter à l’hébergement

ssh user@votre-serveur

2. Se placer dans le répertoire webroot
(ex : public_html ou un sous-dossier dédié, abitrairement appelé webroot ici pour coller à l’environnement local)

cd webroot

3. Initialiser Git s’il ne l’est pas déjà

git init
git remote add origin https://github.com/mon-user/mon-projet.git
git fetch origin

4. Écraser entièrement les fichiers existants par la version Git
👉 C’est volontaire.
👉 On part sur une base propre et maîtrisée.

git reset --hard origin/main

Tous les fichiers modifiés, ajoutés ou supprimés sur la prod seront écrasés par la version validée en local.
C’est ce que l’on veut dans un workflow Git propre.

5. Installer les dépendances PHP

composer install --no-dev --optimize-autoloader

6. Mettre à jour la base de données WordPress (si nécessaire)
Lorsqu’une version locale du core a modifié le schéma SQL :

wp core update-db

(WP-CLI ne fait pas de mise à jour de fichiers : il applique seulement les migrations SQL nécessaires.)

7. Vider le cache

wp cache flush

8. Tester votre site

Votre site devrait être opérationnel et fonctionner comme celui qui existait avant : la production est parfaitement alignée avec le dépôt Git et votre site en local.

Pour information

Pas de de transfert et d’import de la base de données dans ce cas, c’est la base de données de production qui fait foi et est déjà présente puisque le site existait déjà.
C’est votre base de données locale qui devrait être en phase avec celle de production.

🟩 Déploiements suivants (cycle normal)

Une fois l’un de ces deux scénarios effectué, tous les prochains déploiements se résument à :

ssh user@serveur
cd webroot
git pull
wp core update-db
wp cache flush

Votre production reste toujours synchronisée avec ce que vous avez validé en local.

En résumé

  • Production alignée exactement sur Git
  • Aucun transfert FTP hormis dans le cas d’une nouvelle installation pour transférer la base de données locale
  • Aucun conflit
  • Un déploiement propre, reproductible, maîtrisé.

5.4. Bonus — Automatiser le git pull avec GitHub Actions

Une fois le dépôt en production en place, la mise à jour du site se résume à une commande côté serveur : git pull.

J’ai donc poussé l’idée jusqu’au bout en automatisant cette commande via GitHub Actions avec un runner self-hosted (installé sur mon PC et lancé comme service au démarrage).
À chaque push sur main, le workflow se connecte en SSH à mon hébergement, vérifie que le dépôt est “clean”, puis exécute le git pull.

En cas de dépôt non clean (situation exceptionnelle), le déploiement s’arrête et affiche les fichiers concernés dans les logs GitHub Actions.

name: Deploy website-site to hosting

on:
  push:
    branches: [ main ]
  workflow_dispatch: {}

concurrency:
  group: deploy-website-site-production
  cancel-in-progress: false

jobs:
  deploy:
    runs-on: self-hosted
    steps:
      - name: SSH deploy
        run: |
          ssh user@server <<'SSH'
            set -e
            cd webroot
            [ -z "$(git status --porcelain)" ] || { git status --porcelain; exit 1; }
            git pull
          SSH

Pour information

Le runner est « self-hosted » pour garantir facilement l’accès SSH à partir de votre ordinateur; en effet, les accès SSH sont souvent verrouillés chez les hébergeurs à une IP précise pour de simple mesure de sécurité.

Le runner « self-hosted » est attaché à un dépôt GitHub (un runner par dépôt dans mon cas).

🔄 6. Synchroniser la base et les médias entre local et production

Même avec un workflow Git propre, deux éléments essentiels ne sont jamais versionnés :

  • la base de données (contenu, options, URLs, widgets, pages…)
  • les médias (wp-content/uploads/)

Pour garder votre environnement local cohérent avec la production, il faut donc synchroniser régulièrement ces deux éléments — surtout lors de travaux significatifs ou avant un déploiement important.

Cette section présente la méthode la plus simple, robuste et rapide pour synchroniser dans les deux sens (local ↔ production) en utilisant les outils déjà disponibles : WP-CLI, SSH, et rsync.

6.1. Récupérer la base de données de la production vers le local

C’est l’opération la plus courante : vous souhaitez travailler localement sur la vraie base du site.

1️⃣ Exporter la base depuis la production

Sur l’hébergement (SSH) :

wp db export ~/prod.sql

2️⃣ Télécharger le dump vers votre machine

Depuis votre ordinateur :

rsync -avz -e ssh user@serveur:~/prod.sql .

3️⃣ Importer dans votre environnement local

Dans votre projet Lando :

lando wp db import prod.sql

4️⃣ Corriger les URLs (productionlocal)

Très important : production et local n’ont pas les mêmes URLs.

lando wp search-replace 'https://monsite.com' 'https://monsite.lndo.site' --all-tables

Important

WP-CLI corrige automatiquement les données sérialisées : c’est pour cela qu’il ne faut jamais faire ce remplacement “à la main”.

Votre base locale correspond désormais exactement à la production.

6.2. Envoyer la base locale vers la production (cas exceptionnel)

À utiliser uniquement lorsque :

  • vous partez d’un projet « from scratch »,
  • vous réinitialisez une production dégradée,
  • vous migrez un site existant vers un nouveau serveur.

1️⃣ Exporter en local

lando wp db export ../local.sql

2️⃣ Upload du fichier SQL vers la production

rsync -avz -e ssh ../local.sql user@serveur:~/

3️⃣ Import sur le serveur

wp db import local.sql

4️⃣ Corriger les URLs (local → production)

Très important : local et production n’ont pas les mêmes URLs.

wp search-replace 'https://monsite.lndo.site' 'https://monsite.com' --all-tables

Votre production correspond maintenant à votre local.

6.3. Synchroniser les médias entre local et production via rsync

Les médias ne doivent jamais être dans Git, mais doivent être identiques entre local et production pour travailler correctement.

La solution la plus simple est rsync.

6.3.1. Récupérer les uploads de la production vers le local

Depuis votre machine :

rsync -avz -e ssh user@serveur:~/webroot/wp-content/uploads/ webroot/wp-content/uploads/

Options utiles :

  • -a : archive (préserve dates, permissions…)
  • -v : verbose
  • -z : compression lors du transfert

Seuls les nouveaux fichiers ou ceux modifiés seront copiés → très rapide.

6.3.2. Envoyer les uploads du local vers la production

Rare, mais utile lors d’un départ “from scratch” :

rsync -avz -e ssh /webroot/wp-content/uploads/ user@serveur:~/webroot/wp-content/uploads/

En résumé

Pour garder vos environnements synchronisés :

  • la base se synchronise via WP-CLI :
    wp db export, wp db import, wp search-replace
  • les médias se synchronisent via rsync :
    rsync -avz
  • production → local est le cas le plus courant
  • local → production est réservé aux migrations / réinitialisations

Cette approche complète parfaitement le workflow Git :
le code versionné + une base synchronisée + les médias alignés = un environnement local 100% fidèle à la production.

🏁 7. Conclusion — WordPress + Git : un workflow moderne, fiable et reproductible

Adopter un workflow Git pour maintenir un site WordPress — même sur un simple hébergement mutualisé — change profondément la manière de travailler.

On ne “bricole” plus directement sur la production.
On ne dépend plus entièrement des sauvegardes automatisées.
On ne croise plus les doigts pendant les mises à jour.

À la place :

  • chaque modification est tracée, versionnée, contrôlée ;
  • le développement local devient la norme, pas l’exception ;
  • le déploiement est propre, reproductible et sans surprise ;
  • la configuration est centralisée, claire, structurée ;
  • la production est sécurisée, car aucun fichier sensible ne s’y trouve.

Grâce à la combinaison :

  • Git (versionnage du code),
  • une stack locale comme Lando (environnement identique à la prod),
  • Composer + phpdotenv (gestion propre des dépendances et de la configuration),
  • env-loader.php (pont fiable entre .env et WordPress),
  • SSH + WP-CLI (outils d’administration avancée),
  • un .gitignore propre (dépôt léger et pertinent),

…vous obtenez un workflow professionnel, proche de ce qui se fait dans les environnements DevOps modernes — mais parfaitement compatible avec une production mutualisée.

Résultats obtenus

Avec ce workflow, vous bénéficiez de :

🔹 Sécurité

  • aucune donnée sensible dans Git ;
  • .env en dehors du webroot ;
  • wp-config.php propre et versionné ;
  • protection des fichiers Composer / vendor / .env via .htaccess.

🔹 Sérénité lors des mises à jour

  • test local avant la production ;
  • plus aucune modification sauvage en prod ;
  • capacité de revenir en arrière en un instant.

🔹 Stabilité long terme

  • des environnements dev/prod cohérents ;
  • un code maîtrisé dans le temps ;
  • un fonctionnement documenté et reproductible.

🔹 Évolutivité

  • facile d’ajouter staging, CI/CD, tests automatiques, etc.
  • simple d’intégrer d’autres développeurs ou contributeurs.

🚀 Enfin, un WordPress qui se maintient proprement

Avec ce workflow :

  • le local est la source de vérité ;
  • la production reflète toujours le dépôt Git ;
  • les environnements sont isolés mais cohérents ;
  • la configuration dépendante de l’environnement est proprement externalisée ;
  • le déploiement devient un geste simple et maîtrisé.

Ce n’est plus “du WordPress à l’ancienne” :
c’est un vrai projet de développement, robuste, sécurisé et professionnel.

❓ FAQ — Git et WordPress

Oui. Vous pouvez tout à fait ajouter Git sur un site WordPress déjà en production.
La bonne approche consiste à faire une sauvegarde complète (fichiers et base), à créer un dépôt Git à partir du code actuel (thèmes, plugins, mu-plugins, fichiers de configuration), puis à pousser ce dépôt vers un dépôt distant (GitHub, GitLab, etc.). Ensuite, vous faites évoluer le site via Git plutôt qu’en modifiant directement la production, ce qui vous donne un historique propre et la possibilité de revenir en arrière.

Oui, mais il faut encadrer leur usage pour garder un historique propre.
En pratique, vous pouvez laisser les mises à jour automatiques en production (utile pour les correctifs de sécurité), puis reproduire ces mises à jour en local, tester, corriger les éventuels problèmes, commiter et redéployer le code en écrasant la production via Git.
L’élément crucial est de sauvegarder régulièrement la base de données (avant/après les mises à jour) afin de pouvoir revenir en arrière à la fois sur le code et sur la structure de la base si besoin.

Non, la base de données ne doit pas être versionnée telle quelle dans Git. Elle change très souvent, ce qui produirait des conflits permanents et un dépôt énorme.
La bonne pratique est de la sauvegarder via des exports SQL ou des outils comme WP-CLI, puis d’automatiser autant que possible les opérations d’import/export entre local et production.

Pas complètement. Git est idéal pour versionner le code (thèmes, plugins, mu-plugins, scripts de configuration), mais il ne gère ni la base de données ni les fichiers téléversés.
Pour remplacer un plugin de migration, vous devrez combiner Git avec des exports/imports de base (WP-CLI, mysqldump, etc.) et un outil de synchronisation de fichiers (rsync, SSH/SFTP ou un script dédié).

📚 Références

Voici les ressources officielles liées aux outils, concepts et bonnes pratiques utilisés dans cet article. Elles permettent d’aller plus loin, de vérifier les points techniques, ou d’explorer les alternatives.

🔧 Outils & technologies

🛠 Workflow & configuration

🔐 Serveur & sécurité

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *