WP-CRON et WP-CLI

,

WP-CRON et WP-CLI

Remplacer WP-CRON par WP-CLI

Objectif : Remplacer le CRON natif de WordPress (wp-cron.php) par une tâche CRON système avec commandes WP-CLI.

Par défaut, WordPress utilise un système appelé WP-CRON pour exécuter les événements planifiés. Malgré son nom, il ne s’agit pas d’un véritable CRON comme ceux présents sur les systèmes Unix/Linux, mais d’un mécanisme interne reposant sur PHP et le trafic du site. Cette solution permet à WordPress de fonctionner sur la plupart des hébergements, y compris lorsqu’aucun accès aux tâches CRON système n’est disponible.

Pour un blog personnel ou un petit site vitrine, ce fonctionnement est généralement suffisant. En revanche, dès que le nombre de visiteurs augmente, que plusieurs sites WordPress cohabitent sur le même serveur ou que certaines extensions exécutent des traitements lourds (sauvegardes, synchronisations, imports, génération d’images, envois d’e-mails, tâches WooCommerce, etc.), les limites de cette méthode apparaissent rapidement.

La solution consiste à désactiver le système natif de WordPress afin de le remplacer par une véritable tâche CRON gérée par le serveur et exécutant directement les événements WordPress sans passer par PHP et sans charger tout WordPress. Mais comment ? En utilisant WP-CLI. Cette approche offre un meilleur contrôle des ressources système, une exécution plus régulière des traitements planifiés et réduit les risques de chevauchement des tâches.


Comment fonctionne réellement le WP-CRON ?

Contrairement à un système CRON système (ou CRON serveur) exécuté par le système d’exploitation, le système de WordPress dépend entièrement des visites des internautes. À chaque chargement d’une page, WordPress appelle sa fonction interne spawn_cron(), qui vérifie si des événements planifiés sont arrivés à échéance.

Les événements planifiés sont enregistrés dans la base de données, au sein de l’option cron. Chaque événement contient notamment son horodatage d’exécution, le hook à appeler, les éventuels paramètres ainsi que les informations nécessaires pour les événements récurrents.

Si WordPress détecte qu’un ou plusieurs événements doivent être exécutés, il ne les lance généralement pas dans la requête HTTP en cours. À la place, il effectue une nouvelle requête HTTP non bloquante vers le fichier wp-cron.php, auquel il transmet un identifiant temporaire via le paramètre doing_wp_cron. Cette seconde requête est réalisée à l’aide de l’API HTTP de WordPress.

Visiteur
    │
    ▼
Chargement d'une page WordPress
    │
    ▼
spawn_cron()
    │
    ▼
Lecture des événements dans la base de données
    │
    ▼
Événements arrivés à échéance ?
    │
 ┌──┴──┐
 │     │
Non   Oui
 │     │
 ▼     ▼
Fin   Requête HTTP vers wp-cron.php
            │
            ▼
      Exécution des événements

Ce fonctionnement présente un avantage majeur :

Il ne nécessite aucune configuration particulière sur le serveur. En contrepartie, il dépend de plusieurs composants qui n’interviennent pas lorsqu’un véritable CRON système est utilisé : le serveur web, PHP, la pile HTTP, la résolution DNS locale et les délais réseau. Un pare-feu applicatif, une protection anti-bot, une mauvaise résolution DNS ou un délai d’attente trop court peuvent empêcher l’exécution correcte de certains événements.

À l’inverse, une commande WP-CLI exécute directement WordPress depuis le système d’exploitation, sans effectuer de requête HTTP supplémentaire. Le traitement est donc moins dépendant de l’environnement réseau et s’intègre plus naturellement dans les mécanismes d’automatisation classiques des serveurs Linux.


Pourquoi désactiver le WP-CRON ?

Le principal inconvénient du WP-CRON est qu’il ne garantit jamais l’heure exacte d’exécution d’un événement. Si aucun visiteur ne consulte le site pendant plusieurs heures, aucun traitement planifié ne sera lancé durant cette période. À l’inverse, un site très fréquenté peut déclencher de nombreuses vérifications simultanées, augmentant inutilement la charge du serveur.

