Web

WooCommerce Coupons: How They Work and When a Plugin Helps

Web · Published 2026-10-24

Pink and white price tags spilling out of a stack of fabric samples
Price tags spilling from a stack of fabric samples.

WooCommerce has a capable coupon system built in: percentage, fixed-cart and fixed-product discounts, free shipping, expiry dates, spend limits, product and email restrictions, and usage caps. You need an extension only for behavior core does not cover, such as auto-applied coupons, buy-one-get-one offers, store credit, gift cards or bulk code generation.

Turning coupons on

Coupons must be enabled under WooCommerce › Settings › General › Enable the use of coupon codes. When this is off, the coupon field disappears from cart and checkout and existing codes stop working. Coupons themselves are managed under Marketing › Coupons in current WooCommerce versions (they used to live under the WooCommerce menu). The official coupon management documentation covers each field; the summary below focuses on how they interact.

Discount types

TypeInternal valueWhat it does
Percentage discountpercentTakes a percentage off the eligible items in the cart.
Fixed cart discountfixed_cartTakes a fixed amount off the whole cart, spread across eligible items.
Fixed product discountfixed_productTakes a fixed amount off each eligible item, multiplied by quantity.

The difference between the two fixed types matters: 10 off with fixed_cart is 10 off the order; 10 off with fixed_product on a cart with three eligible items is 30 off. A discount never pushes an item below zero.

Free shipping is a checkbox, not a discount type. It only has an effect if a Free shipping method exists in the customer's shipping zone and its requirement is set to "A valid free shipping coupon" (or one of the combined options). A coupon can grant free shipping with a zero amount.

Usage restrictions and limits

The Usage restriction tab controls when a coupon is valid:

The Usage limits tab sets the total number of uses, uses per customer, and for fixed_product and percent coupons, the maximum number of items the discount applies to. The Coupon expiry date on the General tab is evaluated in the store's time zone; the admin field's own help text says the coupon expires at 00:00:00 of that date, so set it to the day after the last valid day. In code you can pass an exact timestamp, as in the example below.

Creating coupons programmatically

For campaigns, onboarding flows or integrations, create coupons with the WC_Coupon CRUD class rather than inserting posts directly. The setters map one-to-one to the admin fields, and save() runs the same data store logic the admin uses:

<?php
/**
 * Create a 15% coupon once, e.g. from a plugin activation hook or WP-CLI.
 */
function lb_create_autumn_coupon(): int {
    $code = 'AUTUMN15';

    // wc_get_coupon_id_by_code() returns 0 when the code does not exist.
    if ( wc_get_coupon_id_by_code( $code ) ) {
        return 0;
    }

    $coupon = new WC_Coupon();
    $coupon->set_code( $code );
    $coupon->set_discount_type( 'percent' );   // 'percent', 'fixed_cart' or 'fixed_product'
    $coupon->set_amount( 15 );
    $coupon->set_description( 'Autumn campaign, newsletter subscribers' );
    $coupon->set_date_expires( '2026-11-30 23:59:59' );
    $coupon->set_individual_use( true );       // cannot be combined with other coupons
    $coupon->set_exclude_sale_items( true );
    $coupon->set_minimum_amount( 50 );
    $coupon->set_usage_limit( 500 );           // total uses
    $coupon->set_usage_limit_per_user( 1 );
    $coupon->set_free_shipping( false );

    return $coupon->save();                    // returns the coupon (post) ID
}

Run code like this once (from a plugin, a WP-CLI command or an admin action), not on every page load. Amounts follow the store's currency; prices entered with or without tax follow your tax settings. To generate many unique codes, loop with a random suffix such as strtoupper( wp_generate_password( 8, false ) ) and check each against wc_get_coupon_id_by_code().

Applying a coupon from a URL

