Commit d44340c26e8 for woocommerce

commit d44340c26e8aad9fddcf0629cbebddd2ffec303d
Author: Luis Felipe Zaguini <26530524+zaguiini@users.noreply.github.com>
Date:   Mon Oct 19 08:19:40 2026 -0300

    Refuse an extension query filter value that fails its schema (#69960)

    * Refuse a query filter value that fails its schema, and a query filter on order items

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

    * Drop the order_item check from register_query_filter()

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

    ---------

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

diff --git a/plugins/woocommerce/changelog/fix-extensible-abilities-query-filter-checks b/plugins/woocommerce/changelog/fix-extensible-abilities-query-filter-checks
new file mode 100644
index 00000000000..ad05a638ed7
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-extensible-abilities-query-filter-checks
@@ -0,0 +1,3 @@
+Significance: patch
+Type: fix
+Comment: Refuse a query filter value that fails its schema in the unreleased extensible abilities feature.
diff --git a/plugins/woocommerce/src/Abilities/ExtensibleAbilities.php b/plugins/woocommerce/src/Abilities/ExtensibleAbilities.php
index 9be9ff482ad..f89a3e5a6f1 100644
--- a/plugins/woocommerce/src/Abilities/ExtensibleAbilities.php
+++ b/plugins/woocommerce/src/Abilities/ExtensibleAbilities.php
@@ -352,7 +352,7 @@ class ExtensibleAbilities {
 	 *
 	 * @param string               $resource_name Resource.
 	 * @param array<string, mixed> $input         Ability input.
-	 * @return array<string, array>|\WP_Error The error of a filter that refused its value or failed.
+	 * @return array<string, array>|\WP_Error The error of a value that fails its schema, or of a filter that refused its value or failed.
 	 */
 	public static function get_query_args( string $resource_name, array $input ) {
 		$query_args = array();
@@ -369,6 +369,10 @@ class ExtensibleAbilities {
 				}

 				$value = rest_sanitize_value_from_schema( $input['filters']['extensions'][ $namespace ][ $filter ], $args['schema'], $filter );
+				if ( is_wp_error( $value ) ) {
+					$value->add_data( array( 'status' => 400 ) );
+					return $value;
+				}
 				try {
 					$clauses = call_user_func( $args['callback'], $value );
 				} catch ( \Throwable $e ) {
diff --git a/plugins/woocommerce/tests/php/src/Internal/AbilitiesApi/ExtensibleAbilitiesTest.php b/plugins/woocommerce/tests/php/src/Internal/AbilitiesApi/ExtensibleAbilitiesTest.php
index bb3fe9e63fc..fe0afac6f76 100644
--- a/plugins/woocommerce/tests/php/src/Internal/AbilitiesApi/ExtensibleAbilitiesTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/AbilitiesApi/ExtensibleAbilitiesTest.php
@@ -758,6 +758,40 @@ class ExtensibleAbilitiesTest extends \WC_REST_Unit_Test_Case {
 		$this->assertSame( array( 'has_code', 'category' ), array_keys( $schema['properties']['filters']['properties']['extensions']['properties']['test-ext']['properties'] ) );
 	}

+	/**
+	 * @testdox Should return a 400 error and not run the filter when a value that skipped validation fails its schema.
+	 */
+	public function test_a_filter_value_that_fails_its_schema_is_refused(): void {
+		$called   = false;
+		$register = static function () use ( &$called ) {
+			ExtensibleAbilities::register_query_filter(
+				array(
+					'resource'  => 'order',
+					'namespace' => 'test-ext',
+					'filter'    => 'tags',
+					'schema'    => array(
+						'type'        => 'array',
+						'items'       => array( 'type' => 'string' ),
+						'uniqueItems' => true,
+					),
+					'callback'  => static function () use ( &$called ) {
+						$called = true;
+						return array();
+					},
+				)
+			);
+		};
+		add_action( 'woocommerce_extensible_abilities_init', $register );
+		$this->get_ability( 'woocommerce/orders-query' );
+		remove_action( 'woocommerce_extensible_abilities_init', $register );
+
+		$result = ExtensibleAbilities::get_query_args( 'order', array( 'filters' => array( 'extensions' => array( 'test-ext' => array( 'tags' => array( 'gift', 'gift' ) ) ) ) ) );
+
+		$this->assertWPError( $result );
+		$this->assertSame( 400, $result->get_error_data()['status'] );
+		$this->assertFalse( $called );
+	}
+
 	/**
 	 * @testdox Should refuse a filter that is registered after the init action.
 	 */