From 94cace2318b609aa4f6989925ddcbdb92c186e3b Mon Sep 17 00:00:00 2001 From: Ashley Gibson Date: Mon, 2 Feb 2026 13:17:15 +0000 Subject: [PATCH 1/4] Apple Pay: validate country against allowed order/shipping countries --- woocommerce/Helpers/CheckoutHelper.php | 52 ++++++++++++++++ ...s-sv-wc-payment-gateway-apple-pay-ajax.php | 60 +++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 woocommerce/Helpers/CheckoutHelper.php diff --git a/woocommerce/Helpers/CheckoutHelper.php b/woocommerce/Helpers/CheckoutHelper.php new file mode 100644 index 000000000..5e651549e --- /dev/null +++ b/woocommerce/Helpers/CheckoutHelper.php @@ -0,0 +1,52 @@ +countries) { + $allowed_countries = WC()->countries->get_allowed_countries(); + + return array_key_exists($countryCode, $allowed_countries); + } + + return true; + } + + /** + * Determines whether the provided country code is allowed for shipping. + * + * @since 6.0.1 + * + * @param string $countryCode recommended to pass through the *shipping* address + * @return bool + */ + public static function isCountryAllowedForShipping(string $countryCode): bool + { + if (empty($countryCode)) { + return false; + } + + if (WC() && WC()->countries) { + $shipping_countries = WC()->countries->get_shipping_countries(); + + return array_key_exists($countryCode, $shipping_countries); + } + + return true; + } +} diff --git a/woocommerce/payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-ajax.php b/woocommerce/payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-ajax.php index 0c54d94f0..ccbca749d 100644 --- a/woocommerce/payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-ajax.php +++ b/woocommerce/payment-gateway/External_Checkout/apple-pay/class-sv-wc-payment-gateway-apple-pay-ajax.php @@ -24,6 +24,8 @@ namespace SkyVerge\WooCommerce\PluginFramework\v6_0_0; +use SkyVerge\WooCommerce\PluginFramework\v6_0_0\Helpers\CheckoutHelper; + defined( 'ABSPATH' ) or exit; if ( ! class_exists( '\\SkyVerge\\WooCommerce\\PluginFramework\\v6_0_0\\SV_WC_Payment_Gateway_Apple_Pay_AJAX' ) ) : @@ -180,6 +182,16 @@ public function recalculate_totals() { $city = $contact['locality']; $postcode = $contact['postalCode']; + // validate country against WooCommerce selling and shipping settings + if ( $country ) { + /* + * Validate country against WooCommerce selling and shipping settings. + * Apple Pay contact info is primarily shipping address, but since we don't have both, we'll use + * the shipping address to validate both billing and shipping settings. + */ + $this->validateAllowedCountry( $country, $country ); + } + WC()->customer->set_shipping_city( $city ); WC()->customer->set_shipping_state( $state ); WC()->customer->set_shipping_country( $country ); @@ -238,6 +250,12 @@ public function process_payment() { try { + // final validation check: ensure billing/shipping country is still allowed + $billing_country = WC()->customer->get_billing_country(); + $shipping_country = WC()->customer->get_shipping_country(); + + $this->validateAllowedCountry( $billing_country ?: '', $shipping_country ?: '' ); + $result = $this->get_handler()->process_payment(); wp_send_json_success( $result ); @@ -254,6 +272,48 @@ public function process_payment() { } + /** + * Validates that the provided countries are allowed for billing and shipping. + * + * @since 6.0.1 + * + * @param string $billingCountry billing country code (empty string if not provided) + * @param string $shippingCountry shipping country code (empty string if not provided) + * @throws \Exception if validation fails + */ + protected function validateAllowedCountry(string $billingCountry, string $shippingCountry) + { + + // validate billing country for orders (if provided) + if (! empty($billingCountry) && ! CheckoutHelper::isCountryAllowedToOrder($billingCountry)) { + + $this->get_handler()->log("Apple Pay: Billing country '{$billingCountry}' is not allowed for orders"); + + throw new \Exception( + sprintf( + /* translators: %s country code. */ + esc_html__('Sorry, we do not allow orders from the provided country (%s)', 'woocommerce'), + esc_html($billingCountry) + ) + ); + } + + // validate shipping country for shipping (if provided) + if (! empty($shippingCountry) && ! CheckoutHelper::isCountryAllowedForShipping($shippingCountry)) { + + $this->get_handler()->log("Apple Pay: Shipping country '{$shippingCountry}' is not allowed for shipping"); + + throw new \Exception( + sprintf( + /* translators: %s country code. */ + esc_html__('Sorry, we do not ship orders to the provided country (%s)', 'woocommerce'), + esc_html($shippingCountry) + ) + ); + } + } + + /** * Gets the Apple Pay handler instance. * From 599c84904e9680adc955d01d6f33edc906fd8cce Mon Sep 17 00:00:00 2001 From: Ashley Gibson Date: Mon, 2 Feb 2026 13:18:05 +0000 Subject: [PATCH 2/4] Update to 6.0.1 namespace --- woocommerce/Helpers/CheckoutHelper.php | 2 +- .../apple-pay/class-sv-wc-payment-gateway-apple-pay-ajax.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/woocommerce/Helpers/CheckoutHelper.php b/woocommerce/Helpers/CheckoutHelper.php index 5e651549e..ee5cc1baf 100644 --- a/woocommerce/Helpers/CheckoutHelper.php +++ b/woocommerce/Helpers/CheckoutHelper.php @@ -1,6 +1,6 @@ Date: Mon, 2 Feb 2026 13:26:50 +0000 Subject: [PATCH 3/4] Add unit tests --- tests/unit/Helpers/CheckoutHelperTest.php | 97 +++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 tests/unit/Helpers/CheckoutHelperTest.php diff --git a/tests/unit/Helpers/CheckoutHelperTest.php b/tests/unit/Helpers/CheckoutHelperTest.php new file mode 100644 index 000000000..e5fc7c465 --- /dev/null +++ b/tests/unit/Helpers/CheckoutHelperTest.php @@ -0,0 +1,97 @@ +countries = $wcCountriesAvailable ? $countriesMock : null; + + WP_Mock::userFunction('WC') + ->andReturn($wcMock); + + $countriesMock->allows('get_allowed_countries') + ->andReturn($allowedCountries); + + $this->assertSame($expected, CheckoutHelper::isCountryAllowedToOrder($countryCode)); + } + + /** + * @covers ::isCountryAllowedForShipping + * @dataProvider countryCodeProvider + */ + public function testCanDetermineIsCountryAllowedForShipping( + string $countryCode, + bool $wcCountriesAvailable, + array $allowedCountries, + bool $expected + ) { + $wcMock = Mockery::mock('WooCommerce'); + + $countriesMock = Mockery::mock('WC_Countries'); + $wcMock->countries = $wcCountriesAvailable ? $countriesMock : null; + + WP_Mock::userFunction('WC') + ->andReturn($wcMock); + + $countriesMock->allows('get_shipping_countries') + ->andReturn($allowedCountries); + + $this->assertSame($expected, CheckoutHelper::isCountryAllowedForShipping($countryCode)); + } + + /** + * @see testCanDetermineIsCountryAllowedToOrder + */ + public function countryCodeProvider() : Generator + { + yield 'empty country code' => [ + 'countryCode' => '', + 'wcCountriesAvailable' => false, + 'allowedCountries' => [], + 'expected' => false, + ]; + + yield 'WC countries not available' => [ + 'countryCode' => 'GB', + 'wcCountriesAvailable' => false, + 'allowedCountries' => [], + 'expected' => true, + ]; + + yield 'not on allow list' => [ + 'countryCode' => 'GB', + 'wcCountriesAvailable' => true, + 'allowedCountries' => ['US' => 'United States', 'FR' => 'France'], + 'expected' => false, + ]; + + yield 'is on allow list' => [ + 'countryCode' => 'GB', + 'wcCountriesAvailable' => true, + 'allowedCountries' => ['US' => 'United States', 'FR' => 'France', 'GB' => 'Great Britain'], + 'expected' => true, + ]; + } +} From 962cea852487cae965fe7218def6a0a17a5c55e1 Mon Sep 17 00:00:00 2001 From: Ashley Gibson Date: Mon, 2 Feb 2026 13:27:48 +0000 Subject: [PATCH 4/4] Update changelog --- woocommerce/changelog.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/woocommerce/changelog.txt b/woocommerce/changelog.txt index a63c4b66f..1214c22a1 100644 --- a/woocommerce/changelog.txt +++ b/woocommerce/changelog.txt @@ -1,7 +1,8 @@ *** SkyVerge WooCommerce Plugin Framework Changelog *** -2025.nn.nn - version 6.0.1 +2026.nn.nn - version 6.0.1 * Dev - Set PHP 8.1 defaults on `html_entity_decode()` usage (ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401) + * Fix - Apple Pay: Check store country restrictions for selling/shipping 2025.nn.nn - version 6.0.0 * Dev - Completely reworked how we handle dynamic properties on WooCommerce order objects. For now this change is backwards compatible with v5, but we will eventually drop support for the legacy method, so migrating ASAP is recommended. See the upgrade guide: https://github.com/godaddy-wordpress/wc-plugin-framework/wiki/Migrating-to-v6