How to Use Select2 Multiselect in Meta Boxes
In this tutorial, I will show you two examples of how to use Select2 when creating custom fields in WordPress admin. Particularly, I will show you how to do it in meta boxes in the classic editor, but you can do the same for taxonomy settings or options pages.
In the first example, we will use Select2 to create a multiselect dropdown with tags. In the second one, it will become more interesting; we will do the same for posts, but also with an AJAX search (both examples will also be implemented in two ways – programmatically and with my Simple Fields plugin).
Before jumping into any of the examples below, you need to make sure that the Select2 library’s CSS and JS are added to your WordPress admin. For example, you can use a CDN version this way:
add_action( 'admin_enqueue_scripts', function(){
wp_enqueue_style( 'select2', 'https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css' );
wp_enqueue_script( 'select2', 'https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js', array( 'jquery' ) );
} );Of course, you don’t need to do that if you decide to create the fields with my plugin.
Example 1. Select2 Multiselect Dropdown with Tags
As I already mentioned before, each example will be first implemented programmatically from scratch, and then we will do it with my Simple Fields plugin.
Below is the code of how you can do it from scratch:
<?php
// registeting our meta box
add_action( 'add_meta_boxes', function() {
add_meta_box( 'misha_test', 'Meta Box for Select2', 'rudr_display_metabox', 'post' );
} );
// displaying the fields inside
function rudr_display_metabox( $post ) {
if( $tags = get_terms( array( 'taxonomy' => 'post_tag', 'hide_empty' => false ) ) ) {
$selected_tags = get_post_meta( $post->ID, 'some_tags', true );
?>
<p>
<label for="some_tags">Tags</label><br />
<select id="some_tags" name="some_tags[]" multiple style="width:99%">
<?php
foreach( $tags as $tag ) :
$selected = is_array( $selected_tags ) && in_array( $tag->term_id, $selected_tags ) ? ' selected="selected"' : '';
?><option value="<?php echo $tag->term_id ?>"<?php echo $selected ?>><?php echo $tag->name ?></option><?php
endforeach;
?>
</select>
</p>
<?php
}
}
// saving metabox data
add_action( 'save_post', function( $post_id ) {
// autosave check ...
// nonce check ...
// post type check ...
$tags = isset( $_POST[ 'some_tags' ] ) && is_array( $_POST[ 'some_tags' ] ) ? array_map( 'absint', $_POST[ 'some_tags' ] ) : array();
update_post_meta( $post_id, 'some_tags', $tags );
} );
// initalizing select2
add_action( 'admin_footer-post.php', function() {
?><script>
jQuery( function($){
$( '#some_tags' ).select2();
} );
</script><?php
} );In the code above, please keep in mind the following:
- This is just a code example, which means it is incomplete. As you can see on lines
34-38, some additional conditional checks are skipped for the sake of simplicity. If you want to learn more, you can read the complete meta boxes tutorial or just scroll down for a second code snippet. - Line
39can also be improved, I mean, we’re just usingabsint()WordPress function to sanitize the input value, but you can also additionally check whether the provided tag ID exists on the website.
And here is the result:

Creating a meta box with a Select2 field with my plugin
In case you have the Simple Fields plugin installed on your website, you can create the same meta box with this simple code snippet:
add_filter( 'simple_register_metaboxes', function( $metaboxes ) {
$tags = get_terms( array( 'taxonomy' => 'post_tag', 'hide_empty' => false ) );
if( $tags ) {
$metaboxes[] = array(
'id' => 'misha_test',
'name' => 'Meta Box for Select2',
'post_type' => 'post',
'fields' => array(
array(
'id' => 'some_tags',
'label' => 'Tags',
'type' => 'select',
'placeholder' => 'Select cities…',
'multiple' => true,
'options' => wp_list_pluck( $tags, 'name', 'term_id' ),
)
)
);
}
return $metaboxes;
} );Looks much simpler, doesn’t it?
Plus, when you do it with the plugin, you don’t have to worry about enqueueing the Select2 library’s CSS and JS (the plugin will include the latest versions).
And as a result, we will have exactly the same meta box:

Another cool thing about my plugin is that when you change the hook from simple_register_metaboxes to simple_register_sidebars, the multiselect field is going to be displayed as a FormTokenField component in a Gutenberg sidebar:

