WordPress’s default dropdowns for Authors and Parent Pages in WP Admin work well for most setups, but sometimes the large number of users can slow page load and exhaust memory. A solution that I like is replacing the user dropdown with Select2 and use AJAX to load results. Below, I include some code that uses select2 version 3.5.0 and walk you through how to solve this problem.
Replacing the Authors dropdown can be achieved by using the “wp_dropdown_users” filter.
function wds_dropdown_users_callback( $output ) { global $post; // Is there an author currently set? $author_id = isset( $post->post_author ) ? $post->post_author : null; $author_data = get_userdata( $author_id ); // create data to be passed into custom js $data = array( 'post_author' => $author_id, 'display_name' => isset( $author_data->display_name ) ? $author_data->display_name : null, 'nonce' => wp_create_nonce( 'wds-replace-user-dd-nonce' ), 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'placeholder_text' => __( 'Select an Author', 'text-domain' ), ); // enqueue css/js wp_enqueue_script( 'select2', plugin_dir_url( __FILE__ ) . '/select2-3.5.0/select2.min.js', array('jquery'), '', true ); wp_enqueue_style( 'select2', plugin_dir_url( __FILE__ ) . '/select2-3.5.0/select2.css', array(), '' ); wp_enqueue_script( 'wds-replace-user-dropdown', plugin_dir_url( __FILE__ ) . '/wds-replace-user-dropdown.js', array( 'jquery', 'select2' ), '', true ); wp_localize_script( 'wds-replace-user-dropdown', 'wds_rud_config', $data ); // return custom markup for return ' <input type="text" name="post_author_override" id="wds-user-search" value="'. $author_id .'"/> '; } add_filter( 'wp_dropdown_users', wds_dropdown_users_callback );
First, we need to see if there is already a post author set and make sure that data gets passed into our JS. After enqueueing the Select2 JS/CSS and our custom JS, we can output the necessary markup for Select2 to use. Next, we have to setup the AJAX function for Select2 to use. This function will take a string and search for users who match based on email and display name.
function wds_get_users() { $security_check_passes = ( ! empty( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && 'xmlhttprequest' === strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && isset( $_GET['nonce'], $_GET['q'] ) && wp_verify_nonce( $_GET['nonce'], 'wds-replace-user-dd-nonce' ) ); if ( ! $security_check_passes ) { wp_send_json_error( $_GET ); } // if we have an author id, get the display_name if ( isset( $_GET['id'] ) && $_GET['id'] ) { $author_data = get_userdata( absint( $_GET['id'] ) ); $results = array( array( 'id' => $author_data->ID, 'text' => $author_data->display_name, ), ); wp_send_json_success( $results ); } $search = sanitize_text_field( $_GET['q'] ); $user_query = new WP_User_Query( array( 'search' => '*'.$search.'*', 'search_columns' => array( 'user_login', 'user_email', 'user_nicename', 'ID' ), 'who' => 'authors', 'number' => 10, ) ); // bail if we don't have any results if ( empty( $user_query->results ) ) { wp_send_json_error( $_GET ); } $results = array(); foreach ( $user_query->results as $user ) { $results[] = array( 'id' => $user->ID, 'text' => $user->display_name ); } wp_send_json_success( $results ); } add_action( 'wp_ajax_wds_get_users', 'wds_get_users' ); add_action( 'wp_ajax_nopriv_wds_get_users', 'wds_get_users' );
The first part of this function verifies that this is a valid AJAX request and then checks to see if we received an ID to query against. If there is an ID, we know an author is already set for this post and only lookup the data for that one user to display in the dropdown. Otherwise, we query all users and make sure the entered string matches part or all of the user’s email or display name. We then return the JSON encoded array of all matching users.
Now we have to tell Select2 which field to use (the input from the dropdown_users_callback function) and to use AJAX.
This can be done in Select2’s AJAX option:
app.$select = $( document.getElementById( 'wds-user-search' ) ); app.$select.select2({ placeholder : app.placeholder_text, minimumInputLength : 3, allowClear: true, width: '60%', ajax : { cache : false, url : ajaxurl, dataType : 'json', data : function (term, page) { return { q : term, action : 'wds_replace_user_dropdown', nonce : app.nonce, }; }, results : app.select2Data }, ...
The next step is to loop through the AJAX results and return the results in the format Select2 expects.
app.select2Data = function( ajax_data, page, query ) { var items=[]; $.each( ajax_data.data, function( i, item ) { var new_item = { 'id' : item.id, 'text' : item.text }; items.push(new_item); }); return { results: items }; };
Large WordPress sites may run into memory and speed issues when the user dropdown is being built. Using Select2/AJAX is an easy way to avoid performance issues and and allows easier searching for authors. There are other ways to solve this issue, like limiting the number of users in the dropdown, but that could cause other problems (like not being able to find an author). So, I recommend recommend the Select2/AJAX solution because it provides a nice search UI and allows for all authors on a site to be selected from.
And here’s your great plugin for people wondering how to put it together 🙂
Thanks!
https://github.com/WebDevStudios/WDS-Dynamic-Dropdowns
Hello Matt, Thank you for this great tutorial.
Please do you have any idea if need to returns with author name and email together?
eg. Matt McAchran – [email protected]
Hi Mohammed – the repository on Github is now updated to show author display name and email. Here’s the commit for the update:
https://github.com/WebDevStudios/WDS-Dynamic-Dropdowns/commit/bf2e4be57d95e94735b1d4ebfbcd15921971101f
There is bug,when we try to use the quick edit setting, then the selectors getting places at the top of the left side of the screen and creating problem…Please fix that…can you please add support for Buddypress selectorbox? I am using BuddyPress Xprofile Custom Fields Type for extending profile fields..But the front end select box are too ugly…like http://imgur.com/a/Bb8MH
Here is Screenshot of Bug http://imgur.com/a/TadVF
While this does solve the solution of issues with huge select boxes, the user query is still ran before the `wp_dropdown_users` filter is called, so while this does replace it with a select box if you have very large user base, there is still the delay on the initial `get_users` call