Headless WordPress Gutenberg & Next.js — Part 1/3: Creating a Block with React

The WordPress ecosystem is surely going towards JavaScript and non-PHP ways to develop plugins, themes and the core itself. Thanks to Gutenberg and WordPress JavaScript API, we can create some cool stuff. One of those would be a production-ready, WordPress static site builder that we’re going to code in this series.

Michal Trykoszko
Geek Culture

--

Before we start

If you don’t know Gutenberg, React or WordPress on some solid level, this article might be too difficult for you. To familiarize myself with Gutenberg development, go ahead and read some articles from the official documentation. It’ll help you understand its purposes and used tech.

Intro

I always look for the best solutions and ways to code. Some can call me lazy, but I don’t like repeating myself in terms of anything, also the code. That’s why I spent some time on research and developed a way of building SSG-generated pages with WordPress as headless backend and Gutenberg as the page editor itself. All with one component structure source.

But how does it differ of all the other articles or tutorials on the internet?

My implementation is custom from the beggining to the end, which means we don’t use the predefined WP blocks (although we can!). We build our own blocks and can use it in three environments at once:

  • admin-side WordPress (post edit screen) — as a fully functional Gutenberg block, with custom data fields, JS events, live editing etc
  • client-side WordPress (front-end) — as a static HTML with optional styles and scripts
  • Next.js (or Gatsby or Nuxt or other SSG/SSR framework) — as a fully functional React component and then a static HTML+CSS+JS

Here’s a quick interview of what we’re going to do:

A video about Gutenberg to Next.js connection

Note that styles or the functionality on the video can differ from the one in the repository of the project as they could be updated.