Example 2. Select2 Field with AJAX Posts Search
But the really cool thing about Select2 is that you can create not just a custom dropdown field, but a dropdown field with an AJAX search. And it is a real game-changer if you, for example, have hundreds of items to select from.
And right now, we’re going to do that just by adding one more field to our custom meta box.
By the way, if you don’t want to deal with all the code below, you can just scroll straight down to the plugin approach.
2.1. Adding the field
I think there is no point in copying the same code again, so you can just add the field to our previous code snippet, starting from line 26.
<?php
}
$selected_posts = get_post_meta( $post->ID, 'some_posts', true );
?>
<p>
<label for="some_posts">Posts</label><br />
<select id="some_posts" name="some_posts[]" multiple style="width:99%">
<?php
if( $selected_posts ) :
foreach( $selected_posts as $selected_post_id ) :
$title = get_the_title( $selected_post_id );
// if the post title is too long, truncate it and add "..." at the end
$title = ( 50 < mb_strlen( $title ) ) ? mb_substr( $title, 0, 49 ) . '…' : $title;
?><option value="<?php echo $selected_post_id ?>" selected="selected"><?php echo $title ?></option><?php
endforeach;
endif;
?>
</select>
</p>Nothing super-special here, just take a look at line 37 – we’re making the post title a little bit shorter if it is too long, and most likely won’t look that good in our select dropdown.
2.2. Select2 initialization
Why am I using jQuery? Because it is included in WordPress admin anyway.
$( '#some_posts' ).select2({
ajax: {
url: ajaxurl, // AJAX URL is predefined in WordPress admin
dataType: 'json',
delay: 250, // delay in ms while typing when to perform a AJAX search
data: function( params ) {
return {
q: params.term, // search query
action: 'mishagetposts' // AJAX action for admin-ajax.php
}
},
processResults: function( data ) {
var options = []
if( data ) {
// data is the array of arrays with an ID and a label of the option
$.each( data, function( index, text ) {
options.push( { id: text[0], text: text[1] } )
})
}
return {
results: options
}
},
cache: true
},
minimumInputLength: 3 // the minimum of symbols to input before perform a search
});2.3. AJAX search (PHP)
This is just a standard WordPress way of processing AJAX requests. We are using the action parameter from the previous code snippet as a part of the wp_ajax_ hook.
// wp_ajax_{action}
// no need for wp_ajax_nopriv_ because the meta box can only be used by WP users
add_action( 'wp_ajax_mishagetposts', 'rudr_get_posts_ajax_callback' );
function rudr_get_posts_ajax_callback(){
// we will pass post IDs and titles to this array
$results = array();
query_posts(
array(
's'=> $_GET[ 'q' ], // the search query
'post_status' => 'publish', // if you don't want drafts to be returned
'posts_per_page' => 50 // how many to show at once
)
);
if( $search_results->have_posts() ) :
while( $search_results->have_posts() ) : $search_results->the_post();
// shorten the title a little
$title = ( mb_strlen( $search_results->post->post_title ) > 50 ) ? mb_substr( $search_results->post->post_title, 0, 49 ) . '…' : $search_results->post->post_title;
$results[] = array(
$search_results->post->ID,
$title,
);
endwhile;
endif;
echo json_encode( $return );
die;
}There is no real difference whether you’re going to use query_posts() or WP_Query or get_posts() to retrieve the posts in this code snippet. And there is no reason to reset the globals before the die; function anyway.
Here we go:

Using Simple Fields to create a Select2 field with the AJAX search
Currently, my plugin supports two types of fields with the AJAX search:
And we already decided that we’re using the first one in our code. Let’s just add this line to our code above
array(
'id' => 'some_posts',
'label' => 'Posts',
'type' => 'post',
'multiple' => true,
'post_type' => 'post',
'placeholder' => 'Select a post',
),And here is the final result:

Misha Rudrastyh
Hey guys and welcome to my website. For more than 15 years I've been doing my best to share with you some superb WordPress guides and tips for free.
Need some developer help? Contact me
Hi Misha,
Thanks for Superb work and ready to use.
How to print Select2 posts as a link on single.php?
Hi,
happy to help :)
If I understand you properly, you can use this:
Thanks it works
Hi Misha. On the first screen I see different post types – video, quote, etc. How can I add them to my WordPress instance? Thank you.
You have to add via the functions.php file. Example below:
add_theme_support('post-formats' , array( 'status' ) );You can add more post-formats according to your needs.
NOTE: You will need to create several PHP files(one by each post format) in order to get the post formats work. Not to forget that you will need to use the
get_template_part('')WordPress function.Hi Misha,
is it possible to choose a post ( by its category ) of another post type and display it’s content on the frontend, with your plug-in ?
Hi Valentin,
Yes, it is possible.
Hello Misha,
What changing required, if i need to add posts from other CPT.
Two custom post type are:
Add meta box to CPT ‘Apple’
Add Posts from CPT ‘orange’
Hello Kam,
To add metabox for CPT Apple, you have to change custom post type name in
add_meta_box()function.If you want to show posts in dropdown search from CPT orange, in
query_posts()add one more parameterpost_type.Thank you for this excellent information no how-to use select2 ajax with WordPress. I adapted it for use on some huge front-end dropdowns I was using, and it is working superbly. The site users are ecstatic because the site is so much faster with ajax for these long selects. Thanks again!
Hi Brad,
That’s awesome! I’m happy to help! :)
Hi Misha,
Thank you for your tutorial!
I would love to integrate the seat chart like this: https://github.com/mateuszmarkowski/jQuery-Seat-Charts to WooCommerce so that I could sell seats online.
Could you feel free to guide me how to do that?
Thank you
Hi John,
I didn’t have a chance to work with this jQuery plugin before :)
Oh, what a pity… Thank you anyway! :)
Hi,
thanks for the great solution! works like a charm!
I wonder if it’s possible to also add the possibility to add new tags and not only choose from existing tags?
Thanks again and best,
Niko
Hi Niko,
No 🙃 but the idea is interesting.
Thanks for the fast reply. Unfortunately I’m not really a dev but i think it should be possible – Similar to this solution: http://jsfiddle.net/XQ8Fw/674/
But of course i understand that’s beyond the friendly support :-)
Anyway; If you may sometime include it, please let me know.
Sorry, I just didn’t understand you.
It is possible if you use AJAX method (example with posts). Good news – you do not need to change anything in your JS code.
In

