Ce message ne décrit pas ce que WordPress fait. Il décrit ce qu’il trouve : une option nommée core_updater.lock dans la table des options, posée au début d’une mise à jour du cœur et retirée à la fin. Si la mise à jour s’est arrêtée avant la fin, l’option reste. Elle bloque toute nouvelle tentative pendant quinze minutes, puis WordPress la remplace de lui-même. Rien n’est cassé sur le site public. Seul l’écran « Mettre à jour WordPress » est concerné.
Attendez quinze minutes après le début de la tentative qui a échoué, puis relancez : dans la plupart des cas, le message a disparu. S’il persiste, vérifiez que personne d’autre ne met le site à jour, puis supprimez l’option, avec WP-CLI (wp option delete core_updater.lock) ou en SQL. Si le site public affiche aussi un message de maintenance, supprimez en plus le fichier .maintenance.
Ce que l’écran affiche, mot pour mot
La chaîne source est « Another update is currently in progress. », déclarée dans Core_Upgrader::upgrade_strings(), fichier wp-admin/includes/class-core-upgrader.php. La traduction française, dans wp-content/languages/admin-fr_FR.po, est « Une autre mise à jour est actuellement en cours. » Elle s’affiche sous le titre « Mettre à jour WordPress », et sans la ligne « Échec de l’installation » : do_core_upgrade(), dans wp-admin/update-core.php, écarte explicitement le code d’erreur locked de ce second message.
Ce message ne concerne que le cœur. Plugin_Upgrader, Theme_Upgrader et Language_Pack_Upgrader ne posent aucun verrou : une extension qui refuse de se mettre à jour a une autre raison, et une autre page.
Le mécanisme, lu dans le code
Core_Upgrader::upgrade() appelle WP_Upgrader::create_lock( 'core_updater', 15 * MINUTE_IN_SECONDS ) juste avant de télécharger l’archive. La fonction, définie dans wp-admin/includes/class-wp-upgrader.php, fait quatre choses :
- elle tente un
INSERT IGNOREdirect dans la table des options, nomcore_updater.lock, valeurtime(), l’heure Unix du serveur, chargement automatique désactivé ; - si l’insertion n’a rien écrit, elle relit l’option avec
get_option(). Aucune valeur : elle renvoie faux. Une valeur plus récente que quinze minutes : elle renvoie faux aussi ; - une valeur plus ancienne : elle appelle
release_lock(), qui n’est qu’undelete_option( 'core_updater.lock' ), puis se rappelle elle-même et obtient le verrou ; - dès qu’elle renvoie faux,
upgrade()retourneWP_Error( 'locked', … ), et c’est le message.
Deux conséquences. Le verrou expire sans intervention : après quinze minutes, la prochaine tentative supprime la vieille ligne et en écrit une nouvelle. Il n’y a rien à nettoyer. Et la valeur n’est jamais rafraîchie pendant la mise à jour : elle date du début. Une mise à jour légitime qui dure plus de quinze minutes peut donc se faire doubler par une seconde tentative.
release_lock( 'core_updater' ) est appelé à chaque sortie de upgrade() : téléchargement en échec, archive illisible, copie refusée, et à la toute fin après update_core(). Ce que le code ne peut pas couvrir, c’est PHP qui meurt en route. C’est la cause 1.
Trois verrous qui ne disent pas la même chose
| Verrou | Qui le pose | Validité | Ce qu’il bloque |
|---|---|---|---|
option core_updater.lock | Core_Upgrader::upgrade(), à la main ou par le cron | 15 minutes | Une seconde mise à jour du cœur. Message de ce guide. |
option auto_updater.lock | WP_Automatic_Updater::run(), par le cron | 1 heure, valeur par défaut de create_lock() | Un second passage des mises à jour automatiques. Aucun message : run() se termine en silence. |
fichier .maintenance | update_core(), pendant la copie des fichiers | 10 minutes | Tout le site public, avec un statut 503. |
Le cron passe par les trois : WP_Automatic_Updater::update() instancie Core_Upgrader, donc une mise à jour automatique du cœur pose auto_updater.lock, puis core_updater.lock, puis le fichier.
Lire le verrou avant d’y toucher
La valeur est une heure Unix. Son âge se calcule dans la requête :
SELECT option_value, FROM_UNIXTIME(option_value) AS pose_le,
UNIX_TIMESTAMP() - option_value AS age_en_secondes
FROM wp_options WHERE option_name = 'core_updater.lock';Avec WP-CLI : wp option get core_updater.lock. Un âge inférieur à 900 secondes explique le message à lui seul. Un âge supérieur, avec le message qui persiste, désigne la cause 4 ou la cause 5.
Avant de supprimer quoi que ce soit, trois vérifications. Un autre administrateur n’a pas lancé la mise à jour il y a moins de quinze minutes. L’option auto_updater.lock est absente ou ancienne, sinon le cron travaille. Et le fichier .maintenance n’existe pas à la racine, ou date de plus de dix minutes : sa présence récente signifie que des fichiers sont en train d’être copiés, et retirer le verrou à ce moment autorise une seconde copie par-dessus la première.
wp option delete core_updater.lock
-- ou, sans WP-CLI :
DELETE FROM wp_options WHERE option_name = 'core_updater.lock';Le préfixe wp_ est celui de $table_prefix dans wp-config.php.
Les causes, par ordre de fréquence
1. Une mise à jour interrompue a laissé le verrou
Délai d’exécution PHP dépassé pendant le téléchargement ou la copie, coupure du serveur, mémoire épuisée, connexion fermée par un proxy. Le processus meurt avant d’atteindre release_lock(). Signature : le message apparaît à la seconde tentative, juste après une première qui a tourné longtemps ou fini sur une erreur critique. Réparation : attendre l’expiration, ou supprimer l’option. Puis chercher pourquoi la première a cassé.
2. Deux lancements en même temps
Deux administrateurs qui cliquent à quelques minutes d’écart, ou le cron des mises à jour automatiques qui est passé juste avant vous. Le verrou fait exactement son travail. Signature : un âge de quelques minutes, un auto_updater.lock récent, ou un .maintenance présent. Réparation : aucune. Attendre, puis vérifier la version dans wp-includes/version.php : elle est souvent déjà à jour.
3. Une mise à jour réellement en cours, et longue
Une archive complète sur un hébergement lent peut dépasser quinze minutes. Le verrou tombe alors que la copie continue. Une seconde tentative obtient le verrou et repart de zéro sur des fichiers en train d’être écrits. Signature : le fichier .maintenance est présent et récent. Réparation : ne rien relancer tant que .maintenance existe. Une fois la première tentative finie, le message n’a plus de raison d’être.
4. Un cache d’objets garde une vieille réponse
create_lock() écrit en SQL direct mais relit avec get_option(), qui passe par le cache d’objets, groupes options et notoptions. Avec un cache persistant (Redis, Memcached) dont la copie a divergé de la base, la relecture peut répondre « pas d’option » alors que la ligne existe : la fonction renvoie faux sans atteindre la branche qui efface un verrou expiré. Le message survit aux quinze minutes. Signature : la requête SQL montre une ligne ancienne que wp option get ne voit pas, ou l’inverse. Réparation : supprimer en SQL, la vérité étant en base, puis vider le cache d’objets (wp cache flush, ou le bouton de l’extension de cache).
5. La base refuse l’écriture
Si l’INSERT IGNORE échoue, $wpdb->query() renvoie faux. create_lock() relit alors l’option, ne trouve rien, et renvoie faux. Le message est le même, sans qu’aucun verrou n’existe. Quota de base atteint, utilisateur MySQL en lecture seule, table des options corrompue. Signature : la requête de lecture ne renvoie aucune ligne et le message revient à chaque essai. Réparation : côté hébergeur. wpdb affiche ses erreurs quand WP_DEBUG et WP_DEBUG_DISPLAY sont tous deux vrais.
Le fichier .maintenance, l’autre verrou
Il ne faut pas les confondre. Le verrou de ce guide protège une procédure ; le fichier protège les visiteurs. update_core(), dans wp-admin/includes/update-core.php, écrit à la racine un fichier d’une ligne, <?php $upgrading = <heure Unix>; ?>, avant de copier les fichiers, et le supprime après. wp_is_maintenance_mode(), dans wp-includes/load.php, l’ignore dès que l’horodatage a plus de dix minutes. Tant qu’il est valide, wp_maintenance() répond 503 avec Retry-After: 600 et le texte « Indisponibilité temporaire pour cause de maintenance. Veuillez revenir dans un instant. », traduction de « Briefly unavailable for scheduled maintenance. Check back in a minute. »
Une mise à jour qui meurt pendant la copie laisse les deux : le fichier ferme le site dix minutes, l’option bloque la relance quinze. Le guide dédié traite le fichier. Si la réparation doit durer, mieux vaut un mode maintenance choisi qu’un fichier qui expire tout seul.
Vérifier que c’est terminé
SELECT option_name FROM wp_options
WHERE option_name IN ('core_updater.lock', 'auto_updater.lock');Attendu : aucune ligne, ou des lignes plus vieilles que leur validité. Relancez la mise à jour. La fin normale affiche « WordPress a bien été mis à jour. », et wp-includes/version.php porte le nouveau numéro. Un échec à une autre étape produit un autre message, suivi cette fois de « Échec de l’installation » : autre problème, et le verrou a été relâché.