Multiple Image Upload Metabox

I had so many requests about multiple image uploads in comments in this tutorial, so I decided to create a separate tutorial specifically about that.

Our goal is to create something like this:

Multiple image upload metabox
So we can not only select multiple images but even sort or delete them after selection.

Guys, there are actually two ways of creating a meta box like that, the first way is an easy-breezy way, but you have to install my Simple Fields plugin first, the second way – is to do everything manually from scratch. But please do not worry, no matter what method you choose, I am going to cover both of them in this tutorial.

Let’s begin with the simple one. So, in order to create a multiple image upload meta box, you just have to go through these two simple steps:

  1. Install and activate my Simple Fields plugin.
  2. Copy the following code snippet into your current theme functions.php file or to a custom plugin:
add_filter( 'simple_register_metaboxes', 'rudr_multiple_img_upload_metabox' );
function rudr_multiple_img_upload_metabox( $metaboxes ) {

	$metaboxes[] = array(
		'id'	=> 'my_metabox',
		'name'	=> 'Meta Box',
		'post_type' => array( 'page' ),
		'fields' => array(
			array(
				'id' => 'my_field',
				'label' => 'Images',
				'type' => 'gallery'
			),
		)
	);

	return $metaboxes;

}

That’s really it, guys. One more thing – if you need to get images somewhere in your code, you can use get_post_meta() function. Example:

$image_ids = get_post_meta( $post_id, 'my_field', true );
// Array( 4, 178, 778 )

Now let’s continue to the tough way.

The HTML part

<ul class="misha-gallery">
	<?php
		$image_ids = ( $image_ids = get_post_meta( $post_id, 'my_field', true ) ) ? $image_ids : array();
		
		foreach( $image_ids as $i => &$id ) {
			$url = wp_get_attachment_image_url( $id, array( 80, 80 ) );
			if( $url ) {
				?>
					<li data-id="<?php echo $id ?>">
						<span style="background-image:url('<?php echo $url ?>')"></span>
						<a href="#" class="misha-gallery-remove">&times;</a>
					</li>
				<?php
			} else {
				unset( $image_ids[ $i ] );
			}
		}
	?>
</ul>
<input type="hidden" name="my_field" value="<?php echo join( ',', $image_ids ) ?>" />
<a href="#" class="button misha-upload-button">Add Images</a>

The JavaScript part

The JavaScript code consists of three parts:

  1. “Add Images” click event.
  2. Click on remove specific image button “&times;”.
  3. Reordering images with drag and drop.
// click event
$( '.misha-upload-button' ).click( function( event ){ // button click
	// prevent default link click event
	event.preventDefault();
	
	const button = $(this)
	// we are going to use <input type="hidden"> to store image IDs, comma separated
	const hiddenField = button.prev()
	const hiddenFieldValue = hiddenField.val().split( ',' )

	const customUploader = wp.media({
		title: 'Insert images',
		library: {
			type: 'image'
		},
		button: {
			text: 'Use these images'
		},
		multiple: true
	}).on( 'select', function() {

		// get selected images and rearrange the array
		let selectedImages = customUploader.state().get( 'selection' ).map( item => {
			item.toJSON();
			return item;
		} )
		
		selectedImages.map( image => {
			// add every selected image to the <ul> list
			$( '.misha-gallery' ).append( '<li data-id="' + image.id + '"><span style="background-image:url(' + image.attributes.url + ')"></span><a href="#" class="misha-gallery-remove">×</a></li>' );
			// and to hidden field
			hiddenFieldValue.push( image.id )
		} );

		// refresh sortable
		$( '.misha-gallery' ).sortable( 'refresh' );
		// add the IDs to the hidden field value
		hiddenField.val( hiddenFieldValue.join() );
			
	}).open();
});

// remove image event
$( '.misha-gallery-remove' ).click( function( event ){

	event.preventDefault();
	
	const button = $(this)
	const imageId = button.parent().data( 'id' )
	const container = button.parent().parent()
	const hiddenField = container.parent().next()
	const hiddenFieldValue = hiddenField.val().split(",")
	const i = hiddenFieldValue.indexOf( imageId )

	button.parent().remove();

	// remove certain array element
	if( i != -1 ) {
		hiddenFieldValue.splice(i, 1);
	}

	// add the IDs to the hidden field value 
	hiddenField.val( hiddenFieldValue.join() );

	// refresh sortable
	container.sortable( 'refresh' );

});

// reordering the images with drag and drop
$( '.misha-gallery' ).sortable({
	items: 'li',
	cursor: '-webkit-grabbing', // mouse cursor
	scrollSensitivity: 40,
	/*
	You can set your custom CSS styles while this element is dragging
	start:function(event,ui){
		ui.item.css({'background-color':'grey'});
	},
	*/
	stop: function( event, ui ){
		ui.item.removeAttr( 'style' );

		let sort = new Array() // array of image IDs
		const container = $(this) // .misha-gallery

		// each time after dragging we resort our array
		container.find( 'li' ).each( function( index ){
			sort.push( $(this).attr( 'data-id' ) );
		});
		// add the array value to the hidden input field
		container.parent().next().val( sort.join() );
		// console.log(sort);
	}
});

Also don’t forget to enqueue scripts: jquery-ui-core, jquery-ui-widget, jquery-ui-sortable and wp_enqueue_media().

Misha Rudrastyh

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

Follow me on X