How to Upload Multiple Images with <MediaUpload>
Now so long ago I published a tutorial about creating a custom image control component for plugin sidebars. The very first question in the comments was “How to select multiple files”?
So let’s dive into it now.
First things first let me show you what we are going to create here.

This feature is also a part of my plugin and once the plugin is installed on your website, you can easily create a gallery in Gutenberg sidebars with a small PHP snippet below.
add_filter( 'simple_register_sidebars', function( $sidebars ) {
$sidebars[] = array(
'id' => 'misha-test',
'post_type' => 'page',
'name' => 'Misha Test',
'icon' => 'format-gallery',
'fields' => array(
array(
'id' => 'my_gallery',
'label' => 'Gallery',
'type' => 'gallery',
)
)
);
return $sidebars;
} );
But now let’s do it without any plugins step by step.
I recommend to begin with registering meta for our custom field. In order to do so we have to use register_meta()
function. I recommend to store an array of image IDs as a meta value, which means that we have to provide the following parameters into the function.
register_meta(
'post',
'misha_gallery',
array(
'type' => 'array',
'single' => true,
'show_in_rest' => array(
'schema' => array(
'type' => 'array',
'items' => array(
'type' => 'integer'
)
)
)
)
)
A little bit more explanation of show_in_rest
and schema
you can find here.
And the component itself:
const { Button, BaseControl } = window.wp.components
const { MediaUpload, MediaUploadCheck } = window.wp.blockEditor
const { useSelect, useDispatch } = window.wp.data
const RudrGalleryControl = ( props ) => {
const { imageIds, images } = useSelect( select => {
const ids = select( 'core/editor' ).getEditedPostAttribute( 'meta' )[ props.metaKey ];
const images = [];
ids.forEach( ( id ) => {
const img = select( 'core' ).getMedia( id )
if( img ) {
images.push( img )
}
} );
return {
imageIds: ids,
images: images,
}
})
const { editPost } = useDispatch( 'core/editor', [ imageIds ] )
return(
<BaseControl label={ props.label }>
<MediaUploadCheck>
<MediaUpload
onSelect={ ( media ) =>
editPost( { meta: { [props.metaKey]: media.map(({ id }) => id ) } } )
}
allowedTypes={ [ 'image' ] }
multiple="add"
value={ imageIds }
render={ ( { open } ) => (
<div>
{ !! images && images.length > 0 &&
images.map( image => <img src={ image.source_url } /> )
}
<Button variant="secondary" onClick={ open }>Add images</Button>
</div>
) }
/>
</MediaUploadCheck>
</BaseControl>
)
}
export default RudrGalleryControl
Some notes:
- You can see
props.metaKey
(lines 9, 32) andprops.label
(line 28), both of them are the properties we pass into<RudrGalleryControl>
at the moment we use it:
<RudrGalleryControl
metaKey="misha_gallery"
label="Gallery"
/>
- The
useSelect
part may seem a little bit complicated, it is because we store only attachment IDs in post meta, but in sidebars we have to display the images themselves. So for each attachment ID we usegetMedia()
function to get the whole image object. Then we are usingsource_url
property of this object on line 40. - And of course a couple words about
multiple
parameter. In the official documentation of<MediaUpload>
at the moment of writing this tutorial, itsmultiple
parameter was documented only as boolean type. If you set it totrue
value, you can select multiple images with SHIFT or CMD/CTRL keys. But you can also set the value of multiple parameter toadd
, which allows you to select multiple images without pressing SHIFT or CMD keys. You can decide for yourself which mode is more convenient to use for you. - The last but not least, take a look at line 32 where we extract specific object key values into a new JavaScript array, just with
media.map(({ id }) => id )
. You canconsole.log( media )
to see what’s inside.

Misha Rudrastyh
Hey guys and welcome to my website. For more than 10 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
Hello Misha – I’m testing out this control, and that’s great. I’ve follow along this fine tutorial, and it seems to work just fine except for the data saving part.
Probably I’ve missed something but after image selection, on post save I get the following message: “Update failed. You don’t have permissions to edit the custom field…”.
I’m pretty sure that this is caused by something else in my testing theme, but maybe you have suggestion.
The console return a 403 (forbidden) error followed by an 400 (bad request) on a POST request to the /wp-includes/js/dist/api-fetch.js , but the url request looks like it’s working fine (meaning is accessible).