Commit a114dffd3b for woocommerce

commit a114dffd3bef1914d48a1bd448d9a809c5665f6b
Author: Ayush Pahwa <ayush.pahwa@automattic.com>
Date:   Fri Jan 23 17:19:15 2026 +0700

    fix: block checkout local pickup fails to render (#62873)

    * update: move local pickup escape hatch outside of the if block

    * test: add coverage for the fix

    * chore: add changelog entry

    * Apply woocommerce_cart_ready_to_calc_shipping filter on local pickup early return

    * chore: add since tag to the docblock

    * chore: update tag version since the functionality hasn't changed

diff --git a/plugins/woocommerce/changelog/fix-wooplug-6140-block-checkout-local-pickup-fails-to-render b/plugins/woocommerce/changelog/fix-wooplug-6140-block-checkout-local-pickup-fails-to-render
new file mode 100644
index 0000000000..dbe69a165b
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-wooplug-6140-block-checkout-local-pickup-fails-to-render
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix Local Pickup not rendering in Block Checkout when third-party plugins call calculate_totals() early with shortcode cart context.
diff --git a/plugins/woocommerce/includes/class-wc-cart.php b/plugins/woocommerce/includes/class-wc-cart.php
index c266b5e9bd..374ca729d5 100644
--- a/plugins/woocommerce/includes/class-wc-cart.php
+++ b/plugins/woocommerce/includes/class-wc-cart.php
@@ -1764,6 +1764,16 @@ class WC_Cart extends WC_Legacy_Cart {
 		}

 		if ( 'yes' === get_option( 'woocommerce_shipping_cost_requires_address' ) ) {
+			// If local pickup is enabled, shipping should be shown so that pickup locations are visible before address entry.
+			if ( LocalPickupUtils::is_local_pickup_enabled() ) {
+				/**
+				 * This filter is documented below.
+				 *
+				 * @since 2.7.0
+				 */
+				return apply_filters( 'woocommerce_cart_ready_to_calc_shipping', true );
+			}
+
 			if ( 'shortcode' === $this->cart_context ) {
 				$country = $this->get_customer()->get_shipping_country();
 				if ( ! $country ) {
@@ -1803,11 +1813,6 @@ class WC_Cart extends WC_Legacy_Cart {
 					return false;
 				}
 			} else {
-				// If local pickup is enabled, shipping should be shown so that pickup locations are visible before address entry.
-				if ( LocalPickupUtils::is_local_pickup_enabled() ) {
-					return true;
-				}
-
 				$customer = $this->get_customer();

 				if ( ! $customer instanceof \WC_Customer || ! $customer->has_full_shipping_address() ) {
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php b/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php
index 69fbcb41c9..3a23a7cd40 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php
@@ -413,6 +413,62 @@ class WC_Cart_Test extends \WC_Unit_Test_Case {
 		WC()->cart->get_customer()->set_shipping_postcode( '' );
 	}

+	/**
+	 * Test that show_shipping returns true when Local Pickup is enabled,
+	 * even when "Hide shipping costs until an address is entered" is enabled
+	 * and no customer address is set.
+	 *
+	 * This tests the fix for https://github.com/woocommerce/woocommerce/issues/62785
+	 * where Local Pickup would not display in the Block Checkout when a third-party
+	 * plugin called calculate_totals() early with the shortcode cart context.
+	 */
+	public function test_show_shipping_returns_true_with_local_pickup_enabled_and_no_address() {
+		// Save original settings.
+		$default_shipping_cost_requires_address = get_option( 'woocommerce_shipping_cost_requires_address', 'no' );
+		$default_pickup_location_settings       = get_option( 'woocommerce_pickup_location_settings', array() );
+
+		// Enable "Hide shipping costs until an address is entered".
+		update_option( 'woocommerce_shipping_cost_requires_address', 'yes' );
+
+		// Enable Local Pickup.
+		update_option(
+			'woocommerce_pickup_location_settings',
+			array(
+				'enabled' => 'yes',
+				'title'   => 'Pickup',
+			)
+		);
+
+		// Add a product to the cart.
+		$product = WC_Helper_Product::create_simple_product();
+		WC()->cart->add_to_cart( $product->get_id(), 1 );
+
+		// Clear customer address to simulate a new guest user.
+		WC()->cart->get_customer()->set_shipping_country( '' );
+		WC()->cart->get_customer()->set_shipping_state( '' );
+		WC()->cart->get_customer()->set_shipping_postcode( '' );
+
+		// Test with shortcode context (the bug scenario).
+		WC()->cart->cart_context = 'shortcode';
+		$this->assertTrue(
+			WC()->cart->show_shipping(),
+			'show_shipping() should return true when Local Pickup is enabled, even with shortcode context and no address'
+		);
+
+		// Test with store-api context (should also work).
+		WC()->cart->cart_context = 'store-api';
+		$this->assertTrue(
+			WC()->cart->show_shipping(),
+			'show_shipping() should return true when Local Pickup is enabled with store-api context and no address'
+		);
+
+		// Clean up.
+		update_option( 'woocommerce_shipping_cost_requires_address', $default_shipping_cost_requires_address );
+		update_option( 'woocommerce_pickup_location_settings', $default_pickup_location_settings );
+		$product->delete( true );
+		WC()->cart->cart_context = 'shortcode'; // Reset to default.
+	}
+
 	/**
 	 * Test show_shipping for countries with various state/postcode requirement.
 	 */