Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog/refactor-google-pay-apple-pay-settings-storage
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: update

refactor: Google Pay/Apple Pay settings storage consistency
40 changes: 38 additions & 2 deletions includes/admin/class-wc-rest-payments-settings-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ public function get_settings(): WP_REST_Response {
'account_branding_primary_color' => $this->wcpay_gateway->get_option( 'account_branding_primary_color' ),
'account_branding_secondary_color' => $this->wcpay_gateway->get_option( 'account_branding_secondary_color' ),
'account_domestic_currency' => $this->wcpay_gateway->get_option( 'account_domestic_currency' ),
'is_payment_request_enabled' => 'yes' === $this->wcpay_gateway->get_option( 'payment_request' ),
'is_payment_request_enabled' => $this->get_is_payment_request_enabled(),
'is_apple_google_pay_in_payment_methods_options_enabled' => 'yes' === $this->wcpay_gateway->get_option( 'apple_google_pay_in_payment_methods_options' ),
'is_debug_log_enabled' => 'yes' === $this->wcpay_gateway->get_option( 'enable_logging' ),
'payment_request_enabled_locations' => $this->wcpay_gateway->get_option( 'payment_request_button_locations' ),
Expand Down Expand Up @@ -842,6 +842,25 @@ private function update_account( WP_REST_Request $request ) {
return $this->wcpay_gateway->update_account_settings( $updated_fields );
}

/**
* Gets the payment request enabled status.
*
* @return bool
*/
private function get_is_payment_request_enabled() {
$google_pay_gateway = WC_Payments::get_payment_gateway_by_id( 'google_pay' );
if ( $google_pay_gateway ) {
return $google_pay_gateway->is_enabled();
}

$apple_pay_gateway = WC_Payments::get_payment_gateway_by_id( 'apple_pay' );
if ( $apple_pay_gateway ) {
return $apple_pay_gateway->is_enabled();
}

return false;
}

/**
* Updates the "payment request" enable/disable settings.
*
Expand All @@ -854,7 +873,24 @@ private function update_is_payment_request_enabled( WP_REST_Request $request ) {

$is_payment_request_enabled = $request->get_param( 'is_payment_request_enabled' );

$this->wcpay_gateway->update_option( 'payment_request', $is_payment_request_enabled ? 'yes' : 'no' );
// Update Google Pay and Apple Pay enabled settings to keep them in sync.
$google_pay_gateway = WC_Payments::get_payment_gateway_by_id( 'google_pay' );
if ( $google_pay_gateway ) {
if ( $is_payment_request_enabled ) {
$google_pay_gateway->enable();
} else {
$google_pay_gateway->disable();
}
}

$apple_pay_gateway = WC_Payments::get_payment_gateway_by_id( 'apple_pay' );
if ( $apple_pay_gateway ) {
if ( $is_payment_request_enabled ) {
$apple_pay_gateway->enable();
} else {
$apple_pay_gateway->disable();
}
}
Comment on lines 873 to 890
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where things get "muddy": Google Pay and Apple Pay are two separate payment methods, implemented with two different payment method classes.
But in the settings page, only one checkbox controls both of them.
In other words:

  • For Google Pay/Apple Pay: 1 checkbox controls both of them.
  • For other payment methods: 1 checkbox controls one payment method.
Image

Now, in order to have them appear "enabled" on the payment methods list at checkout (for the subsequent work), I need to ensure that they are both "enabled".

I considered adding an action somewhere that listened to changes to either the Google Pay or Apple Pay payment method settings and enabled/disabled the other automagically.
But I thought it wasn't very explicit. And since it would have been a filter somewhere else, I thought it wouldn't a "transparent" mechanism, which could have lead to bugs.

}

/**
Expand Down
5 changes: 4 additions & 1 deletion includes/class-duplicates-detection-service.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,10 @@ private function search_for_payment_request_buttons() {
if ( strpos( $gateway->id, $keyword ) !== false ) {
$this->gateways_qualified_by_duplicates_detector[ $prb_payment_method ][] = $gateway->id;
break;
} elseif ( 'yes' === $gateway->get_option( 'payment_request' ) && in_array( $gateway->id, [ 'woocommerce_payments', 'stripe' ], true ) ) {
} elseif ( 'woocommerce_payments' === $gateway->id && method_exists( $gateway, 'is_payment_request_enabled' ) && $gateway->is_payment_request_enabled() ) {
$this->gateways_qualified_by_duplicates_detector[ $prb_payment_method ][] = $gateway->id;
break;
} elseif ( 'stripe' === $gateway->id && 'yes' === $gateway->get_option( 'payment_request' ) ) {
$this->gateways_qualified_by_duplicates_detector[ $prb_payment_method ][] = $gateway->id;
break;
} elseif ( 'yes' === $gateway->get_option( 'express_checkout_enabled' ) ) {
Expand Down
15 changes: 13 additions & 2 deletions includes/class-wc-payment-gateway-wcpay.php
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,7 @@ public function is_available() {
}

// Disable the gateway if it should not be displayed on the checkout page.
$is_gateway_enabled = in_array( $this->stripe_id, $this->get_payment_method_ids_enabled_at_checkout(), true ) ? true : false;
$is_gateway_enabled = in_array( $this->stripe_id, $this->get_payment_method_ids_enabled_at_checkout(), true ) ? true : false;
if ( ! $is_gateway_enabled ) {
return false;
}
Expand Down Expand Up @@ -957,7 +957,18 @@ public function is_saved_cards_enabled() {
* @return bool Whether the setting to show the payment request buttons is enabled or not.
*/
public function is_payment_request_enabled() {
return 'yes' === $this->get_option( 'payment_request' );
$google_pay_gateway = WC_Payments::get_payment_gateway_by_id( 'google_pay' );
if ( $google_pay_gateway && $google_pay_gateway->is_enabled() ) {
return true;
}

// fallback, just in case.
$apple_pay_gateway = WC_Payments::get_payment_gateway_by_id( 'apple_pay' );
if ( $apple_pay_gateway && $apple_pay_gateway->is_enabled() ) {
return true;
}

return false;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion includes/class-wc-payments-account.php
Original file line number Diff line number Diff line change
Expand Up @@ -2726,7 +2726,7 @@ private function get_store_setup_details(): array {
'debug_log_enabled' => 'yes' === $gateway->get_option( 'enable_logging' ),

'payment_request' => [
'enabled' => 'yes' === $gateway->get_option( 'payment_request' ),
'enabled' => $gateway->is_payment_request_enabled(),
'enabled_locations' => $gateway->get_option( 'payment_request_button_locations' ),
'button_type' => $gateway->get_option( 'payment_request_button_type' ),
'button_size' => $gateway->get_option( 'payment_request_button_size' ),
Expand Down
96 changes: 55 additions & 41 deletions includes/class-wc-payments-apple-pay-registration.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ class WC_Payments_Apple_Pay_Registration {
private $domain_name;

/**
* Stores Apple Pay domain verification issues.
* Option name for storing Apple Pay domain verification errors.
*
* @var string
*/
private $apple_pay_verify_notice;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the previous implementation, the error message was stored as an attribute on the class.
The problem is that the settings updates happen over AJAX. And the attribute is not persisted across page refreshes.
So the exact error message was never displayed to the merchant.

I modified the implementation to store the error message in a new wcpay_apple_pay_domain_error option, so it can be persisted across page refreshes.

const APPLE_PAY_DOMAIN_ERROR_OPTION = 'wcpay_apple_pay_domain_error';

/**
* Initialize class actions.
Expand All @@ -63,11 +63,10 @@ class WC_Payments_Apple_Pay_Registration {
* @param WC_Payment_Gateway_WCPay $gateway WooCommerce Payments gateway.
*/
public function __construct( WC_Payments_API_Client $payments_api_client, WC_Payments_Account $account, WC_Payment_Gateway_WCPay $gateway ) {
$this->domain_name = wp_parse_url( get_site_url(), PHP_URL_HOST );
$this->apple_pay_verify_notice = '';
$this->payments_api_client = $payments_api_client;
$this->account = $account;
$this->gateway = $gateway;
$this->domain_name = wp_parse_url( get_site_url(), PHP_URL_HOST );
$this->payments_api_client = $payments_api_client;
$this->account = $account;
$this->gateway = $gateway;
}

/**
Expand All @@ -88,30 +87,44 @@ public function init() {
add_action( 'admin_init', [ $this, 'verify_domain_on_domain_name_change' ] );

add_action( 'woocommerce_woocommerce_payments_admin_notices', [ $this, 'display_error_notice' ] );
add_action( 'add_option_woocommerce_woocommerce_payments_settings', [ $this, 'verify_domain_on_new_settings' ], 10, 2 );
add_action( 'update_option_woocommerce_woocommerce_payments_settings', [ $this, 'verify_domain_on_updated_settings' ], 10, 2 );

// Listen to Apple Pay gateway settings changes for domain verification.
add_action( 'add_option_woocommerce_woocommerce_payments_apple_pay_settings', [ $this, 'verify_domain_on_new_settings' ], 10, 2 );
add_action( 'update_option_woocommerce_woocommerce_payments_apple_pay_settings', [ $this, 'verify_domain_on_updated_settings' ], 10, 2 );
}

/**
* Whether the gateway and Express Checkout Buttons (prerequisites for Apple Pay) are enabled.
* Whether Apple Pay is enabled.
*
* Checks both the main gateway and the Apple Pay gateway are enabled.
*
* @return bool Whether Apple Pay required settings are enabled.
* @return bool Whether Apple Pay is enabled.
*/
private function is_enabled() {
return $this->gateway->is_enabled() && 'yes' === $this->gateway->get_option( 'payment_request' );
// Check if the main gateway is enabled.
if ( ! $this->gateway->is_enabled() ) {
return false;
}

// Check if the Apple Pay gateway is enabled.
$apple_pay_gateway = WC_Payments::get_payment_gateway_by_id( 'apple_pay' );

if ( ! $apple_pay_gateway ) {
return false;
}

return $apple_pay_gateway->is_enabled();
}

/**
* Whether the gateway and Express Checkout Buttons were enabled in previous settings.
* Whether Apple Pay was enabled in previous settings.
*
* @param array|null $prev_settings Gateway settings.
* @param array|null $prev_settings Apple Pay gateway settings.
*
* @return bool Whether Apple Pay required settings are enabled.
* @return bool Whether Apple Pay was enabled.
*/
private function was_enabled( $prev_settings ) {
$gateway_enabled = 'yes' === ( $prev_settings['enabled'] ?? 'no' );
$payment_request_enabled = 'yes' === ( $prev_settings['payment_request'] ?? 'no' );
return $gateway_enabled && $payment_request_enabled;
return 'yes' === ( $prev_settings['enabled'] ?? 'no' );
}

/**
Expand Down Expand Up @@ -153,6 +166,7 @@ public function register_domain() {
if ( isset( $registration_response['id'] ) && ( isset( $registration_response['apple_pay']['status'] ) && 'active' === $registration_response['apple_pay']['status'] ) ) {
$this->gateway->update_option( 'apple_pay_verified_domain', $this->domain_name );
$this->gateway->update_option( 'apple_pay_domain_set', 'yes' );
delete_option( self::APPLE_PAY_DOMAIN_ERROR_OPTION );

Logger::log( __( 'Your domain has been verified with Apple Pay!', 'woocommerce-payments' ) );
Tracker::track_admin(
Expand All @@ -170,11 +184,10 @@ public function register_domain() {
} catch ( API_Exception $e ) {
$error = $e->getMessage();
}
// Display error message in notice.
$this->apple_pay_verify_notice = $error;

$this->gateway->update_option( 'apple_pay_verified_domain', $this->domain_name );
$this->gateway->update_option( 'apple_pay_domain_set', 'no' );
update_option( self::APPLE_PAY_DOMAIN_ERROR_OPTION, $error );

Logger::log( 'Error registering domain with Apple: ' . $error );
Tracker::track_admin(
Expand All @@ -192,7 +205,7 @@ public function register_domain() {
*/
public function verify_domain_if_configured() {
// If Express Checkout Buttons are not enabled,
// do not attempt to register domain.
// do not attempt to register the domain.
if ( ! $this->is_enabled() ) {
return;
}
Expand Down Expand Up @@ -232,29 +245,36 @@ public function display_error_notice() {
return;
}

$empty_notice = empty( $this->apple_pay_verify_notice );
$domain_set = $this->gateway->get_option( 'apple_pay_domain_set' );
$error_notice = get_option( self::APPLE_PAY_DOMAIN_ERROR_OPTION, '' );
$empty_notice = empty( $error_notice );

// Don't display error notice if verification notice is empty and
// apple_pay_domain_set option equals to '' or 'yes'.
if ( $empty_notice && 'no' !== $domain_set ) {
return;
}

// Clear the error after retrieving it so it only displays once.
if ( ! $empty_notice ) {
delete_option( self::APPLE_PAY_DOMAIN_ERROR_OPTION );
}

/**
* Apple pay is enabled by default and domain verification initializes
* when setting screen is displayed. So if domain verification is not set,
* something went wrong so lets notify user.
*/
$allowed_html = [
$allowed_html = [
'a' => [
'href' => [],
'title' => [],
],
];
$payment_request_button_text = __( 'Express checkouts:', 'woocommerce-payments' );
$verification_failed_without_error = __( 'Apple Pay domain verification failed.', 'woocommerce-payments' );
$verification_failed_with_error = __( 'Apple Pay domain verification failed with the following error:', 'woocommerce-payments' );
$check_log_text = WC_Payments_Utils::esc_interpolated_html(
$verification_failed = $empty_notice
? __( 'Apple Pay domain verification failed.', 'woocommerce-payments' )
: __( 'Apple Pay domain verification failed with the following error:', 'woocommerce-payments' );
$check_log_text = WC_Payments_Utils::esc_interpolated_html(
/* translators: a: Link to the logs page */
__( 'Please check the <a>logs</a> for more details on this issue. Debug log must be enabled under <strong>Advanced settings</strong> to see recorded logs.', 'woocommerce-payments' ),
[
Expand All @@ -271,20 +291,14 @@ public function display_error_notice() {

?>
<div class="notice notice-error apple-pay-message">
<?php if ( $empty_notice ) : ?>
<p>
<strong><?php echo esc_html( $payment_request_button_text ); ?></strong>
<?php echo esc_html( $verification_failed_without_error ); ?>
<?php echo $learn_more_text; /* @codingStandardsIgnoreLine */ ?>
</p>
<?php else : ?>
<p>
<strong><?php echo esc_html( $payment_request_button_text ); ?></strong>
<?php echo esc_html( $verification_failed_with_error ); ?>
<?php echo $learn_more_text; /* @codingStandardsIgnoreLine */ ?>
</p>
<p><i><?php echo wp_kses( make_clickable( esc_html( $this->apple_pay_verify_notice ) ), $allowed_html ); ?></i></p>
<?php endif; ?>
<p>
<strong><?php esc_html_e( 'Express checkouts:', 'woocommerce-payments' ); ?></strong>
<?php echo esc_html( $verification_failed ); ?>
<?php echo $learn_more_text; /* @codingStandardsIgnoreLine */ ?>
</p>
<?php if ( ! $empty_notice ) : ?>
<p><i><?php echo wp_kses( make_clickable( esc_html( $error_notice ) ), $allowed_html ); ?></i></p>
<?php endif; ?>
<p><?php echo $check_log_text; /* @codingStandardsIgnoreLine */ ?></p>
</div>
<?php
Expand Down
1 change: 0 additions & 1 deletion includes/class-wc-payments-blocks-payment-method.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ public function is_active() {
* @return string[] A list of script handles.
*/
public function get_payment_method_script_handles() {

if ( ( is_cart() || is_checkout() || is_product() || has_block( 'woocommerce/checkout' ) || has_block( 'woocommerce/cart' ) || is_admin() ) ) {
WC_Payments_Utils::enqueue_style(
'wc-blocks-checkout-style',
Expand Down
20 changes: 16 additions & 4 deletions includes/class-wc-payments-onboarding-service.php
Original file line number Diff line number Diff line change
Expand Up @@ -1439,11 +1439,23 @@ public function update_enabled_payment_methods_ids( $gateway, $capabilities = []
$gateway->update_is_woopay_enabled( false );
}

// Update gateway option with the Apple/Google Pay capability.
if ( ! empty( $capabilities['apple_google'] ) || ( ! empty( $capabilities['apple_pay'] ) || ! empty( $capabilities['google_pay'] ) ) ) {
$gateway->update_option( 'payment_request', 'yes' );
// Update Apple/Google Pay gateway enabled state.
$apple_pay_gateway = WC_Payments::get_payment_gateway_by_id( 'apple_pay' );
$google_pay_gateway = WC_Payments::get_payment_gateway_by_id( 'google_pay' );
if ( ! empty( $capabilities['apple_google'] ) || ! empty( $capabilities['apple_pay'] ) ) {
if ( $apple_pay_gateway ) {
$apple_pay_gateway->enable();
}
if ( $google_pay_gateway ) {
$google_pay_gateway->enable();
}
} else {
$gateway->update_option( 'payment_request', 'no' );
if ( $apple_pay_gateway ) {
$apple_pay_gateway->update_option( 'enabled', 'no' );
}
if ( $google_pay_gateway ) {
$google_pay_gateway->update_option( 'enabled', 'no' );
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion includes/class-wc-payments-status.php
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ public function render_status_report_section() {
<td class="help"><?php echo wc_help_tip( esc_html__( 'Whether the store has Payment Request enabled or not.', 'woocommerce-payments' ) ); /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped, WordPress.Security.EscapeOutput.OutputNotEscaped */ ?></td>
<td>
<?php
$payment_request_enabled = 'yes' === $this->gateway->get_option( 'payment_request' );
$payment_request_enabled = $this->gateway->is_payment_request_enabled();
$payment_request_enabled_locations = $this->gateway->get_option( 'payment_request_button_locations', [] );
$payment_request_enabled_locations = empty( $payment_request_enabled_locations ) ? 'no locations enabled' : implode( ',', $payment_request_enabled_locations );
echo esc_html( $payment_request_enabled ? __( 'Enabled', 'woocommerce-payments' ) . ' (' . $payment_request_enabled_locations . ')' : __( 'Disabled', 'woocommerce-payments' ) );
Expand Down
2 changes: 2 additions & 0 deletions includes/class-wc-payments.php
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,7 @@ function () {
require_once __DIR__ . '/migrations/class-erase-bnpl-announcement-meta.php';
require_once __DIR__ . '/migrations/class-erase-deprecated-flags-and-options.php';
require_once __DIR__ . '/migrations/class-manual-capture-payment-method-settings-update.php';
require_once __DIR__ . '/migrations/class-migrate-payment-request-to-express-checkout-enabled.php';
add_action( 'woocommerce_woocommerce_payments_updated', [ new Allowed_Payment_Request_Button_Types_Update( self::get_gateway() ), 'maybe_migrate' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Allowed_Payment_Request_Button_Sizes_Update( self::get_gateway() ), 'maybe_migrate' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Update_Service_Data_From_Server( self::get_account_service() ), 'maybe_migrate' ] );
Expand All @@ -705,6 +706,7 @@ function () {
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Erase_Bnpl_Announcement_Meta(), 'maybe_migrate' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Erase_Deprecated_Flags_And_Options(), 'maybe_migrate' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Manual_Capture_Payment_Method_Settings_Update( self::get_gateway(), self::get_payment_gateway_map() ), 'maybe_migrate' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Migrate_Payment_Request_To_Express_Checkout_Enabled(), 'maybe_migrate' ] );

include_once WCPAY_ABSPATH . '/includes/class-wc-payments-explicit-price-formatter.php';
WC_Payments_Explicit_Price_Formatter::init();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public function init() {
$this->express_checkout_button_handler->init();

$is_woopay_enabled = WC_Payments_Features::is_woopay_enabled();
$is_payment_request_enabled = 'yes' === $this->gateway->get_option( 'payment_request' );
$is_payment_request_enabled = $this->gateway->is_payment_request_enabled();

if ( $is_woopay_enabled ) {
add_action( 'wc_ajax_wcpay_add_to_cart', [ $this->express_checkout_ajax_handler, 'ajax_add_to_cart' ] );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ public function init() {
return;
}

// Checks if Payment Request is enabled.
if ( 'yes' !== $this->gateway->get_option( 'payment_request' ) ) {
// Checks if Google Pay or Apple Pay are enabled.
if ( ! $this->gateway->is_payment_request_enabled() ) {
return;
}

Expand Down
Loading
Loading