diff --git a/src/wp-admin/network/users.php b/src/wp-admin/network/users.php index 7ddd5f40a662b..183f27bbe8d83 100644 --- a/src/wp-admin/network/users.php +++ b/src/wp-admin/network/users.php @@ -86,16 +86,26 @@ /* translators: %s: User login. */ __( 'Warning! User cannot be modified. The user %s is a network administrator.' ), esc_html( $user->user_login ) - ) + ), + 403 ); } $userfunction = 'all_spam'; - $blogs = get_blogs_of_user( $user_id, true ); - foreach ( (array) $blogs as $details ) { - if ( ! is_main_site( $details->userblog_id ) ) { // Main site is not a spam! - update_blog_status( $details->userblog_id, 'spam', '1' ); + /** + * Filters whether to propagate the blog status when a user is marked as spam. + * + * @since 7.0.0 + * + * @param bool $propagate Whether to propagate the blog status. Default false. + * @param int $user_id User ID. + */ + if ( apply_filters( 'propagate_network_user_spam_to_blogs', false, $user_id ) ) { + foreach ( get_blogs_of_user( $user_id, true ) as $details ) { + if ( ! is_main_site( $details->userblog_id ) ) { // Main site is not a spam! + update_blog_status( $details->userblog_id, 'spam', '1' ); + } } } @@ -107,12 +117,27 @@ case 'notspam': $user = get_userdata( $user_id ); + if ( is_super_admin( $user->ID ) ) { + wp_die( + sprintf( + /* translators: %s: User login. */ + __( 'Warning! User cannot be modified. The user %s is a network administrator.' ), + esc_html( $user->user_login ) + ), + 403 + ); + } $userfunction = 'all_notspam'; $blogs = get_blogs_of_user( $user_id, true ); - foreach ( (array) $blogs as $details ) { - update_blog_status( $details->userblog_id, 'spam', '0' ); + /** This filter is documented in wp-admin/network/users.php */ + if ( apply_filters( 'propagate_network_user_spam_to_blogs', false, $user_id ) ) { + foreach ( get_blogs_of_user( $user_id, true ) as $details ) { + if ( ! is_main_site( $details->userblog_id ) && get_current_network_id() === $details->site_id ) { // Main site is never a spam and part of the current network. + update_blog_status( $details->userblog_id, 'spam', '0' ); + } + } } $user_data = $user->to_array(); diff --git a/tests/phpunit/tests/user.php b/tests/phpunit/tests/user.php index b11d24a5caacc..623f99b3765eb 100644 --- a/tests/phpunit/tests/user.php +++ b/tests/phpunit/tests/user.php @@ -883,6 +883,66 @@ public function test_wp_update_user_should_not_mark_user_as_spam_on_single_site( $this->assertSame( 'no_spam', $u->get_error_code() ); } + /** + * Helper to create a user and add them to multiple blogs. + * + * @param int $num_blogs Number of additional blogs to create and add the user to. + * @param bool $include_main_site Whether to add the user to the main site as well. + * @return array Array with 'user_id' and 'blogs' (array of blog IDs). + */ + private function create_user_with_blogs( $num_blogs = 1, $include_main_site = false ) { + $user_id = self::factory()->user->create(); + + $blogs = array(); + if ( $include_main_site ) { + add_user_to_blog( get_main_site_id(), $user_id, 'administrator' ); + $blogs[] = get_main_site_id(); + } + + for ( $i = 0; $i < $num_blogs; $i++ ) { + $blog_id = self::factory()->blog->create( + array( + 'site_id' => get_current_network_id(), + ) + ); + add_user_to_blog( $blog_id, $user_id, 'administrator' ); + $blogs[] = $blog_id; + } + + return array( + 'user_id' => $user_id, + 'blogs' => $blogs, + ); + } + + /** + * @ticket 61146 + */ + public function test_default_do_not_propagate_network_user_spam_to_blogs_on_multisite() { + if ( ! is_multisite() ) { + $this->markTestSkipped( 'This test is for multisite only.' ); + } + + $data = $this->create_user_with_blogs( 2 ); + $user_id = $data['user_id']; + $blogs = $data['blogs']; + + // Mark user spam in user record (this alone should not change blog spam states). + $u = wp_update_user( + array( + 'ID' => $user_id, + 'spam' => '1', + ) + ); + $this->assertNotWPError( $u ); + $user = get_userdata( $user_id ); + $this->assertSame( '1', $user->spam ); + + foreach ( $blogs as $blog_id ) { + $this->assertNotSame( '1', get_blog_status( $blog_id, 'spam' ), "Blog {$blog_id} should not be marked spam by default." ); + } + } + /** * @ticket 28315 */