WordPress Block Development – Use of RichText and MediaUpload Component

For WordPress developers, it’s essential to learn custom block development. I also started to learn it and decided to share my learning as I progressed with developing blocks. The custom blocks are built on top of components. Though WordPress provides a lot of components we first start with 2 components – RichText and MediaUpload.

Basically, in this tutorial, we are going to create a custom block to generate the following section for the website.

image-text-layout

As you can see, there are 3 elements – heading, paragraph, and image are required to build this section. Here is the HTML markup for this section.

<div class="container">
	<div class="left">
    	<h2>My Section Title</h2>
    	<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
	</div>
	<div class="right">
    	<img src="images/1.jpg" width="600" />
	</div>
</div>

And the CSS of this HTML is as follows.

.container {
	display: flex;
}

.left, .right {
	flex-grow: 1;
}

.left {
	background-color: #f2f2f2;
	padding: 20px;
}

.right {
	background-color: #e6e6e6;
}

Take note markup and styling can differ in your case. My main focus is to show you how to build a WordPress block out of this HTML. So let’s begin with it.

If you want multiple images inside your block then check out my article – Upload Multiple Images Using MediaUpload Component.

Creating Dynamic Block

In WordPress, you can build 2 types of blocks – static and dynamic. The static block stores the HTML markup in the database. The dynamic block allows you to dynamically render markup using PHP on the front end. Using dynamic block, it just stores attributes to the database instead of a whole markup. I prefer to build a dynamic block as it gives full control to render the front end.

Having said that, let’s navigate to the wp-content/plugins directory and run the below command to scaffold a dynamic block. You should have installed NodeJs on your system to run this command.

npx @wordpress/create-block artisansweb-block --variant=dynamic

It might take a couple of minutes to install this package. Upon completion, you’ll see a folder artisansweb-block inside the plugins directory. There are a couple of files to consider inside this block directory.

  • src/block.json – In this file, you’ll define attributes to store the content of your block.
  • src/edit.js – This file is responsible for allowing you to add your content to the Gutenberg.
  • src/render.php – Generate the frontend markup using PHP.
  • src/editor.scss – As the extension suggests, you have to write styling using scss which gets applied on your block in the Gutenberg.
  • src/style.scss – The styling written to this file will be applied on the front end.

Go to your plugin’s page and activate this newly created plugin. Then, head over to this plugin directory inside the terminal and run the npm start command. This command watches for the file changes inside the src folder and compiles the final code using webpack inside the build directory.

Adding Attributes to the block.json

For our section, we have to store 3 attributes in the database. I’ll name them as heading, message, and image. Inside your block.json add these attributes as shown below.

{
	...
	"attributes": {
    	"heading": {
        	"type": "string"
    	},
    	"message": {
        	"type": "string"
    	},
    	"image": {
        	"type": "integer"
    	}
	}
}

While passing attributes, you must pass the type value as per the content. Here, I passed the ‘string’ type for the heading and message. For the image attribute, I passed the ‘integer’ type. This is because I’m going to store the attachment id of the uploaded image.

RichText Component

To add the heading and paragraph, you can use the RichText component. This component allows you to format the content using HTML markup.

In order to use this component, you need to import it into your src/edit.js file.

import { useBlockProps, RichText } from '@wordpress/block-editor';

After this, use the RichText component to enter the heading and message as follows.

export default function Edit({ attributes, setAttributes }) {
    return (
   	 <div { ...useBlockProps() }>
   		 <div className="container">
   			 <div className="left">
   				 <RichText
   					 tagName="h2"
   					 value={ attributes.heading }
   					 allowedFormats={ [] }
   					 onChange={ ( heading ) => setAttributes( { heading } ) }
   					 placeholder="Enter heading here.."
   				 />
   				 <RichText
   					 tagName="p"
   					 value={ attributes.message }
   					 allowedFormats={ [] }
   					 onChange={ ( message ) => setAttributes( { message } ) }
   					 placeholder="Enter message here.."
   				 />
   			 </div>
   			 <div className="right">
   				 {/* image upload here */}
   			 </div>
   		 </div>
   	 </div>
    );
}

To the Edit function, I’ve passed 2 arguments – attributes and setAttributes. They are used to set values for the attributes defined in the block.json.

We can pass html elements as per our markup to the RichText component. I’ve used h2 and p tags respectively. With the onChange event, the values you typed are set to the attributes.

Head over to the editor, search for Artisansweb Block, add it to the editor and you’ll see options to add your heading and paragraph.

MediaUpload Component

Along with the heading and paragraph, our section also requires the image. WordPress provides a MediaUpload component to open the media modal where you can insert a new image or select the existing image. You should import this component before use.

import { useBlockProps, RichText, MediaUpload, MediaUploadCheck } from '@wordpress/block-editor';

