Un studio graphique m’a confié la maintenance d’un thème qu’il revend en marque blanche à une quinzaine de clients, chacun avec ses propres réglages de couleurs, de disposition d’en-tête et d’affichage d’articles. Le thème utilisait déjà l’API des theme mods, mais sans convention de nommage claire ni gestion des valeurs par défaut, ce qui provoquait des erreurs silencieuses à chaque mise à jour majeure : un réglage introduit dans une nouvelle version restait vide chez les clients existants, faute de valeur de repli.
Ce tutoriel détaille comment j’ai structuré le stockage des réglages avec get_theme_mod() et set_theme_mod() pour un thème destiné à plusieurs clients, sans recourir à une table personnalisée ni à une dépendance externe. L’API du Customizer côté interface (contrôles, sections, panneaux) n’est pas traitée ici : seul le stockage et sa fiabilité m’intéressent dans cet article.
Ce que stocke réellement un theme mod
Les réglages enregistrés via set_theme_mod() vivent dans une entrée unique de la table wp_options, nommée theme_mods_{stylesheet}, où {stylesheet} correspond au dossier du thème actif. Concrètement, c’est un tableau PHP sérialisé contenant toutes les paires clé-valeur du thème. Changer de thème actif change automatiquement d’entrée : les réglages d’un thème n’écrasent jamais ceux d’un autre thème installé sur le même site, ce qui est rassurant pour un thème vendu en marque blanche coexistant parfois avec un thème de test.
$header_color = get_theme_mod( 'header_background_color', '#1a1a1a' );
set_theme_mod( 'header_background_color', '#0f3d2e' );
La convention de nommage qui évite les collisions
Rien n’empêche deux thèmes différents de définir un mod nommé header_color, mais un client qui bascule un jour entre deux variantes du thème (une version restaurant, une version cabinet médical, partageant le même socle de code) peut se retrouver avec des noms de mods qui divergent d’une variante à l’autre si la discipline n’est pas tenue. Sur ce projet, j’ai adopté un préfixe court lié à la marque du studio, appliqué systématiquement.
stg_header_layoutplutôt queheader_layout, pour éviter toute collision avec un futur plugin ou thème enfant.- Un seul point d’enregistrement centralisé des noms de mods, dans
inc/customizer-defaults.php, servant de source de vérité. - Aucun mod stocké sans valeur par défaut explicite au moment de la lecture.

Toujours fournir une valeur par défaut à la lecture
L’erreur la plus fréquente que j’ai corrigée consistait à appeler get_theme_mod( 'stg_header_layout' ) sans second argument. Sans valeur par défaut, la fonction renvoie false si le mod n’a jamais été défini, ce qui oblige le reste du code à gérer un cas supplémentaire à chaque utilisation. En centralisant les valeurs par défaut dans un tableau unique, la maintenance devient bien plus prévisible.
function stg_theme_mod_defaults() {
return array(
'stg_header_layout' => 'centered',
'stg_header_background' => '#ffffff',
'stg_show_excerpt_on_home' => true,
);
}
function stg_get_mod( $name ) {
$defaults = stg_theme_mod_defaults();
$default = isset( $defaults[ $name ] ) ? $defaults[ $name ] : '';
return get_theme_mod( $name, $default );
}
Chaque appel dans les templates passe désormais par stg_get_mod() plutôt que directement par get_theme_mod(), ce qui garantit qu’un oubli de valeur par défaut à un endroit du code ne produit jamais un résultat incohérent ailleurs.
Migrer les mods entre versions majeures
Quand la version 3 du thème a renommé stg_header_layout en stg_header_style pour plus de clarté, il fallait éviter que les quinze clients existants perdent leur réglage du jour au lendemain. La solution retenue : une routine de migration exécutée une seule fois, déclenchée par comparaison de version stockée dans un mod dédié.
function stg_maybe_migrate_mods() {
$version = get_theme_mod( 'stg_theme_version', '2.0' );
if ( version_compare( $version, '3.0', '<' ) ) {
$old_value = get_theme_mod( 'stg_header_layout' );
if ( $old_value ) {
set_theme_mod( 'stg_header_style', $old_value );
}
set_theme_mod( 'stg_theme_version', '3.0' );
}
}
add_action( 'after_switch_theme', 'stg_maybe_migrate_mods' );
Ce type de migration reste minimal et ciblé : il ne recopie que les mods réellement renommés, et ne s’exécute qu’une fois par site grâce au verrou de version. Sur les quinze clients concernés, la mise à jour s’est faite sans aucun réglage perdu, ni intervention manuelle de leur part.
Nettoyer les mods obsolètes
Un theme mod qui n’est plus lu nulle part dans le code continue pourtant d’exister dans wp_options, sans gêner le fonctionnement du site mais en alourdissant légèrement l’entrée sérialisée. Sur ce projet, j’ai profité de chaque migration majeure pour supprimer explicitement les mods devenus inutiles avec remove_theme_mod(), plutôt que de les laisser traîner indéfiniment.
En résumé
L’API des theme mods reste largement suffisante pour un thème vendu à plusieurs clients, à condition d’imposer une discipline de nommage préfixé, de centraliser les valeurs par défaut et de prévoir une routine de migration à chaque renommage. Ces trois habitudes évitent la majorité des régressions silencieuses observées lors des montées de version d’un thème partagé entre de nombreux sites indépendants.