Prevent Stripe non-card payments from timing out prematurely#1652
Prevent Stripe non-card payments from timing out prematurely#1652dd32 wants to merge 6 commits intoWordPress:productionfrom
Conversation
Delayed payment methods (boleto, OXXO, etc.) can take days to settle. Previously, the 24-hour timeout would mark these attendees as timed out before payment could complete. Changes: - Mark attendees as pending (not completed) when returning from Stripe with an unpaid delayed payment session - Delay timeout for attendees with pending Stripe payments by resetting their timestamp, with a 7-day maximum safety limit - Include pending attendees in the timeout review process - Delay timeout for open Stripe sessions that have not yet expired Fixes WordPress#1532 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR updates CampTix’s Stripe integration and timeout cron logic to better support Stripe delayed-settlement payment methods (boleto, OXXO, etc.) so attendees aren’t expired before payment actually settles.
Changes:
- Treat Stripe Checkout sessions that are
completebut stillunpaidas CampTixpendinginstead ofcompleted. - Extend the timeout sweep to include
pendingattendees and add Stripe-specific logic intended to delay timeout for pending/open sessions (with a 7‑day cap). - Improve Stripe “cancel” return handling by checking the Checkout session state before cancelling.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| public_html/wp-content/plugins/camptix/camptix.php | Expands timeout review to include pending attendees and re-checks status after pre-timeout hooks. |
| public_html/wp-content/plugins/camptix/addons/payment-stripe.php | Marks delayed Stripe payments as pending, adds session-aware timeout delay logic, and passes session ID through the cancel URL flow. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $camptix->log( "Dying because couldn't get Payment status", $order['attendee_id'], compact( 'payment_token', 'payment_session' ) ); | ||
| wp_die( 'could not find payment details' ); | ||
| } | ||
|
|
||
| // Hmm.. Not finalised. | ||
| if ( 'open' === $session['status'] ) { | ||
| $payment_data = array( | ||
| 'error' => 'Error during Payment checkout', | ||
| 'data' => $session, |
| do_action( 'camptix_pre_attendee_timeout', $attendee_id ); | ||
|
|
||
| // Check the post_status again, incase a filter has caused the post to change. | ||
| if ( 'draft' !== get_post_field( 'post_status', $attendee_id ) ) { | ||
| // Check the post_status again, in case a hook has caused the post to change. | ||
| if ( ! in_array( get_post_field( 'post_status', $attendee_id ), array( 'draft', 'pending' ), true ) ) { | ||
| continue; | ||
| } |
| 'post_type' => 'tix_attendee', | ||
| 'post_status' => 'draft', | ||
| 'post_status' => array( 'draft', 'pending' ), | ||
| 'posts_per_page' => 100, | ||
| 'cache_results' => false, | ||
| 'meta_query' => array( |
| * 3. The session is still open and not expired -- delay the timeout. | ||
| */ | ||
| public function pre_attendee_timeout( $attendee_id ) { | ||
| /** @var CampTix_Plugin $camptix */ | ||
| global $camptix; | ||
|
|
| if ( 'open' === $session['status'] ) { | ||
| $expires_at = $session['expires_at'] ?? 0; | ||
|
|
||
| if ( $expires_at > time() ) { | ||
| $log_data = array( 'expires_at' => $expires_at ); | ||
| $camptix->log( 'Stripe session still open, delaying timeout.', $attendee_id, $log_data ); | ||
|
|
||
| $this->delay_attendee_timeout( $attendee_id ); | ||
| return; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Pull request overview
Updates CampTix’s Stripe integration to better support delayed-settlement payment methods (e.g., boleto/OXXO) by preventing premature attendee timeouts while the Stripe Checkout Session is complete but payment is still pending.
Changes:
- Mark Stripe delayed-settlement returns as
pending(instead ofcompleted) when the Checkout Session is complete butpayment_statusisunpaid. - Expand the timeout sweep to include
pendingStripe attendees and allow hooks to delay timeouts by updating the attendee timestamp (with a 7-day cap enforced in the Stripe addon). - Add PHPUnit coverage for the updated timeout sweep behavior in
review_timeout_payments().
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
public_html/wp-content/plugins/camptix/camptix.php |
Extends timeout sweeping to include pending Stripe attendees and re-checks timestamp/status after the pre-timeout hook. |
public_html/wp-content/plugins/camptix/addons/payment-stripe.php |
Implements pending handling on return/cancel, adds session retry logic, and delays timeouts for still-open/pending Stripe sessions with a max-age cap. |
public_html/wp-content/plugins/camptix/tests/test-camptix-admin.php |
Adds tests ensuring the timeout sweep respects delayed timestamps and only sweeps pending Stripe attendees. |
Comments suppressed due to low confidence (1)
public_html/wp-content/plugins/camptix/addons/payment-stripe.php:458
- In
payment_return(), the log context usescompact( 'payment_token', 'payment_session' ), but$payment_sessionis not defined (the variable in scope is$stripe_session). This will produce incorrect/empty log context and may trigger notices depending on error settings. Use the correct variable name so debugging data is accurate.
if ( empty( $session['status'] ) ) {
$camptix->log( "Dying because couldn't get Payment status", $order['attendee_id'], compact( 'payment_token', 'payment_session' ) );
wp_die( 'could not find payment details' );
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Fetch the Payment details. | ||
| $stripe = new CampTix_Stripe_API_Client( $payment_token, $this->get_api_credentials()['api_secret_key'] ); | ||
| $session = $stripe->get_session( $stripe_session ); | ||
| $session = $this->get_session_with_retry( $stripe, $stripe_session ); | ||
|
|
| if ( ! $stripe_session || '{CHECKOUT_SESSION_ID}' === $stripe_session ) { | ||
| $stripe_session = get_post_meta( $order['attendee_id'], '_stripe_checkout_session_id', true ); | ||
| } | ||
|
|
||
| if ( $stripe_session ) { | ||
| $stripe = new CampTix_Stripe_API_Client( $payment_token, $this->get_api_credentials()['api_secret_key'] ); | ||
| $session = $this->get_session_with_retry( $stripe, $stripe_session ); |
| // Scenario 2: The checkout session completed but payment is still pending. | ||
| // This happens with delayed payment methods like boleto, OXXO, etc. | ||
| if ( 'complete' === $session['status'] && 'unpaid' === $payment_status ) { | ||
| $payment_intent = $session['payment_intent'] ?? array(); | ||
| $payment_intent_status = is_array( $payment_intent ) ? ( $payment_intent['status'] ?? '' ) : ''; | ||
|
|
||
| // Only delay timeout if the payment is still in a pending state. | ||
| if ( in_array( $payment_intent_status, array( 'requires_action', 'processing' ), true ) ) { | ||
| $log_data = array( | ||
| 'payment_intent_status' => $payment_intent_status, | ||
| 'payment_status' => $payment_status, | ||
| ); | ||
| $camptix->log( 'Stripe payment still pending, delaying timeout.', $attendee_id, $log_data ); | ||
|
|
||
| $this->delay_attendee_timeout( $attendee_id ); | ||
| return; |
Summary
pendinginstead ofcompleted, so tickets are not issued until payment actually settles.draftandpendingattendees. For pending Stripe payments, the timeout is delayed by resetting the attendee timestamp (up to a 7-day maximum safety limit).Fixes #1532
Test plan
pending(notpublished) after returning from Stripepublishedon the next timeout review cycleGenerated with Claude Code