We have a WooCommerce store that offers cart level subscriptions. We currently have around 250 subscriptions, and we only process subscriptions on Thursday mornings at 00:00. Over time it seems that some of the subscription renewals have an order created (in pending payment status), but it doesn't even look like the transaction was attempted. We use two different plugins for payments, one for Paypal, and the other for regular credit cards.
So I thought about staggering the next payment dates, and it seemed to help. Subscription renewals were set to be processed one at a time, and the problem didn't go away, but occurred way less frequently. This is what I'm doing:
private static $renewalTime = NULL;
/**
* Do the staggering for tomorrow's subscription renewals
*/
public static function run()
{
// Get all of the subscription that are active
$activeSubs = wcs_get_subscriptions([
'subscriptions_per_page' => -1,
'subscription_status' => 'active',
]);
// Define tomorrow's start and end
$tomorrowStart = new \DateTime('tomorrow', new \DateTimeZone('America/Chicago') );
$tomorrowStart->modify('00:00:00');
$tomorrowEnd = clone $tomorrowStart;
$tomorrowEnd->modify('23:59:59');
// Renewal times start at the beginning of tomorrow
self::$renewalTime = clone $tomorrowStart;
// Loop through the active subscriptions
foreach( $activeSubs as $sub )
self::_processSub( $sub, $tomorrowStart, $tomorrowEnd );
}
// -----------------------------------------------------------------------
/**
* Process an individual sub
*/
private static function _processSub( $sub, $tomorrowStart, $tomorrowEnd )
{
// Create a \DateTime object for the next payment date
$nextPaymentDate = new \DateTime(
$sub->get_date('next_payment'),
new \DateTimeZone('GMT')
);
// Convert timezone to US Central
$nextPaymentDate->setTimezone( new \DateTimeZone('America/Chicago') );
// If the next payment date happens outside the target dates then abort
if(
$nextPaymentDate < $tomorrowStart OR
$nextPaymentDate > $tomorrowEnd
){
return;
}
// Now we'll completely override the next payment date with our own
$nextPaymentDate = clone self::$renewalTime;
// Convert timezone back to GMT
$nextPaymentDate->setTimezone( new \DateTimeZone('GMT') );
// Apply next payment date to the sub!
$sub->update_dates([
'next_payment' => $nextPaymentDate->format('Y-m-d H:i:s')
], 'gmt' );
// Give some feedback to the terminal
\WP_CLI::log( $sub->get_id() . ' renewing at ' . $nextPaymentDate->format('Y-m-d H:i:s') );
// Ensure the next sub processed renews 2 minutes later
self::$renewalTime->modify('+2 minute');
}
I guess this leads me to believe that there's some sort of memory problem, but PHP doesn't show any errors, WooCommerce doesn't report any problems, and we really have no way to troubleshoot this. So we sent a support request to WooCommerce Subscriptions, asking if they have any idea of what's going on, and they sent back a list of things to check:
- Cron Jobs: Check if the WordPress Cron Jobs executed as expected during the time the issue occurred. Delays or hiccups here could impact the timing of renewals. (I see from your System Status that WP Cron is disabled. Are you using a different Cron system and is this the same on the development site?)
Yes, we run cron via crontab, it's the same as the development site, and in the development environment we don't see a problem.
- Server Resources: Insufficient server resources at the time of renewals could lead to uncompleted tasks. Review your server logs for any signs of this.
We're using Cloudways for hosting. Have 16GB ram. Their server monitoring tools show that CPU and memory are never a problem. The server logs don't show anything abnormal.
- Payment Gateway: Investigate if there were any issues or changes with your payment gateway at the specific time the problem occurred.
We're using two payment gateways, and the problem happens with either of them, randomly, so I don't think they are the problem.
- Database Locks: Concurrency issues could cause database locks, preventing orders from being processed. This is more likely since you're running renewals closely together.
This might make sense, but staggering the renewals one minute apart should be plenty of time to let WooCommerce Subscriptions do its thing. WTF?
- WooCommerce Logs: Review WooCommerce logs for any errors or warnings that might give a clue.
Nothing here at all.
- Plugin/Theme Conflicts: Deactivate other plugins and switch to a default theme to rule out conflicts. It's possible that a plugin or theme update could have introduced an issue.
Doesn't happen on the development environment with all the same plugins, so why would this be a problem on production?
- Customer Data: Are there any common factors among the affected subscriptions? E.g., same payment method, user role, etc.
No.
- Manual Test: Conduct manual renewals mimicking the production settings. This may offer some insight even though the issue hasn't reproduced in development.
We've tested the crap out of WooCommerce Subscriptions. There's really nothing else we can think of doing.
So, I guess what I'm wondering is if anyone would know how to debug this? How can we tell if a transaction was even attempted? Are there any reasons why the subscription renewal processing would not attempt a transaction? This is really frustrating. Any help you could give would be greatly appreciated.
I'm afraid we can't help debug it. However, we are having the exact same issue and I can share some info.
Woo has told us that there's some issue (that they can replicate and IS happening with other accounts) where when a customer clicks the "make default" button for a payment method, this adds empty metadata to a subscription, and tokens are being wiped.
They've given us lengthy instructions to send our customers to pay for their order manually, then change the payment card and add the same one again, and then remove the old payment method. How they can differentiate between two sets of identical card details I don't know! We are also supposed to check from the back end if the payment card has changed... even though it's THE SAME CARD so we have no way of differentiating.
It's been going on for ages and people are cancelling because of it. We can't ask people to do this for it and then not to work; we just need an actual fix.
We also did have a cron issue recently where subs payments didn't schedule. This was due to a plugin update and WPRocket cache needing to be purged. But doesn't seem to be related to this random issue of failing subs renewal payments.