WooCommerce quantity limits: the Cart block ignored them, 11.2 fixes it
If your store limits quantities with a custom rule (no more than 5 clearance items, a cap for retail customers, a product sold one at a time), there is a good chance that rule only works in part of your carts. Since WooCommerce started pushing the block-based cart and checkout, two mechanisms coexist, and most snippets you find online only handle one of them.
Version 11.2 finally closes the gap. Here is what happens, and how to write a rule that holds in both cases.
Two carts, two entry points
The “classic” cart, the one rendered by the [woocommerce_cart] shortcode, validates every quantity change through the woocommerce_update_cart_validation filter. That is where custom rules have been hooked for years: add a message with wc_add_notice(), return false, and WooCommerce rejects the change.
The Cart block takes another route: the Store API, a REST API the block calls every time the shopper clicks the quantity selector. That route never fires woocommerce_update_cart_validation. Until 11.2, there was simply no equivalent to reject a quantity based on your own criteria. The result: a rule enforced in the classic cart could be bypassed in the Cart block, with no visible error for the shopper or for you.
The test takes two minutes. Add a product covered by your rule to the cart, open the cart page (block version), raise the quantity past the limit. If the cart accepts it, you are affected.
The new filter in WooCommerce 11.2
WooCommerce 11.2 adds woocommerce_store_api_cart_item_quantity_validation. It runs when a shopper changes the quantity of a cart line, or adds a product that is already in the cart. It runs after the core checks (minimum, maximum, multiple of).
Watch out for the trap: the rejection mechanism is different. Here, return false does nothing and the quantity is accepted. wc_add_notice() is ignored too. To reject, you must return a WP_Error object: the Store API then responds with a 400 error and the block shows your message to the shopper. In other words, copying your old callback onto the new filter gives you a rule that accepts everything, without a single warning.
Two more limits worth knowing. The filter does not run on the first add of a product to the cart (that is the job of the woocommerce_store_api_validate_add_to_cart action). And it can add rejections, but never loosen bounds declared elsewhere.
Fixed cap or conditional rule?
For a plain fixed cap per product, use woocommerce_store_api_product_quantity_maximum instead (along with its siblings _minimum and _multiple_of). These filters declare the bound up front: the block’s quantity selector respects it, so the shopper cannot even go past it. That is cleaner than an error message after the fact.
The new filter is meant for rules that depend on context: the rest of the cart, the logged-in customer, a date, stock shared between several products. That is the case in the example below.
One rule, two carts
Example: no more than 5 items in total from the “clearance” category, across all cart lines. The logic lives in a single function called by both filters. If the rule changes, you edit it in one place.
/**
* Custom rule: 5 items maximum from the "clearance" category.
* Returns an error message, or null if the quantity is accepted.
*/
function wba_clearance_quantity_error( WC_Product $product, int $quantity, string $cart_item_key ): ?string {
$category = 'clearance';
$max = 5;
$product_id = $product->get_parent_id() ?: $product->get_id();
if ( ! has_term( $category, 'product_cat', $product_id ) ) {
return null;
}
$total = $quantity;
foreach ( WC()->cart->get_cart() as $key => $item ) {
if ( $key === $cart_item_key ) {
continue; // The edited line is already counted via $quantity.
}
$id = $item['data']->get_parent_id() ?: $item['data']->get_id();
if ( has_term( $category, 'product_cat', $id ) ) {
$total += (int) $item['quantity'];
}
}
if ( $total > $max ) {
return sprintf( 'Clearance: %d items maximum per order.', $max );
}
return null;
}
// Cart block and Store API (WooCommerce 11.2+).
add_filter( 'woocommerce_store_api_cart_item_quantity_validation', function ( $valid, $quantity, $product, $cart_item ) {
$error = wba_clearance_quantity_error( $product, (int) $quantity, $cart_item['key'] ?? '' );
return $error ? new WP_Error( 'wba_clearance_quantity', $error ) : $valid;
}, 10, 4 );
// Classic cart (shortcode).
add_filter( 'woocommerce_update_cart_validation', function ( $passed, $cart_item_key, $values, $quantity ) {
$error = wba_clearance_quantity_error( $values['data'], (int) $quantity, $cart_item_key );
if ( $error ) {
wc_add_notice( $error, 'error' );
return false;
}
return $passed;
}, 10, 4 );
A few implementation notes. For a variation, the category belongs to the parent product, hence the get_parent_id(). The function skips the line being edited (by its key) so it is not counted twice. The error code passed to WP_Error is up to you, so make it descriptive: it is what shows up in the API response when you debug.
The snippet goes in a custom plugin or in a child theme’s functions.php. On versions older than 11.2, the first filter is never called: the code breaks nothing, it simply protects the classic cart only.
My advice
Search your theme and custom plugins for woocommerce_update_cart_validation (a grep -r is enough). Every match that rejects a quantity is a rule that currently only applies to the classic cart. Upgrade to 11.2 on a staging site, add the Store API counterpart, then run the Cart block test again. If these limits come from a marketplace extension, check that it claims compatibility with the Cart and Checkout blocks: that is not always the case.
Want me to review your cart rules? Let’s talk.
Need a WooCommerce store audit?
I'll send you a personalized report with the top priorities to improve. Free, no strings attached.