How to Let Customers Buy Products With Points Only in WooCommerce

This is the technical reference for buying products with points only. It documents the exact settings, the discount calculation, the redemption lifecycle, and the hooks available for customization. It applies identically to both Points and Rewards for WooCommerce and Loyalty Program for WooCommerce, which share the same points engine.

For a plain-language overview aimed at store owners, see the blog article How to Let Customers Buy Products With Points Only in WooCommerce. For the reward-catalog setup specifically, see Redeem Points for Free Products.

Two Redemption Paths

Path Mechanism Scope
Points-only products A product flag converts the product price into a points cost paid at checkout. Per product or per variation.
Pay with points at checkout A virtual cart discount coupon generated from the points the customer chooses to redeem. Whole cart, up to the cart total.

Checkout Redemption: How It Works Internally

When a customer redeems points at the cart or checkout, the plugin does not create a real WooCommerce coupon post. It generates a virtual coupon whose code is prefixed with loyalty_points_, stores it in a transient and the WooCommerce session, and materializes it on the fly through the woocommerce_get_shop_coupon_data filter.

  • The coupon uses a fixed cart discount type and is applied before tax.
  • It sets individual_use = false and carries no product, category, or sale-item restrictions, so it discounts the whole cart.
  • Two filters (woocommerce_apply_with_individual_use_coupon and woocommerce_apply_individual_use_coupon) force the points coupon to coexist with individual-use coupons, so points stack with normal coupons.

Discount Formula

The discount value for a given number of points is:

discount = ( points / conversionRate.points ) * conversionRate.value

The result is then capped at the cart total. If includeShipping is off, the shipping total and shipping tax are subtracted before the cap, so points discount goods only. When the discount is capped at the cart total, the points charged are recalculated (rounded up) to match the capped amount, so the customer is never over-charged points for a zeroed-out order.

Settings Reference

All values below live in the option wpgens_loyalty_points_settings.

Key Type Default Purpose
conversionRateEnabled bool false Master toggle. Checkout redemption is disabled until this is true.
conversionRate.points int 1 Points side of the ratio.
conversionRate.value number 1 Currency value for those points. Default ratio is 1 point = 1 currency unit.
conversionRate.minPoints int 1 Minimum points a customer can redeem at once.
conversionRate.maxPoints int 1000 Maximum points redeemable per order. This is the main cap on how much of an order points can cover.
conversionRate.includeShipping bool false Whether points can discount shipping as well as goods.
autoOpenPointsRedemption bool false Auto-expands the redemption panel at checkout.
showPointsRedemptionOnCart bool false Shows the redemption panel on the cart page, not only checkout.

Enabling a Full Order Paid in Points

There is no dedicated 100 percent toggle. A full order paid in points is an emergent result of three conditions: conversionRateEnabled is true, maxPoints is high enough that it no longer binds, and the customer holds enough points. Raise maxPoints so that the cart total and the customer balance, rather than the cap, become the limiting factors. With the defaults (1:1 ratio, maxPoints = 1000), the most any order can be discounted is 1000 currency units.

Redemption Lifecycle and Order Meta

  1. Customer applies points. The virtual coupon is added to the session (classic checkout via AJAX, block checkout via the Store API handlers handle_apply_points_discount / handle_remove_points_discount).
  2. On the order-review stage the discount is validated again through woocommerce_check_cart_items.
  3. Points are deducted from the balance only when the order is processed, on woocommerce_checkout_order_processed (classic) or woocommerce_store_api_checkout_order_processed (blocks).

The following meta is written to the order for reporting and refunds:

Order meta key Value
_wpgens_loyalty_points_redeemed Number of points spent.
_wpgens_loyalty_points_discount_amount Currency amount discounted.
_wpgens_loyalty_points_user_id User whose balance was charged.

When includeShipping is enabled, the shipping portion of the discount is applied as a negative fee via woocommerce_cart_calculate_fees rather than through the coupon.

Hooks and Filters Reference

Hook Type Signature Use
wpgens_loyalty_can_apply_points_at_checkout filter ($can_apply = true, $user_id, $points, $conversion_rate) Gate redemption. Return a WP_Error to block it with a message. This is the primary hook for custom caps (for example, limit by cart subtotal).
wpgens_loyalty_calculate_points_discount filter ($discount_amount, $points, $conversion_rate) Adjust the computed discount, for example to apply a product-level multiplier.
wpgens_loyalty_points_redeemed_at_checkout action ($user_id, $points, $amount, $order_id, $order) Run custom logic after points are redeemed on an order.
wpgens_loyalty_show_points_redemption_block filter ($show) Show or hide the redemption UI programmatically.

A worked example of capping redemption per order using wpgens_loyalty_can_apply_points_at_checkout is documented in Limit Points Redemption Based on Cart Total. Redemption UI is also role-gated through the allowed-roles setting.

Points-Only Products

Points-only products are configured on the product itself, not in the global settings. Open a product, go to the Loyalty Points tab in the Product data box, and tick Points-Only Purchase. The points cost defaults to the product price times your conversion rate, or you can set a custom rate for a fixed cost. Variable products expose the same checkbox per variation.

See Redeem Points for Free Products for the complete product-level walkthrough.

Is checkout redemption a real WooCommerce coupon?

No. It is a virtual coupon prefixed with loyalty_points_ that exists only in a transient and the WooCommerce session, materialized through the woocommerce_get_shop_coupon_data filter. No shop_coupon post is created.

Which option stores the conversion rate and caps?

The option wpgens_loyalty_points_settings holds conversionRateEnabled, the conversionRate array (points, value, minPoints, maxPoints, includeShipping), and the display toggles. It is shared by both the Points and Rewards and Loyalty Program plugins.

How do I cap how many points can be redeemed per order in code?

Hook wpgens_loyalty_can_apply_points_at_checkout and return a WP_Error when the requested points exceed your rule. It receives the user ID, requested points, and conversion rate, so you can enforce percentage or cart-size limits.

When are points actually deducted from the balance?

Only when the order is processed, on woocommerce_checkout_order_processed for classic checkout or woocommerce_store_api_checkout_order_processed for block checkout. Previewing the discount in the cart does not deduct points.

Browse our plugins

Lightweight WooCommerce plugins built for speed. No bloat, no frameworks -- just clean code that works.

View all plugins
Stay in the loop

Get notified when we launch new plugins. No spam, just product updates.