Skip to content

Commit b04f20d

Browse files
committed
Merge remote-tracking branch 'origin/release/9.8.1' into trunk
2 parents d9dd714 + 7186086 commit b04f20d

22 files changed

+290
-122
lines changed

changelog.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
*** Changelog ***
22

3+
= 9.8.1 - 2025-08-15 =
4+
* Fix - Remove connection type requirement from PMC sync migration attempt
5+
* Fix - Relax customer validation that was preventing payments from the pay for order page
6+
* Fix - Prevent the PMC migration to run when the plugin is not connected to Stripe
7+
* Fix - Fixes a fatal error in the OC inbox note when the new checkout is disabled
8+
39
= 9.8.0 - 2025-08-11 =
410
* Add - Adds the current setting value for the Optimized Checkout to the Stripe System Status Report data
511
* Add - A new pill to the payment methods page to indicate the credit card requirement when the Optimized Checkout feature is enabled

includes/admin/class-wc-stripe-settings-controller.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ public function admin_scripts( $hook_suffix ) {
277277
'account_country' => $this->account->get_account_country(),
278278
'are_apms_deprecated' => WC_Stripe_Feature_Flags::are_apms_deprecated(),
279279
'is_amazon_pay_available' => WC_Stripe_Feature_Flags::is_amazon_pay_available(),
280-
'is_oc_available' => WC_Stripe_Feature_Flags::is_oc_available(),
280+
'is_oc_available' => WC_Stripe_Feature_Flags::is_oc_available() && WC_Stripe_Feature_Flags::is_upe_checkout_enabled(),
281281
'is_oc_enabled' => $is_oc_enabled,
282282
'oauth_nonce' => wp_create_nonce( 'wc_stripe_get_oauth_urls' ),
283283
'is_sepa_tokens_enabled' => 'yes' === $this->gateway->get_option( 'sepa_tokens_for_other_methods', 'no' ),

includes/class-wc-gateway-stripe.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,4 +1230,17 @@ private function validate_field( $field_key, $field_value ) {
12301230
public function is_payment_request_enabled() {
12311231
return 'yes' === $this->get_option( 'payment_request' );
12321232
}
1233+
1234+
/**
1235+
* Checks if the Optimized Checkout setting is enabled.
1236+
*
1237+
* OC is not supported in the legacy gateway, so we return false here,
1238+
* this method is then overridden by UPE payment gateway which extends from this class.
1239+
*
1240+
* @return bool Always false.
1241+
*/
1242+
public function is_oc_enabled() {
1243+
// Always return false here, as OC is not supported in the legacy gateway.
1244+
return false;
1245+
}
12331246
}

includes/class-wc-stripe-customer.php

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,24 @@
1010
*/
1111
class WC_Stripe_Customer {
1212

13+
/**
14+
* Constant for the customer context when adding a payment method.
15+
*/
16+
public const CUSTOMER_CONTEXT_ADD_PAYMENT_METHOD = 'add_payment_method';
17+
18+
/**
19+
* Constant for the customer context when paying for an order via the "Pay for Order" page.
20+
*/
21+
public const CUSTOMER_CONTEXT_PAY_FOR_ORDER = 'pay_for_order';
22+
23+
/**
24+
* Constants for the customer contexts where minimal billing details are permitted.
25+
*/
26+
public const MINIMAL_BILLING_DETAILS_CONTEXTS = [
27+
self::CUSTOMER_CONTEXT_ADD_PAYMENT_METHOD,
28+
self::CUSTOMER_CONTEXT_PAY_FOR_ORDER,
29+
];
30+
1331
/**
1432
* String prefix for Stripe payment methods request transient.
1533
*/
@@ -209,19 +227,19 @@ protected function generate_customer_request( $args = [] ) {
209227
/**
210228
* Validate that we have valid data before we try to create a customer.
211229
*
212-
* @param array $create_customer_request
213-
* @param bool $is_add_payment_method_page
230+
* @param array $create_customer_request The base data to build the customer request.
231+
* @param null|string $current_context Flag to indicate whether we are in a context where limited details are permitted.
214232
*
215233
* @throws WC_Stripe_Exception
216234
*/
217-
private function validate_create_customer_request( $create_customer_request, $is_add_payment_method_page = false ) {
235+
private function validate_create_customer_request( $create_customer_request, ?string $current_context = null ) {
218236
/**
219237
* Filters the required customer fields when creating a customer in Stripe.
220238
*
221239
* @since 9.7.0
222-
* @param array $required_fields The required customer fields as derived from the required billing fields in checkout.
240+
* @param array $required_fields The required customer fields as derived from the required billing fields in checkout. In some contexts, like adding a payment method, we allow minimal details to be provided.
223241
*/
224-
$required_fields = apply_filters( 'wc_stripe_create_customer_required_fields', $this->get_create_customer_required_fields( $is_add_payment_method_page ) );
242+
$required_fields = apply_filters( 'wc_stripe_create_customer_required_fields', $this->get_create_customer_required_fields( $current_context ) );
225243

226244
foreach ( $required_fields as $field => $field_requirements ) {
227245
if ( true === $field_requirements ) {
@@ -258,13 +276,12 @@ private function validate_create_customer_request( $create_customer_request, $is
258276
/**
259277
* Get the list of required fields for the create customer request.
260278
*
261-
* @param bool $is_add_payment_method_page
279+
* @param string|null $current_context The context we are creating the customer in.
262280
*
263281
* @return array
264282
*/
265-
private function get_create_customer_required_fields( $is_add_payment_method_page = false ) {
266-
// If we are on the add payment method page, we need to check just for the email field.
267-
if ( $is_add_payment_method_page ) {
283+
private function get_create_customer_required_fields( ?string $current_context = null ) {
284+
if ( in_array( $current_context, self::MINIMAL_BILLING_DETAILS_CONTEXTS, true ) ) {
268285
return [
269286
'email' => true,
270287
];
@@ -422,19 +439,22 @@ public function get_existing_customer( $email, $name ) {
422439
* Create a customer via API.
423440
*
424441
* @param array $args
425-
* @param bool $is_add_payment_method_page Whether the request is for the add payment method page.
442+
* @param string|null $current_context The context we are creating the customer in.
426443
* @return WP_Error|int
427444
*
428445
* @throws WC_Stripe_Exception
429446
*/
430-
public function create_customer( $args = [], $is_add_payment_method_page = false ) {
447+
public function create_customer( $args = [], $current_context = null ) {
431448
$args = $this->generate_customer_request( $args );
432449

433450
// For guest users, check if a customer already exists with the same email and name in Stripe account before creating a new one.
434451
if ( ! $this->get_id() && 0 === $this->get_user_id() && ! empty( $args['email'] ) && ! empty( $args['name'] ) ) {
435452
$response = $this->get_existing_customer( $args['email'], $args['name'] );
436453
}
437454

455+
// $current_context was initially introduced as a boolean flag, so check for old callers.
456+
$current_context = $this->normalize_current_context( $current_context );
457+
438458
if ( empty( $response ) ) {
439459
/**
440460
* Filters the arguments used to create a customer.
@@ -445,7 +465,7 @@ public function create_customer( $args = [], $is_add_payment_method_page = false
445465
*/
446466
$create_customer_args = apply_filters( 'wc_stripe_create_customer_args', $args );
447467

448-
$this->validate_create_customer_request( $create_customer_args, $is_add_payment_method_page );
468+
$this->validate_create_customer_request( $create_customer_args, $current_context );
449469

450470
$response = WC_Stripe_API::request( $create_customer_args, 'customers' );
451471
} else {
@@ -523,19 +543,45 @@ public function update_customer( $args = [], $is_retry = false ) {
523543
* Updates existing Stripe customer or creates new customer for User through API.
524544
*
525545
* @param array $args Additional arguments for the request (optional).
546+
* @param string|null $current_context The context we are creating the customer in.
526547
*
527548
* @return string Customer ID
528549
*
529550
* @throws WC_Stripe_Exception
530551
*/
531-
public function update_or_create_customer( $args = [], $is_add_payment_method_page = false ) {
552+
public function update_or_create_customer( $args = [], $current_context = null ) {
532553
if ( empty( $this->get_id() ) ) {
533-
return $this->recreate_customer( $args, $is_add_payment_method_page );
554+
// $current_context was initially introduced as a boolean flag, so check for old callers.
555+
$current_context = $this->normalize_current_context( $current_context );
556+
557+
return $this->recreate_customer( $args, $current_context );
534558
} else {
535559
return $this->update_customer( $args );
536560
}
537561
}
538562

563+
/**
564+
* Normalize the current context to a string, as the argument was initially introduced as a boolean flag.
565+
*
566+
* @param string|bool|null $current_context The current context.
567+
* @return string|null The normalized context.
568+
*/
569+
private function normalize_current_context( $current_context ): ?string {
570+
if ( null === $current_context ) {
571+
return null;
572+
}
573+
574+
if ( is_bool( $current_context ) ) {
575+
return $current_context ? self::CUSTOMER_CONTEXT_ADD_PAYMENT_METHOD : null;
576+
}
577+
578+
if ( is_string( $current_context ) ) {
579+
return $current_context;
580+
}
581+
582+
return null;
583+
}
584+
539585
/**
540586
* Checks to see if error is of invalid request
541587
* error and it is no such customer.
@@ -978,13 +1024,13 @@ public function delete_id_from_meta() {
9781024
* Recreates the customer for this user.
9791025
*
9801026
* @param array $args Additional arguments for the request (optional).
981-
* @param bool $is_add_payment_method_page Whether the request is for the add payment method page.
1027+
* @param string|null $current_context The context we are creating the customer in.
9821028
*
9831029
* @return string ID of the new Customer object.
9841030
*/
985-
private function recreate_customer( $args = [], $is_add_payment_method_page = false ) {
1031+
private function recreate_customer( $args = [], ?string $current_context = null ) {
9861032
$this->delete_id_from_meta();
987-
return $this->create_customer( $args, $is_add_payment_method_page );
1033+
return $this->create_customer( $args, $current_context );
9881034
}
9891035

9901036
/**

includes/class-wc-stripe-helper.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1983,4 +1983,24 @@ public static function validate_intent_for_order( $order, $intent, ?string $sele
19831983

19841984
throw new Exception( __( "We're not able to process this request. Please try again later.", 'woocommerce-gateway-stripe' ) );
19851985
}
1986+
1987+
/**
1988+
* Determines if the store is connected to Stripe.
1989+
*
1990+
* @param string $mode Optional. The mode to check. 'live' or 'test' - if not provided, the currently enabled mode will be checked.
1991+
* @return bool True if connected, false otherwise.
1992+
*/
1993+
public static function is_connected( $mode = null ) {
1994+
// If the mode is not provided, we'll check the current mode.
1995+
if ( null === $mode ) {
1996+
$mode = WC_Stripe_Mode::is_test() ? 'test' : 'live';
1997+
}
1998+
1999+
$options = self::get_stripe_settings();
2000+
if ( 'test' === $mode ) {
2001+
return isset( $options['test_publishable_key'], $options['test_secret_key'] ) && trim( $options['test_publishable_key'] ) && trim( $options['test_secret_key'] );
2002+
} else {
2003+
return isset( $options['publishable_key'], $options['secret_key'] ) && trim( $options['publishable_key'] ) && trim( $options['secret_key'] );
2004+
}
2005+
}
19862006
}

includes/class-wc-stripe-intent-controller.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1197,7 +1197,7 @@ public function create_and_confirm_setup_intent_ajax() {
11971197
// Manually create the payment information array to create & confirm the setup intent.
11981198
$payment_information = [
11991199
'payment_method' => $payment_method,
1200-
'customer' => $customer->update_or_create_customer( [], true ),
1200+
'customer' => $customer->update_or_create_customer( [], WC_Stripe_Customer::CUSTOMER_CONTEXT_ADD_PAYMENT_METHOD ),
12011201
'selected_payment_type' => $payment_type,
12021202
'return_url' => wc_get_account_endpoint_url( 'payment-methods' ),
12031203
'use_stripe_sdk' => 'true', // We want the user to complete the next steps via the JS elements. ref https://docs.stripe.com/api/setup_intents/create#create_setup_intent-use_stripe_sdk

includes/class-wc-stripe-payment-method-configurations.php

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -296,21 +296,18 @@ function ( $id ) use ( $is_test_mode ) {
296296

297297
/**
298298
* Check if the payment method configurations API can be used to store enabled payment methods.
299-
* This requires the Stripe account to be connected to our platform ('connection_type' option to be 'connect').
300-
*
301-
* This is temporary until we finish the re-authentication campaign.
299+
* This requires the Stripe account to be connected to Stripe.
302300
*
303301
* @return bool
304302
*/
305303
public static function is_enabled() {
306-
$stripe_settings = WC_Stripe_Helper::get_stripe_settings();
307-
$connection_type_key = WC_Stripe_Mode::is_test() ? 'test_connection_type' : 'connection_type';
308-
309-
// If the account is not a Connect OAuth account, we can't use the payment method configurations API.
310-
if ( ! isset( $stripe_settings[ $connection_type_key ] ) || 'connect' !== $stripe_settings[ $connection_type_key ] ) {
304+
// Bail if account is not connected.
305+
if ( ! WC_Stripe_Helper::is_connected() ) {
311306
return false;
312307
}
313308

309+
$stripe_settings = WC_Stripe_Helper::get_stripe_settings();
310+
314311
// If we have the pmc_enabled flag, and it is set to no, we should not use the payment method configurations API.
315312
// We only disable the PMC if the flag is set to no explicitly, an empty value means the migration has not been attempted yet.
316313
if ( isset( $stripe_settings['pmc_enabled'] ) && 'no' === $stripe_settings['pmc_enabled'] ) {
@@ -362,18 +359,35 @@ public static function maybe_migrate_payment_methods_from_db_to_pmc( $force_migr
362359
);
363360
}
364361

365-
// Update the PMC if there are any enabled payment methods
362+
// Update the PMC if there are locally enabled payment methods
366363
if ( ! empty( $enabled_payment_methods ) ) {
367-
368364
// Get all available payment method IDs from the configuration.
369365
// We explicitly disable all payment methods that are not in the enabled_payment_methods array
370366
$available_payment_method_ids = [];
371367
foreach ( $merchant_payment_method_configuration as $payment_method_id => $payment_method ) {
372368
if ( isset( $payment_method->display_preference ) ) {
373369
$available_payment_method_ids[] = $payment_method_id;
374370
}
371+
372+
// We want to also include payment methods enabled in the PMC, except for express payment methods.
373+
if (
374+
! in_array( $payment_method_id, WC_Stripe_Payment_Methods::EXPRESS_PAYMENT_METHODS, true ) &&
375+
! in_array( $payment_method_id, $enabled_payment_methods, true ) &&
376+
isset( $payment_method->display_preference->value ) && 'on' === $payment_method->display_preference->value
377+
) {
378+
$enabled_payment_methods[] = $payment_method_id;
379+
}
375380
}
376381

382+
WC_Stripe_Logger::error(
383+
'Switching to Stripe-hosted payment method configuration',
384+
[
385+
'pmc_id' => $merchant_payment_method_configuration->id,
386+
'enabled_payment_methods' => $enabled_payment_methods,
387+
'available_payment_method_ids' => $available_payment_method_ids,
388+
]
389+
);
390+
377391
self::update_payment_method_configuration(
378392
$enabled_payment_methods,
379393
$available_payment_method_ids
@@ -395,7 +409,7 @@ public static function maybe_migrate_payment_methods_from_db_to_pmc( $force_migr
395409
* This is called when no Payment Method Configuration is found that inherits from the WooCommerce Platform.
396410
*/
397411
private static function disable_payment_method_configuration_sync() {
398-
$stripe_settings = WC_Stripe_Helper::get_stripe_settings();
412+
$stripe_settings = WC_Stripe_Helper::get_stripe_settings();
399413
$stripe_settings['pmc_enabled'] = 'no';
400414
WC_Stripe_Helper::update_main_stripe_settings( $stripe_settings );
401415
}

includes/connect/class-wc-stripe-connect.php

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -269,17 +269,7 @@ private function get_default_stripe_config() {
269269
* @return bool True if connected, false otherwise.
270270
*/
271271
public function is_connected( $mode = null ) {
272-
// If the mode is not provided, we'll check the current mode.
273-
if ( is_null( $mode ) ) {
274-
$mode = WC_Stripe_Mode::is_test() ? 'test' : 'live';
275-
}
276-
277-
$options = WC_Stripe_Helper::get_stripe_settings();
278-
if ( 'test' === $mode ) {
279-
return isset( $options['test_publishable_key'], $options['test_secret_key'] ) && trim( $options['test_publishable_key'] ) && trim( $options['test_secret_key'] );
280-
} else {
281-
return isset( $options['publishable_key'], $options['secret_key'] ) && trim( $options['publishable_key'] ) && trim( $options['secret_key'] );
282-
}
272+
return WC_Stripe_Helper::is_connected( $mode );
283273
}
284274

285275
/**

includes/constants/class-wc-stripe-payment-methods.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ class WC_Stripe_Payment_Methods {
7979
self::WECHAT_PAY,
8080
];
8181

82+
const EXPRESS_PAYMENT_METHODS = [
83+
self::AMAZON_PAY,
84+
self::APPLE_PAY,
85+
self::GOOGLE_PAY,
86+
self::LINK,
87+
];
88+
8289
/**
8390
* List of express payment methods labels. Amazon Pay and Link are not included,
8491
* as they have their own payment method classes.

includes/payment-methods/class-wc-stripe-upe-payment-gateway.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2858,10 +2858,12 @@ private function get_customer_id_for_order( WC_Order $order ): string {
28582858
$user = $this->get_user_from_order( $order );
28592859
$customer = new WC_Stripe_Customer( $user->ID );
28602860

2861+
$current_context = $this->is_valid_pay_for_order_endpoint() ? WC_Stripe_Customer::CUSTOMER_CONTEXT_PAY_FOR_ORDER : null;
2862+
28612863
// Pass the order object so we can retrieve billing details
28622864
// in payment flows where it is not present in the request.
28632865
$args = [ 'order' => $order ];
2864-
return $customer->update_or_create_customer( $args );
2866+
return $customer->update_or_create_customer( $args, $current_context );
28652867
}
28662868

28672869
/**

0 commit comments

Comments
 (0)