Limites de quantité WooCommerce : le panier en blocs les ignorait, la 11.2 corrige ça

woocommerce panier blocs store-api php

Si votre boutique limite les quantités avec une règle maison (pas plus de 5 articles en déstockage, un plafond pour les particuliers, un produit vendu à l’unité), il y a de bonnes chances que cette règle ne fonctionne que dans une partie de vos paniers. Depuis que WooCommerce pousse le panier et le tunnel de commande en blocs, deux mécaniques cohabitent, et la plupart des snippets qui circulent n’en couvrent qu’une.

La version 11.2 comble enfin le trou. Voici ce qui se passe, et comment écrire une règle qui tient dans les deux cas.

Deux paniers, deux portes d’entrée

Le panier « classique », celui du shortcode [woocommerce_cart], valide chaque changement de quantité via le filtre woocommerce_update_cart_validation. C’est là que se branchent depuis des années les règles sur mesure : on ajoute un message avec wc_add_notice(), on renvoie false, et WooCommerce refuse la modification.

Le panier en blocs passe par un autre chemin : la Store API, une API REST que le bloc appelle à chaque clic sur le sélecteur de quantité. Ce chemin ne déclenche jamais woocommerce_update_cart_validation. Jusqu’à la 11.2, il n’existait aucun équivalent pour refuser une quantité sur un critère maison. Résultat : une règle respectée dans le panier classique pouvait être contournée dans le panier bloc, sans aucune erreur visible, ni pour le client ni pour vous.

Le test prend deux minutes. Ajoutez au panier un produit concerné par votre règle, ouvrez la page panier (en blocs), montez la quantité au-delà de la limite. Si le panier l’accepte, vous êtes concerné.

Le nouveau filtre de WooCommerce 11.2

WooCommerce 11.2 ajoute woocommerce_store_api_cart_item_quantity_validation. Il s’exécute quand un client modifie la quantité d’une ligne du panier, ou quand il ajoute à nouveau un produit déjà présent. Il passe après les contrôles natifs (minimum, maximum, multiple de).

Attention au piège : la mécanique de refus change. Ici, return false ne fait rien, la quantité est acceptée. wc_add_notice() n’est pas lu non plus. Pour refuser, il faut renvoyer un objet WP_Error : la Store API répond alors par une erreur 400 et le bloc affiche votre message au client. Autrement dit, recopier votre ancien callback sur le nouveau filtre donne une règle qui accepte tout, sans le moindre avertissement.

Deux autres limites à connaître. Le filtre ne s’exécute pas au premier ajout d’un produit au panier (c’est le rôle de l’action woocommerce_store_api_validate_add_to_cart). Et il peut ajouter des refus, jamais assouplir les bornes déclarées ailleurs.

Plafond fixe ou règle conditionnelle ?

Pour un simple plafond fixe par produit, mieux vaut passer par woocommerce_store_api_product_quantity_maximum (et ses cousins _minimum et _multiple_of). Ces filtres déclarent la borne directement : le sélecteur de quantité du bloc la respecte, le client ne peut même pas la dépasser. C’est plus propre qu’un message d’erreur après coup.

Le nouveau filtre sert aux règles qui dépendent du contexte : le reste du panier, le client connecté, une date, un stock partagé entre plusieurs produits. C’est le cas de l’exemple ci-dessous.

Une règle, deux paniers

Exemple : pas plus de 5 articles au total dans la catégorie « destockage », toutes lignes confondues. La logique vit dans une seule fonction, appelée par les deux filtres. Si la règle change, on la modifie à un seul endroit.

/**
 * Règle maison : 5 articles maximum dans la catégorie « destockage ».
 * Renvoie un message d'erreur, ou null si la quantité est acceptée.
 */
function wba_erreur_quantite_destockage( WC_Product $product, int $quantity, string $cart_item_key ): ?string {
	$categorie = 'destockage';
	$max       = 5;

	$produit_id = $product->get_parent_id() ?: $product->get_id();
	if ( ! has_term( $categorie, 'product_cat', $produit_id ) ) {
		return null;
	}

	$total = $quantity;
	foreach ( WC()->cart->get_cart() as $key => $item ) {
		if ( $key === $cart_item_key ) {
			continue; // La ligne modifiée est déjà comptée via $quantity.
		}
		$id = $item['data']->get_parent_id() ?: $item['data']->get_id();
		if ( has_term( $categorie, 'product_cat', $id ) ) {
			$total += (int) $item['quantity'];
		}
	}

	if ( $total > $max ) {
		return sprintf( 'Déstockage : %d articles maximum par commande.', $max );
	}
	return null;
}

// Panier en blocs et Store API (WooCommerce 11.2+).
add_filter( 'woocommerce_store_api_cart_item_quantity_validation', function ( $valid, $quantity, $product, $cart_item ) {
	$erreur = wba_erreur_quantite_destockage( $product, (int) $quantity, $cart_item['key'] ?? '' );
	return $erreur ? new WP_Error( 'wba_quantite_destockage', $erreur ) : $valid;
}, 10, 4 );

// Panier classique (shortcode).
add_filter( 'woocommerce_update_cart_validation', function ( $passed, $cart_item_key, $values, $quantity ) {
	$erreur = wba_erreur_quantite_destockage( $values['data'], (int) $quantity, $cart_item_key );
	if ( $erreur ) {
		wc_add_notice( $erreur, 'error' );
		return false;
	}
	return $passed;
}, 10, 4 );

Quelques détails de mise en œuvre. Pour une variation, la catégorie est portée par le produit parent, d’où le get_parent_id(). La fonction exclut la ligne en cours de modification (via sa clé) pour ne pas la compter deux fois. Le code d’erreur passé à WP_Error est libre, choisissez-le parlant : c’est lui qui apparaît dans la réponse de l’API quand vous déboguez.

Le snippet se place dans une extension maison ou dans le functions.php d’un thème enfant. Sur une version antérieure à 11.2, le premier filtre n’est jamais appelé : le code ne casse rien, il protège seulement le panier classique.

Mon conseil

Cherchez woocommerce_update_cart_validation dans votre thème et vos extensions maison (un grep -r suffit). Chaque occurrence qui refuse une quantité est une règle qui ne s’applique aujourd’hui qu’au panier classique. Passez en 11.2 sur une préproduction, ajoutez le pendant Store API, puis refaites le test du panier bloc. Si ces limites viennent d’une extension du marché, vérifiez qu’elle annonce la compatibilité avec les blocs Panier et Commande : ce n’est pas toujours le cas.

Vous voulez que je passe vos règles de panier en revue ? Parlons-en.

Besoin d'un audit de votre boutique WooCommerce ?

Je vous envoie un diagnostic personnalisé avec les points à améliorer en priorité. Gratuit, sans engagement.

Articles connexes