WordPress utilise bien un mécanisme de verrouillage temporaire afin de limiter les exécutions concurrentes. Ce verrou, basé sur la constante WP_CRON_LOCK_TIMEOUT, évite qu’un même événement soit lancé simultanément. Toutefois, lorsqu’une tâche dépasse cette durée ou que plusieurs requêtes arrivent presque au même instant, des chevauchements restent possibles, notamment avec certaines extensions réalisant des sauvegardes, des imports volumineux ou des synchronisations externes.

Les principales limites du WP-CRON

  • Les événements ne sont exécutés que lorsqu’un visiteur charge une page.
  • Les traitements peuvent être retardés de plusieurs heures sur un site à faible trafic.
  • Chaque vérification nécessite le chargement d’une partie importante de WordPress.
  • Les traitements longs peuvent entrer en concurrence avec les visiteurs.
  • Des exécutions simultanées restent possibles malgré le verrouillage interne.
  • Les performances dépendent indirectement de la couche HTTP et de la configuration du serveur.

Les conséquences sont parfois discrètes, mais peuvent devenir importantes sur des sites fortement automatisés : publications programmées en retard, campagnes d’e-mails différées, sauvegardes incomplètes, synchronisations interrompues, traitements exécutés plusieurs fois ou files d’attente WooCommerce prenant progressivement du retard.


Pourquoi utiliser une véritable tâche CRON ?

Une tâche CRON système est exécutée directement par le planificateur du système d’exploitation selon une fréquence définie par l’administrateur, indépendamment du trafic du site. Les événements WordPress sont alors déclenchés à intervalles réguliers, que le site reçoive mille visiteurs par minute ou aucun pendant plusieurs heures.

Cette approche améliore la prévisibilité des traitements et permet de mieux maîtriser la consommation des ressources serveur. Il devient également possible d’encadrer précisément les processus grâce à des outils tels que flock, timeout, nice ou ionice, afin d’éviter les exécutions simultanées ou les traitements bloquants.

  • Exécution régulière et indépendante du trafic.
  • Réduction des requêtes HTTP inutiles.
  • Meilleur contrôle des ressources CPU et disque.
  • Limitation des exécutions concurrentes.
  • Journalisation plus simple des erreurs.
  • Automatisation plus fiable sur les serveurs hébergeant plusieurs sites WordPress.

La première étape consiste à empêcher WordPress de déclencher automatiquement son faux CRON en ajoutant les constantes suivantes dans le fichier wp-config.php :

define('ALTERNATE_WP_CRON', false); // (?) Défini une méthode alternative, doit rester à "false" si "DISABLE_WP_CRON=true".
define('DISABLE_WP_CRON', true);    // (!) C'est la seule règle vraiment importante ici, on désactive WP-CRON.

Cette constante ne désactive pas le système de planification de WordPress : les événements continuent d’être enregistrés normalement dans la base de données. Elle empêche uniquement WordPress de lancer automatiquement wp-cron.php lors des visites. Les événements devront alors être exécutés par une tâche CRON externe, ce qui constitue précisément l’objectif de la méthode présentée dans cet article.

On vous conseille aussi d’ajuster la valeur de WP_CRON_LOCK_TIMEOUT selon vos besoin : ce paramètre définit la durée (en secondes) pendant laquelle un verrou (cron lock) est maintenu. Ce verrou empêche l’exécution simultanée de plusieurs tâches CRON, garantissant ainsi que les tâches planifiées s’exécutent de manière contrôlée et sans conflit. Par défaut, cette valeur est fixée à 60 secondes, ce qui peut être trop court si vous exécutez des tâches longues comme des sauvegardes, des exports volumineux (données ou fichiers), etc.

Pour modifier ce délai d’expiration, vous pouvez définir la constante suivante dans votre fichier wp-config.php :

define('WP_CRON_LOCK_TIMEOUT', 95);  // (?) Défini la durée de vie maximale d'un processus CRON à 95 secondes,
                                     //     au delà, l'ouverture d'un nouveau processus est autorisée.

Pourquoi utiliser WP-CLI ?

