Skip to content
55 changes: 55 additions & 0 deletions src/js/_enqueues/admin/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -2354,3 +2354,58 @@ $( function( $ ) {
// Expose public methods.
return pub;
})();

/**
* Disable the submit button until all users radio buttons are checked.
*/
(function($){
const usersForm = document.querySelector( '.users-php .delete-and-reassign-users-form' );

// Check if the form contains any radio buttons.
if ( ! usersForm.querySelector( 'input[type="radio"]' ) ) {
Comment on lines +2364 to +2365
Copy link

Copilot AI Oct 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential null reference error. The code checks if usersForm has radio buttons but doesn't first verify that usersForm exists. This will throw an error if the form is not found on the page.

Suggested change
// Check if the form contains any radio buttons.
if ( ! usersForm.querySelector( 'input[type="radio"]' ) ) {
// Check if the form exists and contains any radio buttons.
if ( ! usersForm || ! usersForm.querySelector( 'input[type="radio"]' ) ) {

Copilot uses AI. Check for mistakes.

return;
}

const submitBtn = usersForm.querySelector( 'input[type="submit"]' );

// Disable the submit button until all users radio buttons are checked.
submitBtn.disabled = true;

// Listen for changes on any radio input in the form.
usersForm.addEventListener('change', function(e) {
if ( ! usersForm.checkValidity() ) {
submitBtn.disabled = true;
return;
}

// Check all radio groups for validity.
let allValid = true;
const radioGroups = usersForm.querySelectorAll( 'fieldset' );
radioGroups.forEach( function( fieldset ) {
const radios = fieldset.querySelectorAll( 'input[type="radio"]' );
let checkedRadio = null;
radios.forEach( function( radio ) {
if ( radio.checked ) {
checkedRadio = radio;
}
});

if ( checkedRadio && checkedRadio.value === 'reassign' ) {
const select = fieldset.querySelector( 'select' );
if ( select && select.value === '-1' ) {
allValid = false;
}
}
});

submitBtn.disabled = !allValid;
});

usersForm.querySelectorAll( 'select' ).forEach( function( selectElement ) {
selectElement.addEventListener( 'change', function( e ) {
const radio = e.target.closest( 'li' ).querySelector( 'input[type="radio"]' );
radio.checked = e.target.value !== '-1';
});
});

})(jQuery);
11 changes: 11 additions & 0 deletions src/wp-admin/includes/deprecated.php
Original file line number Diff line number Diff line change
Expand Up @@ -1589,3 +1589,14 @@ function image_attachment_fields_to_save( $post, $attachment ) {

return $post;
}

/**
* Was used to add JavaScript to the delete users form.
*
* @since 3.5.0
* @deprecated 6.9.0
* @access private
*/
function delete_users_add_js() {
_deprecated_function( __FUNCTION__, '6.9.0' );
}
73 changes: 40 additions & 33 deletions src/wp-admin/includes/ms.php
Original file line number Diff line number Diff line change
Expand Up @@ -864,26 +864,25 @@ function confirm_delete_users( $users ) {
if ( ! is_array( $users ) || empty( $users ) ) {
return false;
}

?>
<h1><?php esc_html_e( 'Users' ); ?></h1>
<h1><?php esc_html_e( 'Delete Users' ); ?></h1>

<?php if ( 1 === count( $users ) ) : ?>
<p><?php _e( 'You have chosen to delete the user from all networks and sites.' ); ?></p>
<?php else : ?>
<p><?php _e( 'You have chosen to delete the following users from all networks and sites.' ); ?></p>
<?php endif; ?>

<form action="users.php?action=dodelete" method="post">
<form action="users.php?action=dodelete" method="post" class="delete-and-reassign-users-form">
<input type="hidden" name="dodelete" />
<?php
wp_nonce_field( 'ms-users-delete' );
$site_admins = get_super_admins();
$admin_out = '<option value="' . esc_attr( $current_user->ID ) . '">' . $current_user->user_login . '</option>';
?>
<table class="form-table" role="presentation">
<?php
$allusers = (array) $_POST['allusers'];
foreach ( $allusers as $user_id ) {
foreach ( $users as $user_id ) {
if ( '' !== $user_id && '0' !== $user_id ) {
$delete_user = get_userdata( $user_id );

Expand All @@ -906,6 +905,8 @@ function confirm_delete_users( $users ) {
)
);
}

// TODO: Check if user has content.
?>
<tr>
<th scope="row"><?php echo $delete_user->user_login; ?>
Expand All @@ -930,44 +931,50 @@ function confirm_delete_users( $users ) {
$blog_users = get_users(
array(
'blog_id' => $details->userblog_id,
'fields' => array( 'ID', 'user_login' ),
'fields' => array( 'ID' ),
'exclude' => $users,
)
);

$blog_users = wp_list_pluck( $blog_users, 'ID' );

if ( is_array( $blog_users ) && ! empty( $blog_users ) ) {
$user_site = "<a href='" . esc_url( get_home_url( $details->userblog_id ) ) . "'>{$details->blogname}</a>";
$user_dropdown = '<label for="reassign_user" class="screen-reader-text">' .
/* translators: Hidden accessibility text. */
__( 'Select a user' ) .
'</label>';
$user_dropdown .= "<select name='blog[$user_id][$key]' id='reassign_user'>";
$user_list = '';

foreach ( $blog_users as $user ) {
if ( ! in_array( (int) $user->ID, $allusers, true ) ) {
$user_list .= "<option value='{$user->ID}'>{$user->user_login}</option>";
}
}

if ( '' === $user_list ) {
$user_list = $admin_out;
}

$user_dropdown .= $user_list;
$user_dropdown .= "</select>\n";

?>
<ul style="list-style:none;">
<ul>
<li>
<?php
/* translators: %s: Link to user's site. */
printf( __( 'Site: %s' ), $user_site );
?>
</li>
<li><label><input type="radio" id="delete_option0" name="delete[<?php echo $details->userblog_id . '][' . $delete_user->ID; ?>]" value="delete" checked="checked" />
<?php _e( 'Delete all content.' ); ?></label></li>
<li><label><input type="radio" id="delete_option1" name="delete[<?php echo $details->userblog_id . '][' . $delete_user->ID; ?>]" value="reassign" />
<?php _e( 'Attribute all content to:' ); ?></label>
<?php echo $user_dropdown; ?></li>
<li>
<label>
<input type="radio" id="delete_option_<?php echo esc_attr( $details->userblog_id . '_' . $delete_user->ID ); ?>" name="delete[<?php echo $details->userblog_id . '][' . $delete_user->ID; ?>]" value="delete" required />
<?php _e( 'Delete all content.' ); ?>
</label>
</li>
<li>
<label>
<input type="radio" id="reassign_option_<?php echo esc_attr( $details->userblog_id . '_' . $delete_user->ID ); ?>" name="delete[<?php echo $details->userblog_id . '][' . $delete_user->ID; ?>]" value="reassign" required />
<?php _e( 'Attribute all content to:' ); ?>
</label>

<?php
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}",
)
);
?>

</li>
</li>
</ul>
<?php
}
Expand All @@ -986,7 +993,7 @@ function confirm_delete_users( $users ) {
</table>
<?php
/** This action is documented in wp-admin/users.php */
do_action( 'delete_user_form', $current_user, $allusers );
do_action( 'delete_user_form', $current_user, $users );

if ( 1 === count( $users ) ) :
?>
Expand All @@ -996,7 +1003,7 @@ function confirm_delete_users( $users ) {
<?php
endif;

submit_button( __( 'Confirm Deletion' ), 'primary' );
submit_button( __( 'Confirm Deletion' ), 'primary', 'submit', false, array( 'id' => 'confirm-users-deletion' ) );
?>
</form>
<?php
Expand Down
20 changes: 0 additions & 20 deletions src/wp-admin/includes/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -561,26 +561,6 @@ function default_password_nag() {
);
}

/**
* @since 3.5.0
* @access private
*/
function delete_users_add_js() {
?>
<script>
jQuery( function($) {
var submit = $('#submit').prop('disabled', true);
$('input[name="delete_option"]').one('change', function() {
submit.prop('disabled', false);
});
$('#reassign_user').focus( function() {
$('#delete_option1').prop('checked', true).trigger('change');
});
} );
</script>
<?php
}

/**
* Optional SSL preference that can be turned on by hooking to the 'personal_options' action.
*
Expand Down
5 changes: 3 additions & 2 deletions src/wp-admin/network/users.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@

$doaction = $_POST['action'];
$userfunction = '';
$allusers = (array) $_POST['allusers'];

foreach ( (array) $_POST['allusers'] as $user_id ) {
foreach ( $allusers as $user_id ) {
if ( ! empty( $user_id ) ) {
switch ( $doaction ) {
case 'delete':
Expand All @@ -72,7 +73,7 @@
require_once ABSPATH . 'wp-admin/admin-header.php';

echo '<div class="wrap">';
confirm_delete_users( $_POST['allusers'] );
confirm_delete_users( $allusers );
echo '</div>';

require_once ABSPATH . 'wp-admin/admin-footer.php';
Expand Down
Loading
Loading