Aller au contenu principal
Making DigitalMaking Digital
Note technique

Exporter les produits, les variations et le chiffre d'affaires de WooCommerce

En bref

Pour un export ponctuel, l'exporteur CSV de WooCommerce sort chaque variation sur sa propre ligne avec le SKU du parent. Un connecteur lit /wp-json/wc/v3/products puis /products/{id}/variations, 100 par page au maximum. Pour le chiffre d'affaires, les commandes sont dans les tables HPOS depuis WooCommerce 8.2 : on passe par wc_get_orders() avec les statuts processing et completed, en déduisant les remboursements, plutôt que par du SQL sur wp_posts.

Votre logiciel de gestion ou un logisticien demande la liste de vos produits WooCommerce avec chaque variation et son code article (SKU), pour faire la correspondance avec ses références. En fin d'exercice, il faut aussi le chiffre d'affaires. Export ponctuel : l'exporteur CSV intégré. Connecteur : l'API REST. Script sur le serveur : wc_get_products() et wc_get_orders(). Le SQL sur wp_posts ne marche plus pour les commandes.

Comment exporter les produits et leurs variations sans code ?

L'exporteur intégré se trouve dans Products > All Products > Export. Il permet de choisir les colonnes, les types de produits et les catégories. Dans notre test, chaque variation sort sur sa propre ligne :

ID Type SKU Name Published Parent Attribute 1 name Attribute 1 value(s)
10 variable TSHIRT T-shirt coton bio 1 Taille L, M, S
11 variation TSHIRT-S T-shirt coton bio - S 1 TSHIRT Taille S
14 simple MUG Mug émaillé 1
15 simple CAP Casquette (brouillon) -1

La colonne Parent contient le SKU du parent. Attention : les brouillons sont exportés aussi (Published à -1).

Comment récupérer les produits et les variations par l'API REST ?

Un connecteur interroge la boutique sans accès au serveur, avec une clé API en lecture (WooCommerce > Settings > Advanced > REST API). Si elle répond 401, voir notre note sur l'erreur woocommerce_rest_cannot_view.

Terminal
# Produits publiés, 100 par page (le maximum accepté)
curl -u ck_xxx:cs_xxx "https://boutique.example/wp-json/wc/v3/products?status=publish&per_page=100&page=1"
# Variations d'un produit variable (ici le produit 10)
curl -u ck_xxx:cs_xxx "https://boutique.example/wp-json/wc/v3/products/10/variations?per_page=100"
  • Bouclez sur page jusqu'à la valeur de l'en-tête X-WP-TotalPages. Avec per_page=101, l'API répond 400 (per_page must be between 1 (inclusive) and 100 (inclusive)).
  • Un produit variable liste ses variations dans variations ([11, 12, 13] dans notre test) ; chacune porte sku, price, stock_quantity et attributes ({"name": "Taille", "option": "M"}).
  • Pour une synchronisation régulière, modified_after limite la réponse aux produits modifiés depuis une date.

Et en PHP, directement sur le serveur ?

Le script ci-dessous écrit une ligne par produit simple et par variation, avec le SKU du parent. Remplacez pa_taille par le slug de votre attribut.

PHP
<?php
// export-produits.php : one CSV row per simple product and per variation
$out = fopen('produits.csv', 'w');
fputcsv($out, ['product_id', 'variation_id', 'sku', 'parent_sku', 'name', 'taille', 'price', 'stock'], ';');

$page = 1;
do {
    $products = wc_get_products([
        'status' => 'publish',
        'limit'  => 100,
        'page'   => $page,
    ]);

    foreach ($products as $product) {
        if ($product->is_type('variable')) {
            foreach ($product->get_children() as $variation_id) {
                $variation = wc_get_product($variation_id);
                fputcsv($out, [
                    $product->get_id(),
                    $variation_id,
                    $variation->get_sku(),
                    $product->get_sku(),
                    $product->get_name(),
                    $variation->get_attribute('pa_taille'),
                    $variation->get_price(),
                    $variation->get_stock_quantity(),
                ], ';');
            }
        } else {
            fputcsv($out, [
                $product->get_id(), '', $product->get_sku(), '', $product->get_name(),
                '', $product->get_price(), $product->get_stock_quantity(),
            ], ';');
        }
    }
    $page++;
} while (count($products) === 100);

fclose($out);
Terminal
# Lancer le script depuis la racine du site
wp eval-file export-produits.php

Trois différences avec l'ancien script qui circule :

  • $product->product_type est obsolète (le code de WooCommerce le signale) : $product->is_type('variable') le remplace.
  • get_available_variations() saute des variations : celles en rupture si l'option "masquer les produits en rupture" est cochée, et celles désactivées ou sans prix. Pour un export complet, get_children() renvoie toutes les variations.
  • utf8_encode() est obsolète depuis PHP 8.2 (PHP 8.3 affiche Function utf8_encode() is deprecated) et inutile : les noms sont déjà en UTF-8. fputcsv() gère les guillemets et les séparateurs dans les noms.

Pourquoi l'ancienne requête SQL sur wp_posts ne renvoie plus rien ?

Depuis WooCommerce 8.2, les nouvelles boutiques stockent par défaut les commandes dans leurs propres tables (HPOS) : wp_wc_orders, wp_wc_order_addresses, wp_wc_order_operational_data et wp_wc_orders_meta. Dans notre boutique de test, wp_posts ne contenait plus que des lignes shop_order_placehold. L'ancienne requête (post_type = 'shop_order') renvoyait une erreur de syntaxe (virgule avant FROM, ERROR 1064), puis, corrigée, 0 ligne. Elle excluait en plus les commandes processing, pourtant payées.