WP-CLI est l’interface officielle en ligne de commande de WordPress. Contrairement à une requête HTTP vers wp-cron.php, WP-CLI exécute directement WordPress depuis le système d’exploitation, sans passer par le serveur web. Cette approche réduit le nombre d’intermédiaires susceptibles d’introduire des délais ou des erreurs et facilite l’automatisation des opérations d’administration.

Lorsqu’une commande WP-CLI est exécutée, WordPress est initialisé de manière similaire à une requête classique : le cœur est chargé, les extensions sont initialisées et les hooks sont disponibles. En revanche, il est possible d’éviter certains chargements inutiles grâce à différentes options, ce qui diminue légèrement le temps de démarrage et la consommation mémoire.

Quelques exemples d’utilisation :

  • Exécuter les événements planifiés.
  • Mettre à jour WordPress.
  • Mettre à jour les extensions et les thèmes.
  • Créer ou supprimer des utilisateurs.
  • Importer ou exporter la base de données.
  • Effectuer des recherches/remplacements dans les URLs.
  • Vider les différents caches.
  • Créer des sauvegardes automatisées.
  • Administrer un réseau multisite.

Sur un serveur hébergeant plusieurs installations WordPress, WP-CLI permet également de centraliser de nombreuses opérations de maintenance sans dépendre d’une interface d’administration accessible par navigateur.

WP-CLI constitue aujourd’hui l’outil privilégié pour automatiser l’administration d’un ou de plusieurs sites WordPress. Il s’intègre naturellement dans les tâches CRON, les scripts Bash, les pipelines CI/CD et les outils d’orchestration.


Pourquoi utiliser cron event run --due-now ?

Plusieurs tutoriels utilisent la commande suivante :

wp cron event run --all

Cette commande exécute tous les événements enregistrés, qu’ils soient arrivés à échéance ou non. Bien qu’elle puisse être utile dans certains cas de maintenance, elle ne reproduit pas fidèlement le comportement normal de WordPress.

Dans le cadre d’une automatisation, il est généralement préférable d’utiliser :

wp cron event run --due-now

Cette option limite l’exécution aux seuls événements dont l’heure est effectivement atteinte. Le comportement est ainsi cohérent avec celui attendu par WordPress et évite de lancer prématurément certaines tâches périodiques.

En pratique, cette approche réduit également le nombre d’opérations inutiles lorsque le serveur exécute la tâche CRON à intervalles réguliers.


Comment WordPress gère les événements planifiés ?

Contrairement à un cron Unix, WordPress ne possède pas de fichier de planification système. Tous les événements sont enregistrés dans la base de données au sein de l’option cron. Chaque entrée contient notamment le hook à exécuter, son horodatage ainsi que les informations permettant de gérer les événements récurrents.

Lorsqu’un événement est exécuté, WordPress ne conserve pas simplement la même date en lui ajoutant un intervalle fixe. Le cœur recalcule la prochaine exécution en fonction de la fréquence enregistrée, puis met immédiatement à jour la planification.

Par conséquent, si le CRON est arrêté pendant plusieurs heures, WordPress ne rejoue pas nécessairement toutes les exécutions qui auraient dû avoir lieu durant cette période. Selon le type d’événement et son implémentation, seule la prochaine occurrence pourra être reprogrammée. Ce fonctionnement explique pourquoi certaines tâches périodiques ne « rattrapent » pas automatiquement le temps perdu après une longue interruption.


Pourquoi utiliser certaines options WP-CLI ?

Le script présenté dans cet article utilise plusieurs options destinées à réduire le temps d’initialisation de WordPress sans modifier le comportement des événements planifiés. Vous pouvez trouver ici la liste des options de WP-CLI.

--skip-themes

L’option --skip-themes évite le chargement du thème actif (et du thème enfant s’il est présent). Les hooks des extensions restent disponibles, mais les fichiers du thème et ses éventuelles dépendances ne sont pas exécutés. Sur des thèmes particulièrement volumineux, cela permet de réduire légèrement le temps de démarrage de chaque commande WP-CLI.

Le gain reste modeste pour un site isolé, mais peut devenir important lorsqu’un même script traite plusieurs dizaines d’installations WordPress avec des thèmes complexes. C’est l’optimisation la plus importante, que l’on vous conseille d’appliquer, sauf si l’une de vos tâches dépend d’un thème.