Core WooCommerce does not apply coupons from links. A small snippet in a site-specific plugin (or your theme's functions.php) adds it:

<?php
/**
 * Apply ?coupon=CODE from any URL, e.g. https://example.com/shop/?coupon=AUTUMN15
 */
add_action( 'wp_loaded', function () {
    if ( empty( $_GET['coupon'] ) || is_admin() || ! function_exists( 'WC' ) || ! WC()->cart ) {
        return;
    }

    $code = wc_format_coupon_code( wp_unslash( $_GET['coupon'] ) );

    // Guests have no session cookie until something is in the cart; start one
    // so the coupon survives until the customer adds a product.
    if ( WC()->session && ! WC()->session->has_session() ) {
        WC()->session->set_customer_session_cookie( true );
    }

    if ( ! WC()->cart->has_discount( $code ) ) {
        WC()->cart->apply_coupon( $code );     // adds a success or error notice itself
    }
} );

apply_coupon() validates the coupon like the cart form does and adds the usual success or error notice. One limitation: coupons with a minimum spend or product restrictions fail validation against an empty cart. For those, store the code in the session (WC()->session->set()) and apply it from a woocommerce_add_to_cart hook instead. If the link points to a cached page, see the caching note below.

Common problems

"Sorry, this coupon is not valid for sale items"

The coupon has Exclude sale items checked and the cart contains nothing else it could discount. Sale items are skipped when calculating the discount; when they are all the coupon could apply to, validation fails with this message. Uncheck the option or exclude specific products instead.

A second coupon removes the first

One of them has Individual use only enabled. That flag wins regardless of which coupon was applied first.

The coupon works for you but not for customers

Check allowed emails, the per-user limit (counted against both user ID and billing email), and the expiry date (see the 00:00:00 note above). Also check that the customer's currency or price display (with/without tax) matches the minimum spend you expect.

Coupons or notices behave oddly on cached sites

Cart, checkout and my-account pages must be excluded from full-page caching, and requests carrying WooCommerce session cookies should bypass the cache. Most managed WordPress hosts and caching plugins do this for the standard WooCommerce pages, but URL coupon parameters on other pages may be served from cache before PHP runs. Exclude the query parameter from caching or point coupon links at the cart page.

Free shipping coupon does nothing

No Free shipping method requiring a coupon exists in the zone that matches the customer's address.

When a coupon plugin helps

Extensions add behavior in a few recognizable categories:

Before installing anything, check whether a rule can be expressed with core restrictions, because every discount extension hooks into cart totals and they rarely coexist well. Use one discount plugin, not three.

Six widely used options

The following are long-established extensions, listed in no particular order. Feature sets change between versions, so confirm details on each product page and check compatibility with your WooCommerce version (8.x or newer at the time of writing, including the block-based cart and checkout) before buying.

  1. Smart Coupons (StoreApps, sold on the WooCommerce Marketplace): store credit and gift certificates, bulk coupon generation, auto-applied coupons and coupons sent after purchase.
  2. Advanced Coupons for WooCommerce (free core plugin with a premium tier): cart conditions, BOGO deals, auto-apply, URL coupons and scheduling, built around the standard coupon editor.
  3. URL Coupons (official WooCommerce Marketplace extension): gives a coupon a unique URL that applies it, optionally adding products to the cart and redirecting.
  4. Discount Rules for WooCommerce (Flycart): rule-based automatic discounts such as bulk pricing, cart-total tiers and BOGO, applied without codes.
  5. YITH WooCommerce Dynamic Pricing and Discounts: price rules by quantity, role, category or cart contents, an alternative to coupons for automatic promotions.
  6. WooCommerce Gift Cards (official WooCommerce extension): sells gift cards as products and lets customers redeem balances across orders, which is the right tool when you need prepaid value rather than a discount.

The first three extend coupons themselves; the next two replace coupons with automatic rules; the last covers prepaid balances. Picking the category first usually makes the choice obvious.

Summary

Enable coupons in the general settings, choose between percent, fixed_cart and fixed_product, and use restrictions and limits to control who can use a code and how often. Create coupons in code with WC_Coupon, apply them from links with WC()->cart->apply_coupon(), and when a coupon refuses to apply, check sale-item exclusion, individual use, email restrictions and caching first. Add a single extension only for features core lacks: auto-apply, BOGO, store credit or gift cards, and bulk generation.

Read next

More in Web