Skip to content

Commit b1d1a54

Browse files
Add caching for Stripe payment method configuration (#4241)
* Add caching for Stripe payment method configuration * Fix the correct method signature * More method signature fixes * Move static cache var to get_primary_configuration_from_cache and remove reset_primary_configuration in favor of clear_primary_configuration_cache * Unify var/func names for all PMC related functions * Update PMC function in test mocks * Fix merge conflicts with renamed constants * Add changelog entry * Revert var/func renames * Use different transients for live and test mode * Add log if update payment methods configurations fails --------- Co-authored-by: Diego Curbelo <diego@curbelo.com>
1 parent 3bc7a8c commit b1d1a54

7 files changed

+105
-30
lines changed

changelog.txt

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* Add - New setting to allow merchants to set their preferred title for the Smart Checkout payment element. Defaults to "Stripe".
1111
* Dev - Implements the new Stripe order class into the compatibility classes.
1212
* Dev - Updates the Code Sniffer package to version 1.0.0.
13+
* Fix - Add caching for the Stripe Payment Method Configuration API
1314

1415
= 9.4.1 - 2025-04-17 =
1516
* Dev - Forces rollback of version 9.4.0.

includes/abstracts/abstract-wc-stripe-payment-gateway.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
3333
*
3434
* @return string[]
3535
*/
36-
public function get_upe_enabled_payment_method_ids() {
36+
public function get_upe_enabled_payment_method_ids( $force_refresh = false ) {
3737
return [ WC_Stripe_Payment_Methods::CARD ];
3838
}
3939

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ public function get_settings() {
246246
$is_upe_enabled = WC_Stripe_Feature_Flags::is_upe_checkout_enabled();
247247
$available_payment_method_ids = $is_upe_enabled ? $this->gateway->get_upe_available_payment_methods() : WC_Stripe_Helper::get_legacy_available_payment_method_ids();
248248
$ordered_payment_method_ids = $is_upe_enabled ? WC_Stripe_Helper::get_upe_ordered_payment_method_ids( $this->gateway ) : $available_payment_method_ids;
249-
$enabled_payment_method_ids = $is_upe_enabled ? $this->gateway->get_upe_enabled_payment_method_ids() : WC_Stripe_Helper::get_legacy_enabled_payment_method_ids();
249+
$enabled_payment_method_ids = $is_upe_enabled ? $this->gateway->get_upe_enabled_payment_method_ids( true ) : WC_Stripe_Helper::get_legacy_enabled_payment_method_ids();
250250

251251
return new WP_REST_Response(
252252
[

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

+98-25
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* Class WC_Stripe_Payment_Method_Configurations
99
*/
1010
class WC_Stripe_Payment_Method_Configurations {
11+
1112
/**
1213
* The primary configuration.
1314
*
@@ -30,40 +31,106 @@ class WC_Stripe_Payment_Method_Configurations {
3031
const LIVE_MODE_CONFIGURATION_PARENT_ID = 'pmc_1LEKjAGX8lmJQndTk2ziRchV';
3132

3233
/**
33-
* Reset the primary configuration.
34+
* The test mode payment method configuration transient key (for cache purposes).
35+
*
36+
* @var string
3437
*/
35-
public static function reset_primary_configuration() {
36-
self::$primary_configuration = null;
37-
}
38+
const TEST_MODE_CONFIGURATION_CACHE_TRANSIENT_KEY = 'wcstripe_test_payment_method_configuration_cache';
39+
40+
/**
41+
* The live mode payment method configuration transient key (for cache purposes).
42+
*
43+
* @var string
44+
*/
45+
const LIVE_MODE_CONFIGURATION_CACHE_TRANSIENT_KEY = 'wcstripe_live_payment_method_configuration_cache';
46+
47+
/**
48+
* The payment method configuration transient expiration (for cache purposes).
49+
*
50+
* @var int
51+
*/
52+
const CONFIGURATION_CACHE_TRANSIENT_EXPIRATION = 10 * MINUTE_IN_SECONDS;
3853

3954
/**
4055
* Get the merchant payment method configuration in Stripe.
4156
*
57+
* @param bool $force_refresh Whether to force a refresh of the payment method configuration from Stripe.
58+
* @return object|null
59+
*/
60+
private static function get_primary_configuration( $force_refresh = false ) {
61+
if ( ! $force_refresh ) {
62+
$cached_primary_configuration = self::get_payment_method_configuration_from_cache();
63+
if ( $cached_primary_configuration ) {
64+
return $cached_primary_configuration;
65+
}
66+
}
67+
68+
return self::get_payment_method_configuration_from_stripe();
69+
}
70+
71+
/**
72+
* Get the payment method configuration from cache.
73+
*
4274
* @return object|null
4375
*/
44-
private static function get_primary_configuration() {
76+
private static function get_payment_method_configuration_from_cache() {
4577
if ( null !== self::$primary_configuration ) {
4678
return self::$primary_configuration;
4779
}
4880

49-
$result = WC_Stripe_API::get_instance()->get_payment_method_configurations();
50-
$payment_method_configurations = $result->data ?? null;
51-
52-
if ( ! $payment_method_configurations ) {
81+
$cache_key = WC_Stripe_Mode::is_test() ? self::TEST_MODE_CONFIGURATION_CACHE_TRANSIENT_KEY : self::LIVE_MODE_CONFIGURATION_CACHE_TRANSIENT_KEY;
82+
$cached_primary_configuration = get_transient( $cache_key );
83+
if ( false === $cached_primary_configuration || null === $cached_primary_configuration ) {
5384
return null;
5485
}
5586

56-
foreach ( $payment_method_configurations as $payment_method_configuration ) {
57-
if ( ! $payment_method_configuration->livemode && $payment_method_configuration->parent && self::TEST_MODE_CONFIGURATION_PARENT_ID === $payment_method_configuration->parent ) {
58-
self::$primary_configuration = $payment_method_configuration;
59-
return $payment_method_configuration;
60-
}
87+
self::$primary_configuration = $cached_primary_configuration;
88+
return self::$primary_configuration;
89+
}
90+
91+
/**
92+
* Clear the payment method configuration from cache.
93+
*/
94+
public static function clear_payment_method_configuration_cache() {
95+
self::$primary_configuration = null;
96+
$cache_key = WC_Stripe_Mode::is_test() ? self::TEST_MODE_CONFIGURATION_CACHE_TRANSIENT_KEY : self::LIVE_MODE_CONFIGURATION_CACHE_TRANSIENT_KEY;
97+
delete_transient( $cache_key );
98+
}
99+
100+
/**
101+
* Cache the payment method configuration.
102+
*
103+
* @param object|array $configuration The payment method configuration to set in cache.
104+
*/
105+
private static function set_payment_method_configuration_cache( $configuration ) {
106+
self::$primary_configuration = $configuration;
107+
$cache_key = WC_Stripe_Mode::is_test() ? self::TEST_MODE_CONFIGURATION_CACHE_TRANSIENT_KEY : self::LIVE_MODE_CONFIGURATION_CACHE_TRANSIENT_KEY;
108+
set_transient( $cache_key, $configuration, self::CONFIGURATION_CACHE_TRANSIENT_EXPIRATION );
109+
}
110+
111+
/**
112+
* Get the payment method configuration from Stripe.
113+
*
114+
* @return object|null
115+
*/
116+
private static function get_payment_method_configuration_from_stripe() {
117+
$result = WC_Stripe_API::get_instance()->get_payment_method_configurations();
118+
$configurations = $result->data ?? null;
119+
120+
if ( ! $configurations ) {
121+
return null;
122+
}
61123

62-
if ( $payment_method_configuration->livemode && $payment_method_configuration->parent && self::LIVE_MODE_CONFIGURATION_PARENT_ID === $payment_method_configuration->parent ) {
63-
self::$primary_configuration = $payment_method_configuration;
64-
return $payment_method_configuration;
124+
// When connecting to the WooCommerce Platform account a new payment method configuration is created for the merchant.
125+
// This new payment method configuration has the WooCommerce Platform payment method configuration as parent, and inherits it's default payment methods.
126+
foreach ( $configurations as $configuration ) {
127+
// The API returns data for the corresponding mode of the api keys used, so we'll get either test or live PMCs, but never both.
128+
if ( $configuration->parent && ( self::LIVE_MODE_CONFIGURATION_PARENT_ID === $configuration->parent || self::TEST_MODE_CONFIGURATION_PARENT_ID === $configuration->parent ) ) {
129+
self::set_payment_method_configuration_cache( $configuration );
130+
return $configuration;
65131
}
66132
}
133+
67134
return null;
68135
}
69136

@@ -79,9 +146,10 @@ public static function get_parent_configuration_id() {
79146
/**
80147
* Get the UPE enabled payment method IDs.
81148
*
149+
* @param bool $force_refresh Whether to force a refresh of the payment method configuration from Stripe.
82150
* @return array
83151
*/
84-
public static function get_upe_enabled_payment_method_ids() {
152+
public static function get_upe_enabled_payment_method_ids( $force_refresh = false ) {
85153
// If the payment method configurations API is not enabled, we fallback to the enabled payment methods stored in the DB.
86154
if ( ! self::is_enabled() ) {
87155
$stripe_settings = WC_Stripe_Helper::get_stripe_settings();
@@ -94,7 +162,7 @@ public static function get_upe_enabled_payment_method_ids() {
94162
self::maybe_migrate_payment_methods_from_db_to_pmc();
95163

96164
$enabled_payment_method_ids = [];
97-
$merchant_payment_method_configuration = self::get_primary_configuration();
165+
$merchant_payment_method_configuration = self::get_primary_configuration( $force_refresh );
98166

99167
if ( $merchant_payment_method_configuration ) {
100168
foreach ( $merchant_payment_method_configuration as $payment_method_id => $payment_method ) {
@@ -119,6 +187,11 @@ public static function update_payment_method_configuration( $enabled_payment_met
119187
$newly_enabled_methods = [];
120188
$newly_disabled_methods = [];
121189

190+
if ( ! $payment_method_configuration ) {
191+
WC_Stripe_Logger::log( 'No primary payment method configuration found while updating payment method configuration' );
192+
return;
193+
}
194+
122195
foreach ( $available_payment_method_ids as $stripe_id ) {
123196
$will_enable = in_array( $stripe_id, $enabled_payment_method_ids, true );
124197

@@ -137,15 +210,15 @@ public static function update_payment_method_configuration( $enabled_payment_met
137210
];
138211
}
139212

140-
if ( ! $payment_method_configuration ) {
141-
WC_Stripe_Logger::log( 'No primary payment method configuration found while updating payment method configuration' );
142-
return;
143-
}
144-
145-
WC_Stripe_API::get_instance()->update_payment_method_configurations(
213+
$response = WC_Stripe_API::get_instance()->update_payment_method_configurations(
146214
$payment_method_configuration->id,
147215
$updated_payment_method_configuration
148216
);
217+
if ( ! empty( $response->error ) ) {
218+
WC_Stripe_Logger::log( 'Error: ' . $response->error->message . ': ' . $response->error->request_log_url );
219+
}
220+
221+
self::clear_payment_method_configuration_cache();
149222

150223
self::record_payment_method_settings_event( $newly_enabled_methods, $newly_disabled_methods );
151224
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -631,8 +631,8 @@ private function get_enabled_payment_method_config() {
631631
*
632632
* @return string[]
633633
*/
634-
public function get_upe_enabled_payment_method_ids() {
635-
return WC_Stripe_Payment_Method_Configurations::get_upe_enabled_payment_method_ids();
634+
public function get_upe_enabled_payment_method_ids( $force_refresh = false ) {
635+
return WC_Stripe_Payment_Method_Configurations::get_upe_enabled_payment_method_ids( $force_refresh );
636636
}
637637

638638
/**

readme.txt

+1
Original file line numberDiff line numberDiff line change
@@ -120,5 +120,6 @@ If you get stuck, you can ask for help in the [Plugin Forum](https://wordpress.o
120120
* Add - New setting to allow merchants to set their preferred title for the Smart Checkout payment element. Defaults to "Stripe".
121121
* Dev - Implements the new Stripe order class into the compatibility classes.
122122
* Dev - Updates the Code Sniffer package to version 1.0.0.
123+
* Fix - Add caching for the Stripe Payment Method Configuration API
123124

124125
[See changelog for all versions](https://raw.githubusercontent.com/woocommerce/woocommerce-gateway-stripe/trunk/changelog.txt).

tests/phpunit/wc-mock-stripe-api-unit-test-case.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public function set_up() {
2929
*/
3030
public function tear_down() {
3131
parent::tear_down();
32-
WC_Stripe_Payment_Method_Configurations::reset_primary_configuration();
32+
WC_Stripe_Payment_Method_Configurations::clear_payment_method_configuration_cache();
3333
}
3434

3535
/**

0 commit comments

Comments
 (0)