Custom WP Block using Inner Blocks crashes editor, doesn’t save content

The question:

I’ve finally gotten around to building a custom Gutenberg/WP Block for a project and it’s basically kicking my ass. Working with React, Node, WebPack, Gulp is all new enough to me so there’s a learning curve I have to deal with but the incomplete and inaccurate documentation from WP is making things substantially worse. (Their documentation still says to use wp.editor but reading through tickets in GitHub I learned that was deprecated and should instead be wp.blockEditor, as an example.)

As of right now, I’ve got a custom block loading in my editor that is supposed to accept InnerBlocks. The process of adding a block and adding blocks into it works just fine.

Where things go wrong is after the page/post is ‘Updated’. I get a bunch of different errors and a white screen of death. One of the errors that sometimes comes up is a React Minification #321 error. But there’s others as well and not always the same errors.

Here is the code used to register my block:

const { __, setLocaleData } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { InnerBlocks } = wp.blockEditor; //was wp.editor

const blockStyle = {
    backgroundColor: '#777',
    color: '#FFF',
    padding: '24px 2.5% 24px 2.5%',
};

registerBlockType( 'custom-layout-blocks/custom-stripe-rows', {
    title: __( 'Striped Block Row', 'custom-layout-blocks' ),
    icon: 'tide',
    category: 'layout',
    styles: [
        {
            name: 'magenta-stripes',
            label: 'Magenta',
            isDefault: true
        },
        {
            name: 'teal-stripes',
            label: 'Teal'
        },
        {
            name: 'evergreen-stripes',
            label: 'Evergreen'
        },
    ],
    edit() {
        return (
            <div style={blockStyle}><InnerBlocks /></div>
        );
    },
    save() {
        return (
            <div style={blockStyle}><InnerBlocks /></div>
        );
    }
} );

Now here’s the relevant PHP:

defined( 'ABSPATH' ) || exit;
    function custom_layoutblocks_load_textdomain() {
        load_plugin_textdomain( 'custom-layout-blocks', false, basename( __DIR__ ) . '/languages' );
    }
    add_action( 'init', 'custom_layoutblocks_load_textdomain' );

    function custom_layoutblocks_register_block() {
        if( !function_exists( 'register_block_type' ) ) {
            // Gutenberg is not active.
            return;
        }
        wp_register_script(
            'custom-striped-rows',
            plugins_url( 'build/index.js', __FILE__ ),
            array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-block-editor' ),
            filemtime( plugin_dir_path( __FILE__ ) . 'build/index.js' )
        );
        wp_register_style(
            'custom-editor',
            plugins_url( 'css/custom-editor.css', __FILE__ ),
            array( 'wp-edit-blocks' ),
            filemtime( plugin_dir_path( __FILE__ ) . 'css/custom-editor.css' )
        );
        wp_register_style(
            'custom-style',
            plugins_url( 'css/custom-front.css', __FILE__ ),
            array(),
            filemtime( plugin_dir_path( __FILE__ ) . 'css/custom-front.css' )
        );
        wp_style_add_data( 'custom-style', 'path', dirname( __FILE__ ) . '/css/custom-front.css' );
        register_block_type( 'custom-layout-blocks/custom-stripe-rows', array(
            'api_version'   => 2,
            'style'         => 'custom-style',
            'editor_style'  => 'custom-editor',
            'editor_script' => 'custom-striped-rows',
        ) );
        if( function_exists( 'wp_set_script_translations' ) ) {
            wp_set_script_translations( 'custom-striped-rows', 'custom-layout-blocks' );
        }
    }
    add_action( 'init', 'custom_layoutblocks_register_block' );

** I’ve changed all the prefixes to ‘custom’ to keep this generic and applicable to anyone else that comes across this.

WebPack is tracking changes and the files are all being updated, I can run the plugin in my dev environment and on a staging site. Where it all falls apart is when I update an entry with my custom block in it. Everything seems to go haywire from there and the content doesn’t show up in the front end, not even in the source.

Update:

Here’s the error I get on the edit screen after I’ve added the block and added a paragraph block to it.

TypeError: null is not an object (evaluating '(e.target.getAttribute("data-block")?e.target:e.target.closest("[data-block]")).getAttribute')

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

Explanation of the issues in your code:

  1. The main one which causes the block editor to crash, is because you used InnerBlocks in the save function. You should instead use InnerBlocks.Content.

    See this and this for more details on InnerBlocks usage, accepted props, etc.

  2. As for the getAttribute error, it’s because you did not use useBlockProps in the edit function (which should also be used in the save function).

    And why should you use useBlockProps, is because when you registered the block type in JavaScript (using registerBlockType()), you didn’t set the apiVersion property, hence Gutenberg uses the api_version value (which is 2) you set via PHP (using register_block_type()), and when using the block API version 2, useBlockProps should be used, so that the block is properly wrapped, centered and “clickable”.

So to fix the issues:

  • At the top in your script, replace the const { InnerBlocks } = wp.blockEditor; with:

    const { InnerBlocks, useBlockProps } = wp.blockEditor;
    
  • Use useBlockProps() in the edit function, and useBlockProps.save() and InnerBlocks.Content in the save function:

    edit() {
        const blockProps = useBlockProps( { style: blockStyle } );
    
        return (
            <div { ...blockProps }><InnerBlocks /></div>
        );
    },
    save() {
        const blockProps = useBlockProps.save( { style: blockStyle } );
    
        return (
            <div { ...blockProps }><InnerBlocks.Content /></div>
        );
    }
    

Additional Notes

  • Are you already using the @wordpress/scripts package to build your scripts (see JavaScript build setup in the block editor handbook)?

    Because if you are, you wouldn’t need to manually specify the dependencies for your script, which is array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-block-editor' ) in the question.

    However, you will need to use the import statement and not const when loading the dependencies in your script. So for example:

    // Instead of using "const":
    const { InnerBlocks, useBlockProps } = wp.blockEditor;
    
    // Use "import":
    import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
    

In response to your comment…

if I replace array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-block-editor' ) with just array() or any other combination,
excluding any of them or all of them, I still get an error

The following excerpt might help:

Here is how to use this asset file to automatically set the dependency
list for enqueuing the script. This prevents having to manually update
the dependencies, it will be created based on the package imports
used within your block.

$asset_file = include( plugin_dir_path( __FILE__ ) . 'build/index.asset.php');

wp_register_script(
  'myguten-block',
  plugins_url( 'build/index.js', __FILE__ ),
  $asset_file['dependencies'],
  $asset_file['version']
);


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment