3 requêtes de vérification de structure à chaque ouverture d’une page d’administration, multipliées par le nombre de visites d’un back-office actif : c’est le coût discret d’une extension qui revérifie son schéma de base de données sans condition. Le correctif tient en une seule option bien pensée.
Une extension qui gère une table personnalisée doit, à un moment ou un autre, faire évoluer sa structure : ajouter une colonne, créer un index, modifier un type de champ. La tentation la plus simple consiste à relancer l’appel de mise à jour de structure sur chaque chargement d’écran d’administration, pour être sûr que la table est toujours à jour. Cela fonctionne, mais cela coûte cher pour un résultat qui ne change presque jamais.
Ce que fait réellement une revérification systématique
L’appel qui compare la structure demandée à la structure existante interroge le schéma de la table à chaque exécution. Sur un site avec plusieurs administrateurs actifs, cela représente une requête supplémentaire à chaque page vue dans le back-office, alors que la structure n’a changé qu’une fois, lors de la dernière mise à jour de l’extension. Le gaspillage est proportionnel au trafic d’administration, pas à la fréquence réelle des changements de schéma.
Le principe pour corriger cela est simple : stocker, dans une option, la version de schéma déjà appliquée, puis ne relancer la mise à jour que si cette version diffère de celle attendue par le code actuellement chargé.

Implémenter la comparaison de version
define( 'MON_EXTENSION_DB_VERSION', '1.3.0' );
function mon_extension_verifier_schema() {
$version_installee = get_option( 'mon_extension_db_version', '0' );
if ( version_compare( $version_installee, MON_EXTENSION_DB_VERSION, '<' ) ) {
mon_extension_appliquer_migration( $version_installee );
update_option( 'mon_extension_db_version', MON_EXTENSION_DB_VERSION );
}
}
add_action( 'plugins_loaded', 'mon_extension_verifier_schema' );
La fonction se contente de lire une option — une opération peu coûteuse et souvent déjà mise en cache par un objet cache — puis compare deux chaînes de version avec version_compare(). Tant que les deux versions correspondent, aucune requête de structure n’est déclenchée. La migration ne s’exécute qu’une seule fois, juste après la mise à jour de l’extension, puis se tait pour toutes les visites suivantes.
Gérer les migrations incrémentales
Quand plusieurs versions de schéma se sont succédé, il devient utile de faire correspondre chaque palier à sa propre fonction de migration plutôt que de tout regrouper dans un seul bloc. La fonction mon_extension_appliquer_migration() reçoit la version installée et enchaîne les étapes nécessaires :
- Version antérieure à 1.1.0 : ajout d’une colonne
statut. - Version antérieure à 1.2.0 : création d’un index sur la colonne
date_creation. - Version antérieure à 1.3.0 : changement de type de la colonne
montant.
Chaque étape reste indépendante et testable isolément, ce qui simplifie beaucoup la maintenance quand plusieurs versions d’une extension coexistent encore chez différents clients.
Le piège de l’option en cache d’objet non persistant
Sur un hébergement sans cache d’objet persistant, chaque exécution PHP repart avec un cache vide, ce qui n’est pas un problème pour cette vérification : l’option est relue depuis la base à chaque requête, mais reste une lecture unique et rapide. En revanche, sur un site multisite où une option est mal isolée par site, une migration peut sembler appliquée alors qu’elle ne l’a été que sur un seul sous-site. Il est donc préférable d’utiliser get_option() classique (isolée par site) plutôt qu’une option réseau partagée pour ce genre de suivi de schéma propre à chaque base.
Pourquoi ne pas simplement vérifier à l’activation seule
On pourrait penser qu’une vérification uniquement à l’activation suffit. Ce n’est pas le cas : une mise à jour de l’extension via l’interface d’administration ne redéclenche pas le hook d’activation, sauf si l’utilisateur désactive puis réactive manuellement l’extension, ce qui n’arrive presque jamais après une mise à jour automatique. Le hook plugins_loaded, exécuté à chaque chargement, reste donc le point d’entrée fiable pour cette comparaison de version, précisément parce qu’il s’exécute systématiquement, contrairement au hook d’activation.
Une migration qui se rejoue sans condition n’est jamais visible tant que le trafic d’administration reste faible — elle le devient dès qu’une équipe entière travaille dans le back-office toute la journée.
Notre verdict
Stocker un numéro de version de schéma dans une option et le comparer à chaque chargement coûte une lecture d’option ; revérifier la structure d’une table à chaque page coûte une requête de schéma. La différence semble minime isolément, mais elle s’accumule vite sur un back-office actif. C’est l’un de ces réflexes simples qui distinguent une extension pensée pour durer d’une extension qui fonctionne juste au premier essai.