--skip-packages

WP-CLI peut être enrichi par des packages installés dans le répertoire utilisateur, généralement ~/.wp-cli/packages. Ces extensions sont chargées au démarrage de chaque commande.

L’option --skip-packages empêche leur chargement. Sur la majorité des serveurs, l’impact est faible, mais elle garantit que seuls les composants nécessaires à l’exécution des événements CRON sont initialisés. Si vous n’avez pas besoin de logique complexe, on vous conseille de l’utiliser afin de lancer un environnement minimal et ainsi de réduire (même de manière très minime), le nombre de processus et le temps d’exécution des tâches. On peut considérer cela comme une micro optimisation.

--no-color

L’option --no-color désactive les codes ANSI utilisés pour coloriser la sortie du terminal. Les journaux générés par une tâche CRON restent ainsi parfaitement lisibles et ne contiennent aucun caractère d’échappement inutile, autrement dit, on force une sortie en texte brut. Ce n’est pas une optimisation en soi, ni un gain de performances, simplement un choix esthétique, à vous de juger si vous souhaitez l’utiliser ou non, en sachant qu’une tâche CRON dont les logs sont redirigés seront par défaut en texte brut. En pratique, --no-color est surtout utile pour forcer ce comportement dans les rares cas où des séquences ANSI se retrouveraient malgré tout dans les journaux.


Pourquoi remplacer complètement le déclenchement HTTP ?

Certains administrateurs choisissent de conserver le WP-CRON interne tout en appelant régulièrement wp-cron.php via wget ou curl. Cette méthode améliore la régularité des traitements, mais continue de dépendre d’une requête HTTP et de tous les composants associés : serveur web, configuration PHP, résolution DNS, certificats TLS, pare-feu applicatifs ou encore délais réseau.

Exemple de tâche CRON HTTP :
(utilise le serveur web comme n’importe quel utilisateur le ferait, ce qui implique de sécuriser le fichier wp-cron.php et/ou le point de terminaison visé par cette requête)

wget -q -O - https://mon-domaine.fr/wp-cron.php?doing_wp_cron >/dev/null 2>&1

Exemple de tâche CRON PHP :
(utilise le système d’exploitation et PHP, permettant de meilleures performances et une meilleure sécurité – utilise toujours la méthode wp-cron.php)

php /repertoire/wordpress/wp-cron.php >/dev/null 2>&1

À l’inverse, WP-CLI exécute directement les événements depuis le système d’exploitation. Les traitements sont lancés sans passer par une requête HTTP, ce qui simplifie leur intégration dans les mécanismes d’automatisation et réduit les sources potentielles d’échec.

Exemple de tâche CRON WP-CLI :
(utilise le système d’exploitation et WP-CLI, garantissant contrôle, performances et sécurité optimales)

cd /repertoire/wordpress && wp cron event run --due-now >/dev/null 2>&1

Pour cette raison, l’utilisation d’une véritable tâche CRON associée à WP-CLI est aujourd’hui considérée comme l’approche la plus robuste pour les serveurs hébergeant plusieurs sites WordPress ou exécutant régulièrement des traitements planifiés.


Une tâche CRON compatible avec la plupart des hébergements cPanel

De nombreux tutoriels proposent des scripts Bash complexes s’appuyant sur des fonctionnalités spécifiques à certaines distributions Linux ou nécessitant des dépendances rarement disponibles sur les hébergements mutualisés. L’objectif du script présenté ici est différent : privilégier la compatibilité, la simplicité et la robustesse afin qu’il puisse être exécuté sur la majorité des environnements cPanel disposant de WP-CLI.

Le script a été testé sur des serveurs Alma Linux hébergeant plusieurs installations WordPress classiques et multisites (en architectures multi-domaines, sous-domaines et répertoires). Il ne nécessite aucun outil/module supplémentaire ni aucun outil externe autre que les utilitaires généralement présents sur les distributions modernes.

La philosophie est la suivante : disposer d’un script autonome en une seule ligne, performant, fiable, largement compatible, ne nécessitant aucun fichier ou script supplémentaire, fonctionnant aussi bien sur un site WordPress seul que sur un réseau de plusieurs multi-sites WordPress, sans coder en dur le nom du serveur ni le nom des répertoires cibles. Ambitieux n’est-ce pas ?

