Skip to content
Products
AI Website Builder New VPS Hosting Cloud Servers Web Hosting Dedicated Servers Domains
Company
About Documentation Support Center Contact Get Started Call +91 75795 45488
Login
Hosting Panel — cPanel & Billing Console Panel — VPS Management
ALL SYSTEMS OPERATIONAL
Troubleshooting

WooCommerce Subscription Renewals Failing? The Real Fix

Getwebup 5 min read

If WooCommerce Subscriptions has started skipping renewals - orders stuck on "On hold," customers not charged, or subscriptions silently flipping to "Cancelled" - the checkout itself is usually fine. Renewals run in the background with no customer present, and that's exactly where they break. Here's how to find out which of the four usual causes you're dealing with, and fix it without re-billing anyone twice.

What "Renewal Failed" Actually Looks Like

A few symptoms tend to show up together, and it's worth telling them apart before you start changing settings:

  • A subscription's next payment date comes and goes, but no renewal order is ever created.
  • A renewal order is created, but it sits on "Pending" or "Failed" forever.
  • The customer gets charged on their bank statement but WooCommerce still shows the subscription as unpaid.
  • Renewals worked fine for months, then stopped all at once after a plugin or gateway update.

Each of those points at a different layer - cron, the stored payment method, the card itself, or the webhook that tells WooCommerce the charge succeeded.

Cause 1: WP-Cron Never Fires the Renewal

WooCommerce Subscriptions schedules renewals through WP-Cron, and WP-Cron only runs when someone visits the site. On a low-traffic subscription site - or one behind aggressive full-page caching that serves cached HTML without ever loading PHP - the renewal event can sit queued for days without triggering.

Check what's actually scheduled:

wp cron event list --fields=hook,next_run_relative | grep subscription

If you see woocommerce_scheduled_subscription_payment events sitting well past their "next run" time, cron isn't firing on schedule. That's the problem, not the payment gateway.

Cause 2: No Stored Payment Token for Automatic Renewal

Automatic renewals need a saved, tokenized payment method on file - not the one-time transaction ID from the original checkout. If a customer paid via a gateway that doesn't support tokenization for your setup (or they checked out before you enabled "Save payment method" support), WooCommerce Subscriptions has nothing to charge and quietly falls back to "manual renewal," which just waits for the customer to pay themselves.

In WooCommerce, open the subscription and check the Payment box in the sidebar. If it says "Manual Renewal" instead of naming a gateway and a token, that's your answer.

Cause 3: The Card Was Actually Declined

Sometimes this one is just true - expired card, insufficient funds, or the issuing bank blocking a recurring charge it doesn't recognize. The difference from the causes above is that WooCommerce did attempt the charge and got a real decline response back from the gateway.

Check WooCommerce > Status > Logs and pull the log file for your gateway (named something like woocommerce-gateway-stripe-2026-07-28.log). A genuine decline shows a specific reason code from the processor - card_declined, insufficient_funds, expired_card - rather than a connection error or timeout.

Cause 4: The Webhook Never Reaches Your Site

Some gateways (Stripe, Razorpay, PayPal) confirm a successful renewal asynchronously via webhook, separate from the initial API call. If that webhook is blocked - by ModSecurity, an IP allowlist that's gone stale, or a WAF rule your CDN added after a security update - the charge succeeds on the gateway's side but WooCommerce never finds out, and the order stays "Pending" indefinitely.

Confirm this quickly in your gateway's dashboard: look up the transaction by amount and date. If it shows as successful there but the WooCommerce order still says pending, the webhook is the broken link, not the card or the cron schedule.

The Fix, Step by Step

1. Get WP-Cron running reliably

Disable the request-triggered cron and replace it with a real system cron entry, so renewals fire on schedule regardless of traffic:

// wp-config.php
define( 'DISABLE_WP_CRON', true );

Then add this in cPanel under Cron Jobs, running every 15 minutes:

*/15 * * * * php /home/username/public_html/wp-cron.php >/dev/null 2>&1

2. Fix the missing payment token

You can't retroactively tokenize an old transaction. The customer needs to re-enter their card once through My Account > Subscriptions > [subscription] > Change Payment Method. After that, future renewals go through automatically again.

3. Retry a specific failed renewal manually

For a one-off stuck renewal, open the subscription in wp-admin and use Related Orders > Process renewal, or run it from the command line:

wp wc shell
>>> $subscription = wcs_get_subscription( 12345 );
>>> $subscription->get_last_order()->payment_complete();

Only do this after confirming in the gateway dashboard that the charge actually succeeded - don't force "payment complete" on a genuinely declined card.

4. Re-open the webhook path

Whitelist the gateway's published webhook IP ranges in ModSecurity or your firewall, and re-save the webhook endpoint URL in the gateway's dashboard so it re-sends any missed events for the last 24-48 hours. Most gateways will replay recent webhook attempts once the endpoint responds correctly again.

Prevention Checklist

PracticeWhy it matters
Real system cron instead of relying on visitor-triggered WP-CronRenewals fire on schedule even on low-traffic subscription sites
Enable WooCommerce's built-in renewal retry (dunning) emailsGives customers 2-3 automatic retry attempts before a subscription cancels
Monitor gateway webhook logs weekly, not just after a customer complainsCatches a blocked webhook before dozens of renewals pile up unpaid
Test "Change Payment Method" after any gateway plugin updateConfirms tokenization still works before it silently breaks live renewals

When to Just Ask Support

If the gateway confirms a successful charge but the order never updates, and re-saving the webhook URL doesn't fix it, that's usually a server-side rule blocking the callback rather than anything wrong in WooCommerce. Send your Getwebup support the gateway's transaction ID and the approximate time - it's faster to check the raw access logs for a blocked POST request than to keep guessing from the WordPress side.

Frequently asked questions

Why did WooCommerce Subscriptions renewals stop working after months of running fine?

The most common cause is a plugin or gateway update that changed how payment tokens are stored, or a firewall/WAF rule added afterward that started blocking the gateway's webhook. Check WooCommerce > Status > Logs for the gateway's log file around the date renewals stopped.

Is it safe to manually mark a failed renewal order as paid?

Only after you've confirmed in the payment gateway's own dashboard that the charge actually succeeded. Marking an order paid without that confirmation risks giving access or product without ever collecting payment.

How do I know if the problem is WP-Cron and not the payment gateway?

Run `wp cron event list --fields=hook,next_run_relative | grep subscription`. If `woocommerce_scheduled_subscription_payment` events are overdue, WP-Cron isn't firing on schedule - the gateway was never even contacted.

Can a customer fix a missing payment token themselves?

Yes. They can go to My Account > Subscriptions > [subscription] > Change Payment Method and re-enter their card once. That creates a fresh token and automatic renewals resume from the next billing cycle.

Do I need SSH access to fix cron-related renewal failures?

No. You can add the real cron job entry directly in cPanel under Cron Jobs, and set DISABLE_WP_CRON in wp-config.php through cPanel's File Manager if you'd rather not use SSH.

#woocommerce #subscriptions #renewal-payments #wp-cron #payment-gateway #wordpress

Keep reading

Chat with Support