Image Control Component for Gutenberg Sidebars

I have a super-detailed tutorial about plugin sidebars on my blog. But there were described only some basic field types like TextControl, TextareaControl and ToggleControl.

What about something much more interesting? I mean when there were no Gutenberg years ago, I already created an image uploader field for WordPress meta boxes or options pages. What about creating a custom ImageControl component for Gutenberg sidebars right now?

Image control in Gutenberg plugin sidebars

This is a JSX tutorial guys, but I always try to provide you a PHP option when it is possible and doesn’t make the code ugly.

Well, where to start. Let’s create a component first. I called it RudrImageControl to prevent possible conflicts in case one day WordPress will use ImageControl name.

const RudrImageControl = ( props ) => {
	
	
}

export default RudrImageControl

Let’s begin with some metadata work. We actually have to do three things:

  1. Get an image ID (I am going to store an attachment ID as a meta value in database, and yes, do not forget to register meta with an integer type).
  2. Get a URL of that image.
  3. Update the ID once the image has been set or replaced.

In order to get an image ID and URL we are going to use useSelect hook, in order to update the meta data – useDispatch hook. I know that when we do our work with fields in this tutorial, we used withSelect and withDispatch. Hooks useSelect and useDispatch are a little bit more fresh, but you can use whatever fits you the best, because withSelect and withDispatch aren’t going to be deprecated at this moment.

const { useSelect, useDispatch } = window.wp.data;

const RudrImageControl = ( props ) => {
	// get meta data
	const { imageId, image } = useSelect( select => {

		const id = select( 'core/editor' ).getEditedPostAttribute( 'meta' )[ props.metaKey ];

		return {
			imageId: id,
			image: select( 'core' ).getMedia( id ),
		};
	});
	// update meta data
	const { editPost } = useDispatch( 'core/editor', [ imageId ] );
	
}

export default RudrImageControl

At this moment we have available imageId (image ID), image (image object) and editPost() function that allows to update metadata. You might say, why we use a separate constants for image ID and image object? It is because the image object is not available from the very beginning and getMedia() returns undefined.

Our next step is to create a field. The key moment to understand here is that a field – is an abstraction when we are working with plugin sidebars. So you don’t have to create a hidden field like we did it here for example. We are going to use BaseControl just to display the field label and HTML markup but it is also not necessary. MediaUploadCheck and MediaUpload are just for media uploader but these components are not a form field either. We just get and update props, that is all.

Let’s start with importing everything I’ve just mentioned.

const { useSelect, useDispatch } = window.wp.data
const { 
	BaseControl,
	Button, 
	Spinner
} = window.wp.components
const { MediaUpload, MediaUploadCheck } = window.wp.blockEditor

const RudrImageControl = ( props ) => {

Finally, the uploader field (sorry for separating the code into parts like this. Anyway you can get the whole and complete component from GitHub or you can use PHP example).

<BaseControl label={ props.label }>
	<MediaUploadCheck>
		<MediaUpload
			onSelect={ ( media ) => editPost( { meta: { [props.metaKey]: media.id } } ) }
			allowedTypes={ [ 'image' ] }
			value={ imageId }
			render={ ( { open } ) => (
				<div>
					{ ! imageId && <Button variant="secondary" onClick={ open }>Upload image</Button> }
					{ !! imageId && ! image && <Spinner /> }
					{ !! image && image &&
						<Button variant="link" onClick={ open }>
							<img src={ image.source_url } />
						</Button>
					}
				</div>
			) }
		/>
	</MediaUploadCheck>
	{ !! imageId &&
		<Button onClick={ () => editPost( { meta: { [props.metaKey]: 0 } } ) } isLink isDestructive>
			Remove image
		</Button>
	}
</BaseControl>

The first thing I would like to highlight in the code above is what conditions I used.

Everything else you can easily find in official Gutenberg component documentation.

And finally, you can use this custom image control component in plugin sidebars:

<RudrImageControl 
	metaKey={ field.id } 
	label={ field.label } 
/>

PHP Example

In case JSX code seems overwhelming, you can still use a PHP way. Just two steps:

  1. Install and activate my Simple Fields plugin on your website.
  2. Copy and paste the following code into your current theme functions.php file or to a custom plugin:
add_filter( 'simple_register_sidebars', 'misha_gutenberg_sidebars' );

function misha_gutenberg_sidebars( $sidebars ) {

	$sidebars[] = array(
		'id' => 'misha-test',
		'post_type' => 'page',
		'name' => 'Misha Test',
		'icon' => 'palmtree',
		'fields' => array(
			array(
				'id' => 'mishapicturefield',
				'type' => 'image',
				'label' => 'Image',
			),
		)
	);
	return $sidebars;
}

Enjoy.

Image control in Gutenberg plugin sidebars
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