Mais c’est possible et c’est même la meilleure approche si vous n’avez pas d’automatisations complexes à faire, ou si elles sont toutes enregistrées dans les tâches planifiées WordPress. Si vous avez des scripts lourds et des automatisations qui ne dépendant pas directement du cycle WordPress, nous vous conseillons de faire une tâche simple qui se contente d’appeler votre script, tout simplement.

Dépendances utilisées

  • WP-CLI (nécessaire)
  • PHP avec le module raphf (nécessaire à WP-CLI)
  • bash
  • flock
  • timeout
  • nice
  • ionice
  • sed
  • cut

Les commandes timeout et ionice sont fournies par la plupart des distributions GNU/Linux modernes (Debian, Ubuntu, AlmaLinux, Rocky Linux, CloudLinux, etc.). Sur certains hébergements mutualisés très limités, elles peuvent être absentes ; leur suppression n’empêche pas le fonctionnement du script mais retire les mécanismes de limitation des ressources.

Le module PHP raphf est nécessaire au bon fonctionnement de WP-CLI, en plus de tous les modules PHP requis par la configuration minimale de WordPress.


Les objectifs du script CRON

Le script a été conçu pour automatiser l’exécution des événements planifiés sur plusieurs installations WordPress hébergées dans un même compte cPanel, sans nécessiter de configuration spécifique pour chaque site. Cela suppose une architecture définie avec une arborescence fixe : ~/public_html/nom-du-site-ou-du-reseau/wordpress/.

  • Recherche en boucle des dossiers */wordpress/ dans le répertoire ~/public_html/.
  • Ignore les dossiers inexistants.
  • Détecte automatiquement les installations multisites.
  • Traite individuellement chaque sous-site d’un réseau multisite.
  • Exécute uniquement les événements arrivés à échéance.
  • Empêche les exécutions simultanées grâce à flock.
  • Réduit volontairement la priorité CPU et disque.
  • Interrompt les traitements anormalement longs.
  • Conserve un journal d’erreurs distinct pour chaque installation.

L’ensemble de ces choix vise à rendre l’exécution du CRON aussi prévisible que possible, même lorsqu’un même serveur héberge plusieurs dizaines de sites WordPress. Cela permet aussi de réduire l’impact sur la mémoire, le processeur et le réseau.


Pourquoi utiliser flock ?

WordPress possède déjà son propre mécanisme de verrouillage interne, mais celui-ci ne protège que l’exécution des événements au niveau de l’application (comprendre, au niveau de WordPress). Il n’empêche pas deux tâches CRON système de démarrer simultanément si elles sont lancées par erreur ou si une précédente exécution est toujours en cours.
Dans ce cas les tâches CRON système étant exécutées par le serveur, elles sont hors du cycle de WordPress.

La commande flock crée un verrou au niveau du système de fichiers (dans notre cas, un fichier wp-cron.flock est créé à la racine de chaque installation WordPress). Tant que ce verrou est détenu par un processus, toute nouvelle tentative d’exécution est immédiatement abandonnée grâce à l’option -n.

flock -n "$d/wp-cron.lock" -c "..."

Cette protection évite qu’une seconde tâche CRON démarre alors que la précédente n’est pas encore terminée. Elle constitue une sécurité supplémentaire particulièrement utile lors des sauvegardes volumineuses, des imports de catalogues ou des synchronisations avec des services externes.


Pourquoi réduire la priorité du processus ?

Une tâche de maintenance ne devrait jamais pénaliser les visiteurs d’un site web. Pour cette raison, le script diminue volontairement sa priorité CPU et disque avant de lancer WP-CLI.

nice

La commande suivante réduit la priorité CPU du processus :

nice -n5

Le noyau Linux favorisera ainsi les processus interactifs, notamment les requêtes HTTP des visiteurs, lorsque plusieurs tâches sollicitent simultanément le processeur.

ionice

Les sauvegardes, les optimisations de base de données ou les imports volumineux génèrent souvent de nombreux accès disque. La commande suivante attribue au processus une faible priorité d’entrées/sorties afin de limiter son impact sur les autres services du serveur :

