WooCommerce provides a built-in coupon system that, at first glance, seems flexible enough for most online stores. However, when you try to implement real-world discounting rules—such as including or excluding specific products, brands, or categories—you quickly run into limitations. The system often fails to enforce inclusion and exclusion conditions correctly, leading to unintended discounts or coupons that simply don’t apply when they should.
Another major frustration arises when additional parameters are introduced. For example, if you require a coupon to apply only when a specific product is in the cart and only if the cart total meets a minimum price, WooCommerce’s default logic struggles to process these layered conditions properly. Instead of allowing these conditions to work together, the system frequently results in conflicts, forcing store owners to seek custom solutions.
In this article, I aim to demonstrate how you can surpass the limitations of traditional coupon systems and the constraints of coupon add-ons. By the end, you will feel empowered to create intricate promotions that reflect your vision.
Percent, Fixed, Cart, and BOGO discounts all together

Why the Default WooCommerce Coupon System Fails
- Inclusion & Exclusion Rules Are Unreliable
- WooCommerce’s built-in coupon system provides options to include or exclude certain products and categories, but these rules often don’t apply correctly.
- The validation mechanism frequently ignores brand-based exclusions, requiring workarounds to prevent unintended discounts.
- Stacking Multiple Conditions Causes Conflicts
- If you set a coupon to work only with a specific product and require a minimum cart amount, WooCommerce sometimes fails to validate both conditions simultaneously.
- Instead of smoothly integrating different rules, WooCommerce’s logic often prevents the coupon from applying altogether or allows it when it shouldn’t.
- Customizations Are Essential for a Fully Functional Coupon System
- Due to the limitations of WooCommerce’s default validation, store owners must manually adjust coupon behavior to enforce the intended rules.
- Overriding WooCommerce hooks is often necessary to ensure proper validation.
How to Fix WooCommerce’s Coupon System
To create a reliable and flexible coupon system, we need to:
Here’s how you can implement these fixes.
Example Coupon Validation
The following PHP code modifies WooCommerce’s coupon system to correctly apply inclusion and exclusion rules while ensuring multiple conditions work without conflicts.
/**
* Validate coupons based on inclusions and exclusions.
* Ensures WooCommerce applies discounts correctly based on brands, categories, and specific products.
*/
public function set_coupon_validity_for_excluded_products( $valid, $product, $coupon, $values ) {
$all_include_categories = [];
$all_exclude_categories = [];
/**
* Get the Product BRAND and CATEGORY
*/
$product_id = $product->is_type( 'variation' ) ? $product->get_parent_id() : $product->get_id();
$product_categories = wp_get_post_terms( $product_id, 'product_cat', array( 'fields' => 'ids' ) );
$product_brands = wp_get_post_terms( $product_id, 'product_brand', array( 'fields' => 'ids' ) );
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \\
/**
* Get the Coupon BRAND, CATEGORY and PRODUCT restictions
*/
// Brands
$include_coupon_brands = get_post_meta( $coupon->get_id(), 'product_brands', true );
$exclude_coupon_brands = get_post_meta( $coupon->get_id(), 'exclude_product_brands', true );
// Categories
$include_coupon_categories = $coupon->get_product_categories();
$exclude_coupon_categories = $coupon->get_excluded_product_categories();
// Products
$include_coupon_product_ids = $coupon->get_product_ids();
$exclude_coupon_product_ids = $coupon->get_excluded_product_ids();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \\
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Prevention ~~~~~~~~~~~~~~~~~~~~~~~~~~~ \\
// If no restrictions, return the validity
if ( ( ! count( $include_coupon_brands ) ) &&
( ! count( $exclude_coupon_brands ) ) &&
( ! count( $include_coupon_categories ) ) &&
( ! count( $exclude_coupon_categories ) ) &&
( null === $include_coupon_product_ids || ! count( $include_coupon_product_ids ) ) &&
( null === $exclude_coupon_product_ids || ! count( $exclude_coupon_product_ids ) ) ) {
return $valid;
}
$valid = false;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \\
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Inclusion ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \\
// Check if coupon has a brand inclusion and if this product has that brand attached.
if ( count( $include_coupon_brands ) && count( array_intersect( $product_brands, $include_coupon_brands ) ) ) {
$valid = true;
}
// Check if coupon has a category inclusion and if this product has that category attached.
if ( count( $include_coupon_categories ) ) {
$all_include_categories[] = $include_coupon_categories;
foreach ( $include_coupon_categories as $include_coupon_category ) {
$all_include_categories[] = get_term_children( $include_coupon_category, 'product_cat' );
}
$flat_cats = array_merge([], ...$all_include_categories);
if ( count( array_intersect( $product_categories, $flat_cats ) ) ) {
$valid = true;
}
}
// Check if coupon has a product inclusion and if this product is it.
if ( count( $include_coupon_product_ids ) && count( array_intersect( [$product->get_id()], $include_coupon_product_ids ) ) ) {
$valid = true;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \\
// ~~~~~~~~~~~~~~~~~~~~~~~~~~ Exclusion ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \\
// Check if coupon has a brand exclusion and if this product has that brand attached.
if ( count( $exclude_coupon_brands ) && count( array_intersect( $product_brands, $exclude_coupon_brands ) ) ) {
$valid = false;
}
// Check if coupon has a category exclusion and if this product has that category attached.
if ( count( $exclude_coupon_categories ) ) {
$all_exclude_categories[] = $exclude_coupon_categories;
foreach ( $exclude_coupon_categories as $exclude_coupon_categories ) {
$all_exclude_categories[] = get_term_children( $exclude_coupon_categories, 'product_cat' );
}
$flat_cats = array_merge([], ...$all_exclude_categories);
if ( count( array_intersect( $product_categories, $flat_cats ) ) ) {
$valid = false;
}
}
// Check if coupon has a product exclusion and if this product is it.
if ( count( $exclude_coupon_product_ids ) && count( array_intersect( [$product->get_id()], $exclude_coupon_product_ids ) ) ) {
$valid = false;
}
return $valid;
}
How This Fix Works
This is only one of many filters. I had to create another one that deals specifically with cart and item totals of the included or excluded products.
Final Thoughts
WooCommerce’s default coupon system may work for simple discounts, but as soon as you introduce exclusions, product-specific rules, or multi-condition validation, it quickly becomes unreliable. Instead of struggling with built-in limitations, store owners can extend WooCommerce’s functionality by dynamically managing required products and brand exclusions.
With the custom fields added to the coupon settings, administrators can now:
By integrating these changes, your WooCommerce store can finally have a fully functional coupon system that works reliably across different discounting scenarios. No more unexpected coupon errors or unintended discounts—just flexible, rules-based coupon functionality that actually does what you expect.