Commit 191cd69dd11 for woocommerce
commit 191cd69dd111827b6ace08a08b9fb3fdcf0b175b
Author: Waqas Ahmed <wakqasahmed@gmail.com>
Date: Wed Oct 14 09:02:48 2026 -0700
Only tax pickup_location rates at a block pickup location (#69346)
* Only use pickup location addresses for pickup_location tax lookups
ShippingController::filter_taxable_address() treated the number after the
colon of any local pickup rate id as an index into the block pickup
locations. For the zone local_pickup method that number is a shipping zone
instance id, so the cart could be taxed at an unrelated pickup location.
Restrict the lookup to pickup_location rates and default missing
state/postcode/city keys.
Fixes #69267
* Add changefile(s) from automation for the following project(s): woocommerce
* delete extra changelog
* Apply suggestion from @senadir
* Apply suggestion from @senadir
* Add changefile(s) from automation for the following project(s): woocommerce
* Remove duplicate local pickup changelog entry
---------
Co-authored-by: woocommercebot <woocommercebot@users.noreply.github.com>
Co-authored-by: Seghir Nadir <nadir.seghir@gmail.com>
diff --git a/plugins/woocommerce/changelog/69346-fix-issue-69267-local-pickup-tax-address b/plugins/woocommerce/changelog/69346-fix-issue-69267-local-pickup-tax-address
new file mode 100644
index 00000000000..86850af637d
--- /dev/null
+++ b/plugins/woocommerce/changelog/69346-fix-issue-69267-local-pickup-tax-address
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Stop taxing a zone Local pickup order at the block pickup location whose list position matches the method's instance id.
diff --git a/plugins/woocommerce/src/Blocks/Shipping/ShippingController.php b/plugins/woocommerce/src/Blocks/Shipping/ShippingController.php
index 8a17a052e33..cf0edf5ca46 100644
--- a/plugins/woocommerce/src/Blocks/Shipping/ShippingController.php
+++ b/plugins/woocommerce/src/Blocks/Shipping/ShippingController.php
@@ -450,17 +450,18 @@ class ShippingController {
$chosen_method_id = explode( ':', $chosen_method )[0];
$chosen_method_instance = explode( ':', $chosen_method )[1] ?? 0;
+ // Only pickup_location rates should get their address from the saved settings, local_pickup has another filter, and third party pickup locations should have their own filter and logic for the address as well.
// phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment -- Documented in WC_Abstract_Order::get_tax_location().
- if ( $chosen_method_id && true === apply_filters( 'woocommerce_apply_base_tax_for_local_pickup', true ) && in_array( $chosen_method_id, LocalPickupUtils::get_local_pickup_method_ids(), true ) ) {
+ if ( 'pickup_location' === $chosen_method_id && true === apply_filters( 'woocommerce_apply_base_tax_for_local_pickup', true ) ) {
$pickup_locations = get_option( 'pickup_location_pickup_locations', array() );
$pickup_location = $pickup_locations[ $chosen_method_instance ] ?? array();
if ( isset( $pickup_location['address'], $pickup_location['address']['country'] ) && ! empty( $pickup_location['address']['country'] ) ) {
$address = array(
- $pickup_locations[ $chosen_method_instance ]['address']['country'],
- $pickup_locations[ $chosen_method_instance ]['address']['state'],
- $pickup_locations[ $chosen_method_instance ]['address']['postcode'],
- $pickup_locations[ $chosen_method_instance ]['address']['city'],
+ $pickup_location['address']['country'],
+ $pickup_location['address']['state'] ?? '',
+ $pickup_location['address']['postcode'] ?? '',
+ $pickup_location['address']['city'] ?? '',
);
}
}
diff --git a/plugins/woocommerce/tests/php/src/Blocks/Shipping/ShippingControllerTest.php b/plugins/woocommerce/tests/php/src/Blocks/Shipping/ShippingControllerTest.php
index b89e67e7469..c93708745f4 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/Shipping/ShippingControllerTest.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/Shipping/ShippingControllerTest.php
@@ -93,6 +93,7 @@ class ShippingControllerTest extends \WC_Unit_Test_Case {
try {
$woocommerce = $this->backup_wc;
+ WC()->session->set( 'chosen_shipping_methods', null );
foreach ( $this->previous_shipping_address as $key => $value ) {
WC()->customer->{"set_shipping_{$key}"}( $value );
}
@@ -317,6 +318,91 @@ class ShippingControllerTest extends \WC_Unit_Test_Case {
$this->assertSame( $default_location, $location, 'Without a captured pickup address the location should be unchanged.' );
}
+ /**
+ * @testdox filter_taxable_address does not tax a zone local_pickup rate at the pickup location sharing its instance id.
+ */
+ public function test_filter_taxable_address_ignores_pickup_locations_for_zone_local_pickup(): void {
+ $this->save_pickup_locations();
+ WC()->session->set( 'chosen_shipping_methods', array( 'local_pickup:1' ) );
+
+ $address = array( 'US', 'CA', '90210', 'Beverly Hills' );
+
+ $this->assertSame( $address, $this->shipping_controller->filter_taxable_address( $address ), 'A zone local_pickup instance id is not a pickup location index.' );
+ }
+
+ /**
+ * @testdox filter_taxable_address returns the chosen pickup location address for pickup_location rates.
+ */
+ public function test_filter_taxable_address_returns_chosen_pickup_location_address(): void {
+ $this->save_pickup_locations();
+ WC()->session->set( 'chosen_shipping_methods', array( 'pickup_location:1' ) );
+
+ $this->assertSame(
+ array( 'US', 'NY', '10001', 'New York' ),
+ $this->shipping_controller->filter_taxable_address( array( 'US', 'CA', '90210', 'Beverly Hills' ) )
+ );
+ }
+
+ /**
+ * @testdox filter_taxable_address tolerates a pickup location address without a state.
+ */
+ public function test_filter_taxable_address_handles_pickup_location_without_state(): void {
+ update_option(
+ 'pickup_location_pickup_locations',
+ array(
+ array(
+ 'name' => 'Paris',
+ 'address' => array(
+ 'country' => 'FR',
+ 'postcode' => '75001',
+ 'city' => 'Paris',
+ ),
+ 'details' => '',
+ 'enabled' => true,
+ ),
+ )
+ );
+ WC()->session->set( 'chosen_shipping_methods', array( 'pickup_location:0' ) );
+
+ $this->assertSame(
+ array( 'FR', '', '75001', 'Paris' ),
+ $this->shipping_controller->filter_taxable_address( array( 'US', 'CA', '90210', 'Beverly Hills' ) )
+ );
+ }
+
+ /**
+ * Saves two pickup locations, Austin at index 0 and New York at index 1.
+ */
+ private function save_pickup_locations(): void {
+ update_option(
+ 'pickup_location_pickup_locations',
+ array(
+ array(
+ 'name' => 'Austin',
+ 'address' => array(
+ 'country' => 'US',
+ 'state' => 'TX',
+ 'postcode' => '73301',
+ 'city' => 'Austin',
+ ),
+ 'details' => '',
+ 'enabled' => true,
+ ),
+ array(
+ 'name' => 'New York',
+ 'address' => array(
+ 'country' => 'US',
+ 'state' => 'NY',
+ 'postcode' => '10001',
+ 'city' => 'New York',
+ ),
+ 'details' => '',
+ 'enabled' => true,
+ ),
+ )
+ );
+ }
+
/**
* Overrides the WC logger.
*