ionice -c2 -n7

Sur un VPS ou un serveur dédié hébergeant plusieurs sites, cette précaution améliore généralement la réactivité globale durant les traitements planifiés. L’impact est cependant négligeable sur de petites tâches sur un seul ou peu de sites, les gains sont notables uniquement sur des sites à fort trafic et sur des clusters serveur hébergeant de nombreuses instances de WordPress + WP-CLI.


Pourquoi limiter la durée d’exécution ?

Certaines extensions exécutent des traitements particulièrement longs : sauvegardes distantes, génération de miniatures, synchronisations ERP, importations XML ou calculs de paniers/sessions WooCommerce. En cas de dysfonctionnement, une seule tâche peut monopoliser le processus pendant plusieurs dizaines de minutes, impactant les autres tâches ou pire, empêchant les tâches des autres sites du réseau de s’exécuter normalement :

Le script utilise donc :

timeout -k 5 --preserve-status 90

Cette commande interrompt automatiquement le traitement après 90 secondes (timeout 90) tout en laissant un délai supplémentaire de 5 secondes (-k 5) pour permettre au processus de se terminer proprement avant un arrêt forcé.

Ce mécanisme évite qu’un site défaillant retarde l’exécution des événements planifiés des autres installations hébergées sur le même serveur.

Petites subtilités de cohérence dans votre infrastructure serveur :

1) Idéalement, la valeur de WP_CRON_LOCK_TIMEOUT doit être égale à l’addition de timout et de -k afin de correspondre au temps maximum que peut théoriquement prendre une tâche, avant que WordPress ne puisse lancer un second processus. Dans notre cas cette valeur est de 5 + 90, soit une limite maximale de 95 secondes par processus.

2) Si vous avez accès à la configuration de PHP, la valeur de max_execution_time devrait, idéalement aussi, être plus élevée que la valeur de WP_CRON_LOCK_TIMEOUT ; non seulement pour éviter un incohérence entre les deux mécanismes (on souhaite éviter qu’un processus soit stoppé par PHP avant la durée de vie paramétrée dans WordPress et/ou dans notre tâche CRON) mais aussi et surtout pour savoir quand un processus est stoppé : on souhaite ainsi que le processus soit stoppé par la tâche CRON elle-même (via timeout avec filet de sécurité -k pour quelques secondes supplémentaires au cas où…) avant qu’il n’atteigne le limite globale de PHP. Dans notre cas max_execution_time aura donc une valeur strictement supérieure à 95 secondes.


Gestion des installations multisites

Les réseaux WordPress multisites nécessitent une attention particulière. Les événements planifiés ne sont pas tous exécutés au niveau du site principal ; certains sont spécifiques à chaque sous-site, et chaque sous-site du réseau dispose de ses propres tables dans la base de données.

Le script commence donc par déterminer si l’installation correspond à un réseau multisite grâce à WP-CLI, avec l’argument is-installed et l’option --network :

wp core is-installed --network

En cas de réponse positive, il récupère automatiquement la liste des URLs enregistrées dans le réseau :

wp site list --field=url

Chaque URL est ensuite traitée individuellement grâce au paramètre --url, ce qui garantit que les événements propres à chaque sous-site sont correctement exécutés.

Cette approche très flexible évite d’avoir à maintenir une liste statique des sites et reste pleinement compatible avec l’ajout ou la suppression de sites et sous-sites au fil du temps. On évite ainsi d’ajouter de la maintenance sur les tâches CRON.


Le script complet et commenté

On ne le répète jamais assez, ne jamais copier-coller aveuglément du code, faites le uniquement si vous le comprenez et surtout, adaptez le à votre propre usage/infrastructure.

