Un développeur reçoit une mission a priori simple : exposer le catalogue WooCommerce d’un client à Google Shopping. Les extensions génériques de génération de flux existent en nombre, mais celle testée en premier sur ce projet ne gérait pas correctement les identifiants GTIN absents pour une partie du catalogue fabriqué en petite série, ni la distinction entre produits neufs et produits reconditionnés vendus sur la même boutique. Plutôt que de contourner ces limites avec des réglages bricolés, la décision a été de construire un générateur de flux XML sur mesure, directement depuis les données produit WooCommerce. Ce billet ne traite pas la configuration du compte Google Merchant Center lui-même, uniquement la construction technique du flux côté boutique.
Le format attendu par Google Shopping
Google Merchant Center attend un flux respectant la structure RSS 2.0 étendue par l’espace de noms g:, avec un ensemble d’attributs obligatoires (identifiant, titre, description, lien, image, disponibilité, prix) et des attributs conditionnels selon la catégorie de produit, comme le GTIN ou le genre pour les vêtements.
Générer le squelette XML

La génération s’appuie sur XMLWriter, plus robuste qu’une concaténation de chaînes pour éviter les problèmes d’échappement sur des titres ou descriptions produit contenant des caractères spéciaux :
function catalogue_generer_flux_google_shopping() {
$writer = new XMLWriter();
$writer->openMemory();
$writer->startDocument( '1.0', 'UTF-8' );
$writer->startElementNs( null, 'rss', null );
$writer->writeAttribute( 'version', '2.0' );
$writer->writeAttributeNs( 'xmlns', 'g', null, 'http://base.google.com/ns/1.0' );
$writer->startElement( 'channel' );
$writer->writeElement( 'title', get_bloginfo( 'name' ) );
$writer->writeElement( 'link', home_url( '/' ) );
$produits = wc_get_products( array(
'status' => 'publish',
'limit' => -1,
) );
foreach ( $produits as $produit ) {
catalogue_ecrire_item_flux( $writer, $produit );
}
$writer->endElement();
$writer->endElement();
$writer->endDocument();
return $writer->outputMemory();
}
Mapper chaque attribut produit
Le cœur du travail se situe dans le mapping entre les données WooCommerce et les attributs exigés par Google, notamment pour la disponibilité et la condition du produit, deux valeurs codifiées différemment côté Google et côté WooCommerce :
function catalogue_ecrire_item_flux( XMLWriter $writer, $produit ) {
$writer->startElement( 'item' );
$writer->writeElement( 'g:id', (string) $produit->get_id() );
$writer->writeElement( 'title', $produit->get_name() );
$writer->writeElement( 'link', get_permalink( $produit->get_id() ) );
$writer->writeElement( 'g:image_link', wp_get_attachment_url( $produit->get_image_id() ) );
$writer->writeElement( 'g:availability', $produit->is_in_stock() ? 'in stock' : 'out of stock' );
$writer->writeElement( 'g:price', $produit->get_regular_price() . ' EUR' );
if ( $produit->is_on_sale() ) {
$writer->writeElement( 'g:sale_price', $produit->get_sale_price() . ' EUR' );
}
$condition = $produit->get_meta( '_condition_produit' );
$writer->writeElement( 'g:condition', $condition ? $condition : 'new' );
$gtin = $produit->get_meta( '_gtin' );
if ( $gtin ) {
$writer->writeElement( 'g:gtin', $gtin );
} else {
$writer->writeElement( 'g:identifier_exists', 'no' );
}
$writer->endElement();
}
La clause g:identifier_exists réglée sur no en l’absence de GTIN évite un rejet pur et simple du produit par Merchant Center, une subtilité de la spécification facile à manquer et qui a bloqué une bonne partie du catalogue lors des premiers tests.
Publier le flux à une URL stable
Le flux se sert via une réécriture d’URL dédiée plutôt qu’un fichier statique régénéré manuellement, ce qui garantit que Merchant Center récupère toujours une version à jour :
add_action( 'init', function() {
add_rewrite_rule( '^flux-google-shopping\.xml$', 'index.php?flux_google_shopping=1', 'top' );
} );
add_filter( 'query_vars', function( $vars ) {
$vars[] = 'flux_google_shopping';
return $vars;
} );
add_action( 'template_redirect', function() {
if ( get_query_var( 'flux_google_shopping' ) ) {
header( 'Content-Type: application/xml; charset=utf-8' );
echo catalogue_generer_flux_google_shopping();
exit;
}
} );
Éviter de régénérer le flux à chaque appel de Merchant Center
Générer l’intégralité du flux à chaque requête de Merchant Center, sur un catalogue de plusieurs milliers de produits, devient rapidement coûteux en temps de réponse. Une régénération planifiée toutes les six heures, stockée en fichier statique dans les uploads, résout ce problème sans complexifier la logique de génération elle-même :
as_schedule_recurring_action(
time(),
6 * HOUR_IN_SECONDS,
'catalogue_regenerer_flux_shopping',
array(),
'catalogue-flux'
);
add_action( 'catalogue_regenerer_flux_shopping', function() {
$upload_dir = wp_upload_dir();
file_put_contents(
$upload_dir['basedir'] . '/flux-google-shopping.xml',
catalogue_generer_flux_google_shopping()
);
} );
Ce qu’il reste à surveiller après mise en ligne
- Le rapport de diagnostic de Merchant Center signale les produits rejetés et le motif exact, souvent plus précis qu’une supposition a priori.
- Un changement de prix côté catalogue met jusqu’à la prochaine régénération planifiée à se refléter dans le flux, un délai à documenter clairement pour le client.
- Les produits variables demandent un item distinct par variation exposée à la vente, avec un identifiant propre à chaque combinaison.
Une vérification qui a évité une déconvenue sur ce projet : valider le flux généré avec un validateur XML strict avant la première soumission, un simple caractère mal échappé dans une description produit suffisant à invalider l’ensemble du fichier aux yeux de Merchant Center.
Pour aller plus loin
Construire son propre générateur de flux demande davantage de rigueur qu’une extension clé en main, mais offre un contrôle total sur le mapping des attributs les plus spécifiques au métier du client, là où une extension générique impose souvent des compromis mal adaptés à un catalogue qui sort de l’ordinaire.