Commit 7fd0a35962c for woocommerce

commit 7fd0a35962c80054011e5e0fc8534ddf08da51be
Author: Raluca Stan <ralucastn@gmail.com>
Date:   Tue Sep 8 16:51:02 2026 +0200

    Fix the Store API and local pickup hook docblocks (#68153)

    * Stop marking woocommerce_check_cart_items deprecated

    The docblock called the hook a filter and carried a bare @deprecated,
    so the reference struck the heading through and printed "This hook is
    deprecated and will be removed". That is not true of the hook: core
    fires it live from WC_Checkout and both shortcodes, and attaches its
    own validators to it.

    What the prose meant is that the Store API intends to stop firing it,
    because callbacks reach for wc_add_notice and the route then has to
    capture those notices and convert them to WP_Error objects. Say that,
    scoped to the Store API, and name woocommerce_store_api_cart_errors as
    the replacement — it hands callbacks a WP_Error directly. The tag goes,
    since nothing deprecates the hook itself.

    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

    * Correct the woocommerce_get_item_data description

    The long description was copy-pasted from
    woocommerce_variation_option_name and talked about variation option
    names. Describe what the filter actually collects: the name/value pairs
    the Store API returns in a cart item's item_data field.

    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

    * Name the woocommerce_return_previous_exceptions parameter

    The @param tag carried a type and a description but no variable name,
    so the reference rendered the signature as `bool $` and a parameter row
    titled `$`. Name it after what it controls.

    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

    * Describe woocommerce_store_api_checkout_order_processed accurately

    The docblock said the order "has completed processing and is ready for
    payment" while its own summary said the action fires before the order
    is processed. Both checkout routes fire it after the order is built and
    validated but before process_payment(), so say that once, consistently.

    Keep the summary route-neutral: create_or_update_draft_order() updates a
    reused draft as often as it creates one, and CheckoutOrder loads an
    existing order by ID, so neither route always builds an order from the
    request.

    Also repair the stray blank line between @example and @param, which
    broke out of the docblock's leading-asterisk column.

    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

    * Replace the -dev @since values in OrderController

    Both pay-for-order stock filters carried @since 9.8.0-dev, a dev
    version that was never released and that now reads as WooCommerce 9.8.0
    (April 2025) — two years off. The filters came in with 26f1a59378
    (woocommerce-blocks#8960), which reached core through the Blocks 10.6.x
    bundle, first tagged 8.1.0.

    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

    * Rename the $this param on the integration registration action

    `$this` is not a valid PHP parameter name, so the reference published a
    parameter row called `$this` and PHPStan's hook-docs rule flagged the
    docblock (baselined as phpDoc.parseError). Call it $registry and drop
    the now-resolved baseline entry.

    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

    * Say where the local pickup tax filters are documented

    Both woocommerce_apply_base_tax_for_local_pickup call sites carried a
    bare phpcs:ignore, which reads as an oversight rather than a decision.
    These are core filters, documented in WC_Abstract_Order::get_tax_location(),
    and WordPress' inline documentation standards say a hook fired in more
    than one place is documented once with the other sites naming where it
    lives.

    Give both ignores that reason, matching the woocommerce_local_pickup_methods
    site a few lines below which already had it.

    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

    * Add changelog entry for the Store API and shipping hook docs

    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

    * Drop the baseline entries these docblock fixes resolved

    The `@param` corrections in `Checkout.php` and `CheckoutOrder.php` fixed four
    phpDoc.parseError entries that are still listed in `phpstan-baseline.neon`, so
    PHPStan fails with "ignored error pattern was not matched". Removing them, which
    is the direction the baseline is meant to move anyway.

    * Point the checkout order processed example at the current hook

    The example under woocommerce_store_api_checkout_order_processed
    registered woocommerce_blocks_checkout_order_processed, deprecated since
    Blocks 7.2.0. It is the docs' only mention of that name: the hook has no
    docblock, so it never enters the generated reference.

    Following the example costs a deprecation notice on every checkout, and
    the old name only fires from Checkout, so the callback silently never
    runs for the /checkout/{id} order-pay route CheckoutOrder serves.

    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

    ---------

    Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

diff --git a/plugins/woocommerce/changelog/67855-hook-docs-storeapi-shipping b/plugins/woocommerce/changelog/67855-hook-docs-storeapi-shipping
new file mode 100644
index 00000000000..1fd1cb9f4ad
--- /dev/null
+++ b/plugins/woocommerce/changelog/67855-hook-docs-storeapi-shipping
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+
+Correct the Store API cart and checkout hook docblocks, and say where the local pickup tax filters are documented.
diff --git a/plugins/woocommerce/client/blocks/docs/examples/checkout-order-processed.md b/plugins/woocommerce/client/blocks/docs/examples/checkout-order-processed.md
index a76b59d2068..321b4faa91b 100644
--- a/plugins/woocommerce/client/blocks/docs/examples/checkout-order-processed.md
+++ b/plugins/woocommerce/client/blocks/docs/examples/checkout-order-processed.md
@@ -7,5 +7,5 @@ function my_function_callback( $order ) {
   $order->save();
 }

-add_action( 'woocommerce_blocks_checkout_order_processed', 'my_function_callback', 10 );
+add_action( 'woocommerce_store_api_checkout_order_processed', 'my_function_callback', 10 );
 ```
diff --git a/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/actions.md b/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/actions.md
index 4b22828d8fb..c4f1b9b166b 100644
--- a/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/actions.md
+++ b/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/actions.md
@@ -546,7 +546,7 @@ do_action( 'woocommerce_blocks_validate_location_{$location}_fields', \WP_Error
 Fires when the IntegrationRegistry is initialized.

 ```php
-do_action( 'woocommerce_blocks_{$this->registry_identifier}_registration', \IntegrationRegistry $this )
+do_action( 'woocommerce_blocks_{$this->registry_identifier}_registration', \IntegrationRegistry $registry )
 ```

 ### Description
@@ -557,7 +557,7 @@ Runs before integrations are initialized allowing new integration to be register

 | Argument | Type | Description |
 | -------- | ---- | ----------- |
-| $this | \IntegrationRegistry | Instance of the IntegrationRegistry class which exposes the IntegrationRegistry::register() method. |
+| $registry | \IntegrationRegistry | Instance of the IntegrationRegistry class which exposes the IntegrationRegistry::register() method. |

 ### Source

@@ -565,7 +565,7 @@ Runs before integrations are initialized allowing new integration to be register

 ---

-## ~~woocommerce_check_cart_items~~
+## woocommerce_check_cart_items


 Fires when cart items are being validated.
@@ -575,14 +575,13 @@ do_action( 'woocommerce_check_cart_items' )
 ```


-**Deprecated:** This hook is deprecated and will be removed
-
-
 **Note:** Matches action name in WooCommerce core.

 ### Description

-Allow 3rd parties to validate cart items. This is a legacy hook from Woo core. This filter will be deprecated because it encourages usage of wc_add_notice. For the API we need to capture notices and convert to wp errors instead.
+Allow 3rd parties to validate cart items. This is a legacy hook from Woo core.
+
+This action will be deprecated in the Store API because it encourages wc_add_notice: the API has to capture those notices and convert them to WP_Error objects. Prefer `woocommerce_store_api_cart_errors`, which passes a WP_Error to callbacks directly. Core keeps firing this action from the classic cart and checkout, so it is not deprecated there.

 ### Source

@@ -860,7 +859,7 @@ Use this hook for first-touch logic that should only run when the draft order is
 ## woocommerce_store_api_checkout_order_processed


-Fires before an order is processed by the Checkout Block/Store API.
+Fires after the Checkout Block/Store API request has populated and validated the order.

 ```php
 do_action( 'woocommerce_store_api_checkout_order_processed', \WC_Order $order )
@@ -868,7 +867,7 @@ do_action( 'woocommerce_store_api_checkout_order_processed', \WC_Order $order )

 ### Description

-This hook informs extensions that $order has completed processing and is ready for payment.
+The action runs before payment is processed, so callbacks can still act on the order on its way to the gateway.

 This is similar to existing core hook woocommerce_checkout_order_processed. We're using a new action:

@@ -892,7 +891,7 @@ function my_function_callback( $order ) {
   $order->save();
 }

-add_action( 'woocommerce_blocks_checkout_order_processed', 'my_function_callback', 10 );
+add_action( 'woocommerce_store_api_checkout_order_processed', 'my_function_callback', 10 );
 ```


diff --git a/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md b/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md
index f96c32c75c0..ff29e44fbe8 100644
--- a/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md
+++ b/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md
@@ -1079,7 +1079,7 @@ apply_filters( 'woocommerce_get_item_data', array $item_data, array $cart_item )

 ### Description

-Filters the variation option name for custom option slugs.
+Allows extensions to attach their own name/value pairs to a cart item, which the Store API returns in the item's `item_data` field.

 ### Parameters

@@ -1477,14 +1477,14 @@ apply_filters( 'woocommerce_quantity_input_placeholder', int $max_value, \WC_Pro
 Allows to check if WP_DEBUG mode is enabled before returning previous Exception.

 ```php
-apply_filters( 'woocommerce_return_previous_exceptions', bool $ )
+apply_filters( 'woocommerce_return_previous_exceptions', bool $return_previous_exceptions )
 ```

 ### Parameters

 | Argument | Type | Description |
 | -------- | ---- | ----------- |
-| $ | bool | The WP_DEBUG mode. |
+| $return_previous_exceptions | bool | Whether to include the previous exception. Defaults to the WP_DEBUG value. |

 ### Source

diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index 91d140c01be..fff7b9ff431 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -53115,12 +53115,6 @@ parameters:
 			count: 1
 			path: src/Blocks/Integrations/IntegrationInterface.php

-		-
-			message: '#^@param tag must not be named \$this\. Choose a descriptive alias, for example \$instance\.$#'
-			identifier: phpDoc.parseError
-			count: 1
-			path: src/Blocks/Integrations/IntegrationRegistry.php
-
 		-
 			message: '#^Method Automattic\\WooCommerce\\Blocks\\Integrations\\IntegrationRegistry\:\:initialize\(\) has no return type specified\.$#'
 			identifier: missingType.return
@@ -68178,18 +68172,6 @@ parameters:
 			count: 1
 			path: src/StoreApi/Routes/V1/Checkout.php

-		-
-			message: '#^One or more @param tags has an invalid name or invalid syntax\.$#'
-			identifier: phpDoc.parseError
-			count: 1
-			path: src/StoreApi/Routes/V1/Checkout.php
-
-		-
-			message: '#^PHPDoc tag @param has invalid value \(bool The WP_DEBUG mode\.\)\: Unexpected token "The", expected variable at offset 115 on line 4$#'
-			identifier: phpDoc.parseError
-			count: 1
-			path: src/StoreApi/Routes/V1/Checkout.php
-
 		-
 			message: '#^PHPDoc tag @return has invalid value \(\\WC_Order\|null;\)\: Unexpected token ";", expected TOKEN_HORIZONTAL_WS at offset 99 on line 4$#'
 			identifier: phpDoc.parseError
@@ -68406,18 +68388,6 @@ parameters:
 			count: 1
 			path: src/StoreApi/Routes/V1/CheckoutOrder.php

-		-
-			message: '#^One or more @param tags has an invalid name or invalid syntax\.$#'
-			identifier: phpDoc.parseError
-			count: 1
-			path: src/StoreApi/Routes/V1/CheckoutOrder.php
-
-		-
-			message: '#^PHPDoc tag @param has invalid value \(bool The WP_DEBUG mode\.\)\: Unexpected token "The", expected variable at offset 115 on line 4$#'
-			identifier: phpDoc.parseError
-			count: 1
-			path: src/StoreApi/Routes/V1/CheckoutOrder.php
-
 		-
 			message: '#^Parameter \#1 \$redirect_url of method Automattic\\WooCommerce\\StoreApi\\Payments\\PaymentResult\:\:set_redirect_url\(\) expects array, string given\.$#'
 			identifier: argument.type
diff --git a/plugins/woocommerce/src/Blocks/Integrations/IntegrationRegistry.php b/plugins/woocommerce/src/Blocks/Integrations/IntegrationRegistry.php
index 1dbc4b5ad8f..05c3412a518 100644
--- a/plugins/woocommerce/src/Blocks/Integrations/IntegrationRegistry.php
+++ b/plugins/woocommerce/src/Blocks/Integrations/IntegrationRegistry.php
@@ -45,7 +45,7 @@ class IntegrationRegistry {
 		 *
 		 * @since 4.6.0
 		 *
-		 * @param IntegrationRegistry $this Instance of the IntegrationRegistry class which exposes the IntegrationRegistry::register() method.
+		 * @param IntegrationRegistry $registry Instance of the IntegrationRegistry class which exposes the IntegrationRegistry::register() method.
 		 */
 		do_action( 'woocommerce_blocks_' . $this->registry_identifier . '_registration', $this );

diff --git a/plugins/woocommerce/src/Blocks/Shipping/ShippingController.php b/plugins/woocommerce/src/Blocks/Shipping/ShippingController.php
index 5ca6ce616cf..8a17a052e33 100644
--- a/plugins/woocommerce/src/Blocks/Shipping/ShippingController.php
+++ b/plugins/woocommerce/src/Blocks/Shipping/ShippingController.php
@@ -450,7 +450,7 @@ class ShippingController {
 		$chosen_method_id       = explode( ':', $chosen_method )[0];
 		$chosen_method_instance = explode( ':', $chosen_method )[1] ?? 0;

-		// phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
+		// 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 ) ) {
 			$pickup_locations = get_option( 'pickup_location_pickup_locations', array() );
 			$pickup_location  = $pickup_locations[ $chosen_method_instance ] ?? array();
@@ -492,7 +492,7 @@ class ShippingController {
 			return $location;
 		}

-		// phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
+		// phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment -- Documented in WC_Abstract_Order::get_tax_location().
 		if ( true !== apply_filters( 'woocommerce_apply_base_tax_for_local_pickup', true ) ) {
 			return $location;
 		}
diff --git a/plugins/woocommerce/src/StoreApi/Routes/V1/Checkout.php b/plugins/woocommerce/src/StoreApi/Routes/V1/Checkout.php
index 6a5c15fd228..e02f627e696 100644
--- a/plugins/woocommerce/src/StoreApi/Routes/V1/Checkout.php
+++ b/plugins/woocommerce/src/StoreApi/Routes/V1/Checkout.php
@@ -676,9 +676,10 @@ class Checkout extends AbstractCartRoute {
 		// Order save-point: 2.

 		/**
-		 * Fires before an order is processed by the Checkout Block/Store API.
+		 * Fires after the Checkout Block/Store API request has populated and validated the order.
 		 *
-		 * This hook informs extensions that $order has completed processing and is ready for payment.
+		 * The action runs before payment is processed, so callbacks can still act on the order
+		 * on its way to the gateway.
 		 *
 		 * This is similar to existing core hook woocommerce_checkout_order_processed. We're using a new action:
 		 * - To keep the interface focused (only pass $order, not passing request data).
@@ -688,7 +689,7 @@ class Checkout extends AbstractCartRoute {
 		 *
 		 * @see https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3238
 		 * @example docs/examples/checkout-order-processed.md
-
+		 *
 		 * @param \WC_Order $order Order object.
 		 */
 		do_action( 'woocommerce_store_api_checkout_order_processed', $this->order );
diff --git a/plugins/woocommerce/src/StoreApi/Routes/V1/CheckoutOrder.php b/plugins/woocommerce/src/StoreApi/Routes/V1/CheckoutOrder.php
index 28addef323c..47a883e24d2 100644
--- a/plugins/woocommerce/src/StoreApi/Routes/V1/CheckoutOrder.php
+++ b/plugins/woocommerce/src/StoreApi/Routes/V1/CheckoutOrder.php
@@ -140,9 +140,10 @@ class CheckoutOrder extends AbstractCartRoute {
 		$this->order_controller->validate_existing_order_before_payment( $this->order );

 		/**
-		 * Fires before an order is processed by the Checkout Block/Store API.
+		 * Fires after the Checkout Block/Store API request has populated and validated the order.
 		 *
-		 * This hook informs extensions that $order has completed processing and is ready for payment.
+		 * The action runs before payment is processed, so callbacks can still act on the order
+		 * on its way to the gateway.
 		 *
 		 * This is similar to existing core hook woocommerce_checkout_order_processed. We're using a new action:
 		 * - To keep the interface focused (only pass $order, not passing request data).
@@ -152,7 +153,7 @@ class CheckoutOrder extends AbstractCartRoute {
 		 *
 		 * @see https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3238
 		 * @example docs/examples/checkout-order-processed.md
-
+		 *
 		 * @param \WC_Order $order Order object.
 		 */
 		do_action( 'woocommerce_store_api_checkout_order_processed', $this->order );
diff --git a/plugins/woocommerce/src/StoreApi/Schemas/V1/CartItemSchema.php b/plugins/woocommerce/src/StoreApi/Schemas/V1/CartItemSchema.php
index 0052bb0620d..92a82df602a 100644
--- a/plugins/woocommerce/src/StoreApi/Schemas/V1/CartItemSchema.php
+++ b/plugins/woocommerce/src/StoreApi/Schemas/V1/CartItemSchema.php
@@ -157,7 +157,8 @@ class CartItemSchema extends ItemSchema {
 		/**
 		 * Filters cart item data.
 		 *
-		 * Filters the variation option name for custom option slugs.
+		 * Allows extensions to attach their own name/value pairs to a cart item, which the Store
+		 * API returns in the item's `item_data` field.
 		 *
 		 * @since 4.3.0
 		 *
diff --git a/plugins/woocommerce/src/StoreApi/Utilities/CartController.php b/plugins/woocommerce/src/StoreApi/Utilities/CartController.php
index 72570ee73ab..1181f14e12c 100644
--- a/plugins/woocommerce/src/StoreApi/Utilities/CartController.php
+++ b/plugins/woocommerce/src/StoreApi/Utilities/CartController.php
@@ -514,12 +514,15 @@ class CartController {
 		 * Fires when cart items are being validated.
 		 *
 		 * Allow 3rd parties to validate cart items. This is a legacy hook from Woo core.
-		 * This filter will be deprecated because it encourages usage of wc_add_notice. For the API we need to capture
-		 * notices and convert to wp errors instead.
+		 *
+		 * This action will be deprecated in the Store API because it encourages wc_add_notice:
+		 * the API has to capture those notices and convert them to WP_Error objects. Prefer
+		 * `woocommerce_store_api_cart_errors`, which passes a WP_Error to callbacks directly.
+		 * Core keeps firing this action from the classic cart and checkout, so it is not
+		 * deprecated there.
 		 *
 		 * @since 7.2.0
 		 *
-		 * @deprecated
 		 * @internal Matches action name in WooCommerce core.
 		 */
 		do_action( 'woocommerce_check_cart_items' );
diff --git a/plugins/woocommerce/src/StoreApi/Utilities/CheckoutTrait.php b/plugins/woocommerce/src/StoreApi/Utilities/CheckoutTrait.php
index 5a5f8f9f4de..e6bd00f2651 100644
--- a/plugins/woocommerce/src/StoreApi/Utilities/CheckoutTrait.php
+++ b/plugins/woocommerce/src/StoreApi/Utilities/CheckoutTrait.php
@@ -124,7 +124,7 @@ trait CheckoutTrait {
 			/**
 			 * Allows to check if WP_DEBUG mode is enabled before returning previous Exception.
 			 *
-			 * @param bool The WP_DEBUG mode.
+			 * @param bool $return_previous_exceptions Whether to include the previous exception. Defaults to the WP_DEBUG value.
 			 */
 			if ( apply_filters( 'woocommerce_return_previous_exceptions', Constants::is_true( 'WP_DEBUG' ) ) && $e->getPrevious() ) {
 				$additional_data = [
diff --git a/plugins/woocommerce/src/StoreApi/Utilities/OrderController.php b/plugins/woocommerce/src/StoreApi/Utilities/OrderController.php
index 6c61a9ead16..9a444d7affe 100644
--- a/plugins/woocommerce/src/StoreApi/Utilities/OrderController.php
+++ b/plugins/woocommerce/src/StoreApi/Utilities/OrderController.php
@@ -770,7 +770,7 @@ class OrderController {
 						 * @param \WC_Product $product Product.
 						 * @param \WC_Order|\WC_Order_Refund|false $order Order.
 						 *
-						 * @since 9.8.0-dev
+						 * @since 8.1.0
 						 */
 						if ( ! apply_filters( 'woocommerce_pay_order_product_in_stock', $product->is_in_stock(), $product, $order ) ) {
 							return array(
@@ -796,7 +796,7 @@ class OrderController {
 						 * @param \WC_Product $product Product.
 						 * @param \WC_Order|\WC_Order_Refund|false $order Order.
 						 *
-						 * @since 9.8.0-dev
+						 * @since 8.1.0
 						 */
 						if ( ! apply_filters( 'woocommerce_pay_order_product_has_enough_stock', ( $product->get_stock_quantity() >= ( $held_stock + $required_stock ) ), $product, $order ) ) {
 							/* translators: 1: product name 2: quantity in stock */