# Parcourt tous les répertoires "/wordpress/" :
# ~/public_html/<site>/wordpress
for d in ~/public_html/*/wordpress; do

    # Ignore les dossiers inexistants.
    [ -d "$d" ] || continue

    # Construit le nom du site pour les logs, à partir du nom du répertoire parent.
    s=$(echo "$d" | sed 's!.*/public_html/!!')
    f=$(echo "$s" | cut -d'/' -f1)

    ## Détection automatique du multisite avec WP-CLI.
    # 1 - Si WordPress est effectivement un multi-site :
    if /usr/local/bin/php /usr/local/bin/wp --path=$d core is-installed --network >/dev/null 2>&1; then

        # Création du verrou "wp-cron.lock" dans le répertoire courant.
        flock -n "$d/wp-cron.lock" -c "

            # Réduction de la priorité et définition d'une durée maximale d'exécution.
            nice -n5
            ionice -c2 -n7
            timeout -k 5 --preserve-status 90

            # Liste des sous-sites de chaque réseau multi-site.
            /usr/local/bin/php /usr/local/bin/wp \
                --path=$d \
                site list \
                --field=url \
                2>/dev/null |

            while IFS= read -r url; do

                # Exécution des tâches en chargeant un environnement minimal.
                /usr/local/bin/php /usr/local/bin/wp \
                    --path=$d \
                    --url=\$url \
                    --no-color \
                    --skip-themes \
                    --skip-packages \
                    cron event run \
                    --due-now

            done

        " \

        # On log la sortie de chaque sous-site individuellement dans des fichiers "nom-du-sous-site-cron.log"
        1>/dev/null \
        2>> ~/logs/cron/$f-cron.log

    # 2 - Si WordPress est site unique :
    else

        # Création du verrou "wp-cron.lock" dans le répertoire courant.
        flock -n "$d/wp-cron.lock" -c "

            # Réduction de la priorité et définition d'une durée maximale d'exécution.
            nice -n5
            ionice -c2 -n7
            timeout -k 5 --preserve-status 90

            # Exécution des tâches en chargeant un environnement minimal.
            /usr/local/bin/php /usr/local/bin/wp \
                --path=$d \
                --no-color \
                --skip-themes \
                --skip-packages \
                cron event run \
                --due-now

        " \

        # On log la sortie de chaque sous-site individuellement dans des fichiers "nom-du-site-cron.log"
        1>/dev/null \
        2>> ~/logs/cron/$f-cron.log

    fi

done

Le script reste volontairement compact afin de pouvoir être facilement adapté à d’autres arborescences ou à d’autres environnements d’hébergement. Son fonctionnement repose uniquement sur des commandes standard et sur WP-CLI, ce qui facilite son intégration sur la majorité des serveurs Linux.


Retour d’expérience

Le remplacement du WP-CRON par une tâche CRON exécutant directement WP-CLI est une pratique largement adoptée sur les serveurs hébergeant plusieurs installations WordPress. Lors de différents déploiements sur des environnements mutualisés, VPS et serveurs dédiés, cette approche s’est montrée légèrement plus performante que le déclenchement automatique reposant sur les visites des internautes (on parle ici de quelques millisecondes, sur un parc d’une centaine de sites WordPress a trafic faible à modéré) mais les plus gros avantages sont les suivants :

  • Absence totale de maintenance sur les tâches CRON,
  • Régularité parfaite d’exécution des tâches,
  • Optimisation de la charge serveur (par exemple, les scripts les plus gourmands sont lancés exactement sur les « heures creuses » de notre infrastructure réseau, et aucun script n’est lancé en simultané).

Le principal bénéfice observé ne réside donc pas dans une augmentation spectaculaire des performances, mais dans la prévisibilité de l’exécution des tâches planifiées. Les publications programmées, les synchronisations, les tâches WooCommerce ou les sauvegardes sont exécutées selon la fréquence définie par la tâche CRON système, indépendamment du trafic du site, exactement à la fréquence et à l’instant que l’on souhaite définir.

Sur les serveurs hébergeant plusieurs dizaines de sites WordPress, la combinaison de flock, timeout, nice et ionice permet également d’éviter qu’un traitement particulièrement long monopolise inutilement les ressources ou retarde les autres sites hébergés sur le même compte. Pour une entreprise avec plusieurs noms de domaine et réseaux multi-sites les exploitant, cette approche est donc un gain réel en termes de déploiement opérationnel.


Les limites de cette approche

Comme toute solution technique, cette méthode présente également quelques limites qu’il convient de connaître avant son déploiement :

