Multiple RichText components cause issues in WordPress

While building Gutenberg Block plugins for WordPress I’ve run into a problem with the inbuilt RichText component where the blocks don’t validate when reloaded. It’s caused by using RichText in multiple places within the block while sticking to the format of WordPress’ example code.

Digging deeper I found that the block’s save function would write the data out correctly, but when I reloaded the page in the editor, it seemed to no longer know the right data and confuse the two fields.

This article will look at the cause of that and the fairly straightforward fix.

The problem

Most tutorials I found, as well as the RichText documentation (At the time of writing), present you with example attribute definition for RichText that looks like this.

// Attributes definition
cardBackContent: {
   type: 'string',
   source: 'html',
   selector: 'p',
},

Which would be used in an edit and save function like this.

// Edit JSX
<RichText
   tagName = "p"
   value = {attributes.cardBackContent}
   onChange = { (value) => setAttributes({cardBackContent: value}) }
   placeholder = "Enter text..."
/>

// Save JSX
<RichText
   tagName = "p"
   value = {attributes.cardBackContent}
 />

If you happen to be making a block that needs two RichText components in it. You will end up with something like below—And this is where the code stops working.

You’ll find that your block seems to work fine while editing and viewing on the front end, but as soon as you open the file again in the editor, it doesn’t validate and appears broken (see console screenshot below).

This is roughly what your code might look like for reference.

// Attributes definition
cardBackContent: {
   type: 'string',
   source: 'html',
   selector: 'p',
},

cardFrontContent: {
   type: 'string',
   source: 'html',
   selector: 'p',
},

// Edit JSX
<div class="card-back">
   <RichText
      tagName = "p"
      value = {attributes.cardBackContent}
      onChange = { (value) => setAttributes({cardBackContent: value}) }
      placeholder = "Enter text..."
   />
</div>
<div class="card-front">
   <RichText
      tagName = "p"
      value = {attributes.cardFrontContent}
      onChange = { (value) => setAttributes({cardFrontContent: value}) }
      placeholder = "Enter text..."
   />
</div>

// Save JSX
<div class="card-back">
   <RichText
      tagName = "p"
      value = {attributes.cardBackContent}
   />
</div>
<div class="card-front">
   <RichText
      tagName = "p"
      value = {attributes.cardFrontContent}
   />
</div>

This is an example error seen on opening the file again in the editor.

The error shown above from the console describes that the content produced by the save function (when reloading the page in the editor), doesn’t match what was saved last time the file was edited.

This is a validation check by WordPress to prevent the user interacting with blocks that have broken during an upgrade or something else.

The cause

What causes this are those lines in our attributes definition: “source: html” and “selector: p”. These two lines tell WordPress how to save and retrieve the data.

Specifically, those tell WordPress the source of the data will be the HTML that’s output. So upon reload, WordPress should select the p tag and grab the content straight out of it.

The problem with this, is there are two p tags. This doesn’t create an issue when WordPress is writing the data, but when the file is opened again in the editor, each RichText component looks for a p tag and takes the first one it finds. This is why you might have noticed in your file that both fields show the same content.

The solution

To solve this, there are two solutions.

Solution 1

Remove the lines source: html and selector: p from the attributes definition.

These lines are an optional way to tell WordPress that you will manage how it saves data. But you don’t have to. If you remove those lines WordPress will save the data as comments in the block’s code and will  handle multiple RichText components properly on it’s own.

Solution 2

If you  want to manage the data yourself, you need to make sure that the selector value you define in the attributes file is guaranteed to be unique.

Ordinarily, you might think about using an id name on the paragraph block here, however, remember this is a block’s definition. The user might choose to add multiple of these blocks and then you’ll end up with multiple, identical id’s on the page—Which will create other issues (as id’s must be unique to a page).

Instead, use a class name.

// Attributes
cardFrontContent: {
    type: 'string',
    source: 'html',
    selector: '.front-content',
    default: defaultAttributes.frontContent
},

// Edit.jsx
<RichText
    tagName = "p"
     class = "front-content"
    value = {attributes.cardFrontContent}
    onChange = { (value) => setAttributes({cardFrontContent: value}) }
    placeholder = "Enter text..."
/>

Save.jsx
<RichText
    tagName = "p"
    class = "front-content"
    value = {attributes.cardFrontContent}
/>

Note that the RichText components only search within the content of the block their in, so the selector doesn’t need to be unique to the whole page, just the block.

That’s it!

Remember, there were two options above. The easier one only involves deleting a couple of lines, and unless you have a reason to work the second way, you can just do that.

Why would you go for the more complicated option when WordPress can manage it for you?

If you’re really worried about download size of each pages html, it might be advantageous to specify source: html, to minimise the extra comments WordPress needs to add in. However, as an optimisation, that’s something you can always improve later if you still find it necessary.

Keep things simple unless you really need to.

I’d love to know if any of these articles helped you.
Share what you’re building or ask me a question on Threads or somewhere else.

Instagram is a great place to see my final creative coding experiments, while the others are are great place to connect or see progress updates.

If my content has helped you, I’d never say no to donations to help me keep writing.

Here are some other things you might like


Author:

Date:

Comments

2 responses to “Multiple RichText components cause issues in WordPress”

  1. Matt Jennings Avatar

    Thank you, Dale! I’m working on a custom WordPress block plugin right now, and as of October 2023, this problem still exists.

    Your solution fixed the problem of JavaScript console errors appearing (and my block getting messed up) when adding multiple `RichText` blocks.

    1. Dale de Silva Avatar

      Thanks for dropping a comment Matt. Really glad it got you unstuck :)

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.