How to Replace the RichText Editor with TinyMCE in your Custom WordPress Block

Erika Dike
The Andela Way
Published in
4 min readJul 25, 2019
Photo by Florian Olivo on Unsplash

One feature, I found most exciting with the introduction of the Gutenberg editor to WordPress is the ability to create custom blocks. This feature allows a developer to create blocks that represent reusable sections or components of a site. These components can be distributed in a plugin and made available to a wider audience.

One thing that you might find frustrating is how limited the RichText block is. An instance of the RichText block within your custom block cannot have both paragraph and list type texts. If you wanted to have a paragraph and then an unordered/ordered list following, then you would have to declare two instances of the RichText block like so:

return (
<div>
<RichText
onChange={content => setAttributes({ content1: content })}
value={attributes.content1}
tagName="p"
placeholder="Text"
/>
<RichText
onChange={content => setAttributes({ content2: content })}
value={attributes.content2}
tagName="ul"
placeholder="Text"
/>
</div>

This might be fine for a simple block where it is clear what the order of text would look like but would not be practical where the text could be ordered in any fashion. An approach that might work better is to use the InnerBlocks component so the user can alternatively switch between paragraph or list blocks as he/she populates the page. However, I couldn’t use that approach in my recent project because my block was supposed to have multiple tabs (with identical structure) within it. I couldn’t find a way to manipulate the content of the InnerBlocks for each tab individually.

Asides the difficulty in having multiple text types within a single instance, I found that the format control options were not as rich as TinyMCE’s. Of course, you could add more format controls but I was not willing to bear that cost. So I wondered if it was possible to integrate trusty TinyMCE with a custom Gutenberg block. And surprise surprise, I found a way to integrate TinyMCE in a ReactJS component and then use that component anywhere I expected to receive a block of text.

Here is the code below:

Now, we will quickly go through some interesting methods in the ClassicEditor class, so we get an idea of what is going on.

constructor

Here we initialize the component by calling the initialize, onSetup and focus method.

componentDidMount

First, we override the default settings of the TinyMCE editor manager. Then, we initialize the editor by calling the initialize method.

initialize

The initialize method retrieves the editor from the global wp variable and calls its initialize function. The clientId to be passed as a prop to the ClassicEditor component should be unique. The clientId differentiates the different instances of the editor that are currently running on your page. You could have multiple instances of the ClassicEditor in your custom block. As long, as you have unique client identifiers, they would be treated as separate entities and you won’t have content from one editor instance suddenly appearing in another editor instance.

onSetup

Here, the editor is setup with handlers to handle actions on the editor. The first thing we want to do is to populate the editor with content from props.

Next, we set up the onblur event, which is fired whenever the editor loses focus. The handler retrieves the current location or selection of the cursor and then updates the state with the content of the editor. Note that the update function and its arguments are passed as props to the ClassicEditor component. Finally, we add a handler to return to our saved selection/position when the editor regains focus.

On keydown, we capture certain keyboard events and react based on the keys pressed. This could be different for you but the comments explain what each block is doing.

render

In the render function, we return the markup for our editor. The first div represents where the toolbar will be injected. And the second div is where the actual editor will be injected. We don’t have to worry about how it will be injected. As long as we set it up right, TinyMCE knows to replace the placeholders with the TinyMCE toolbar and editor.

Using the Component

Now that we have created the component. We can reference it in our code. Typically we would use it in the edit function of our block. In the save function, I currently render the component using the RichText block.

registerBlockType('new-block/main', {
title: 'New Block',
attributes: {
content: {
default: ''
},
},
edit({ attributes, setAttributes }) {
return (
<div>
<ClassicEditor
attributes={attributes}
setAttributes={setAttributes}
key={`uniqueClientId1`}
clientId={`uniqueClientId1`}
/>
</div>
);
},
save({ attributes }) {
return (
<div>
<RichText value={attributes.content} />
</div>
)
}
});

If you would like the ClassicEditor component to be re-rendered in certain situations like when the current tab is changed (when you have multiple tabs in a single component), consider including the key prop. This would force the ClassicEditor instance in the previous tab to be unmounted and a new one mounted for the new tab.

While the RichText block is sufficient for simple text blocks, you might find it inadequate for some use cases. TinyMCE is a tried and trusted alternative that offers a much more robust editing experience. Fortunately, we can easily integrate it into our custom blocks. And even in our custom blocks, it works like a charm.

--

--

Erika Dike
The Andela Way

I write software and occasionally publish stuff about some things I found interesting.