La documentation de WooCommerce déconseille le SQL direct sur les commandes et renvoie vers wc_get_orders(). Pour connaître le stockage de votre boutique (installée par WP-CLI, la nôtre était sans HPOS, activé ensuite par wp wc hpos enable) :

Terminal
wp wc hpos status

Quelles commandes compter dans le chiffre d'affaires ?

Statut Signification (documentation WooCommerce) Dans le CA ?
pending reçue, aucun paiement Non
failed paiement refusé Non
on-hold en attente de confirmation du paiement (virement) À part, tant que le paiement n'est pas confirmé
processing payée, à expédier Oui
completed expédiée, terminée Oui
cancelled annulée Non
refunded remboursée en totalité Non (son remboursement l'annule)

Les outils de WooCommerce ne comptent pas la même chose. Analytics excluent par défaut pending, cancelled et failed, donc incluent on-hold. L'ancien rapport de l'API (/wp-json/wc/v3/reports/sales) compte completed, processing, on-hold et refunded. Et il place chaque remboursement à sa propre date : dans notre test, deux remboursements de janvier faits en octobre (24 €) apparaissaient en octobre, pas en janvier.

Deux façons de lire les remboursements

Vue commerciale : les commandes payées du mois, moins ce qui a été remboursé dessus. Vue comptable : les remboursements datés du mois où ils ont été faits. Choisissez avant de comparer deux chiffres.

Comment calculer le chiffre d'affaires en PHP, compatible HPOS ?

PHP
<?php
// chiffre-affaires.php : paid orders of the period, refunds deducted
$orders = wc_get_orders([
    'type'      => 'shop_order',
    'status'    => ['wc-processing', 'wc-completed'],
    'date_paid' => '2026-01-01...2026-01-31',
    'limit'     => -1,
]);

$ttc = $tva = $port = $rembourse = 0;
foreach ($orders as $order) {
    $ttc       += (float) $order->get_total();
    $tva       += (float) $order->get_total_tax();
    $port      += (float) $order->get_shipping_total();
    $rembourse += (float) $order->get_total_refunded();
}

printf("Commandes : %d\n", count($orders));
printf("CA TTC : %.2f (dont TVA %.2f, port %.2f)\n", $ttc, $tva, $port);
printf("Remboursements : %.2f\n", $rembourse);
printf("CA TTC net : %.2f\n", $ttc - $rembourse);

Sur notre jeu d'essai de janvier 2026, le script a retenu 4 des 9 commandes : 123,40 € TTC dont 2,40 € de TVA et 5 € de port, 12 € remboursés, soit 111,40 € net. Les statuts on-hold, pending, cancelled, failed et refunded sont restés dehors.

Pour la vue comptable, on interroge les remboursements, qui sont un type de commande :

PHP
<?php
// remboursements.php : refunds dated in the period (the accounting view)
$refunds = wc_get_orders([
    'type'         => 'shop_order_refund',
    'date_created' => '2026-10-01...2026-10-31',
    'limit'        => -1,
]);

$total = 0;
foreach ($refunds as $refund) {
    $total += (float) $refund->get_amount();
}
printf("Remboursements du mois : %d pour %.2f\n", count($refunds), $total);

date_paid accepte une plage AAAA-MM-JJ...AAAA-MM-JJ, dans le fuseau horaire du site. Sur une grosse boutique, remplacez 'limit' => -1 par une boucle sur 'page'. Côté API : /wp-json/wc/v3/orders?status=processing,completed&after=2026-01-01T00:00:00&before=2026-02-01T00:00:00 (dates de création) renvoie pour chaque commande total, total_tax et ses refunds.

Quand ces exports deviennent réguliers, un connecteur les remplace : il lit produits et commandes par l'API et les envoie au logiciel qui les attend.

À retenir
  • Export ponctuel : l'exporteur CSV intégré, variations en lignes avec le SKU du parent (brouillons compris).
  • Connecteur : /products puis /products/{id}/variations, 100 par page au maximum.
  • Commandes : wc_get_orders() ou l'API, jamais wp_posts depuis HPOS.
  • Chiffre d'affaires : processing + completed, moins les remboursements, en choisissant leur date.

Testé avec WordPress 7.1.3, WooCommerce 11.2.1 (HPOS activé), PHP 8.3.35, WP-CLI 2.12.0 et MariaDB 11.4.13.

Questions fréquentes

Faut-il une clé API en écriture pour exporter les produits ?

Non. Une clé en lecture suffit pour lister les produits, les variations et les commandes. Elle agit avec les droits de l'utilisateur WordPress auquel elle est rattachée.

Comment savoir si ma boutique utilise HPOS ?

La commande wp wc hpos status l'indique, avec l'état du mode de compatibilité. Dans du code, OrderUtil::custom_orders_table_usage_is_enabled() renvoie la même information.

Le chiffre d'affaires doit-il être calculé HT ou TTC ?

get_total() renvoie le total TTC, port compris. get_total_tax() contient la TVA des produits et celle du port : la différence des deux donne le total HT, port compris.

Pourquoi mon total ne correspond-il pas aux rapports de WooCommerce ?

Les rapports Analytics comptent aussi les commandes en attente (on-hold) et se basent par défaut sur la date de paiement. L'ancien rapport de l'API place les remboursements à leur propre date. Vérifiez ces trois points avant de comparer.

Making Digital

Nous connectons les logiciels des PME, automatisons leurs tâches répétitives et créons des assistants IA, depuis 2010. Nos articles partent de nos projets réels.

Notre parcours
Une question sur ce sujet ?

Parlons-en 30 minutes.

Vous saurez si votre problème se règle, comment, et en combien de temps. Sans engagement.

Un échange de 30 minutes, en visio ou par téléphone

Gratuit, sans engagement. On parle de votre problème, pas de technique.