wp cron event list renvoyait plus de mille quatre cents lignes sur un site d’actualités locales, alors qu’un site de cette taille ne devrait raisonnablement en compter que quelques dizaines à un instant donné. Chaque requête visiteur, en l’absence de cron système externe, déclenchait la vérification de cette liste entière avant de décider si un événement devait s’exécuter, ajoutant un coût silencieux à chaque affichage de page.
Le symptôme initial ressemblait à un ralentissement général et diffus du site, sans page précise identifiable comme responsable. Le diagnostic a mené à un comportement récurrent : la republication d’un même article, plusieurs fois par jour dans le cadre d’une politique éditoriale de mise à jour de contenu, réinscrivait systématiquement un événement cron sans jamais désinscrire les précédents.
Diagnostic : retrouver la source de l’accumulation
Une extension maison, chargée de republier un rappel de notification par e-mail cinq minutes après chaque mise à jour d’un article, programmait cet événement via wp_schedule_single_event() à chaque déclenchement du hook save_post, sans jamais vérifier au préalable si un événement similaire existait déjà pour cet article :
// Code fautif : aucune vérification avant la programmation
add_action( 'save_post', function ( $post_id ) {
wp_schedule_single_event(
time() + 5 * MINUTE_IN_SECONDS,
'notifier_mise_a_jour_article',
array( $post_id )
);
} );
Sur un article republié dix fois par jour, pendant plusieurs semaines, ce code accumulait un événement cron distinct à chaque republication, sans jamais nettoyer les anciens événements déjà exécutés ou devenus obsolètes, en particulier lorsque l’article était republié avant même que le premier événement de cinq minutes ne se soit déclenché.

Correctif : vérifier avant de programmer, et désinscrire l’ancien
La correction consiste à vérifier systématiquement si un événement existe déjà pour cet article précis avant d’en programmer un nouveau, et à désinscrire explicitement tout événement précédent devenu redondant :
add_action( 'save_post', function ( $post_id ) {
$args = array( $post_id );
// Désinscrire tout événement précédent pour cet article
$timestamp_existant = wp_next_scheduled( 'notifier_mise_a_jour_article', $args );
if ( $timestamp_existant ) {
wp_unschedule_event( $timestamp_existant, 'notifier_mise_a_jour_article', $args );
}
wp_schedule_single_event(
time() + 5 * MINUTE_IN_SECONDS,
'notifier_mise_a_jour_article',
$args
);
} );
La fonction wp_clear_scheduled_hook() offre une alternative plus radicale quand plusieurs occurrences doivent être supprimées d’un coup, en désinscrivant toutes les instances programmées d’un hook donné pour des arguments identiques, plutôt que de traiter une seule occurrence à la fois.
Nettoyer l’accumulation déjà présente
Une fois la source corrigée, les événements déjà accumulés restent en base de données jusqu’à leur exécution naturelle ou leur suppression manuelle. Un nettoyage via WP-CLI permet de purger rapidement les doublons identifiés :
wp cron event list --hook=notifier_mise_a_jour_article --format=csv
wp cron event delete notifier_mise_a_jour_article
Cette commande supprime l’ensemble des occurrences programmées pour ce hook précis, offrant un point de départ propre avant que le code corrigé ne reprenne la main sur les futures programmations.
Prévention : les réflexes à adopter
- Toujours vérifier l’existence d’un événement avec
wp_next_scheduled()avant d’en programmer un nouveau pour les mêmes arguments. - Préférer
wp_schedule_single_event()à un événement récurrent quand la logique métier ne nécessite qu’une seule exécution différée, pour limiter le risque d’accumulation en cas de logique de désinscription manquante. - Surveiller périodiquement la taille de la file cron via
wp cron event list, en particulier après l’ajout d’une extension qui programme des événements en réaction à des actions fréquentes du contenu.
En résumé
Un événement cron mal désinscrit reste discret jusqu’à ce que son accumulation devienne suffisamment massive pour ralentir chaque requête entrante, chargée de vérifier une file toujours plus longue. Vérifier systématiquement l’existence d’un événement avant sa programmation, et désinscrire proprement les occurrences devenues redondantes, évite cette dérive silencieuse qui finit toujours par se remarquer trop tard.