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.

Bluesky
Threads
Twitter / X
Mastodon
Instagram

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.

Thanks…

I also dissect and speculate on design and development.
Digging into subtle details and implications, and exploring broad perspectives and potential paradigm shifts.
Check out my conceptual articles on Substack or find my latest below.


You can also find me on Threads, Bluesky, Mastodon, or X for more diverse posts about ongoing projects.

My latest articles

Focal point blocking for XR media

Planning out a linear VR experience requires thinking about where the viewers attention might be. Thinking about the focal points…

Designing immersive experiences

In traditional cinema, TV, or even the more modern phone screen, there’s limited screen real-estate. But removing that limitation creates a design problem…

The future is not prompt engineered

Let’s not pretend the importance of prompt engineering is ubiquitous. The most prevalent power of generative AI is in the way it adapts to us, not the other way around…

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.