Skip to content
ThemesIonic — home
WooCommerce

WooCommerce Subscriptions

A subscription is a schedule that generates renewal orders. Everything that goes wrong — missed renewals, failed payments, silent cancellations — traces back to the scheduler, the gateway's tokens, or both.

5 min read intermediate

The model in one sentence: a subscription is a record with a billing schedule, and each billing cycle produces a normal WooCommerce order linked back to it. Renewals are not a special payment path — they are orders created by a scheduler and paid with a token the gateway is holding.

Hold onto that. Every common failure is one of three things: the scheduler did not run, the gateway could not charge the saved method, or the subscription's status no longer matches what the customer believes.

Statuses, and what each one means

Status Meaning Access to content or product
Pending Created, first payment not completed No
Active Paid and scheduled Yes
On hold Payment failed or manually suspended No
Pending cancellation Cancelled, paid period still running Yes, until the period ends
Cancelled Ended No
Expired Reached its natural end date No

On hold is the one that generates support tickets. To the customer nothing happened — no email they noticed, no cancellation they requested — and access is gone. Whatever else you configure, configure the emails around that transition.

Automatic versus manual renewals

Automatic renewal requires the gateway to store a token or reference against the customer, so the store can charge later without the card being present. Gateways that do not support this can still sell subscriptions, but every renewal becomes an invoice the customer pays by hand, and manual renewal churn is dramatically higher.

Before launching, confirm with the gateway:

  • tokenised or reference payments are supported and enabled on your account;
  • renewals that trigger a bank authentication challenge can prompt the customer rather than failing silently;
  • the account is not in a test mode that quietly declines live renewals;
  • refunds and partial refunds on renewal orders behave sensibly.

There is also a store-wide setting for manual renewal payments. Leaving it on when your gateway supports automatic renewals is a self-inflicted churn problem worth checking before you debug anything else.

The scheduler is the usual culprit

Renewals are queued as scheduled actions in the database and processed when something triggers the queue. Two things break that chain:

WP-Cron does not fire. WordPress's scheduler runs on page loads. A low-traffic store may go hours without one, so renewals due at 03:00 process late or not at all. Replace it with a real system cron:

# Disable the request-triggered scheduler in wp-config.php
define('DISABLE_WP_CRON', true);
# Then run it on a schedule, every five minutes
*/5 * * * * cd /path/to/site && wp cron event run --due-now >/dev/null 2>&1

The full swap is described in how to disable WP-Cron.

The action queue is stalled. Check WooCommerce → Status → Scheduled Actions for a growing pile of pending actions with past dates, or actions stuck in in-progress. A queue that never drains usually means a fatal error inside one action, a PHP timeout on a large batch, or an object cache serving stale data. Turn on debug mode and read the log before changing settings.

Failed payments

Cards expire, banks decline, balances run out. A store without a retry schedule loses those customers permanently for a reason none of them chose.

Configure, in this order:

  1. A retry schedule — several attempts spread over days, not hours. Banks decline repeated same-day retries as suspicious.
  2. A customer email at the first failure that says what happened and links straight to the payment-method update page. Not a generic "there was a problem".
  3. A grace period where access continues while retries run, if the product allows it.
  4. A final notice before the subscription is cancelled.

Then confirm those emails actually leave the server. Subscription email is transactional and silence is expensive — WooCommerce emails not sending covers the diagnosis, and sending through authenticated SMTP rather than PHP mail is the baseline.

Signup fees, trials and prorating

  • Free trials delay the first payment. Decide whether a card is captured up front; capturing it converts far better at renewal, and deters casual signups.
  • Signup fees are charged with the first order only.
  • Synchronised renewals bill everyone on the same day of the month, which simplifies fulfilment for box products and complicates the first, prorated period.
  • Switching between plans mid-period needs an explicit proration policy. Decide what happens to the unused remainder before a customer asks, and write it into the plan descriptions.

Each of these interacts with tax and with your refund policy. Test them with real amounts on a staging site in the gateway's sandbox.

Subscriptions and caching

Nothing about a subscriber's account page can be cached. Make sure cart, checkout, my-account and any early-renewal endpoints are excluded from page caching, and prefer object caching for the logged-in experience — the layers are set out in choosing a WordPress cache plugin. A cached account page that shows one customer another customer's subscription is the worst bug in this entire area, and it comes from a missing exclusion, not from the subscription plugin.

If account endpoints return 404s or blank pages rather than stale ones, the problem is routing rather than caching — see WooCommerce endpoints not working.

Diagnosing a renewal that never happened

Work in this order and stop when something is wrong:

  1. Open the subscription. Is the next payment date in the past, and is the status active?
  2. Check Scheduled Actions for that subscription's renewal action. Pending, failed, or absent?
  3. Is the queue processing at all — are unrelated actions completing?
  4. Is a payment token still stored against the subscription, or was the customer's saved method deleted?
  5. Does the gateway's own dashboard show a declined attempt? If so, this is a payment problem, not a WooCommerce one.
  6. Was a renewal order created but never paid? That points at the gateway integration rather than the scheduler.

Before you launch

Place a real subscription with a real card, then force an early renewal and watch the whole chain: the renewal order is created, the gateway charges, the status stays active, the customer email arrives, and access continues. Then do it again with a card designed to decline, and confirm the hold, the retry, the email and the eventual recovery when the customer updates their payment method.

Both paths matter. Most stores test the first one only, and discover the second one from an angry customer months later.

Frequently asked

Almost always the scheduler. Renewals are queued as scheduled actions that need to be triggered regularly; on a low-traffic site WP-Cron may not fire often enough, and a stalled action queue leaves renewals sitting as pending forever.
No. The gateway must support tokenised or reference payments so the store can charge a saved payment method later. Gateways without that support only allow manual renewal, where the customer pays each invoice by hand.
The subscription goes on hold and a retry schedule runs if one is configured. Without retries, a single declined card ends the subscription permanently even though the customer never intended to cancel.

Related guides