Le WordPress d'aujourd'hui, décodé pour les développeurs

E-commerce

wc_get_orders() contre une requête SQL directe : quand contourner l’API sur un très gros catalogue

Sur un rapport portant sur plusieurs centaines de milliers de commandes, wc_get_orders() commence à peser lourd. Une requête SQL directe change-t-elle vraiment la donne ?

Par WordPress Développement • 1 octobre 2023 • 5 min de lecture • Aucun commentaire
wc_get_orders() contre une requête SQL directe : quand contourner l'API sur un très gros catalogue

Un rapport agrégé sur trois cent mille commandes, exécuté une fois par nuit : à ce volume, la question de l’outil à utiliser cesse d’être théorique. wc_get_orders(), l’API haut niveau recommandée par WooCommerce, instancie un objet WC_Order complet pour chaque résultat, avec toutes ses lignes de commande, ses méta, et ses éventuels objets associés. Sur un tel volume, cette instanciation systématique devient le principal poste de coût en temps d’exécution et en mémoire.

La tentation de contourner l’API au profit d’une requête SQL directe contre les tables sous-jacentes se pose alors naturellement. Ce billet compare les deux approches sur ce cas concret, sans conclusion universelle valable pour tous les volumes.

Ce que fait réellement wc_get_orders()

Chaque appel à wc_get_orders() passe par la couche d’abstraction de stockage de WooCommerce, qui charge la commande, ses éléments de ligne, et ses métadonnées associées, indépendamment du mode de stockage actif sur le site. Cette abstraction garantit la cohérence des données et le déclenchement des hooks associés à la lecture, mais elle a un coût direct : pour un rapport qui n’a besoin que du total et de la date d’une commande, charger l’objet complet représente un travail largement disproportionné par rapport au besoin réel.

La requête SQL directe : plus rapide, mais plus fragile

L'essentiel à retenir : wc_get_orders() instancie un objet complet par commande, coûteux en mémoire ; Une requête SQL directe reste plus rapide mais ignore les hooks et la sécurité de l'API ; Le choix dépend du volume traité et du besoin réel d'objets complets

Une requête SQL directe, ciblant uniquement les colonnes nécessaires, réduit considérablement le volume de données chargées et le temps de traitement :

global $wpdb;

$resultats = $wpdb->get_results(
    "SELECT id, total_amount, date_created_gmt
     FROM {$wpdb->prefix}wc_orders
     WHERE status = 'wc-completed'
       AND date_created_gmt BETWEEN '2023-09-01' AND '2023-09-30'"
);

Cette requête cible directement la table wc_orders, utilisée lorsque le stockage haute performance des commandes est actif sur le site. Sur un site où ce mode n’est pas activé, les commandes restent stockées comme des articles, et la requête équivalente devrait interroger wp_posts et wp_postmeta à la place, avec une structure de requête sensiblement différente.

Ce que cette approche fait perdre

Contourner l’API expose à plusieurs risques concrets, à évaluer avant toute décision :

  • Aucun hook de lecture n’est déclenché, ce qui peut ignorer une logique métier ajoutée par une extension qui s’accroche normalement à la lecture d’une commande.
  • La requête cible une structure de table qui peut changer d’une version à l’autre de WooCommerce, contrairement à wc_get_orders() qui reste stable en façade même si le stockage sous-jacent évolue.
  • Aucune vérification de capacité utilisateur n’est appliquée automatiquement, contrairement à certains contextes d’utilisation de l’API haut niveau.
  • Le format des données retournées reste brut : pas de conversion de devise, pas de formatage de montant, tout doit être géré manuellement par le code appelant.

Comparatif synthétique

Critèrewc_get_orders()Requête SQL directe
Temps d’exécution sur 300 000 lignesÉlevé, croissant avec le nombre de méta chargéesNettement plus faible
Déclenchement des hooksOuiNon
Stabilité face aux évolutions de structureÉlevée, façade stableFaible, dépend du schéma exact
Sécurité et validationGérées par l’APIÀ la charge du développeur

Le compromis retenu sur ce rapport

La solution finalement adoptée n’a pas consisté à choisir un camp de façon définitive, mais à réserver la requête SQL directe à ce rapport spécifique, en lecture seule, sans aucune écriture ni logique métier sensible aux hooks. Le reste de l’application, notamment tout ce qui touche à la création ou à la modification de commandes, continue de passer intégralement par wc_get_orders() et les méthodes de WC_Order, sans exception.

Contourner l’API pour un rapport en lecture seule reste défendable si le volume le justifie réellement. Le faire pour modifier une commande, en revanche, revient à se priver des garanties que l’API existe précisément pour offrir.

Une question de volume, pas de principe

Sur un rapport portant sur quelques milliers de commandes, la différence de performance entre les deux approches reste rarement perceptible, et le confort de développement de wc_get_orders() l’emporte largement. La bascule vers une requête directe ne se justifie qu’à partir d’un volume où le temps d’exécution de l’API haut niveau devient lui-même un problème opérationnel, comme un rapport qui dépasserait la fenêtre de traitement nocturne allouée.

Notre verdict

Pour un rapport de lecture seule sur un volume très important, une requête SQL directe, ciblée et documentée, se justifie pleinement à condition de rester circonscrite à ce cas d’usage précis. Pour toute opération d’écriture, ou pour un volume plus modeste, wc_get_orders() reste le choix le plus sûr, et de loin le plus simple à maintenir dans la durée.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi