Creating a Reusable Media Picker in Wordpress

September 1, 2024
When developing with WordPress Gutenberg Blocks, you'll eventually run into a scenario when you will need to upload media to the site from your custom block. The following is a little snippet that I've used through development to give the user to upload media, and then render out that image.

The implementation is fairly straightforward and can easily be extended. This makes use of React components.

At a glance, here is the registerBlockType implementation. We will be storing the media as a URL string

index.js
import { registerBlockType } from '@wordpress/blocks';
import Edit from './edit';

registerBlockType( 'my-custom-block', {
	title: 'My Custom Block',
	icon: 'slides',
	category: 'common',
	attributes: {
		'imageUrl': {
			type:'string'
		}
	},

	edit: Edit,

	save: function() {
		return null;
	}
});

Next, we use the built in Wordpress block editor components MediaUpload and MediaUploadCheck

MediaUploadCheck ensures appropriate permissions are applied to users when they begin uploading.

The actual ImageUploader component will take in three items as props, the URL, the update function, and whatever label we want to assign this section.

Then it's just a matter of checking to see if there is an image URL. If there is, we render out the image and give the option to remove the image. If remove, we simply update the Attributes.imageUrl to be null.

imageUpload.js
import { Button } from '@wordpress/components';
import { MediaUpload, MediaUploadCheck } from '@wordpress/block-editor';

const ImageUploader = ({imageUrl, updateImage, label = 'Image'}) => {
	const removeImage = () => {
		updateImage(null);
	}

	return (
		<div className='image-uploader'>
			<div>
				{label}
			</div>
			<div className='image-uploader-main'>
				{imageUrl == null ? (
					<MediaUploadCheck>
						<MediaUpload
							onSelect={ ( media ) => {
								updateImage(media.url)
							}}
							render={ ( { open } ) => (
								<Button variant='link' onClick={ open }>Open Media Library</Button>
							)}
						/>
					</MediaUploadCheck>
				) : (
					<>
						<div className='image-uploader-wrapper'>
							<img src={imageUrl} />
						</div>
						<Button variant='link' onClick={removeImage}>Remove Image</Button>
					</>
				)}
			</div>
		</div>
	)
}

export default ImageUploader;

And lastly, we can call this component by doing the following...

<ImageUploader imageUrl={attributes.imageUrl} label='Event Card Image' updateImage={(url) => setAttributes({...attributes, imageUrl: url})}/>