get_post_meta( $order->get_id(), '_billing_email', true ) renvoie une chaîne vide dans un template cart/cart.php personnalisé, alors que l’adresse existe bel et bien dans les réglages de la commande. Le symptôme est discret : rien ne plante, aucune erreur PHP ne remonte, mais des champs disparaissent silencieusement des templates de panier et de récapitulatif de commande d’un thème enfant hérité.
C’est exactement ce qui arrive lorsque WooCommerce bascule le stockage des commandes vers les tables personnalisées HPOS (High-Performance Order Storage, disponible depuis WooCommerce 8.2 mi-2022 en version bêta) et qu’un thème continue d’interroger directement wp_postmeta par des appels de fonctions pensés pour l’ancien modèle « commande = article ».
Symptôme observé sur le terrain
Le cas typique : un thème boutique livré plusieurs années auparavant contient un fichier woocommerce/cart/cart-totals.php surchargé, avec des appels du type get_post_meta( $post->ID, '_order_total', true ) pour afficher un total personnalisé, ou des lectures de _billing_email, _shipping_method, _payment_method_title directement en base. Tant que les commandes sont stockées comme des articles du type shop_order, cela fonctionne. Dès qu’une boutique active le stockage HPOS, ces commandes ne sont plus des lignes de wp_posts : elles vivent dans wp_wc_orders et leurs métadonnées dans wp_wc_orders_meta.
Résultat concret : les champs lus via get_post_meta() renvoient une chaîne vide ou false, sans avertissement, sans notice PHP, parce que la fonction cherche un article qui n’existe simplement plus à cet identifiant dans wp_posts.

Diagnostic : où chercher dans le thème
La première étape consiste à cartographier les appels problématiques. Une recherche dans les fichiers du thème sur les motifs suivants suffit généralement à isoler les zones à risque :
get_post_meta( $orderouget_post_meta( $post->IDdans un contexte de commandeupdate_post_metaappliqué à un identifiant de commandeWP_Queryavec'post_type' => 'shop_order'pour lister des commandes dans un tableau de bord thème- accès direct à
$wpdb->postmetavia une requête SQL sur mesure
Sur un thème d’agence audité récemment, ce sont sept fichiers de templates surchargés qui contenaient ce type d’appel : le récapitulatif de commande, l’e-mail de confirmation personnalisé, un widget « dernières commandes » du compte client, et un rapport interne affiché en pied de page administrateur.
Pourquoi ça ne plante pas immédiatement
WooCommerce maintient par défaut, pendant la période de transition, un mode de compatibilité qui synchronise les données entre les tables HPOS et wp_posts/wp_postmeta. Ce mode peut masquer le problème pendant des mois, jusqu’au jour où la synchronisation est désactivée dans les réglages, ou jusqu’à ce qu’une commande créée par une extension tierce ne passe plus par ce pont de compatibilité.
Correctif : passer par les getters de l’objet commande
La correction consiste à remplacer chaque lecture directe de métadonnée par l’API orientée objet de WooCommerce, qui fonctionne indépendamment du mode de stockage choisi :
// Avant : lecture directe, fragile face à HPOS
$email = get_post_meta( $order_id, '_billing_email', true );
$total = get_post_meta( $order_id, '_order_total', true );
// Après : passe par l'objet WC_Order, compatible HPOS
$order = wc_get_order( $order_id );
if ( $order instanceof WC_Order ) {
$email = $order->get_billing_email();
$total = $order->get_total();
}
Pour les méta personnalisées ajoutées par le thème lui-même (par exemple une case « commande urgente » stockée sous _urgent_flag), la méthode get_meta() de l’objet commande fait le même travail que get_post_meta(), mais interroge la bonne table selon le mode actif :
$urgent = $order->get_meta( '_urgent_flag', true );
$order->update_meta_data( '_urgent_flag', 'yes' );
$order->save();
Pour les requêtes qui listent des commandes, WP_Query sur shop_order doit céder la place à wc_get_orders(), qui accepte des arguments similaires (limit, status, customer_id) mais interroge la couche de stockage réellement active.
Prévention pour les prochains projets
Trois habitudes évitent de retomber dans ce piège sur les futurs chantiers de thèmes WooCommerce :
- Déclarer explicitement la compatibilité HPOS du thème lorsqu’il embarque des templates de commande, via le hook
before_woocommerce_initetFeaturesUtil::declare_compatibility() - Bannir tout accès direct à
wp_postmetaouwp_postspour des données de commande, même dans un script de maintenance ponctuel - Tester le thème avec HPOS activé en environnement de recette avant chaque livraison, la bascule étant désormais activée par défaut sur les nouvelles installations
Un thème qui n’accède jamais directement à
wp_postmetapour une commande survit à tous les changements de stockage internes de WooCommerce, présents et futurs.
En résumé
Le passage à HPOS ne casse rien de façon spectaculaire dans un thème ancien : il vide silencieusement des champs qui semblaient acquis. La correction est mécanique une fois les appels problématiques repérés — remplacer get_post_meta() par les getters de WC_Order — mais elle demande un audit complet des templates de commande, pas seulement du panier. Sur ce projet, l’audit des sept fichiers a pris une demi-journée ; la correction, à peine plus.