Skip to content

Commit 6172a05

Browse files
superdav42claude
andcommitted
Fix: free trial lost on abandoned WooCommerce checkout
has_trialed() was counting pending memberships (created before payment) as consumed trials. Any abandoned checkout permanently blocked future trials for the customer with no error message. Also prevent ghost "pending payment" popups from surfacing for pending/cancelled memberships in check_pending_payments() and render_pending_payments(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 18c9c97 commit 6172a05

File tree

2 files changed

+27
-0
lines changed

2 files changed

+27
-0
lines changed

inc/managers/class-payment-manager.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,16 @@ public function check_pending_payments($user): void {
154154
}
155155

156156
foreach ($customer->get_memberships() as $membership) {
157+
/*
158+
* Skip memberships that never completed checkout. A pending
159+
* membership represents an abandoned checkout — showing a popup
160+
* for it is misleading and may point to a WC order that no
161+
* longer exists.
162+
*/
163+
if (in_array($membership->get_status(), ['pending', 'cancelled'], true)) {
164+
continue;
165+
}
166+
157167
$pending_payment = $membership->get_last_pending_payment();
158168

159169
if ($pending_payment) {
@@ -236,6 +246,10 @@ public function render_pending_payments(): void {
236246
$pending_payments = [];
237247

238248
foreach ($customer->get_memberships() as $membership) {
249+
if (in_array($membership->get_status(), ['pending', 'cancelled'], true)) {
250+
continue;
251+
}
252+
239253
$pending_payment = $membership->get_last_pending_payment();
240254

241255
if ($pending_payment) {

inc/models/class-customer.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,10 +398,23 @@ public function has_trialed() {
398398
$this->has_trialed = $this->get_meta(self::META_HAS_TRIALED);
399399

400400
if ( ! $this->has_trialed) {
401+
/*
402+
* Exclude pending memberships from this check.
403+
*
404+
* WP Ultimo sets date_trial_end at form submit, before payment is
405+
* collected. Without this filter an abandoned checkout permanently
406+
* blocks future trials because has_trialed() finds the pending
407+
* membership and returns true immediately.
408+
*
409+
* We intentionally keep 'cancelled' in scope: a user who started a
410+
* trial, then cancelled their active membership, genuinely consumed
411+
* their trial and should not receive a second one.
412+
*/
401413
$trial = wu_get_memberships(
402414
[
403415
'customer_id' => $this->get_id(),
404416
'date_trial_end__not_in' => [null, '0000-00-00 00:00:00'],
417+
'status__not_in' => ['pending'],
405418
'fields' => 'ids',
406419
'number' => 1,
407420
]

0 commit comments

Comments
 (0)