{ interpolateComponents( {
diff --git a/client/settings/index.js b/client/settings/index.js
index ca60a5dec..ae7b15f56 100644
--- a/client/settings/index.js
+++ b/client/settings/index.js
@@ -49,6 +49,7 @@ if ( newAccountContainer ) {
ReactDOM.render(
,
newAccountContainer
);
diff --git a/client/settings/stripe-auth-account/stripe-auth-actions.js b/client/settings/stripe-auth-account/stripe-auth-actions.js
index ccce29a67..86859315e 100644
--- a/client/settings/stripe-auth-account/stripe-auth-actions.js
+++ b/client/settings/stripe-auth-account/stripe-auth-actions.js
@@ -1,4 +1,5 @@
/* global wc_stripe_settings_params */
+import { __ } from '@wordpress/i18n';
import { React } from 'react';
import { Button } from '@wordpress/components';
import ConfigureWebhookButton from './configure-webhook-button';
@@ -17,9 +18,21 @@ const StripeAuthActions = ( { testMode, displayWebhookConfigure } ) => {
{ displayWebhookConfigure && (
diff --git a/includes/admin/class-wc-stripe-settings-controller.php b/includes/admin/class-wc-stripe-settings-controller.php
index 90d94bb9c..fae5010d1 100644
--- a/includes/admin/class-wc-stripe-settings-controller.php
+++ b/includes/admin/class-wc-stripe-settings-controller.php
@@ -130,9 +130,10 @@ public function admin_scripts( $hook_suffix ) {
);
$oauth_url = woocommerce_gateway_stripe()->connect->get_oauth_url();
- if ( is_wp_error( $oauth_url ) ) {
- $oauth_url = '';
- }
+ $oauth_url = is_wp_error( $oauth_url ) ? '' : $oauth_url;
+
+ $test_oauth_url = woocommerce_gateway_stripe()->connect->get_oauth_url( '', 'test' );
+ $test_oauth_url = is_wp_error( $test_oauth_url ) ? '' : $test_oauth_url;
$message = sprintf(
/* translators: 1) Html strong opening tag 2) Html strong closing tag */
@@ -146,6 +147,7 @@ public function admin_scripts( $hook_suffix ) {
'i18n_out_of_sync' => $message,
'is_upe_checkout_enabled' => WC_Stripe_Feature_Flags::is_upe_checkout_enabled(),
'stripe_oauth_url' => $oauth_url,
+ 'stripe_test_oauth_url' => $test_oauth_url,
'show_customization_notice' => get_option( 'wc_stripe_show_customization_notice', 'yes' ) === 'yes' ? true : false,
'is_test_mode' => $this->gateway->is_in_test_mode(),
'plugin_version' => WC_STRIPE_VERSION,
diff --git a/includes/class-wc-gateway-stripe.php b/includes/class-wc-gateway-stripe.php
index adad5e5f7..3381ca53e 100644
--- a/includes/class-wc-gateway-stripe.php
+++ b/includes/class-wc-gateway-stripe.php
@@ -1122,20 +1122,6 @@ public function get_required_settings_keys() {
return [ 'publishable_key', 'secret_key' ];
}
- /**
- * Get the connection URL.
- *
- * @return string Connection URL.
- */
- public function get_connection_url( $return_url = '' ) {
- $api = new WC_Stripe_Connect_API();
- $connect = new WC_Stripe_Connect( $api );
-
- $url = $connect->get_oauth_url( $return_url );
-
- return is_wp_error( $url ) ? null : $url;
- }
-
/**
* Get help text to display during quick setup.
*
diff --git a/includes/class-wc-stripe-account.php b/includes/class-wc-stripe-account.php
index 8b2c17c17..3b972d681 100644
--- a/includes/class-wc-stripe-account.php
+++ b/includes/class-wc-stripe-account.php
@@ -46,42 +46,52 @@ public function __construct( WC_Stripe_Connect $connect, $stripe_api ) {
/**
* Gets and caches the data for the account connected to this site.
*
+ * @param string|null $mode Optional. The mode to get the account data for. 'live' or 'test'. Default will use the current mode.
* @return array Account data or empty if failed to retrieve account data.
*/
- public function get_cached_account_data() {
- if ( ! $this->connect->is_connected() ) {
+ public function get_cached_account_data( $mode = null ) {
+ if ( ! $this->connect->is_connected( $mode ) ) {
return [];
}
- $account = $this->read_account_from_cache();
+ $account = $this->read_account_from_cache( $mode );
if ( ! empty( $account ) ) {
return $account;
}
- return $this->cache_account();
+ return $this->cache_account( $mode );
}
/**
* Read the account from the WP option we cache it in.
*
+ * @param string|null $mode Optional. The mode to get the account data for. 'live' or 'test'. Default will use the current mode.
* @return array empty when no data found in transient, otherwise returns cached data
*/
- private function read_account_from_cache() {
- $account_cache = json_decode( wp_json_encode( get_transient( $this->get_transient_key() ) ), true );
+ private function read_account_from_cache( $mode = null ) {
+ $account_cache = json_decode( wp_json_encode( get_transient( $this->get_transient_key( $mode ) ) ), true );
return false === $account_cache ? [] : $account_cache;
}
/**
* Caches account data for a period of time.
+ *
+ * @param string|null $mode Optional. The mode to get the account data for. 'live' or 'test'. Default will use the current mode.
*/
- private function cache_account() {
- $expiration = 2 * HOUR_IN_SECONDS;
+ private function cache_account( $mode = null ) {
+ // If a mode is provided, we'll set the API secret key to the appropriate key to retrieve the account data.
+ if ( ! is_null( $mode ) ) {
+ WC_Stripe_API::set_secret_key_for_mode( $mode );
+ }
- // need call_user_func() as ( $this->stripe_api )::retrieve this syntax is not supported in php < 5.2
+ // need call_user_func() as ( $this->stripe_api )::retrieve this syntax is not supported in php < 5.2
$account = call_user_func( [ $this->stripe_api, 'retrieve' ], 'account' );
+ // Restore the secret key to the original value.
+ WC_Stripe_API::set_secret_key_for_mode();
+
if ( is_wp_error( $account ) || isset( $account->error->message ) ) {
return [];
}
@@ -90,21 +100,27 @@ private function cache_account() {
$account_cache = $account;
// Create or update the account option cache.
- set_transient( $this->get_transient_key(), $account_cache, $expiration );
+ set_transient( $this->get_transient_key( $mode ), $account_cache, 2 * HOUR_IN_SECONDS );
return json_decode( wp_json_encode( $account ), true );
}
/**
- * Checks Stripe connection mode if it is test mode or live mode
+ * Fetches the transient key for the account data for a given mode.
+ * If no mode is provided, it will use the current mode.
*
+ * @param string|null $mode Optional. The mode to get the account data for. 'live' or 'test'. Default will use the current mode.
* @return string Transient key of test mode when testmode is enabled, otherwise returns the key of live mode.
*/
- private function get_transient_key() {
+ private function get_transient_key( $mode = null ) {
$settings_options = get_option( 'woocommerce_stripe_settings', [] );
- $key = isset( $settings_options['testmode'] ) && 'yes' === $settings_options['testmode'] ? self::TEST_ACCOUNT_OPTION : self::LIVE_ACCOUNT_OPTION;
- return $key;
+ // If the mode is not provided or is invalid, we'll check the current mode.
+ if ( is_null( $mode ) || ! in_array( $mode, [ 'test', 'live' ] ) ) {
+ $mode = isset( $settings_options['testmode'] ) && 'yes' === $settings_options['testmode'] ? 'test' : 'live';
+ }
+
+ return 'test' === $mode ? self::TEST_ACCOUNT_OPTION : self::LIVE_ACCOUNT_OPTION;
}
/**
diff --git a/includes/class-wc-stripe-api.php b/includes/class-wc-stripe-api.php
index 4f0141538..46aadf7f8 100644
--- a/includes/class-wc-stripe-api.php
+++ b/includes/class-wc-stripe-api.php
@@ -39,17 +39,28 @@ public static function set_secret_key( $secret_key ) {
*/
public static function get_secret_key() {
if ( ! self::$secret_key ) {
- $options = get_option( 'woocommerce_stripe_settings' );
- $secret_key = $options['secret_key'] ?? '';
- $test_secret_key = $options['test_secret_key'] ?? '';
-
- if ( isset( $options['testmode'] ) ) {
- self::set_secret_key( 'yes' === $options['testmode'] ? $test_secret_key : $secret_key );
- }
+ self::set_secret_key_for_mode();
}
return self::$secret_key;
}
+ /**
+ * Set secret key based on mode.
+ *
+ * @param string|null $mode Optional. The mode to set the secret key for. 'live' or 'test'. Default will set the secret for the currently active mode.
+ */
+ public static function set_secret_key_for_mode( $mode = null ) {
+ $options = get_option( 'woocommerce_stripe_settings' );
+ $secret_key = $options['secret_key'] ?? '';
+ $test_secret_key = $options['test_secret_key'] ?? '';
+
+ if ( is_null( $mode ) || ! in_array( $mode, [ 'test', 'live' ] ) ) {
+ $mode = isset( $options['testmode'] ) && 'yes' === $options['testmode'] ? 'test' : 'live';
+ }
+
+ self::set_secret_key( 'test' === $mode ? $test_secret_key : $secret_key );
+ }
+
/**
* Generates the user agent we use to pass to API request so
* Stripe can identify our application.
diff --git a/includes/connect/class-wc-stripe-connect-api.php b/includes/connect/class-wc-stripe-connect-api.php
index 374f568f4..1e5720f54 100644
--- a/includes/connect/class-wc-stripe-connect-api.php
+++ b/includes/connect/class-wc-stripe-connect-api.php
@@ -18,13 +18,14 @@ class WC_Stripe_Connect_API {
/**
* Send request to Connect Server to initiate Stripe OAuth
*
- * @param string $return_url return address.
+ * @param string $return_url The URL to return to after the OAuth is completed.
+ * @param string $mode Optional. The mode to connect to. 'live' or 'test'. Default is 'live'.
*
- * @return array
+ * @return array|WP_Error The response from the server.
*/
- public function get_stripe_oauth_init( $return_url ) {
-
+ public function get_stripe_oauth_init( $return_url, $mode = 'live' ) {
$current_user = wp_get_current_user();
+ $account = WC_Stripe::get_instance()->account->get_cached_account_data( $mode );
$business_data = [];
$business_data['url'] = get_site_url();
$business_data['business_name'] = html_entity_decode( get_bloginfo( 'name' ), ENT_QUOTES );
@@ -55,21 +56,30 @@ public function get_stripe_oauth_init( $return_url ) {
'businessData' => $business_data,
];
- return $this->request( 'POST', '/stripe/oauth-init', $request );
+ // If the store is already connected to an account and the account is connected to an Application, send the account ID so
+ // api.woocommerce.com can determine the type of connection needed.
+ if ( isset( $account['id'], $account['controller']['type'] ) && 'application' === $account['controller']['type'] ) {
+ $request['accountId'] = $account['id'];
+ }
+
+ $path = 'test' === $mode ? '/stripe-sandbox/oauth-init' : '/stripe/oauth-init';
+
+ return $this->request( 'POST', $path, $request );
}
/**
* Send request to Connect Server for Stripe keys
*
- * @param string $code OAuth server code.
+ * @param string $code OAuth server code.
+ * @param string $mode Optional. The mode to connect to. 'live' or 'test'. Default is 'live'.
*
* @return array
*/
- public function get_stripe_oauth_keys( $code ) {
-
+ public function get_stripe_oauth_keys( $code, $mode = 'live' ) {
$request = [ 'code' => $code ];
- return $this->request( 'POST', '/stripe/oauth-keys', $request );
+ $path = 'test' === $mode ? '/stripe-sandbox/oauth-keys' : '/stripe/oauth-keys';
+ return $this->request( 'POST', $path, $request );
}
/**
diff --git a/includes/connect/class-wc-stripe-connect.php b/includes/connect/class-wc-stripe-connect.php
index 7a65aa65b..32aa0a859 100644
--- a/includes/connect/class-wc-stripe-connect.php
+++ b/includes/connect/class-wc-stripe-connect.php
@@ -33,11 +33,12 @@ public function __construct( WC_Stripe_Connect_API $api ) {
/**
* Gets the OAuth URL for Stripe onboarding flow
*
- * @param string $return_url url to return to after oauth flow.
+ * @param string $return_url The URL to return to after OAuth flow.
+ * @param string $mode Optional. The mode to connect to. 'live' or 'test'. Default is 'live'.
*
* @return string|WP_Error
*/
- public function get_oauth_url( $return_url = '' ) {
+ public function get_oauth_url( $return_url = '', $mode = 'live' ) {
if ( empty( $return_url ) ) {
$return_url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=stripe&panel=settings' );
@@ -49,7 +50,7 @@ public function get_oauth_url( $return_url = '' ) {
$return_url = add_query_arg( '_wpnonce', wp_create_nonce( 'wcs_stripe_connected' ), $return_url );
- $result = $this->api->get_stripe_oauth_init( $return_url );
+ $result = $this->api->get_stripe_oauth_init( $return_url, $mode );
if ( is_wp_error( $result ) ) {
return $result;
@@ -63,12 +64,13 @@ public function get_oauth_url( $return_url = '' ) {
/**
* Initiate OAuth connection request to Connect Server
*
- * @param string $state State token to prevent request forgery.
- * @param string $code OAuth code.
+ * @param string $state State token to prevent request forgery.
+ * @param string $code OAuth code.
+ * @param string $mode Optional. The mode to connect to. 'live' or 'test'. Default is 'live'.
*
* @return string|WP_Error
*/
- public function connect_oauth( $state, $code ) {
+ public function connect_oauth( $state, $code, $mode = 'live' ) {
// The state parameter is used to protect against CSRF.
// It's a unique, randomly generated, opaque, and non-guessable string that is sent when starting the
// authentication request and validated when processing the response.
@@ -76,7 +78,7 @@ public function connect_oauth( $state, $code ) {
return new WP_Error( 'Invalid state received from Stripe server' );
}
- $response = $this->api->get_stripe_oauth_keys( $code );
+ $response = $this->api->get_stripe_oauth_keys( $code, $mode );
if ( is_wp_error( $response ) ) {
return $response;
@@ -84,7 +86,7 @@ public function connect_oauth( $state, $code ) {
delete_transient( 'wcs_stripe_connect_state' );
- return $this->save_stripe_keys( $response );
+ return $this->save_stripe_keys( $response, $mode );
}
/**
@@ -107,11 +109,15 @@ public function maybe_handle_redirect() {
return new WP_Error( 'Invalid nonce received from Stripe server' );
}
- $response = $this->connect_oauth( wc_clean( wp_unslash( $_GET['wcs_stripe_state'] ) ), wc_clean( wp_unslash( $_GET['wcs_stripe_code'] ) ) );
+ $state = wc_clean( wp_unslash( $_GET['wcs_stripe_state'] ) );
+ $code = wc_clean( wp_unslash( $_GET['wcs_stripe_code'] ) );
+ $mode = isset( $_GET['wcs_stripe_mode'] ) ? wc_clean( wp_unslash( $_GET['wcs_stripe_mode'] ) ) : 'live';
+
+ $response = $this->connect_oauth( $state, $code, $mode );
$this->record_account_connect_track_event( is_wp_error( $response ) );
- wp_safe_redirect( esc_url_raw( remove_query_arg( [ 'wcs_stripe_state', 'wcs_stripe_code' ] ) ) );
+ wp_safe_redirect( esc_url_raw( remove_query_arg( [ 'wcs_stripe_state', 'wcs_stripe_code', 'wcs_stripe_mode' ] ) ) );
exit;
}
}
@@ -119,17 +125,18 @@ public function maybe_handle_redirect() {
/**
* Saves stripe keys after OAuth response
*
- * @param array $result OAuth response result.
+ * @param array $result OAuth response result.
+ * @param string $mode Optional. The mode to connect to. 'live' or 'test'. Default is 'live'.
*
* @return array|WP_Error
*/
- private function save_stripe_keys( $result ) {
+ private function save_stripe_keys( $result, $mode = 'live' ) {
if ( ! isset( $result->publishableKey, $result->secretKey ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
return new WP_Error( 'Invalid credentials received from WooCommerce Connect server' );
}
- $is_test = false !== strpos( $result->publishableKey, '_test_' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
+ $is_test = 'live' !== $mode;
$prefix = $is_test ? 'test_' : '';
$default_options = $this->get_default_stripe_config();
$options = array_merge( $default_options, get_option( self::SETTINGS_OPTION, [] ) );
diff --git a/tests/phpunit/test-class-wc-stripe-account.php b/tests/phpunit/test-class-wc-stripe-account.php
index 0f0579424..1fd4b6e5e 100644
--- a/tests/phpunit/test-class-wc-stripe-account.php
+++ b/tests/phpunit/test-class-wc-stripe-account.php
@@ -192,4 +192,72 @@ public function test_get_account_country() {
set_transient( 'wcstripe_account_data_test', $account );
$this->assertEquals( 'US', $this->account->get_account_country() );
}
+
+ /**
+ * Test for get_cached_account_data() with test mode parameter.
+ */
+ public function test_get_cached_account_data_test_mode() {
+ $this->mock_connect->method( 'is_connected' )->with( 'test' )->willReturn( true );
+
+ // Test mode account data.
+ $account = [
+ 'id' => 'acct_1234',
+ 'email' => 'test@example.com',
+ 'country' => 'US',
+ ];
+ set_transient( 'wcstripe_account_data_test', $account );
+
+ $this->assertSame( $this->account->get_cached_account_data( 'test' ), $account );
+ }
+
+ /**
+ * Test for get_cached_account_data() with live mode parameter.
+ */
+ public function test_get_cached_account_data_live_mode() {
+ $this->mock_connect->method( 'is_connected' )->with( 'live' )->willReturn( true );
+
+ // Live mode account data.
+ $account = [
+ 'id' => 'acct_1234',
+ 'email' => 'live@example.com',
+ 'country' => 'US',
+ ];
+ set_transient( 'wcstripe_account_data_live', $account );
+
+ $this->assertSame( $this->account->get_cached_account_data( 'live' ), $account );
+ }
+
+ /**
+ * Test for get_cached_account_data() with no mode parameter.
+ */
+ public function test_get_cached_account_data_no_mode() {
+ $stripe_settings = get_option( 'woocommerce_stripe_settings' );
+ $this->mock_connect->method( 'is_connected' )->with( null )->willReturn( true );
+
+ $test_account = [
+ 'id' => 'acct_test-1234',
+ 'email' => 'john@example.com',
+ ];
+
+ $live_account = [
+ 'id' => 'acct_live-1234',
+ 'email' => 'john@example.com',
+ ];
+ set_transient( 'wcstripe_account_data_test', $test_account );
+ set_transient( 'wcstripe_account_data_live', $live_account );
+
+ // Enable TEST mode.
+ $stripe_settings['testmode'] = 'yes';
+ update_option( 'woocommerce_stripe_settings', $stripe_settings );
+
+ // Confirm test mode data is returned.
+ $this->assertSame( $this->account->get_cached_account_data(), $test_account );
+
+ // Enable LIVE mode.
+ $stripe_settings['testmode'] = 'no';
+ update_option( 'woocommerce_stripe_settings', $stripe_settings );
+
+ // Confirm live mode data is returned.
+ $this->assertSame( $this->account->get_cached_account_data(), $live_account );
+ }
}
diff --git a/tests/phpunit/test-class-wc-stripe-api.php b/tests/phpunit/test-class-wc-stripe-api.php
new file mode 100644
index 000000000..2878a1e84
--- /dev/null
+++ b/tests/phpunit/test-class-wc-stripe-api.php
@@ -0,0 +1,97 @@
+assertEquals( $secret_key, WC_Stripe_API::get_secret_key() );
+ }
+
+ /**
+ * Test WC_Stripe_API::set_secret_key_for_mode() with no parameter.
+ */
+ public function test_set_secret_key_for_mode_no_parameter() {
+ // Base test - current mode is test.
+ WC_Stripe_API::set_secret_key_for_mode();
+
+ $this->assertEquals( self::TEST_SECRET_KEY, WC_Stripe_API::get_secret_key() );
+
+ // Enable live mode.
+ $stripe_settings = get_option( 'woocommerce_stripe_settings' );
+ $stripe_settings['testmode'] = 'no';
+ update_option( 'woocommerce_stripe_settings', $stripe_settings );
+
+ WC_Stripe_API::set_secret_key_for_mode();
+
+ $this->assertEquals( self::LIVE_SECRET_KEY, WC_Stripe_API::get_secret_key() );
+ }
+
+ /**
+ * Test WC_Stripe_API::set_secret_key_for_mode() with mode parameters.
+ */
+ public function test_set_secret_key_for_mode_with_parameter() {
+ WC_Stripe_API::set_secret_key_for_mode( 'test' );
+ $this->assertEquals( self::TEST_SECRET_KEY, WC_Stripe_API::get_secret_key() );
+
+ WC_Stripe_API::set_secret_key_for_mode( 'live' );
+ $this->assertEquals( self::LIVE_SECRET_KEY, WC_Stripe_API::get_secret_key() );
+
+ // Invalid parameters will set the secret key to the current mode.
+ WC_Stripe_API::set_secret_key_for_mode( 'invalid' );
+ $this->assertEquals( self::TEST_SECRET_KEY, WC_Stripe_API::get_secret_key() );
+
+ // Set the mode to live and test the invalid parameter.
+ $stripe_settings = get_option( 'woocommerce_stripe_settings' );
+ $stripe_settings['testmode'] = 'no';
+ update_option( 'woocommerce_stripe_settings', $stripe_settings );
+
+ WC_Stripe_API::set_secret_key_for_mode( 'invalid' );
+ $this->assertEquals( self::LIVE_SECRET_KEY, WC_Stripe_API::get_secret_key() );
+ }
+}