Commit de4776acd43 for woocommerce

commit de4776acd43fa87bd2ad098f1eb847b797100b62
Author: Néstor Soriano <konamiman@konamiman.com>
Date:   Mon Sep 7 14:30:28 2026 +0200

    Limit WooCommerce user fields in the users REST endpoint to the edit context (#68380)

    The is_super_admin and woocommerce_meta fields added to the wp/v2/users
    endpoint are now returned only for requests with context=edit, and only
    when the current user is the requested user or has the list_users
    capability. The same conditions are checked in the field callbacks.

    The fields now declare a proper schema: is_super_admin is a read-only
    boolean and woocommerce_meta is an object (it is an associative array,
    and the array type would make updates fail validation). Remove the
    related phpstan baseline entries.

diff --git a/plugins/woocommerce/changelog/pr-402-users-endpoint-field-permissions b/plugins/woocommerce/changelog/pr-402-users-endpoint-field-permissions
new file mode 100644
index 00000000000..d6d5f305829
--- /dev/null
+++ b/plugins/woocommerce/changelog/pr-402-users-endpoint-field-permissions
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Return is_super_admin and woocommerce_meta fields in users REST endpoint only for requests in 'edit' context, and only when requesting own user or with 'list_users' capability.
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index ece0f380a1a..71f8c1074a2 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -59055,12 +59055,6 @@ parameters:
 			count: 1
 			path: src/Internal/Admin/WCAdminAssets.php

-		-
-			message: '#^Access to offset ''id'' on an unknown class Automattic\\WooCommerce\\Internal\\Admin\\WP_User\.$#'
-			identifier: class.notFound
-			count: 1
-			path: src/Internal/Admin/WCAdminUser.php
-
 		-
 			message: '#^Access to property \$ID on an unknown class Automattic\\WooCommerce\\Internal\\Admin\\WP_User\.$#'
 			identifier: class.notFound
@@ -59091,12 +59085,6 @@ parameters:
 			count: 1
 			path: src/Internal/Admin/WCAdminUser.php

-		-
-			message: '#^Parameter \$user of method Automattic\\WooCommerce\\Internal\\Admin\\WCAdminUser\:\:get_user_data_values\(\) has invalid type Automattic\\WooCommerce\\Internal\\Admin\\WP_User\.$#'
-			identifier: class.notFound
-			count: 1
-			path: src/Internal/Admin/WCAdminUser.php
-
 		-
 			message: '#^Parameter \$user of method Automattic\\WooCommerce\\Internal\\Admin\\WCAdminUser\:\:update_user_data_values\(\) has invalid type Automattic\\WooCommerce\\Internal\\Admin\\WP_User\.$#'
 			identifier: class.notFound
diff --git a/plugins/woocommerce/src/Internal/Admin/WCAdminUser.php b/plugins/woocommerce/src/Internal/Admin/WCAdminUser.php
index 894d3a99276..6df98e4166c 100644
--- a/plugins/woocommerce/src/Internal/Admin/WCAdminUser.php
+++ b/plugins/woocommerce/src/Internal/Admin/WCAdminUser.php
@@ -41,14 +41,22 @@ class WCAdminUser {
 			'user',
 			'is_super_admin',
 			array(
-				'get_callback' => function( $user ) {
-					if ( ! isset( $user['id'] ) || 0 === $user['id'] ) {
+				'get_callback' => function ( $user, $attr, $request ) {
+					if ( 'edit' !== ( $request['context'] ?? null ) ) {
+						return false;
+					}
+
+					if ( ! $this->current_user_can_read_user_data( $user['id'] ?? 0 ) ) {
 						return false;
 					}

 					return is_super_admin( $user['id'] );
 				},
-				'schema'       => null,
+				'schema'       => array(
+					'type'     => 'boolean',
+					'context'  => array( 'edit' ),
+					'readonly' => true,
+				),
 			)
 		);
 		register_rest_field(
@@ -57,7 +65,10 @@ class WCAdminUser {
 			array(
 				'get_callback'    => array( $this, 'get_user_data_values' ),
 				'update_callback' => array( $this, 'update_user_data_values' ),
-				'schema'          => null,
+				'schema'          => array(
+					'type'    => 'object',
+					'context' => array( 'edit' ),
+				),
 			)
 		);
 	}
@@ -66,9 +77,24 @@ class WCAdminUser {
 	 * For all the registered user data fields (  Loader::get_user_data_fields ), fetch the data
 	 * for returning via the REST API.
 	 *
-	 * @param WP_User $user Current user.
+	 * Returns an empty array unless the request has the 'edit' context and the current user
+	 * is either the requested user or has the 'list_users' capability.
+	 *
+	 * @param array                  $user The prepared user data from the users endpoint response.
+	 * @param mixed                  $attr The name of the requested field.
+	 * @param \WP_REST_Request|array $request The current request.
+	 *
+	 * @phpstan-param \WP_REST_Request<array<string, mixed>>|array $request
 	 */
-	public function get_user_data_values( $user ) {
+	public function get_user_data_values( $user, $attr = null, $request = array() ) {
+		if ( 'edit' !== ( $request['context'] ?? null ) ) {
+			return array();
+		}
+
+		if ( ! $this->current_user_can_read_user_data( $user['id'] ?? 0 ) ) {
+			return array();
+		}
+
 		$values = array();
 		foreach ( $this->get_user_data_fields() as $field ) {
 			$values[ $field ] = self::get_user_data_field( $user['id'], $field );
@@ -76,6 +102,22 @@ class WCAdminUser {
 		return $values;
 	}

+	/**
+	 * Checks whether the current user is allowed to read the extra data registered by
+	 * WooCommerce for a given user.
+	 *
+	 * @param int $user_id The id of the user whose data is being read.
+	 * @return bool True if the current user can read the extra data for the given user.
+	 */
+	private function current_user_can_read_user_data( $user_id ) {
+		$user_id = (int) $user_id;
+		if ( 0 === $user_id ) {
+			return false;
+		}
+
+		return get_current_user_id() === $user_id || current_user_can( 'list_users' );
+	}
+
 	/**
 	 * For all the registered user data fields ( Loader::get_user_data_fields ), update the data
 	 * for the REST API.