Users: Make wp_dropdown_users() scalable via autocomplete on large sites#11447
Users: Make wp_dropdown_users() scalable via autocomplete on large sites#11447sanketio wants to merge 2 commits intoWordPress:trunkfrom
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
Summary
wp_dropdown_users()loads every user in the database unconditionally. On sites with tens of thousands of users this causes fatal memory exhaustion and browser hangs. This ticket has been open since 2012. This patch implements the approach originally proposed by Helen Hou-Sandi in 19867.3.diff, modernised for the current codebase.What changed
wp_dropdown_users()—wp-includes/user.php'autocomplete' => falseargument. Whentrue, renders a jQuery UI autocomplete text input backed by an AJAX user search instead of a<select>.wp_is_large_user_count()returnstrue(> 10,000 users), unless the caller passes an explicit'include'list or'show_option_all'.<input class="wp-suggest-user">— the user types into this; jQuery UI shows suggestions.<input class="wp-suggest-user-helper" name="...">— stores the selected user ID for form submission.data-autocomplete-labelattribute is derived from the'show'argument so suggestion items match what<option>text would have shown (e.g.display_name_with_login→{{display_name}} ({{user_login}})).wp_dropdown_users_autocomplete— allows overriding the autocomplete decision.wp_dropdown_users_argsnow fires unconditionally, before the autocomplete/select branch, so existing hooks continue to work regardless of mode.wp_ajax_autocomplete_user()—wp-admin/includes/ajax-actions.php-1on any non-multisite install.list_userscapability. Email search column is only included for users withedit_users.user_idas a supportedautocomplete_fieldvalue, returning the numeric user ID as the suggestion value.{{user_login}},{{user_email}},{{display_name}},{{user_id}}. The{{user_email}}token is silently stripped for users withoutedit_users.'number' => 20inget_users().wp_send_json()(correctContent-Type: application/jsonheader).autocomplete_term_length— minimum search term length (default 2).autocomplete_user_results— allows modifying the final results array.autocomplete_users_for_site_adminspreserved.user-suggest.js—js/_enqueues/lib/user-suggest.jsdata-autocomplete-labelattribute and passes it to the AJAX source URL asautocomplete_label.hasHelperpattern (user_idfield + sibling.wp-suggest-user-helperinput).focushandler: showsui.item.label(the display text) while keyboard-navigating, not the raw ID.selecthandler: writes the user ID to the hidden helper input, the label to the visible input.users.php—wp-admin/users.php$_REQUEST['reassign_user']is now passed throughabsint()and validated (> 0and!== $id) before being forwarded towp_delete_user(). Previously, if the autocomplete visible input was partially typed and the hidden helper remained0, content would be silently deleted instead of reassigned.Tests
tests/phpunit/tests/user/wpDropdownUsers.php— 10 new test methods:<input>elements, not<select>nameattributewp_dropdown_users_autocompletefilter can force-enable or force-disablewp_dropdown_users_argsfires in both modeswp_dropdown_usersHTML filter fires in both modesincludeorshow_option_allis setdata-autocomplete-labelmatches theshowargument (data-provider: 5 cases)tests/phpunit/tests/ajax/wpAjaxAutocompleteUser.php— new file, 14 test methods:autocomplete_term_lengthfilterautocomplete_fieldselection (user_login,user_id,user_email){{user_email}}stripping for non-edit_usersautocomplete_user_resultsfilter fires and can modify resultslabel+value)Backward compatibility
All existing filters fire unconditionally. The
<select>path is fully preserved and is the default on small sites. No existing callers are broken:export.phpcalls withinclude+show_option_allsuppress auto-enable; the Quick Edit path has its ownwp_is_large_user_count()guard.Trac ticket: https://core.trac.wordpress.org/ticket/19867
Use of AI Tools
AI assistance: Yes
Tool(s): GitHub Copilot
Model(s): Claude Sonnet 4.6
Used for: Initial code skeleton, test suggestions, and bug diagnosis; final implementation, logic, and all tests were reviewed and edited by me.
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.