As you can see in the video, the whole thing is about:

  1. creating a React component which will become our block
  2. getting use of React component we created above inside WordPress, as a Gutenberg Block using only JavaScript and React (we can also use many @wordpress/* packages such as @wordpress/blocks , @wordpress/i18n)
  3. adding some basic styling and making the block interactive with extra JavaScript
  4. creating a communication layer between WordPress and external apps (REST API or GraphQL)
  5. building a SSG-generated website with Next.js or Gatsby, using previously built blocks and a communication layer with (headless) WordPress

WordPress development environment

To kick off with our project, we’ll need to have a working WordPress instance. Personally, for such small projects, I use Docker and a basic docker-compose.yml config file from the Docker docs. It’s very easy to use.

docker-compose.yml (placed inside project root folder)

Please note that I’ve added a few lines inside the default file:

  • lines 9–10: this will map our ports and allow us to connect to MySQL (with TablePlus or Sequel Pro) from outside the Docker container — it’ll be accessible on port 33061 defined in line 10
  • lines 29–31: this will map our WordPress files outside the container and allow us to edit files locally, without getting “inside” the Docker container. it’s in a subfolder so it’s possible to add it to .gitignore later

You can now open terminal and type docker-compose up -d --remove-orphans. This will run our Docker containers and “start up” our new WordPress Instance. The flags -d and --remove-orphans are described in Docker docs.

It should output green “done” flags twice — one for database and one for WordPress container

Now open your browser and type http://localhost:8000 . Why :8000? Because we’ve defined this port earlier in docker-compose, in line 22.

You should now see the default WordPress’ config screen. Go ahead and configure the site.

WordPress new instance config screen

The PHP part

As I said before, we’ll need to write PHP. But don’t worry — it’s only a few lines inside one file. And also it can be done once per whole project. What will we need to code in PHP?

  • the plugin core (home of our blocks)
  • use some WP filters or hooks (but this can be also done with JavaScript @wordpress/hooks)
  • enqueue block’s assets

First off, let’s create the plugin. In order to do this, create a folder inside ./wp/wp-content/plugins. I’ll name it fancy-block. Inside this folder, I’ll create the main plugin file: index.php.

Basic structure of a plugin

Next, we’ll need to write some PHP code. We’ll need to:

  1. add a <?php declaration (so the server understands) — line 1
  2. add a comment with plugin information in plugin’s header (for WordPress) — lines 2–8— as always in WP plugin or theme
  3. prevent from accessing the plugin outside of WordPress’ scope — line 10
  4. get our generated assets — line 14 (more info below)
  5. register the assets from pt 4 with wp_register_script — lines 15–20
  6. register our Gutenberg block with register_block_type — lines 21–24
  7. hook to init — line 26
All the PHP code we need for now

Good job! 👏

BTW. Don’t enable your plugin yet! It’ll probably crash your WP install.

React Components

React Components

First we’ll need to create the React component and any functionalities we’ll need in our future Gutenberg block, like events, API fetches, state or mocks, and all the other stuff.

React Component Generation

There are plenty of ways of starting a React project such as project boilerplates, frameworks etc. We could also create components straight inside our Next.js app. But that could be problematic to use with Gutenberg. I’ll use the well-known CRA in this project. We’ll use it to build our components, which we will then use as a base for our Gutenberg Block.

Why CRA? 😠

Must I say that it’s the least time-consuming way?

Starting point

To start, go ahead to the plugin’s root directory and create a sub-folder for our components. Let’s just create it along with CRA:

npx create-react-app components

Next, we’ll need to just create our React component. I won’t cover this part in my article as it would take too long. You can find many resources for React online. Here are some tips though.

RFC or RCC

You can create functional or class components for Gutenberg. Both will work and…

  • …YES! You will be able to use React Hooks such as useEffect() inside functional components and…
  • …YES! You will be able to use lifecycle methods such as componentDidMount() inside class components

…and use all of them inside Gutenberg, on the WP front-end and in Next.js.

State

To manage state of your component, you can use any kind of React state management such as Redux, React Context or any other way, just as you’re creating a standalone React app. You can also mock your API, just like I did.

More on React state and lifecycle here.

Example component

I made a component which shows user’s data in a small box. In addition, there’s a modal/accordion which opens and closes on button click.

An example of React Functional Component (UserCardWrapper) I made for this article
An example of component (UserCard) which will be imported to parent

Note the usage of and React Hooks (e.g. useState()) only in the parent component. I’ll explain later why it’s only in the top level component.

And that’s how the component looks like:

The component itself (isModalOpen = false) (please don’t dislike me for taste! 😂)
The component itself (isModalOpen = true)

That will be enough of pure React for now. Let’s mix it with WordPress!

registerBlockType: "WordPressify" React component

This is the part where we’ll be combining JavaScript and WordPress.

As you probably know, JavaScript’s ecosystem allows us to use NPM for managing packages, just like Composer in PHP. @wordpress/* mentioned above are of course available there. And we’re going to use it.

Start off with creating a package.json file inside root of your plugin (next to index.php). To do it, open terminal, go to plugin root, type npm init and go through all the steps to configure the package.

Then, install @wordpress/scripts by typing npm install @wordpress/scripts --save-dev. As you can surely know, React needs compilation in order to run in the browser. That’s why we’ll need to import the official WordPressscripts package. Then, to make use of it, add two scripts to package.json:

  1. buildwp-scripts build ./src/index.js
  2. startwp-scripts start ./src/index.js

Now your package.json should look like this:

package.json with @wordpress/blocks and scripts

In order to run the scripts, let’s create the ./src/index.js file which we’ve linked inside package.json before:

./src/index.js

As you can see, I already installed, imported and used registerBlockType function from @wordpress/blocks and provided some data, like title, icon, category and empty attributes object to it. I also imported React as it’s mandatory to use JSX.

Here’s the above example in use:

You can already add your block to any of your posts
Here’s the live example of block we created

The two nice functions — edit() and save()

According to official WordPress documentation, there are two handy functions we can use inside our registerBlockType().

One of them is edit() , which will be used when rendering the block inside wp-admin post edit screen.

The other one is save(). It will be used when saving the block as static HTML into the database (because all blocks are being saved to database as a static HTML!).

Remember that passing the same component to both is possible, but it doesn’t make much sense in my opinion. Usually theedit() is much more complex than save(), as we can use InspectorControls and other good stuff from WordPress here. We also manage our sidebar “metaboxes” in edit().

Note: more complex functionalities like CSS-in-JS or React hooks don’t work in save() unfortunately. That’s why I’ve splitted the component into child and parent in the first place.

Let’s make use of our React component we’ve created before.

Our React Component inside Gutenberg

What I added here is:

  • I’ve passed our React component to render inside Gutenberg now
  • I’ve assigned some default attributes to block (just like I mocked the API inside component before)
  • I’ve added some wrapping <divs> inside both edit() and save() — to use React Hooks in edit()

This is how our block looks like inside Gutenberg:

WordPress Gutenberg block made from React Functional Component

And that’s how it looks on the front-end:

React-built Gutenberg block

Try it out and play with it!

Of course styles differ and JavaScript doesn’t work. Those problems will be covered in next episodes.

Summary

If you feel like missing or stuck somewhere, I also made a demo block, here: https://github.com/trykoszko/gutenberg-block-hydration-example. You can use it or contribute if you want.

I also published a video on Gutenberg Block Hydration about a year ago:

Make your React Gutenberg block interactive

BTW! I have one tip for you regarding the WordPress JavaScript API. Go to Post edit screen, open console and type wp. You’ll see many of cool things!

wp object inside WordPress post edit screen

That’s all for today. In the next parts of this article we’ll cover more advanced and in-depth topics, like Gutenberg Block Hydration and Headless WordPress Gutenberg + Next.js. They’ll come out soon.

Feel free to let me know any of your thoughts! Is this the future of WordPress? What’s your opinion?

--

--

Michal Trykoszko
Geek Culture

PHP and JavaScript Full-stack Developer specialized in WordPress