LWC WP Plugin Development: Blocks, Gutenberg & React


Updated Oct 13th, 2021

Gutenberg Block Types with React. Learn the methodology behind custom block types here and in the next section we create a “Quick Question” and a “Professor Callout” custom block type.

Table of Contents

Chapter Details

Introduction to JavaScript Plugin Development

WP ships with basic block types but we can create our own and share with the world as a plugin. Create a new empty plugin folder, “are-you-paying-attention” and open in the text editor.

Test alert

Create and “index.php” file generic plugin attributes and “exit if accessed directly” code.

Add a “AreYouPayingAttention” class.


  Plugin Name: Are You Paying Attention Quiz
  Description: Give your readers a multiple choice question.
  Version: 1.0
  Author: Brad
  Author URI: https://www.udemy.com/user/bradschiff/

if( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

class AreYouPayingAttention {
  function __construct() {
    add_action('init', array($this, 'adminAssets'));

  function adminAssets() {
    wp_register_style('quizeditcss', plugin_dir_url(__FILE__) . 'build/index.css');
    wp_register_script('ournewblocktype', plugin_dir_url(__FILE__) . 'build/index.js', array('wp-blocks', 'wp-element', 'wp-editor'));
    register_block_type('ourplugin/are-you-paying-attention', array(
      'editor_script' => 'ournewblocktype',
      'editor_style' => 'quizeditcss',
      'render_callback' => array($this, 'theHTML')

  function theHTML($attributes) {
    if (!is_admin()) {
      wp_enqueue_script('attentionFrontend', plugin_dir_url(__FILE__) . 'build/frontend.js', array('wp-element'));
      wp_enqueue_style('attentionFrontendStyles', plugin_dir_url(__FILE__) . 'build/frontend.css');

    ob_start(); ?>
    <div class="paying-attention-update-me"><pre style="display: none;"><?php echo wp_json_encode($attributes) ?></pre></div>
    <?php return ob_get_clean();

$areYouPayingAttention = new AreYouPayingAttention();

Activate new plugin in WP admin. Make sure editing screen is loading. In the “test.js” file the function below and begin building out.

wp.blocks.registerBlockType(a, b)

Inside we see another WP function

return wp.element.createElement(a, b, c)

Best practice to describe what our plugin needs in the “index.php” file.

On the front-end WP is not loading JS, it converts to text and stores in the database when the post or page is saved. Later we will see how to add JS on the front-end.

Put JSX in “createElement” but need to configure and this is easy thanks to the official “@wordpress/script” package

Introduction to JSX

JSX solves the problem of not wanting to type out html structures with multiple “createElement” lines, one for each html element.

Can’t fed JSX directly in the browser, doesn’t make sense, so we need a tool that stands in the middle, that converts to html.

Make sure you have Node installed with “node –version” command. Start by creating a “package.json” file with “npm init -y” command and then run “npm install @wordpress/script –save-dev” command, (–save-dev not really necessary in 2021?)

Create an “src” folder and then create two scripts in the “package.json” file “build and start.”

"build": "wp-scripts build",
"start": "wp-scripts start"

This package will create a “build” folder when the script is run with a few files inside, including an “index.js” file. We want to tell WP to load that file by going to the “index.php” file in the plugin’s root directory and adding to the function named “adminAssets,” and in the “wp_enqueue_script” function, add ‘build/index.js’ as a parameter, (in place of ‘test.js’).

Continue building wp.block.registerBlockType function with JSX now that you are all configured.

Note: To gte tab triggers to work in VS Code you may need to update the “settings.json” file by adding ‘”*.js”: “javscriptreact”‘ as an object to the “file.associates” key.

If you modify the “save” function what happens to an existing custom block instance? You get a WP error that reads “This block contains unexpected or invalid content.”

Stop the “start” command with “control+c” command.

Block Type Attributes

What is a block type attribute? Let’s try to make it interactive. Add two inputs to the block.

An attribute is a way to bridge the gap between the admin editor code and saved output code.

Add an “attributes” key to the config object in the “wp.blocks.registerBlockType” function. Set this to an object with more keys that are set to objects of their own.

Add an “onChange” prop that triggers an “updateSkyColor” function that has an event parameter and inside the function use “props.setAttributes” functionality. make sure the edit fucntion is accepting props as a parameter.

Refer to “props.attributes.skyColor” in the JSX.

Front-end working good but the values not showing in the Editor so we need to add a value props to the input in the JSX that references “props.attributes.skyColor”

In the DB, in the “post_content” field, WP saves the attributes object in the html comment.

Can use “source” approach to make the html be our source of truth. set “source” and “selector” keys in a nested object in the attributes object. Brad never uses this approach but shows so we are aware.

Let’s Discuss the Output of Our Block (Part 1)

Why does the error mentioned above happen?

Learn how to make the output of the block truly dynamic.

In order to trust the data, change the save html structure and let WP figure it out on its own.

Give WP sort of a history but providing a top level property called “Deprecated” that gets an array of objects. Create a backup copy of the current working version.

Can create variable but we can have some duplicate code here for now.

Now we are free to make changes without receiving error message.

Can have multiple objects in the “deprecated” array.

Even with this in place, Brad never creates block types like this. Although the docs say this is standard, Brad thinks this is useless because we still need to have post in admin page re-saved. This is silly.

Instead we do what?

dynamic block. save property returns null. moving from JavaScript to PHP, lets PHP determine the value on the fly, and all will be updated immediately.

Go into plugin’s “index.php” file, and register a block type with the exact same name

Let’s Discuss the Output of Our Block (Part 2)

Register a block type from within php and change “enqueue_block_editor_assets” to “init.”

don’t load JS directly, by update enqueue to register script and then register block type with the same name and in the second argument have an array of options.



create an “theHTML” function that returns a paragraph and accepts $attributes that you can reference using the “concatentation with period” PHP approach.

Now if we make changes we don’t; need to go into the admin panel to update, it is happening on the fly.

now in the database…

Pros and cons to everything so what is drawback here? May take extra 2 milliseconds but if you are caching this is a non-issue.

Can escape or don’t bother.

Use “ob_start” where “ob” stands for output buffer.

Can type regular html now instead of concatenating long strings together.

In the next section we create two custom block types, a “Quick Question” custom block type and a “Professor Callout” custom block type.