Opened 8 days ago
Last modified 5 hours ago
#66012 reopened defect (bug)
Multisite: reassign dropdown missing when deleting a user, silently destroying content (7.1 regression)
| Reported by: | mgyura | Owned by: | joedolson |
|---|---|---|---|
| Priority: | normal | Milestone: | 7.1.1 |
| Component: | Networks and Sites | Version: | 7.1 |
| Severity: | major | Keywords: | has-patch has-unit-tests dev-feedback fixed-major |
| Cc: | Focuses: | multisite |
Description
On Multisite in 7.1, the Network Admin "Delete Users" screen offers "Attribute all
content to another user", but on most networks the dropdown of users to attribute the
content to is missing entirely. Choosing that option deletes the content anyway, with
no error and no warning.
This is a regression introduced in 7.1 by [62688] (#56914). 7.0 and earlier are not
affected.
Impact
When the dropdown is missing, both options on the screen destroy the content:
- "Delete all content." deletes it, as expected.
- "Attribute all content to another user." also deletes it, because no reassignment ever happens.
The missing_reassign guard added in the same changeset cannot catch this. It iterates
$_POST['blog'], and when no dropdown is rendered there is no blog[...] field to
submit. So the guard is skipped, remove_user_from_blog() is never called with a
reassign target, and wpmu_delete_user() then runs wp_delete_post() over every post
the user owns.
On a production network, this destroyed 2,059 posts and 2,668 media files on one subsite.
The administrator had deliberately chosen "Attribute all content to another user" and
expected to be asked for a target.
Steps to reproduce
- Multisite on 7.1.
- Create a subsite.
- Create a user and add them to that subsite only. Do not add them to the main site. This is the key condition: a user who also belongs to the main site will not reproduce it.
- Give that user a post on the subsite.
- Network Admin > Users > select the user > Delete.
Expected: a dropdown listing the subsite's other users to reassign the content to.
Actual: the "Attribute all content to another user" radio appears with no dropdown
beside it. Selecting it and confirming deletes the user's content.
Root cause
In confirm_delete_users() (wp-admin/includes/ms.php), the blog context is restored
before the dropdown is rendered, and wp_dropdown_users() is not given a blog_id:
switch_to_blog( $details->userblog_id ); $user_has_content = ... restore_current_blog(); // context dropped here ... wp_dropdown_users( array( 'show_option_none' => __( 'Select a user' ), 'name' => "blog[$user_id][$key]", 'include' => $blog_users, // members of the subsite 'show' => 'display_name_with_login', 'id' => "reassign_user_{$details->userblog_id}_{$delete_user->ID}", ) );
blog_id therefore falls back to get_current_blog_id(), which in Network Admin is the
network's main site. On Multisite, any non-zero blog_id makes WP_User_Query add a
capabilities meta query for that blog. The query then asks for users belonging to the
main site, while include restricts the results to members of the subsite. Where those
two sets do not overlap the result is empty, and wp_dropdown_users() returns an empty
string instead of a dropdown.
#30175 describes this empty-string behavior in wp_dropdown_users() itself. This is a
new caller running into it.
Why 7.0 was not affected
7.0 built the dropdown by hand and handled the empty case explicitly:
if ( '' === $user_list ) { $user_list = $admin_out; // fall back to the current super admin }
[62688] replaced that markup with wp_dropdown_users(), and the fallback was not
carried over.
Suggested patch
Pass the subsite explicitly:
wp_dropdown_users( array( 'show_option_none' => __( 'Select a user' ), 'name' => "blog[$user_id][$key]", 'include' => $blog_users, 'show' => 'display_name_with_login', 'id' => "reassign_user_{$details->userblog_id}_{$delete_user->ID}", 'blog_id' => $details->userblog_id, ) );
Rendering the dropdown before restore_current_blog() would work as well.
The validation is worth hardening separately. It should key off the delete[...] radio
rather than the presence of blog[...], so that "reassign" chosen with no submitted
target is rejected instead of silently proceeding to deletion.
Related
Attachments (1)
Change History (12)
This ticket was mentioned in PR #13391 on WordPress/wordpress-develop by @joedolson.
6 days ago
#4
- Keywords has-unit-tests added; needs-unit-tests removed
Applies patch by https://profiles.wordpress.org/mgyura/ and adds related tests.
Trac ticket: https://core.trac.wordpress.org/ticket/66012
## Use of AI Tools
AI assistance: Yes
Tool(s): GitHub Copilot, Claude
Model(s): Sonnet 5
Used for: Test framing; reviewed by me.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)