Limites techniques empêchant un bon déploiement :

  • WP-CLI doit être installé et accessible depuis le compte utilisateur,
  • Le module PHP raphf peut être désactivé sur certains hébergeurs,
  • Une tâche CRON système doit pouvoir être créée sur l’hébergement (accès au terminal conseillé pour tester les tâches),
  • Certaines anciennes extensions supposent encore que wp-cron.php est appelé par une requête HTTP,
  • Les commandes ionice ou timeout peuvent être absentes sur certains hébergements très limités.

Limites opérationnelles :

  • Ce type de tâche CRON peut est difficile à lire et à comprendre pour un développeur qui reprend le projet,
  • Il est difficile de faire des logiques complexes directement dans une tâche CRON en ligne,
  • Ce genre de tâche est inadaptée si toute votre logique d’automatisations repose sur des scripts externes.

Dans la pratique, ces situations restent relativement rares sur les distributions Linux actuelles, mais elles méritent d’être vérifiées avant toute mise en production. Seul le cas des scripts externes est réellement inadapté : une tâche ultra-simple servant uniquement à lancer vos scripts externes suffira alors.


Bonnes pratiques complémentaires

Le remplacement du WP-CRON constitue une amélioration importante, mais il ne dispense pas d’une surveillance régulière des tâches planifiées.

Quelques recommandations permettent d’améliorer encore la fiabilité de l’ensemble :

  • Contrôler régulièrement les journaux d’erreurs générés par WP-CLI.
  • Vérifier qu’aucun événement ne reste constamment en attente.
  • Tester périodiquement la tâche CRON après une mise à jour majeure de WordPress ou de WP-CLI.
  • Éviter que plusieurs tâches de maintenance lourdes soient exécutées exactement à la même minute.
  • Surveiller la durée d’exécution des sauvegardes et des synchronisations volumineuses.
  • Conserver une fréquence adaptée à la charge réelle du serveur, généralement toutes les cinq minutes pour la plupart des sites.
  • Mettre en place une politique de rotation des logs pour éviter une augmentation infinie du volume d’informations.

WP-CLI fournit également plusieurs commandes utiles pour diagnostiquer le fonctionnement des événements planifiés :

# Liste les événements enregistrés
wp cron event list

# Exécute uniquement les événements arrivés à échéance
wp cron event run --due-now

# Exécute un événement particulier
wp cron event run nom_du_hook

# Vérifie la version de WP-CLI
wp --info

Ces commandes facilitent le diagnostic lorsqu’un traitement semble ne plus être exécuté correctement.


Exemple de planification CRON

Une fois le script installé et rendu exécutable, il suffit de le planifier via le gestionnaire CRON de l’hébergement.

Un déclenchement toutes les 15 minutes constitue généralement un bon compromis entre réactivité et consommation des ressources (sur une boutique en ligne on conseille généralement un délais plus court comme 5 minutes) :

*/15 * * * * ~/public_html/scripts/mon-script-cron.sh

Pour des sites fortement sollicités avec beaucoup de tâches et de contenu dynamique, une exécution chaque minute peut être envisagée si les traitements restent suffisamment courts et que les ressources du serveur le permettent.


Conclusion

Le système WP-CRON a été conçu pour permettre à WordPress de fonctionner sur tous les types d’hébergement, même lorsqu’aucun accès aux tâches CRON système n’est disponible. Cette simplicité explique son succès, mais elle montre rapidement ses limites dès que les tâches planifiées deviennent nombreuses ou coûteuses.

Le remplacement du déclenchement HTTP par une véritable tâche CRON en ligne de commande utilisant WP-CLI apporte une exécution plus régulière, un meilleur contrôle des ressources et une réduction des risques de chevauchement des tâches. Associée à des mécanismes tels que flock, timeout, nice et ionice, cette approche offre un niveau de robustesse nettement supérieur pour l’administration de plusieurs sites WordPress.

Le script présenté dans cet article privilégie volontairement la compatibilité avec les environnements cPanel tout en restant facilement adaptable à d’autres architectures Linux. Sans chercher à remplacer des outils d’orchestration plus avancés, il constitue une solution simple, fiable et éprouvée pour automatiser l’exécution des tâches planifiées sur une ou plusieurs installations WordPress, y compris multi-site.