« Aucune facture synchronisée depuis hier » : c’est le ticket qui a déclenché l’audit. Le client, un cabinet comptable qui synchronise les commandes WooCommerce vers son logiciel de gestion via une extension maison, avait simplement mis à jour WooCommerce vers une version où le stockage des commandes en tables personnalisées (High-Performance Order Storage, HPOS) était activé par défaut sur les nouvelles installations. Ce billet recense les hooks qui ont changé de comportement ; la migration HPOS elle-même, ses étapes et sa bascule progressive, a déjà été traitée dans un article dédié.
Symptôme : la synchronisation s’arrête net
Le connecteur comptable s’appuyait sur le hook save_post, filtré sur le type de post shop_order, pour déclencher l’envoi de chaque commande modifiée vers l’API du logiciel comptable. En HPOS, les commandes ne sont plus des objets post : elles vivent dans des tables dédiées (wp_wc_orders et consorts), et save_post ne se déclenche donc plus du tout à leur sauvegarde.
Diagnostic : quatre hooks à remplacer
| Ancien hook (post-based) | Équivalent HPOS | Remarque |
|---|---|---|
save_post_shop_order | woocommerce_new_order / woocommerce_update_order | Deux hooks distincts à couvrir, contre un seul auparavant. |
WP_Query avec post_type => shop_order | wc_get_orders() | Fonctionne dans les deux modes, à privilégier systématiquement. |
get_post_meta( $order_id, ... ) | $order->get_meta( ... ) | La lecture directe en base échoue silencieusement en HPOS. |
delete_post_meta | $order->delete_meta_data() + save() | Nécessite un appel explicite à save() pour persister. |

Correctif appliqué
Le connecteur a été réécrit autour des hooks natifs WooCommerce plutôt que des hooks WordPress génériques, ce qui a l’avantage de fonctionner que HPOS soit activé ou non, tant que la compatibilité est correctement déclarée par ailleurs :
add_action( 'woocommerce_update_order', 'wpm_sync_order_to_accounting' );
add_action( 'woocommerce_new_order', 'wpm_sync_order_to_accounting' );
function wpm_sync_order_to_accounting( int $order_id ): void {
$order = wc_get_order( $order_id );
if ( ! $order ) {
return;
}
$payload = array(
'reference' => $order->get_order_number(),
'total' => $order->get_total(),
'client' => $order->get_billing_email(),
'vat' => $order->get_meta( '_wpm_vat_number' ),
);
wpm_push_to_accounting_api( $payload );
}
La lecture des meta personnalisées, notamment le numéro de TVA intracommunautaire stocké par une autre extension, posait un problème supplémentaire : cette donnée était toujours écrite via update_post_meta par l’extension tierce, non mise à jour pour HPOS, ce qui l’envoyait dans wp_postmeta alors que la commande elle-même vivait désormais dans les nouvelles tables. La méthode get_meta() de WooCommerce gère heureusement cette compatibilité descendante de façon transparente, à condition que la déclaration de compatibilité HPOS de cette extension tierce soit correcte.
Vérifier la compatibilité déclarée avant de migrer
Avant toute bascule HPOS sur un site avec des extensions tierces critiques, l’écran WooCommerce > Réglages > Avancé > Fonctionnalités affiche la liste des extensions incompatibles déclarées. Un connecteur qui n’a pas explicitement déclaré son support via FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__ ) est traité par défaut comme potentiellement incompatible, ce qui bloque l’activation du mode HPOS tant que ce n’est pas corrigé ou ignoré manuellement.
Sur un connecteur comptable, mieux vaut casser l’activation de HPOS que de laisser passer silencieusement une commande non synchronisée : la première option se voit immédiatement, la seconde coûte un rapprochement bancaire raté en fin de mois.
Prévention pour les prochaines montées de version
- Grep systématique de
shop_order,save_postetget_post_metasur tout connecteur avant chaque montée majeure de WooCommerce. - Ajout d’un environnement de recette avec HPOS activé, distinct de l’environnement de production encore en mode legacy.
- Déclaration explicite de compatibilité dans l’extension, même si aucun problème n’est identifié immédiatement.
En résumé
HPOS ne casse rien pour l’utilisateur final, mais déplace silencieusement le sol sous les pieds de toute extension qui accédait directement aux données de commande via les mécanismes WordPress génériques. Le passage par l’API WooCommerce officielle (wc_get_order(), méthodes de l’objet WC_Order) reste, et restera, le seul chemin réellement pérenne.