Take more control over Inner Block Areas (as a block developer)

Prior to WordPress 5.9 the only way to work with inner blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. was to use the <InnerBlocks /> component. One downside of this approach is that in the editor this creates additional DOM nodes that wrap the markup of the inner blocks. This makes it more difficult to style these inner blocks areas to match what the enduser will see on the site.

With WordPress 5.9 we’re introducing a new reactReact React is a JavaScript library that makes it easy to reason about, construct, and maintain stateless and stateful user interfaces. https://reactjs.org/. hook called useInnerBlocksProps that allows you to change this and take more control over the markup of inner blocks areas. The useInnerBlocksProps is exported from the @wordpress/block-editor package same as the InnerBlocks component itself and supports everything the component does. It also works like the useBlockProps hook introduced with apiVersion: 2 in WordPress 5.6.

To use the hook, take the object returned from calling the hook and spread it onto the host element you want to render the inner blocks into. For example:

function BlockEdit(props) {
    const blockProps = useBlockProps();
    const innerBlocksProps = useInnerBlocksProps();

    return (
        <section {...blockProps}>
             <div {...innerBlocksProps} />
        </section>
    );
}

The above code will render to the following markup in the editor:

<section>
    <div>
        <!-- Inner Blocks get inserted here -->
    </div>
</section>

The hook also accepts two arguments:

  1. The first argument accepts an object containing additional props that are added to the element in the dom. For example, to add a custom class name to the inner blocks area you pass { className: 'my-class' } as the first argument.
  2. The second argument is also an object and can contain any properties to control the behavior of the inner blocks area. It accepts all options like allowedBlocks, template, templateLock, renderAppender, etc. You can find the full list of supported properties in the InnerBlocks props documentation
useInnerBlocksProps( additionalWrapperProps, innerBlocksProps );

Saving the inner blocks

To save inner blocks content there is a special variant of the hook, this is similar to the component-based approach that uses <InnerBlocks.Content /> in the save method of a block. For hooksHooks In WordPress theme and development, hooks are functions that can be applied to an action or a Filter in WordPress. Actions are functions performed when a certain event occurs in WordPress. Filters allow you to modify certain functions. Arguments used to hook both filters and actions look the same., you add .save to the end of the hook like so:

function BlockSave( props ) {
    const innerBlocksProps = useInnerBlocksProps.save( { className: 'my-class' } );

    return (
        <section {...innerBlocksProps} ) />
    );
}

When you use the useInnerBlocksProps.save() hook it only accepts the first parameter, these are the options you want to add to the container element.

Why use hooks?

The hooks allow for new options and nice enhancements. For example, you can take the object returned from the useBlockProps hook—these contain the properties for the block’s wrapping container—and pass them to the useInnerBlocksProps hook. This reduces the number of elements we need to create. For example:

function BlockEdit(props) {
    const blockProps = useBlockProps();
    const innerBlocksProps = useInnerBlocksProps( blockProps );

    return (
        <section {...innerBlocksProps} />
    );
}
<section>
    <!-- Inner Blocks get inserted here -->
</section>

Another benefit to using the hook approach is using the returned value, which is just an object, and deconstruct to get the react children from the object. This property contains the actual child inner blocks thus we can place elements on the same level as our inner blocks.

function BlockEdit(props) {
    const blockProps = useBlockProps();
    const { children, ...innerBlocksProps } = useInnerBlocksProps( blockProps );

    return (
        <section {...innerBlocksProps}>
            { children }
            <!-- Insert any arbitrary html here at the same level as the children -->
        </section>
    );
}
<section>
    <!-- Inner Blocks get inserted here -→
    <!-- The custom html gets rendered on the same level -->
</section>

Example:

block.json

{
    "apiVersion": 2,
    "name": "example/block",
    "title": "Example",
    "category": "text",
    "editorScript": "file:./index.js"
}

index.js

import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';

import metadata from './block.json';

function BlockEdit(props) {
    const blockProps = useBlockProps( { className: 'my-class' } );
    const innerBlocksProps = useInnerBlocksProps(
        blockProps,
        { allowedBlocks: [ 'core/heading', 'core/paragraph', 'core/image' ] }
    );

    return (
        <section {...innerBlocksProps} />
    );
}

function BlockSave(props) {
    const blockProps = useBlockProps.save( { className: 'my-class' } );
    const innerBlocksProps = useInnerBlocksProps.save( blockProps );

    return <section {...innerBlocksProps} />
}

registerBlockType( metadata, {
    edit: BlockEdit,
    save: BlockSave,
} )

Thank you, @gziolo and @mkaz for reviewing and proofreading this post.

#5-9, #dev-notes