Auto-apply coupon: how 209 lines of code replaced ~13,000

Before BFCM last year, on WooCommerce.com, we were running a third-party plugin to apply tiered discounts. That plugin worked, but it came with a lot of overhead.

So we investigated replacing it for BFCM.

The idea was simple: just use WooCommerce’s built-in coupon system with a small plugin that auto-applies the right coupon silently on cart recalculation. All the actual validation like usage limits, product restrictions, and expiry happens in WooCommerce, so we don’t reimplement anything.

Final result: +209 lines, -12,888 lines, and a simpler codebase 🙂

What the plugin does

  • Adds a checkbox to the coupon edit screen: “Apply coupon automatically”
  • On cart recalculation, fetches coupons marked with _auto_apply = yes (cached 12 hours, this helps with high-volume stores like WooCommerce.com), checks each via WC_Coupon::is_valid(), and applies or removes it silently (no notices shown to the customer)
  • Hides the coupon remove button in both block cart and classic checkout, to enforce BFCM discount
  • WooCommerce.com-specific: prevents BFCM coupons from applying to subscription renewals and other selected flows
// Get all auto-apply coupon codes.
$auto_apply_codes = $this->get_auto_apply_coupon_codes();

foreach ( $auto_apply_codes as $code ) {
	$coupon = new WC_Coupon( $code );

	// Skip if coupon doesn't exist or isn't marked for auto-apply.
	if ( ! $coupon->get_id() || ! $coupon->get_auto_apply() ) {
		continue;
	}

	$is_valid = $coupon->is_valid();

	// Remove if applied but no longer valid.
	if ( $this->has_discount( $code ) && ! $is_valid ) {
		$this->remove_coupon( $code );
	}

	// Apply if not applied but now valid.
	if ( ! $this->has_discount( $code ) && $is_valid ) {
		$this->apply_coupon( $code );
	}
}

The only tricky bit for the WooCommerce.com-specific implementation was the re-entrancy guard: applying a coupon triggers woocommerce_after_calculate_totals again, so we have a static $running flag to avoid the loop. Without that there was infinite recursion, so that one was fun to debug 🙂

BFCM 2025

The plugin got its first real test during BFCM 2025 (Nov 19 – Dec 2). Tens of thousands of completed orders across tens of thousands of unique customers, all three discount tiers (20/30/40%), and we had no coupon bugs nor any outages.

Working with WooCommerce coupons had other benefits as well, for example, multi-currency was handled out of the box. The numbers came out well too: refund rates dropped from 13.1% to 7.8%, and net cash per customer increased +25% YoY.

If you want to pull the same breakdown for a future sale (adjust or remove the coupon names):

SELECT
    oi.order_item_name                  AS coupon_code,
    COUNT(DISTINCT oi.order_id)         AS orders_with_coupon,
    COUNT(DISTINCT o.customer_id)       AS unique_customers
FROM wp_woocommerce_order_items oi
JOIN wp_wc_orders o ON oi.order_id = o.id
WHERE oi.order_item_type = 'coupon'
  AND oi.order_item_name IN ('sale-20%', 'sale-30%', 'sale-40%')
  AND o.date_created_gmt BETWEEN '2025-11-19 14:00:00' AND '2025-12-02 23:59:59'
  AND o.status IN ('wc-completed', 'wc-processing')
GROUP BY oi.order_item_name
ORDER BY orders_with_coupon DESC;

Open source

I filed a draft PR upstream: https://github.com/woocommerce/woocommerce/pull/61958. The WooCommerce.com-specific restrictions aren’t there, but the core mechanic _auto_apply (meta + silent apply/remove on cart recalculation) feels like something WooCommerce could support natively.

So, we’ve prioritized this in WooCommerce core, and it will ship in a future release. In the meantime, feel free to use the PR as a reference or as a starting point for your own mini-plugin.

What’s left

A few rough edges worth noting:

  • The _auto_apply meta lives in wp_postmeta. When coupon HPOS migration happens, this will need revisiting (see query in WC_Cart::get_auto_apply_coupon_codes)
  • WooCommerce.com specific implementation
    • The JS hides remove buttons by targeting specific block class names that could drift across WooCommerce versions
    • The BFCM coupon names are hardcoded with a filter, which is fine for now, but worth cleaning up if the plugin gets more general use

Moral of the story

Less code, less headaches.

WooCommerce’s coupon system is actually pretty powerful once you get out of its way. We had a whole plugin doing what a checkbox and 200 lines of PHP can do more reliably. The trade-off was clearly worth it.


2 responses to “Auto-apply coupon: how 209 lines of code replaced ~13,000”

  1. Wait… What? Why wasn’t this the standard approach into he first place? This seems incredibly obvious and I’m amazed a plugin was used for such functionality when you have developers in-house. Am I reading this correctly that it was implemented on WooCommerce.com?

  2. Brian Avatar

    Would love to see this feature in core!

Leave a Reply

Your email address will not be published. Required fields are marked *