Adding Gutenberg / WordPress editor blocks to the front end


People love to play with a little web app on a site. Quizzes, small games, anything to take a break for a minute or two. Wouldn’t it be great to be able to add and edit these in the WordPress editor then reuse the React components on the front end? Yes! The answer is yes. (Unless it’s no for you. That’s ok! I’m not sure why you’d read past this point though.)

So what needs to be done to make this happen? I’ve come up with *one way* to do it which I’ll outline below. It might not be the best way and is almost certainly not the only way but I like it and it’s working for me. In the coming weeks, I’ll make posts about each of the steps.

First off, let me define exactly what it is I want to do which is:

Render a React app into an html element in the content using the block attributes as the app props.

This has two parts:

  1. creating an html element in the front end content with the block attributes in the element’s attributes
  2. rendering the correct React element into that html element and picking up the block attributes for use as props.

1. Create an html element in the front end content

This is the WordPress side of things and will leverage the commented content saved by the block editor which is briefly explained in the WordPress documentation.

Here’s an example of a block in the raw, unfiltered content* with the block name “mjj/component-to-use” and two attributes – “postsToShow” with a value of 4 and “displayPostDate” with a value of true:

MARKUP
<!-- mjj:component-to-use {"postsToShow":4,"displayPostDate":true} /-->

I want to transform it into this when rendered onto the page.

MARKUP
<div 
  class="mjj component-to-use" 
  data-attr='{"postsToShow": 4,  "displayPostDate": true}' 
  data-block="mjj/component-to-use">
</div>

ie a div with the class created from the block name, data-attr set as the stringified JSON attributes object, and data-block as the registered block name.

Once I have that, I can pick up the attributes and block name and use those as props in the app.

2. Render the correct React element into that html element

This bit should be familiar to anyone who has ever written something like

JSX
ReactDOM.render(<App/>, document.getElementById('root'));

(A note here: this post is for people familiar with making React apps, however large or small.)

What I want to do is use, as much as possible, the React components I’m using in my editor blocks to create a React app which I render into a given element.

For the app, I’ll need to build a script for use on the front end with all of the app’s code.

The final front end jsx which handles rendering the apps into the correct elements will look something like this. Please note that there are places here where the code could be a bit more sleek. I am ignoring those in favour of clarity for now and because I tend to do that last, after I know the process is set.

JSX
/**
 * The entry point for building the front end.
 * This is working around the file structure already set up for the block editor blocks.
 */

import React from 'react'
import ReactDOM from 'react-dom'

// Each React component needs to be imported.
import ComponentToUse from './blocks/element-to-use/front-end/ComponentToUse.js'

// Get all the html elements with my block "namespace" mjj.
const elementsToRender = document.getElementsByClassName( 'mjj')

// Map the components to the block.
const componentsArray = {
	'mjj/component-to-use': ComponentToUse
}

// Iterate over the html elements. 
// Get the JSON string of the attributes and the block name.
// Use those to render the correct component into the correct element 
// and populate the props.
for ( let element of elementsToRender ) {
	const attrString     = element.getAttribute( 'data-attr' )
	const blockName      = element.getAttribute( 'data-block' )
	const attr           = JSON.parse( attrString )
	const ComponentToUse = componentsArray[ blockName ]
	ReactDOM.render( <ComponentToUse block={attr} />, element )
}

What I need to do

Even though there are two steps, there’s more setup I will need in each individual steps. Here’s the list of things I want to do when it’s all broken down:

  • start from a scaffold
  • make the editor block
  • filter the content on the front end to create the html elements for the built scripts to use
  • update webpack to develop and build the front end block and add the scripts to the front end of the site (these are interrelated)

… over the next while I’ll make all of those posts. I guess stay tuned for more!

Footnotes

*like milk fresh from a cow

Leave a Reply

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

By submitting this comment, you are agreeing to the use of Akismet which helps reduce spam. You can view Akismet’s privacy policy here. Your email, website and name are also stored on this site.