Changeset 62688
- Timestamp:
- 07/10/2026 05:01:47 PM (less than one hour ago)
- Location:
- trunk/src
- Files:
-
- 7 edited
-
js/_enqueues/admin/common.js (modified) (1 diff)
-
wp-admin/css/common.css (modified) (1 diff)
-
wp-admin/includes/deprecated.php (modified) (1 diff)
-
wp-admin/includes/ms.php (modified) (7 diffs)
-
wp-admin/includes/user.php (modified) (1 diff)
-
wp-admin/network/users.php (modified) (4 diffs)
-
wp-admin/users.php (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/js/_enqueues/admin/common.js
r61771 r62688 2357 2357 return pub; 2358 2358 })(); 2359 2360 /** 2361 * Validate the delete-and-reassign users form and surface an accessible 2362 * error summary instead of disabling the submit button. 2363 * 2364 * Disabled buttons can't be discovered by assistive technology, so rather 2365 * than blocking submission we let the form submit, intercept it when content 2366 * decisions are still missing, and present a focusable error summary that 2367 * lists how many decisions remain and links straight to each one. 2368 * 2369 * Shared by both the single-site (wp-admin/users.php) and multisite/network 2370 * (confirm_delete_users() in wp-admin/includes/ms.php) deletion forms. The two 2371 * differ in markup: single site has one content decision per user, multisite 2372 * has one decision per site a user belongs to (several radio groups per 2373 * fieldset), and their reassign dropdowns use different "no selection" values. 2374 * The logic below works per radio group so it covers both. 2375 * 2376 * @since 7.1.0 2377 */ 2378 (function(){ 2379 const { _n, sprintf } = wp.i18n; 2380 const usersForm = document.querySelector( '.delete-and-reassign-users-form' ); 2381 2382 // Check if the form exists and contains any radio buttons. 2383 if ( ! usersForm || ! usersForm.querySelector( 'input[type="radio"]' ) ) { 2384 return; 2385 } 2386 2387 const summaryId = 'delete-users-error-summary'; 2388 2389 /** 2390 * Whether a reassign dropdown has no user selected. 2391 * 2392 * The "Select a user" placeholder value differs between the forms: the 2393 * single-site dropdown uses an empty string, the multisite one uses the 2394 * wp_dropdown_users() default of '-1'. 2395 * 2396 * @param {HTMLSelectElement} select The reassign dropdown. 2397 * @return {boolean} True when no real user is selected. 2398 */ 2399 function hasNoSelectedUser( select ) { 2400 return '' === select.value || '-1' === select.value; 2401 } 2402 2403 /** 2404 * Builds a human-readable label for a radio group's decision. 2405 * 2406 * Combines the fieldset legend (the user) with the site context that 2407 * precedes the group on multisite, so each summary entry is identifiable. 2408 * 2409 * @param {HTMLElement} group The radio group (<ul>) element. 2410 * @return {string} The composed label. 2411 */ 2412 function getDecisionLabel( group ) { 2413 const fieldset = group.closest( 'fieldset' ); 2414 const legend = fieldset ? fieldset.querySelector( 'legend' ) : null; 2415 const parts = []; 2416 2417 if ( legend ) { 2418 parts.push( legend.textContent.trim() ); 2419 } 2420 2421 // On multisite each radio group is preceded by a "Site: …" paragraph. 2422 const previous = group.previousElementSibling; 2423 if ( previous && previous !== legend && previous.textContent.trim() ) { 2424 parts.push( previous.textContent.trim() ); 2425 } 2426 2427 return parts.join( ' – ' ); 2428 } 2429 2430 // Keep the radio selection in sync with the reassign dropdown. 2431 usersForm.querySelectorAll( 'select' ).forEach( function( selectElement ) { 2432 selectElement.addEventListener( 'change', function( e ) { 2433 const item = e.target.closest( 'li' ); 2434 const radio = item ? item.querySelector( 'input[type="radio"]' ) : null; 2435 if ( radio ) { 2436 radio.checked = ! hasNoSelectedUser( e.target ); 2437 } 2438 }); 2439 }); 2440 2441 /** 2442 * Returns the radio groups whose content decision is still incomplete. 2443 * 2444 * A decision unit is a single radio group (<ul>), which maps to one user on 2445 * single site and one site-per-user on multisite. 2446 * 2447 * @return {Array} Objects describing each incomplete decision. 2448 */ 2449 function getIncompleteDecisions() { 2450 const incomplete = []; 2451 2452 usersForm.querySelectorAll( 'fieldset ul' ).forEach( function( group ) { 2453 const radios = group.querySelectorAll( 'input[type="radio"]' ); 2454 if ( ! radios.length ) { 2455 return; 2456 } 2457 2458 const checked = group.querySelector( 'input[type="radio"]:checked' ); 2459 2460 // No option chosen yet. 2461 if ( ! checked ) { 2462 incomplete.push( { target: radios[ 0 ], label: getDecisionLabel( group ) } ); 2463 return; 2464 } 2465 2466 // "Attribute to another user" chosen, but no user selected. 2467 if ( 'reassign' === checked.value ) { 2468 const select = group.querySelector( 'select' ); 2469 if ( select && hasNoSelectedUser( select ) ) { 2470 incomplete.push( { target: select, label: getDecisionLabel( group ) } ); 2471 } 2472 } 2473 }); 2474 2475 return incomplete; 2476 } 2477 2478 /** 2479 * Builds or refreshes the error summary markup. 2480 * 2481 * @param {Array} incomplete Incomplete decisions from getIncompleteDecisions(). 2482 * @return {string} The summary title, for announcing to assistive technology. 2483 */ 2484 function renderErrorSummary( incomplete ) { 2485 let summary = document.getElementById( summaryId ); 2486 2487 if ( ! summary ) { 2488 summary = document.createElement( 'div' ); 2489 summary.id = summaryId; 2490 summary.className = 'notice notice-error'; 2491 summary.setAttribute( 'tabindex', '-1' ); 2492 2493 // The wrapper contains the form on single site and wraps it on 2494 // multisite; insert the summary right after the page heading. 2495 const wrap = usersForm.querySelector( '.wrap' ) || usersForm.closest( '.wrap' ) || usersForm; 2496 const heading = wrap.querySelector( 'h1' ); 2497 wrap.insertBefore( summary, heading ? heading.nextSibling : wrap.firstChild ); 2498 } 2499 2500 const count = incomplete.length; 2501 const title = sprintf( 2502 /* translators: %s: Number of content decisions still required. */ 2503 _n( 2504 '%s content decision is still required before you can delete.', 2505 '%s content decisions are still required before you can delete.', 2506 count 2507 ), 2508 count 2509 ); 2510 2511 // Clear any previous markup and invalid states before rebuilding, 2512 // so decisions resolved since the last render are no longer flagged. 2513 summary.textContent = ''; 2514 usersForm.querySelectorAll( '[aria-invalid]' ).forEach( function( el ) { 2515 el.removeAttribute( 'aria-invalid' ); 2516 }); 2517 2518 const titleEl = document.createElement( 'p' ); 2519 const strong = document.createElement( 'strong' ); 2520 strong.textContent = title; 2521 titleEl.appendChild( strong ); 2522 summary.appendChild( titleEl ); 2523 2524 const list = document.createElement( 'ul' ); 2525 incomplete.forEach( function( item ) { 2526 const li = document.createElement( 'li' ); 2527 const link = document.createElement( 'a' ); 2528 link.href = '#' + item.target.id; 2529 link.textContent = item.label; 2530 link.addEventListener( 'click', function( e ) { 2531 e.preventDefault(); 2532 item.target.focus(); 2533 }); 2534 li.appendChild( link ); 2535 list.appendChild( li ); 2536 2537 item.target.setAttribute( 'aria-invalid', 'true' ); 2538 }); 2539 summary.appendChild( list ); 2540 2541 return title; 2542 } 2543 2544 /** 2545 * Removes the error summary and clears invalid states. 2546 */ 2547 function clearErrorState() { 2548 const summary = document.getElementById( summaryId ); 2549 if ( summary ) { 2550 summary.remove(); 2551 } 2552 usersForm.querySelectorAll( '[aria-invalid]' ).forEach( function( el ) { 2553 el.removeAttribute( 'aria-invalid' ); 2554 }); 2555 } 2556 2557 /** 2558 * Refreshes the error summary to match the current form state. 2559 * 2560 * @param {boolean} moveFocus Whether to move focus to the summary and 2561 * announce it (used on a failed submit). 2562 * @return {number} The number of incomplete decisions. 2563 */ 2564 function updateSummary( moveFocus ) { 2565 const incomplete = getIncompleteDecisions(); 2566 2567 if ( ! incomplete.length ) { 2568 clearErrorState(); 2569 return 0; 2570 } 2571 2572 const title = renderErrorSummary( incomplete ); 2573 2574 if ( moveFocus ) { 2575 document.getElementById( summaryId ).focus(); 2576 if ( window.wp && window.wp.a11y ) { 2577 window.wp.a11y.speak( title, 'assertive' ); 2578 } 2579 } 2580 2581 return incomplete.length; 2582 } 2583 2584 usersForm.addEventListener( 'submit', function( e ) { 2585 if ( updateSummary( true ) > 0 ) { 2586 e.preventDefault(); 2587 } 2588 }); 2589 2590 // Keep an existing summary current as decisions are resolved, without 2591 // stealing focus on every interaction. 2592 usersForm.addEventListener( 'change', function() { 2593 if ( document.getElementById( summaryId ) ) { 2594 updateSummary( false ); 2595 } 2596 }); 2597 })(); -
trunk/src/wp-admin/css/common.css
r62526 r62688 2606 2606 } 2607 2607 2608 .delete-and-reassign-users-form legend { 2609 margin: 1em 0; 2610 line-height: 1.5; 2611 float: inline-start; 2612 } 2613 2614 .delete-and-reassign-users-form fieldset > fieldset, 2615 .delete-and-reassign-users-form fieldset > ul { 2616 clear: both; 2617 } 2618 2619 .delete-and-reassign-users-form fieldset:has(select[aria-invalid="true"]):not(fieldset:has(fieldset)) { 2620 border-left: 4px solid #cc1818; 2621 background: #fcf0f0; 2622 padding-left: 12px; 2623 } 2624 2608 2625 .importers { 2609 2626 font-size: 16px; -
trunk/src/wp-admin/includes/deprecated.php
r61440 r62688 1590 1590 return $post; 1591 1591 } 1592 1593 /** 1594 * Was used to add JavaScript to the delete users form. 1595 * 1596 * @since 3.5.0 1597 * @deprecated 7.1.0 1598 * @access private 1599 */ 1600 function delete_users_add_js() { 1601 _deprecated_function( __FUNCTION__, '7.1.0' ); 1602 } -
trunk/src/wp-admin/includes/ms.php
r62086 r62688 857 857 */ 858 858 function confirm_delete_users( $users ) { 859 global $wpdb; 860 859 861 $current_user = wp_get_current_user(); 860 862 if ( ! is_array( $users ) || empty( $users ) ) { 861 863 return false; 862 864 } 865 863 866 ?> 864 <h1><?php esc_html_e( ' Users' ); ?></h1>867 <h1><?php esc_html_e( 'Delete Users' ); ?></h1> 865 868 866 869 <?php if ( 1 === count( $users ) ) : ?> … … 870 873 <?php endif; ?> 871 874 872 <form action="users.php?action=dodelete" method="post" >875 <form action="users.php?action=dodelete" method="post" class="delete-and-reassign-users-form"> 873 876 <input type="hidden" name="dodelete" /> 874 877 <?php 875 878 wp_nonce_field( 'ms-users-delete' ); 876 879 $site_admins = get_super_admins(); 877 $admin_out = '<option value="' . esc_attr( $current_user->ID ) . '">' . $current_user->user_login . '</option>';878 880 ?> 879 881 <table class="form-table" role="presentation"> 880 882 <?php 881 $allusers = (array) $_POST['allusers']; 882 foreach ( $allusers as $user_id ) { 883 foreach ( $users as $user_id ) { 883 884 if ( '' !== $user_id && '0' !== $user_id ) { 884 885 $delete_user = get_userdata( $user_id ); … … 903 904 ); 904 905 } 906 905 907 ?> 906 908 <tr> … … 913 915 if ( ! empty( $blogs ) ) { 914 916 ?> 915 <td><fieldset>< p><legend>917 <td><fieldset><legend> 916 918 <?php 917 919 printf( 918 /* translators: %s: User login. */ 919 __( 'What should be done with content owned by %s?' ), 920 '<em>' . $delete_user->user_login . '</em>' 920 /* translators: 1: User login, 2: User ID. */ 921 __( '%1$s (ID #%2$s): What should be done with the content owned by this user?' ), 922 '<strong>' . $delete_user->user_login . '</strong>', 923 $user_id 921 924 ); 922 925 ?> 923 </legend> </p>926 </legend> 924 927 <?php 925 928 foreach ( (array) $blogs as $key => $details ) { … … 927 930 array( 928 931 'blog_id' => $details->userblog_id, 929 'fields' => array( 'ID', 'user_login' ), 932 'fields' => array( 'ID' ), 933 'exclude' => $users, 930 934 ) 931 935 ); 932 936 937 $blog_users = wp_list_pluck( $blog_users, 'ID' ); 938 933 939 if ( is_array( $blog_users ) && ! empty( $blog_users ) ) { 934 $user_site = "<a href='" . esc_url( get_home_url( $details->userblog_id ) ) . "'>{$details->blogname}</a>"; 935 $user_dropdown = '<label for="reassign_user" class="screen-reader-text">' . 936 /* translators: Hidden accessibility text. */ 937 __( 'Select a user' ) . 938 '</label>'; 939 $user_dropdown .= "<select name='blog[$user_id][$key]' id='reassign_user'>"; 940 $user_list = ''; 941 942 foreach ( $blog_users as $user ) { 943 if ( ! in_array( (int) $user->ID, $allusers, true ) ) { 944 $user_list .= "<option value='{$user->ID}'>{$user->user_login}</option>"; 940 $user_site = "<a href='" . esc_url( get_home_url( $details->userblog_id ) ) . "'>{$details->blogname}</a>"; 941 switch_to_blog( $details->userblog_id ); 942 /* This filter is documented in wp-admin/users.php */ 943 $user_has_content = (bool) apply_filters( 'users_have_additional_content', false, array( $delete_user->ID ) ); 944 945 if ( ! $user_has_content ) { 946 if ( $wpdb->get_var( 947 $wpdb->prepare( 948 "SELECT ID FROM {$wpdb->posts} 949 WHERE post_author = %d 950 LIMIT 1", 951 $delete_user->ID 952 ) 953 ) ) { 954 $user_has_content = true; 955 } elseif ( $wpdb->get_var( 956 $wpdb->prepare( 957 "SELECT link_id FROM {$wpdb->links} 958 WHERE link_owner = %d 959 LIMIT 1", 960 $delete_user->ID 961 ) 962 ) ) { 963 $user_has_content = true; 945 964 } 946 965 } 947 948 if ( '' === $user_list ) { 949 $user_list = $admin_out; 950 } 951 952 $user_dropdown .= $user_list; 953 $user_dropdown .= "</select>\n"; 954 ?> 955 <ul style="list-style:none;"> 956 <li> 966 restore_current_blog(); 967 968 if ( ! $user_has_content ) { 969 ?> 970 <p> 971 <?php 972 /* translators: %s: Link to user's site. */ 973 printf( __( 'Site: %s' ), $user_site ); 974 ?> 975 </p> 976 <input type="hidden" 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 /> 977 <p><?php _e( 'This user does not have any content.' ); ?></p> 978 <?php 979 } else { 980 ?> 981 <fieldset> 982 <legend> 957 983 <?php 958 984 /* translators: %s: Link to user's site. */ 959 985 printf( __( 'Site: %s' ), $user_site ); 960 986 ?> 961 </li> 962 <li><label><input type="radio" id="delete_option0" name="delete[<?php echo $details->userblog_id . '][' . $delete_user->ID; ?>]" value="delete" checked="checked" /> 963 <?php _e( 'Delete all content.' ); ?></label></li> 964 <li><label><input type="radio" id="delete_option1" name="delete[<?php echo $details->userblog_id . '][' . $delete_user->ID; ?>]" value="reassign" /> 965 <?php _e( 'Attribute all content to:' ); ?></label> 966 <?php echo $user_dropdown; ?></li> 967 </ul> 968 <?php 987 </legend> 988 <ul> 989 <li> 990 <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 /> 991 <label for="delete_option_<?php echo esc_attr( $details->userblog_id . '_' . $delete_user->ID ); ?>"><?php _e( 'Delete all content.' ); ?></label> 992 </li> 993 <li> 994 <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 /> 995 <label for="reassign_option_<?php echo esc_attr( $details->userblog_id . '_' . $delete_user->ID ); ?>"><?php _e( 'Attribute all content to another user.' ); ?></label> 996 997 <label for="reassign_user_<?php echo esc_attr( $details->userblog_id . '_' . $delete_user->ID ); ?>" class="screen-reader-text"><?php _e( 'Select a user to attribute the content to.' ); ?></label> 998 <?php 999 wp_dropdown_users( 1000 array( 1001 'show_option_none' => __( 'Select a user' ), 1002 'name' => "blog[$user_id][$key]", 1003 'include' => $blog_users, 1004 'show' => 'display_name_with_login', 1005 'id' => "reassign_user_{$details->userblog_id}_{$delete_user->ID}", 1006 ) 1007 ); 1008 ?> 1009 1010 </li> 1011 </ul> 1012 </fieldset> 1013 <?php 1014 } 969 1015 } 970 1016 } … … 983 1029 <?php 984 1030 /** This action is documented in wp-admin/users.php */ 985 do_action( 'delete_user_form', $current_user, $ allusers );1031 do_action( 'delete_user_form', $current_user, $users ); 986 1032 987 1033 if ( 1 === count( $users ) ) : … … 993 1039 endif; 994 1040 995 submit_button( __( 'Confirm Deletion' ), 'primary' );1041 submit_button( __( 'Confirm Deletion' ), 'primary', 'submit', false, array( 'id' => 'confirm-users-deletion' ) ); 996 1042 ?> 997 1043 </form> -
trunk/src/wp-admin/includes/user.php
r62632 r62688 564 564 565 565 /** 566 * @since 3.5.0567 * @access private568 */569 function delete_users_add_js() {570 ?>571 <script>572 jQuery( function($) {573 var submit = $('#submit').prop('disabled', true);574 $('input[name="delete_option"]').one('change', function() {575 submit.prop('disabled', false);576 });577 $('#reassign_user').focus( function() {578 $('#delete_option1').prop('checked', true).trigger('change');579 });580 } );581 </script>582 <?php583 }584 585 /**586 566 * Optional SSL preference that can be turned on by hooking to the 'personal_options' action. 587 567 * -
trunk/src/wp-admin/network/users.php
r61660 r62688 57 57 $doaction = $_POST['action']; 58 58 $userfunction = ''; 59 60 foreach ( (array) $_POST['allusers'] as $user_id ) { 59 $allusers = (array) $_POST['allusers']; 60 61 foreach ( $allusers as $user_id ) { 61 62 if ( ! empty( $user_id ) ) { 62 63 switch ( $doaction ) { … … 73 74 74 75 echo '<div class="wrap">'; 75 confirm_delete_users( $ _POST['allusers']);76 confirm_delete_users( $allusers ); 76 77 echo '</div>'; 77 78 … … 189 190 } 190 191 192 /* 193 * Validate that every "reassign" choice has a real target before making 194 * any changes. The confirmation form blocks this client-side, so this is 195 * a defense-in-depth guard against an invalid reassignment (e.g. content 196 * reassigned to the non-existent user "-1") when JavaScript is bypassed. 197 * Bail out entirely so the deletion is all-or-nothing. 198 */ 199 if ( ! empty( $_POST['blog'] ) && is_array( $_POST['blog'] ) && ! empty( $_POST['delete'] ) ) { 200 foreach ( $_POST['blog'] as $id => $blogs ) { 201 foreach ( $blogs as $blogid => $reassign_user_id ) { 202 if ( isset( $_POST['delete'][ $blogid ][ $id ] ) 203 && 'reassign' === $_POST['delete'][ $blogid ][ $id ] 204 && (int) $reassign_user_id < 1 205 ) { 206 wp_redirect( 207 add_query_arg( 208 array( 'error' => 'missing_reassign' ), 209 network_admin_url( 'users.php' ) 210 ) 211 ); 212 exit; 213 } 214 } 215 } 216 } 217 191 218 if ( ! empty( $_POST['blog'] ) && is_array( $_POST['blog'] ) ) { 192 219 foreach ( $_POST['blog'] as $id => $users ) { … … 311 338 ); 312 339 } 340 341 if ( isset( $_REQUEST['error'] ) && 'missing_reassign' === $_REQUEST['error'] ) { 342 wp_admin_notice( 343 __( 'No users were deleted because no user was selected for content reassignment.' ), 344 array( 345 'type' => 'error', 346 'dismissible' => true, 347 'id' => 'message', 348 ) 349 ); 350 } 313 351 ?> 314 352 <div class="wrap"> -
trunk/src/wp-admin/users.php
r62026 r62688 214 214 } 215 215 216 switch ( $_REQUEST['delete_option'] ) { 216 if ( 'reassign' === $_REQUEST['delete_option'][ $id ] && empty( $_REQUEST['reassign_user'][ $id ] ) ) { 217 $update = 'err_missing_reassign'; 218 continue; 219 } 220 221 switch ( $_REQUEST['delete_option'][ $id ] ) { 217 222 case 'delete': 218 223 wp_delete_user( $id ); 219 224 break; 220 225 case 'reassign': 221 wp_delete_user( $id, $_REQUEST['reassign_user'] );226 wp_delete_user( $id, $_REQUEST['reassign_user'][ $id ] ); 222 227 break; 223 228 } … … 307 312 } 308 313 309 /**310 * Filters whether the users being deleted have additional content311 * associated with them outside of the `post_author` and `link_owner` relationships.312 *313 * @since 5.2.0314 *315 * @param bool $users_have_additional_content Whether the users have additional content. Default false.316 * @param int[] $user_ids Array of IDs for users being deleted.317 */318 $users_have_content = (bool) apply_filters( 'users_have_additional_content', false, $user_ids );319 320 if ( $user_ids && ! $users_have_content ) {321 if ( $wpdb->get_var(322 "SELECT ID FROM {$wpdb->posts}323 WHERE post_author IN( " . implode( ',', $user_ids ) . ' )324 LIMIT 1'325 ) ) {326 $users_have_content = true;327 } elseif ( $wpdb->get_var(328 "SELECT link_id FROM {$wpdb->links}329 WHERE link_owner IN( " . implode( ',', $user_ids ) . ' )330 LIMIT 1'331 ) ) {332 $users_have_content = true;333 }334 }335 336 if ( $users_have_content ) {337 add_action( 'admin_head', 'delete_users_add_js' );338 }339 340 314 require_once ABSPATH . 'wp-admin/admin-header.php'; 341 315 ?> 342 <form method="post" name="updateusers" id="updateusers" >316 <form method="post" name="updateusers" id="updateusers" class="delete-and-reassign-users-form"> 343 317 <?php wp_nonce_field( 'delete-users' ); ?> 344 318 <?php echo $referer; ?> … … 366 340 <ul> 367 341 <?php 368 $go_delete = 0; 342 $go_delete = 0; 343 $users_have_content = false; 369 344 370 345 foreach ( $all_user_ids as $id ) { … … 386 361 esc_attr( $id ) 387 362 ); 388 printf( 389 /* translators: 1: User ID, 2: User login. */ 390 __( 'ID #%1$s: %2$s' ), 391 $id, 392 $user->user_login 393 ); 363 364 /** 365 * Filters whether the users being deleted have additional content 366 * associated with them outside of the `post_author` and `link_owner` relationships. 367 * 368 * @since 5.2.0 369 * 370 * @param bool $users_have_additional_content Whether the users have additional content. Default false. 371 * @param int[] $user_ids Array of IDs for users being deleted. 372 */ 373 $user_has_content = (bool) apply_filters( 'users_have_additional_content', false, array( $id ) ); 374 375 if ( ! $user_has_content ) { 376 if ( $wpdb->get_var( 377 $wpdb->prepare( 378 "SELECT ID FROM {$wpdb->posts} 379 WHERE post_author = %d 380 LIMIT 1", 381 $id 382 ) 383 ) ) { 384 $user_has_content = true; 385 } elseif ( $wpdb->get_var( 386 $wpdb->prepare( 387 "SELECT link_id FROM {$wpdb->links} 388 WHERE link_owner = %d 389 LIMIT 1", 390 $id 391 ) 392 ) ) { 393 $user_has_content = true; 394 } 395 } 396 397 if ( ! $user_has_content ) { 398 ?> 399 <input type="hidden" name="delete_option[<?php echo esc_attr( $id ); ?>]" value="delete" required /> 400 <p> 401 <?php 402 printf( 403 /* translators: 1: User login. 2: User ID */ 404 __( '%1$s (ID #%2$s): This user does not have any content.' ), 405 '<strong>' . $user->user_login . '</strong>', 406 $id 407 ); 408 ?> 409 </p> 410 <?php 411 } else { 412 ?> 413 <fieldset> 414 <legend> 415 <?php 416 printf( 417 /* translators: 1: User login, 2: User ID. */ 418 __( '%1$s (ID #%2$s): What should be done with the content owned by this user?' ), 419 '<strong>' . $user->user_login . '</strong>', 420 $id 421 ); 422 ?> 423 </legend> 424 425 <ul> 426 <li> 427 <input type="radio" id="delete_option_<?php echo esc_attr( $id ); ?>" name="delete_option[<?php echo esc_attr( $id ); ?>]" value="delete" required /> 428 <label for="delete_option_<?php echo esc_attr( $id ); ?>"><?php _e( 'Delete all content.' ); ?></label> 429 </li> 430 <li> 431 <input type="radio" id="reassign_option_<?php echo esc_attr( $id ); ?>" name="delete_option[<?php echo esc_attr( $id ); ?>]" value="reassign" required /> 432 <label for="reassign_option_<?php echo esc_attr( $id ); ?>"><?php _e( 'Attribute all content to another user.' ); ?></label> 433 434 <label for="reassign_user_<?php echo esc_attr( $id ); ?>" class="screen-reader-text"><?php _e( 'Select a user to attribute the content to.' ); ?></label> 435 <?php 436 wp_dropdown_users( 437 array( 438 'show_option_none' => __( 'Select a user' ), 439 'option_none_value' => '', 440 'name' => 'reassign_user[' . $id . ']', 441 'id' => 'reassign_user_' . $id, 442 'exclude' => $user_ids, 443 'show' => 'display_name_with_login', 444 ) 445 ); 446 ?> 447 </li> 448 </ul> 449 </fieldset> 450 <?php 451 $users_have_content = true; 452 } 453 394 454 echo "</li>\n"; 395 455 … … 402 462 <?php 403 463 if ( $go_delete ) : 404 405 if ( ! $users_have_content ) :406 ?>407 <input type="hidden" name="delete_option" value="delete" />408 <?php else : ?>409 <fieldset>410 <?php if ( 1 === $go_delete ) : ?>411 <p><legend><?php _e( 'What should be done with content owned by this user?' ); ?></legend></p>412 <?php else : ?>413 <p><legend><?php _e( 'What should be done with content owned by these users?' ); ?></legend></p>414 <?php endif; ?>415 416 <ul style="list-style:none;">417 <li>418 <input type="radio" id="delete_option0" name="delete_option" value="delete" />419 <label for="delete_option0"><?php _e( 'Delete all content.' ); ?></label>420 </li>421 <li>422 <input type="radio" id="delete_option1" name="delete_option" value="reassign" />423 <label for="delete_option1"><?php _e( 'Attribute all content to:' ); ?></label>424 <?php425 wp_dropdown_users(426 array(427 'name' => 'reassign_user',428 'exclude' => $user_ids,429 'show' => 'display_name_with_login',430 )431 );432 ?>433 </li>434 </ul>435 </fieldset>436 <?php437 endif;438 439 464 /** 440 465 * Fires at the end of the delete users form prior to the confirm button. … … 613 638 $messages = array(); 614 639 if ( isset( $_GET['update'] ) ) : 640 $delete_count = isset( $_GET['delete_count'] ) ? (int) $_GET['delete_count'] : 0; 641 615 642 switch ( $_GET['update'] ) { 616 643 case 'del': 617 644 case 'del_many': 618 $delete_count = isset( $_GET['delete_count'] ) ? (int) $_GET['delete_count'] : 0;619 645 if ( 1 === $delete_count ) { 620 646 $message = __( 'User deleted.' ); … … 696 722 ) 697 723 ); 698 $messages[] = wp_get_admin_notice( 699 __( 'Other user roles have been changed.' ), 700 array( 701 'id' => 'message', 702 'additional_classes' => array( 'updated' ), 703 'dismissible' => true, 704 ) 705 ); 724 if ( $delete_count > 0 ) { 725 $messages[] = wp_get_admin_notice( 726 __( 'Other user roles have been changed.' ), 727 array( 728 'id' => 'message', 729 'additional_classes' => array( 'updated' ), 730 'dismissible' => true, 731 ) 732 ); 733 } 706 734 break; 707 735 case 'err_admin_del': … … 714 742 ) 715 743 ); 716 $messages[] = wp_get_admin_notice( 717 __( 'Other users have been deleted.' ), 718 array( 719 'id' => 'message', 720 'additional_classes' => array( 'updated' ), 721 'dismissible' => true, 722 ) 723 ); 744 if ( $delete_count > 0 ) { 745 $messages[] = wp_get_admin_notice( 746 __( 'Other users have been deleted.' ), 747 array( 748 'id' => 'message', 749 'additional_classes' => array( 'updated' ), 750 'dismissible' => true, 751 ) 752 ); 753 } 754 break; 755 case 'err_missing_reassign': 756 $messages[] = wp_get_admin_notice( 757 __( 'Users could not be deleted because no user was selected for content reassignment.' ), 758 array( 759 'id' => 'message', 760 'additional_classes' => array( 'error' ), 761 'dismissible' => true, 762 ) 763 ); 764 if ( $delete_count > 0 ) { 765 $messages[] = wp_get_admin_notice( 766 __( 'Other users have been deleted.' ), 767 array( 768 'id' => 'message', 769 'additional_classes' => array( 'updated' ), 770 'dismissible' => true, 771 ) 772 ); 773 } 724 774 break; 725 775 case 'remove':
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)