While working on a website, you may want to display multiple images. It can be the image gallery, carousel, bulk photos, etc. To build this functionality, you need the option at the backend to upload multiple images. These images will be rendered at the front end. In this tutorial, we’ll build a custom Gutenberg block that will allow you to upload multiple images. The block will also have the option to delete these images.
Getting Started
Between static and dynamic blocks, I always preferred a dynamic block. The static block stores the markup in the database whereas the dynamic block stores only attributes in the database. These attributes can then be used to render the front end using PHP. For our custom block, the attribute will be an array of attachment ids. This array will be available on the front end and you can build anything out of it.
Head over to the wp-content/plugins
directory in the terminal and run the below command.
npx @wordpress/create-block artisansweb-block --variant=dynamic
This command will create the artisansweb-block
folder into the plugins directory. From the terminal, run npm start
command from inside this artisansweb-block
folder. This command should remain active while we developing a block.
Define Attributes for Custom Block
As we are dealing with multiple images, we should define the attribute with the type array. Add below lines in the src/block.json
file.
{
...
"attributes": {
"images": {
"type": "array",
"default": []
}
}
}
Of course, at first, we don’t have any values so the default value is set to empty array [].
MediaUpload Component
MediaUpload is a React component used to open a WordPress media modal. From this modal, you can either upload new images or choose existing ones. This component provides the object of the selected images which helps to set the attributes value.
Before using this component, you first need to import it. Add the below statement to the src/edit.js
file.
import { useBlockProps, MediaUpload, MediaUploadCheck } from '@wordpress/block-editor';
Let’s import a few more components required for different reasons.
import { Button, Spinner, BaseControl } from '@wordpress/components';
Button
– I’ll add 2 buttonsAdd Images
, andRemove Image
using this component.Spinner
– The Spinner component helps to show a loader until the image object is fully loaded from the server.BaseControl
– It adds a label to your custom block.
Next, write a JSX code that allows you to upload multiple images into your block.
export default function Edit({ attributes, setAttributes }) {
return (
<div { ...useBlockProps() }>
<BaseControl label="Artisans Web - Upload Multiple Images">
<MediaUploadCheck>
<MediaUpload
onSelect={ ( media ) =>
setAttributes( { images: media.map(image => image.id) } )
}
multiple={true}
allowedTypes={ ['image'] }
value={ attributes.images }
render={ ( { open } ) => (
<div>
<Button variant="secondary" onClick={ open }>Add images</Button>
</div>
) }
/>
</MediaUploadCheck>
</BaseControl>
</div>
);
}
Head over to the backend and add your block to the editor. You can now upload multiple images and these images will be stored in the database. You can check this entry in the post_content
column of the wp_posts
table.
However, the work is not done yet. The uploaded images should also be displayed in the editor. It can be done via useSelect
hook. This hook helps to retrieve dynamic data from the server.
useSelect Hook
We have stored attachment ids in the database. Using useSelect
hook, we’ll loop through each attachment, fetch its data from the server and build the image object. This object will help to display images in the editor. Let’s import this hook into the block.
import { useSelect } from '@wordpress/data';
The code with useSelect
hook will be as follows.
export default function Edit({ attributes, setAttributes }) {
const { mediaIds, medias } = useSelect( select => {
const medias = [];
attributes.images.forEach( (id) => {
const img = select('core').getMedia(id);
if ( img ) {
medias.push(img)
}
});
return {
mediaIds: attributes.images,
medias: medias
}
}, [attributes.images] )
return (
...
);
}
Once you are ready with your media objects, the next thing is to display images in the editor. To achieve this, we’ll modify the code written for render
props into the MediaUpload
.
<MediaUpload
onSelect={ ( media ) =>
setAttributes( { images: media.map(image => image.id) } )
}
multiple={true}
allowedTypes={ ['image'] }
value={ attributes.images }
render={ ( { open } ) => (
<div>
{ mediaIds.length > 0 && medias.length == 0 && <Spinner /> }
{ !! medias && medias &&
medias.map( image =>
<div className="image-container">
<img src={ image.source_url } />
<Button onClick={ () => setAttributes( { images: attributes.images.filter(function(item){return item !== image.id}) } ) } isLink isDestructive>
Remove image
</Button>
</div>
)
}
<Button variant="secondary" onClick={ open }>Add images</Button>
</div>
) }
/>
Your images should now display on the block. But, it’s not looking nice. It needs some styling.
I wrapped the img
tag and Remove image
button inside the div
having a class image-container
. Let’s add some styling using this container. The below code will go directly into the src/editor.scss
file.
.wp-block-create-block-multiple-images {
display: flex;
flex-wrap: wrap;
justify-content: center;
// Adjust the margin and width as per your requirement
margin: 20px;
.image-container {
position: relative;
margin: 10px;
float: left;
img {
display: block;
width: 200px; // Adjust the image width as per your requirement
height: auto;
}
button {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
margin-top: 10px;
}
}
}
Feel free to adjust this styling as per your convenience. After this, your block will look like as screenshot below.
Bravo! You’ve successfully completed the back-end work of your custom block. Let’s move to the front end.
Render Front End
When you add the images to our block, it stores the attachment ids in the database as follows.
<!-- wp:create-block/multiple-images {"images":[43,38,39,28]} /-->
These values are available to the $attributes
variable in your src/render.php
file. This file is responsible for printing your block content on the front end.
To print the images using the block attributes(images in our case), I’ll write the code as follows.
<div <?php echo get_block_wrapper_attributes(); ?>>
<?php
foreach( $attributes['images'] as $image ) :
echo wp_get_attachment_image($image, 'medium');
endforeach;
?>
</div>
Here, I am just displaying images with medium sizes using the wp_get_attachment_image() function. It renders an HTML img element for the given attachment id.
Now it’s up to you how to render these images on your website. You can wrap them inside the carousel, columns, etc. Take a note to add styling on the front end, you require to add CSS into the src/style.scss
file.
That’s it! I hope you understand building a custom block to upload multiple images. If you want to add content along with these images then check out my article on using RichText and MediaUpload components.
If you liked this article, then please subscribe to our YouTube Channel for video tutorials.