# HPOS activé, panier qui affiche du vide : le template thème qui lit encore l’ancien format

> Un thème WooCommerce hérité continue d'appeler get_post_meta sur la commande après le passage aux tables HPOS. Voici comment repérer et corriger ces appels dans les templates.

- Auteur : WordPress Développement
- Publié le : 2022-12-12
- Mis à jour le : 2022-12-12
- Catégorie : Thèmes
- URL : https://www.wpmoderne.fr/themes/hpos-vieux-theme-template-panier-get-post-meta/

## L’essentiel

- HPOS déplace les métadonnées hors de wp_postmeta
- get_post_meta reste souvent fonctionnel en compatibilité, mais pas toujours
- La bonne pratique : passer par les getters de l'objet commande

`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`.

> L'essentiel à retenir : HPOS déplace les métadonnées hors de wp_postmeta ; get_post_meta reste souvent fonctionnel en compatibilité, mais pas toujours ; La bonne pratique : passer par les getters de l'objet commande

## 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( $order` ou `get_post_meta( $post->ID` dans un contexte de commande
- `update_post_meta` appliqué à un identifiant de commande
- `WP_Query` avec `'post_type' => 'shop_order'` pour lister des commandes dans un tableau de bord thème
- accès direct à `$wpdb->postmeta` via 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_init` et `FeaturesUtil::declare_compatibility()`
- Bannir tout accès direct à `wp_postmeta` ou `wp_posts` pour 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_postmeta` pour 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.