wp_ajax_callback function you have to add a condition – if search query doesn’t match exactly with any of the given results, add another element to the$returnarray. I made it with:array_unshift( $return, array('uniqueid', $_GET['q'] . ' (new)') );And got this:
Then, in
save_postaction hook add code that checks uniqueid and if it matches, it creates new element in database, for posts you can usewp_insert_post(), for post tagswp_insert_term().Hi Misha
Thanks so much for sharing this code with the world.
I followed your instructions however I am not able to get the title of the new post inside the save_post action hook (only the id). How can I make the content of $_GET[‘q’] available to save_post.
Again thanks a lot for sharing.
Hi,
Did you try to replace "uniqueid" with the post title?
Hello Misha, Another nice code.
How can I make the tag dropdown Ajax also? I have more that 5000 tags on a wordpress installation.
Hi, thank you,
All the information is in this article 🙃 making tags dropdown is very similar to posts dropdown.
Adamsın :) Perfect
Hello Misha,
I see you are saving the terms in post meta. but isn’t it proper to set post terms? How can I do that?
Hello,
Why?
Because terms need relationship with taxonomy. But in you example terms are saving as post meta not creating relationship with taxonomy (post_tag). How can I do that?
You need
register_taxonomy_for_object_type()in this case! 😁Hey Misha!
I spent the entire day trying to convert your ideas to search for users, but I can’t seem to find the issue with my code.
Hey,
Do you mean it doesn’t search for users? Check
search_columnsparameter.Hi Misha
I duplicated your metabox to have two of them (I need to display two different CPT links).
I am now having problems with the second WP_Query as I am not able to reset the first WP_Query (So I am always getting the posts from the first WP_Query). Whats the correct way to handle it with your code?
Hi Simon,
Didn’t you forget about
wp_reset_postdata()function?Hi Misha !
Thank you for this article :)
We are using select2 on a wordpress site.
It is working fine, but it doesn’t display the data after saving or updating the post.
I guess we should include some code in the admin init hook?
I´m not sure, that is my guess..
I will really appreciate any suggestions/guidelines on how to proceed.
Thanks so much,
Seba.
Just one additional comment I just realized.
When I say that the data is not being displayed, I mean on the admin select metabox.
Hey Seba,
so, on the website everything displays ok, right?
Thanks for the great tutorial.
I used it to add admin option input fields with post selection.
On step 4 instead of doing
json_encode( $results );you could do simplywp_send_json( $results );.It does the encoding, echo and die for you.
Awesome!
Thank you for suggestion.
Hi Misha,
Can you please help create a similar tutorial to add select2 to Contact Form 7 (CF7) on a website which also runs Woocommerce?
I am sure the code would be much simpler.
I am learning to code and have found your articles very useful.
Thanks a lot!
Hi,
I’m not sure, but I will think about it.
Thank you for your consideration
Very helpful. Thanks!
Thank you, I followed your instruction and made a custom meta box for my CPT “Artworks” to select terms from custom taxonomy “Object Types” with select2 UI. However, the meta box does not save selected terms.
After saving either draft or published post, there is nothing in metabox field, no selected terms displayed.
What should I check to fix that?
Hello,
Please contact me and I will help you.
Hi,
thank you so mich. Awesome tutorial.
But I don´t get the post search field to work for a custom post type. Maybe, you can give an example for it too.
Additional, these fields are really nice, but it would be a lot better to have to more options:
1. Decide, if a field is required or not before post submission
2. Set a “Select Option” first option to the field (actually, first term is pre-selected.
I am learning wordpress and you would really help me with examplles.
Later on, I need to select taxonomies inside other taxonomies (as metabox fields) and more… a long progress, but I love to learn :)
Hi Holger,
You can set a
post_typeparameter inquery_posts().I need to add categories and custom taxonomies for posts and custom posts. There are over 1,000 taxonomies.
I don’t understand the examples provided and can’t figure it out.
Is there a plugin that will remove the default taxonomy selection and replace it with Select2?