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

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ère | wc_get_orders() | Requête SQL directe |
|---|---|---|
| Temps d’exécution sur 300 000 lignes | Élevé, croissant avec le nombre de méta chargées | Nettement plus faible |
| Déclenchement des hooks | Oui | Non |
| Stabilité face aux évolutions de structure | Élevée, façade stable | Faible, dépend du schéma exact |
| Sécurité et validation | Gé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.