Commit a8be23289e6 for woocommerce
commit a8be23289e60780d7b58931384c3bedc303418cb
Author: agent-sandbox-woocommerce[bot] <282076412+agent-sandbox-woocommerce[bot]@users.noreply.github.com>
Date: Mon Jun 8 08:55:39 2026 -0400
Fix fatal TypeError in wc_modify_map_meta_cap() on PHP 8+ for invalid user IDs (#65506)
* Fix fatal TypeError in wc_modify_map_meta_cap() on PHP 8+
On PHP 8+, property_exists() throws a TypeError when its first argument
is not an object or string. get_userdata() returns false for invalid
user IDs (e.g. 0, deleted users), causing a fatal crash when
current_user_can() is called with a user-modification capability
(edit_user, remove_user, promote_user, delete_user) and a non-existent
user ID—reliably triggered by Yoast SEO's First-Time Configuration
wizard for shop_manager users when site is configured as Organization.
Guard the property_exists() call by checking that get_userdata() returns
a WP_User instance before proceeding; break out of the switch case
otherwise, leaving $caps unchanged.
Fixes: https://linear.app/a8c/issue/WOOPLUG-6719
Triggered-By: michael.pretty
* Remove stale PHPStan baseline entry and strengthen invalid-user test
Drop the suppressed property_exists argument.type error from phpstan-baseline.neon
now that the instanceof WP_User guard in wc_modify_map_meta_cap() resolves the
underlying type issue. Also convert the invalid-user-id test to a @dataProvider
covering both 0 and a stale non-zero id, and tighten the assertion to
assertEquals( array( 'edit_users' ), $caps ) to pin the actual contract.
Co-authored-by: prettyboymp
---------
Co-authored-by: matticbot <matticbot@users.noreply.github.com>
diff --git a/plugins/woocommerce/changelog/fix-wooplug-6719-property-exists-false-php8 b/plugins/woocommerce/changelog/fix-wooplug-6719-property-exists-false-php8
new file mode 100644
index 00000000000..d13ff0acc99
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-wooplug-6719-property-exists-false-php8
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix fatal TypeError in wc_modify_map_meta_cap() on PHP 8+ when get_userdata() returns false for an invalid user ID.
diff --git a/plugins/woocommerce/includes/wc-user-functions.php b/plugins/woocommerce/includes/wc-user-functions.php
index f4c28eb9392..544271723bb 100644
--- a/plugins/woocommerce/includes/wc-user-functions.php
+++ b/plugins/woocommerce/includes/wc-user-functions.php
@@ -737,9 +737,12 @@ function wc_modify_map_meta_cap( $caps, $cap, $user_id, $args ) {
$caps[] = 'do_not_allow';
} elseif ( wc_current_user_has_role( 'shop_manager' ) ) {
// Shop managers can only edit customer info.
- $userdata = get_userdata( $args[0] );
+ $userdata = get_userdata( $args[0] );
+ if ( ! $userdata instanceof WP_User ) {
+ break;
+ }
$shop_manager_editable_roles = apply_filters( 'woocommerce_shop_manager_editable_roles', array( 'customer' ) ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
- if ( property_exists( $userdata, 'roles' ) && ! empty( $userdata->roles ) && ! array_intersect( $userdata->roles, $shop_manager_editable_roles ) ) {
+ if ( ! empty( $userdata->roles ) && ! array_intersect( $userdata->roles, $shop_manager_editable_roles ) ) {
$caps[] = 'do_not_allow';
}
}
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index d24e26ec5cf..e1f6d821e43 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -36525,12 +36525,6 @@ parameters:
count: 1
path: includes/wc-user-functions.php
- -
- message: '#^Parameter \#1 \$object_or_class of function property_exists expects object\|string, WP_User\|false given\.$#'
- identifier: argument.type
- count: 1
- path: includes/wc-user-functions.php
-
-
message: '#^Parameter \#1 \$user of function user_can expects int\|WP_User, WP_User\|false given\.$#'
identifier: argument.type
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 f8f3d6cca0e..8d4f6a755a1 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,50 @@ class WC_Tests_User_Functions extends WC_Unit_Test_Case {
$this->assertEquals( array( 'edit_users' ), $caps );
}
+ /**
+ * Data provider for test_wc_modify_map_meta_cap_invalid_user_id.
+ *
+ * @return array[]
+ */
+ public function invalid_user_id_provider() {
+ return array(
+ 'zero id' => array( 0 ),
+ 'stale non-zero' => array( 999999 ),
+ );
+ }
+
+ /**
+ * Test that wc_modify_map_meta_cap does not fatal when $args[0] is not a valid user ID.
+ *
+ * On PHP 8+, property_exists() throws a TypeError when passed false (the return value
+ * of get_userdata() for a missing user). This test ensures no fatal occurs and that
+ * $caps is returned unchanged when the target user ID is invalid (e.g. 0 or a stale id).
+ *
+ * @dataProvider invalid_user_id_provider
+ * @see https://github.com/woocommerce/woocommerce/issues/65171
+ *
+ * @param int $invalid_id A user ID that does not correspond to an existing user.
+ */
+ public function test_wc_modify_map_meta_cap_invalid_user_id( $invalid_id ) {
+ $password = wp_generate_password();
+
+ $manager_id = wp_insert_user(
+ array(
+ 'user_login' => 'test_manager_invalid',
+ 'user_pass' => $password,
+ 'user_email' => 'manager_invalid@example.com',
+ 'role' => 'shop_manager',
+ )
+ );
+
+ wp_set_current_user( $manager_id );
+
+ // Passing an invalid user ID should not throw a TypeError on PHP 8+.
+ // The caps array must be returned unchanged — exactly the WordPress default.
+ $caps = map_meta_cap( 'edit_user', $manager_id, $invalid_id );
+ $this->assertEquals( array( 'edit_users' ), $caps );
+ }
+
/**
* Test wc_shop_manager_has_capability function.
*