Commit eb42b9b3b24 for woocommerce
commit eb42b9b3b24724b31587e06e4403214761f18baa
Author: Michal Iwanow <4765119+mcliwanow@users.noreply.github.com>
Date: Wed Oct 7 13:31:46 2026 +0200
Prevent shop managers from editing users with additional roles they cannot edit (#69527)
Co-authored-by: Thomas Roberts <5656702+opr@users.noreply.github.com>
diff --git a/plugins/woocommerce/changelog/fix-shop-manager-mixed-role-permissions b/plugins/woocommerce/changelog/fix-shop-manager-mixed-role-permissions
new file mode 100644
index 00000000000..64a8ccf4be4
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-shop-manager-mixed-role-permissions
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Prevent shop managers from editing users who have additional roles that cannot be edited by shop managers.
diff --git a/plugins/woocommerce/includes/wc-rest-functions.php b/plugins/woocommerce/includes/wc-rest-functions.php
index 4aa7cca12f3..deeb5ed1e65 100644
--- a/plugins/woocommerce/includes/wc-rest-functions.php
+++ b/plugins/woocommerce/includes/wc-rest-functions.php
@@ -275,10 +275,10 @@ function wc_rest_check_user_permissions( $context = 'read', $object_id = 0 ) {
$shop_manager_editable_roles = apply_filters( 'woocommerce_shop_manager_editable_roles', array( 'customer' ) );
if ( isset( $user_data->roles ) ) {
- $can_manage_users = array_intersect( $user_data->roles, array_unique( $shop_manager_editable_roles ) );
+ $can_manage_user = ! empty( $user_data->roles ) && empty( array_diff( $user_data->roles, array_unique( $shop_manager_editable_roles ) ) );
- // Check if Shop Manager can edit customer or with the is same shop manager.
- if ( 0 < count( $can_manage_users ) || intval( $object_id ) === intval( get_current_user_id() ) ) {
+ // Check if the Shop Manager can edit the user or is editing themselves.
+ if ( $can_manage_user || intval( $object_id ) === intval( get_current_user_id() ) ) {
$permission = current_user_can( $contexts[ $context ], $object_id );
}
}
diff --git a/plugins/woocommerce/includes/wc-user-functions.php b/plugins/woocommerce/includes/wc-user-functions.php
index 708ac3b89ba..727b8b5eda5 100644
--- a/plugins/woocommerce/includes/wc-user-functions.php
+++ b/plugins/woocommerce/includes/wc-user-functions.php
@@ -748,7 +748,8 @@ function wc_modify_map_meta_cap( $caps, $cap, $user_id, $args ) {
break;
}
$shop_manager_editable_roles = apply_filters( 'woocommerce_shop_manager_editable_roles', array( 'customer' ) ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
- if ( ! empty( $userdata->roles ) && ! array_intersect( $userdata->roles, $shop_manager_editable_roles ) ) {
+ $can_manage_user = ! empty( $userdata->roles ) && empty( array_diff( $userdata->roles, array_unique( $shop_manager_editable_roles ) ) );
+ if ( ! $can_manage_user ) {
$caps[] = 'do_not_allow';
}
}
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/util/class-wc-tests-user-functions.php b/plugins/woocommerce/tests/legacy/unit-tests/util/class-wc-tests-user-functions.php
index 8d4f6a755a1..a5edbfce37d 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/util/class-wc-tests-user-functions.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/util/class-wc-tests-user-functions.php
@@ -129,6 +129,34 @@ class WC_Tests_User_Functions extends WC_Unit_Test_Case {
$this->assertEquals( array( 'edit_users' ), $caps );
}
+ /**
+ * @testdox A shop manager cannot edit a customer who also has a custom role.
+ */
+ public function test_shop_manager_cannot_edit_customer_with_extra_custom_role() {
+ $options_role = 'test_manage_options_role';
+ add_role(
+ $options_role,
+ 'Test manage options role',
+ array(
+ 'manage_options' => true,
+ )
+ );
+
+ try {
+ $manager_id = self::factory()->user->create( array( 'role' => 'shop_manager' ) );
+ $customer_id = self::factory()->user->create( array( 'role' => 'customer' ) );
+ $customer_only_id = self::factory()->user->create( array( 'role' => 'customer' ) );
+ $customer = new WP_User( $customer_id );
+ $customer->add_role( $options_role );
+ wp_set_current_user( $manager_id );
+
+ $this->assertTrue( current_user_can( 'edit_user', $customer_only_id ), 'A shop manager can edit a customer-only user.' );
+ $this->assertFalse( current_user_can( 'edit_user', $customer_id ), 'A shop manager cannot edit a customer with a custom role.' );
+ } finally {
+ remove_role( $options_role );
+ }
+ }
+
/**
* Data provider for test_wc_modify_map_meta_cap_invalid_user_id.
*
diff --git a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version3/class-wc-rest-customers-controller-tests.php b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version3/class-wc-rest-customers-controller-tests.php
index 39f1c50b1f1..3c1760aed02 100644
--- a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version3/class-wc-rest-customers-controller-tests.php
+++ b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version3/class-wc-rest-customers-controller-tests.php
@@ -137,6 +137,24 @@ class WC_REST_Customers_Controller_Test extends WC_Unit_Test_Case {
$this->assertEquals( 'customer', $customer->get_role() );
}
+ /**
+ * @testdox A shop manager cannot update a customer who also has a role outside the editable roles.
+ */
+ public function test_shop_manager_cannot_update_user_with_extra_role(): void {
+ $customer = new WP_User( $this->customer_id );
+ $customer->add_role( 'administrator' );
+
+ $api_request = new WP_REST_Request( 'PUT', '/wc/v3/customers/' );
+ $api_request->set_param( 'id', $this->customer_id );
+ $api_request->set_param( 'first_name', 'Test' );
+ wp_set_current_user( $this->shop_manager_id );
+
+ $result = $this->sut->update_item_permissions_check( $api_request );
+
+ $this->assertWPError( $result, 'A shop manager cannot update a mixed-role administrator.' );
+ $this->assertSame( 'woocommerce_rest_cannot_edit', $result->get_error_code() );
+ }
+
/**
* @testDox Test deleting customers.
*/