I am going to import a few more components to make the image upload work.

  • Button: It adds a button. In our case, it’ll be the Upload Image button.
  • Spinner: It’s a loader that will appear until the image object loads.
  • useSelect: This hook is used to retrieve dynamic data from the server. As we’re storing the attachment id in the database, it needs to get an image object from the server using this attachment id.
import { Button, Spinner } from '@wordpress/components';
import { useSelect } from '@wordpress/data';

In the below code, I’m fetching the image object with the help of the useSelect hook. Of course, it’ll be empty the first time.

export default function Edit({ attributes, setAttributes }) {
    const { mediaId, media } = useSelect( select => {
   	 return {
   		 mediaId: attributes.image,
   		 media: select('core').getMedia(attributes.image)
   	 }
    }, [attributes.image] )
    ....
}

Next, let’s add the MediaUpload component in our custom block so the user selects the image which will appear in the editor. Optionally, users can also remove or replace the image.

<div className="right">
    <MediaUploadCheck>
   	 <MediaUpload
   		 onSelect={ ( media ) =>
   			 setAttributes( { image: media.id } )
   		 }
   		 allowedTypes={ ['image'] }
   		 value={ attributes.image }
   		 render={ ( { open } ) => (
   			 <div>
   				 { ! mediaId && <Button variant="secondary" onClick={ open }>Upload Image</Button> }
   				 { !! mediaId && ! media && <Spinner /> }
   				 { !! media && media &&
   					 <Button variant="link" onClick={ open }>
   						 <img src={ media.source_url } />
   					 </Button>
   				 }
   			 </div>
   		 ) }
   	 />
    </MediaUploadCheck>
    { !! mediaId && media &&
   	 <Button onClick={ () => setAttributes( { image: 0 } ) } isLink isDestructive>
   		 Remove image
   	 </Button>
    }
</div>

There are a couple of conditions used inside the render props. You should be familiar with these conditions. With the help of these conditions, I added a Button, Spinner, and img tag.

  • ! mediaId – It checks whether the media is set or not.
  • !! mediaId && ! media – This means the media is set but not loaded yet. It takes a few moments to load as it’s coming from a server.
  • !! media && media – It indicates the media is set and its object is also available.
  • !! mediaId – The media is set.

On clicking the Remove image button, I’m setting the image attribute’s value to 0 which means no media is selected.

Let’s add some styling to our custom block. Add the below code to the src/editor.scss file.

.wp-block-create-block-artisansweb-block {
    .container {
   	 display: flex;
    }

    .left, .right {
   	 flex-grow: 1;
    }

    .left {
   	 background-color: #f2f2f2;
   	 padding: 20px;
    }

    .right {
   	 background-color: #e6e6e6;
    }
}

I’ve used the parent class wp-block-create-block-artisansweb-block in the above CSS. This auto-generated class is added to the parent div because of the following statement.

<div { ...useBlockProps() }>

Now you can try to add the content in this block. It should work now. Keep your Browser Console open to see the errors if any.

If you are curious about how WordPress stores your block data, go to your database and check out the post_content column from the wp_posts table. The data will be stored in something like the below format.

<!-- wp:create-block/artisansweb-block {"heading":"My Section Title","message":"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.","image":28} /-->

Here artisansweb-block is the name given inside the block.json.

Render the Block on Front End

You’ve successfully completed the back-end part and you have content stored in your database. The next thing is to display this data on the front end. For this, open the src/render.php file and use the code below for it.

<div <?php echo get_block_wrapper_attributes(); ?>>
    <div class="wp-block-create-block-artisansweb-block_content">
   	 <div class="left">
   		 <h2><?php echo $attributes['heading']; ?></h2>
   		 <p><?php echo $attributes['message']; ?></p>
   	 </div>
   	 <div class="right">
   		 <?php echo wp_get_attachment_image($attributes['image'], 'medium'); ?>
   	 </div>
    </div>
</div>

Any attributes saved in the database are available to the $attributes variable inside the render.php file.

Add the styling for this section into the src/style.scss file.

.wp-block-create-block-artisansweb-block_content {
    display: flex;

    .left, .right {
   	 flex: 1;
    }

    .left {
   	 background-color: #f2f2f2;
   	 padding: 20px;
    }

    .right {
   	 background-color: #e6e6e6;
   	 position: relative;
    }

    .right img {
   	 position: absolute;
   	 top: 50%;
   	 left: 50%;
   	 transform: translate(-50%, -50%);
    }
}

Feel free to change styling as per your needs. I’m just adding a basic styling for the tutorial purpose.

That’s it! I hope you understand the basic workflow of custom block development in WordPress. I’ll keep posting new tutorials on block development regularly so stay tuned and let me know your thoughts in the comment section below.

If you liked this article, then please subscribe to our YouTube Channel for video tutorials.

Leave a Reply

Your email address will not be published. Required fields are marked *