How to Build Nested Gutenberg Blocks (InnerBlocks) Without JavaScript
Some of the most useful blocks are containers: a card that holds a heading, text and a button; a tabs block that holds tab panels; a section with a fixed layout where editors only type the content. In Gutenberg this is called InnerBlocks, and it’s the best way to give editors freedom inside a design that can’t break.
Why container blocks
A block with fields in the sidebar is fine for short values. For real content (headings, paragraphs, lists, images), editors prefer typing directly on the page. A container block lets them use normal core blocks inside your layout.
The four settings that matter
| Setting | What it does | Example |
|---|---|---|
| Allowed blocks | Which blocks can go inside | Only core/heading, core/paragraph, core/buttons |
| Template | Blocks inserted automatically | A heading + paragraph + buttons, ready to fill in |
| Lock | Stop adding, removing or moving inner blocks | Fixed card structure, editable text |
| Parent | Where *this* block may be placed | A “Tab” block only inside a “Tabs” block |
The React way
In a React block you render <InnerBlocks allowedBlocks={…} template={…} templateLock="all" /> in edit.js, and <InnerBlocks.Content /> in save.js. That means a build step and two components to keep in sync.
The PHP way with FanCoolo WP
In FanCoolo WP, turn on Inner Blocks Settings in the block editor and set:
- Allowed Block Types: type block names like
core/paragraphand press Enter. Leave empty to allow everything. - Block added by default: the template that appears when the block is inserted.
- Lock Template: users can only edit the content of the blocks you provided.
- Parent Block: restrict where this block can be inserted.
Then decide where the nested blocks render by placing the <InnerBlocks /> tag in your block’s PHP, inside your wrapper:
<section <?php echo get_block_wrapper_attributes( [ 'class' => 'feature-card' ] ); ?>>
<div class="feature-card__icon"><?php echo esc_html( $attributes['icon'] ?? '' ); ?></div>
<div class="feature-card__body">
<InnerBlocks />
</div>
</section>
In the editor it becomes the area where users add and arrange blocks; on the front end FanCoolo replaces it with the rendered inner blocks.
Parent and child blocks
Setting a Parent Block makes a child block, like core’s Button inside Buttons. There’s a catch in plain WordPress: many parents keep their own whitelist of allowed children, so declaring the parent alone can hide your block everywhere. FanCoolo makes the relationship work both ways: when you set a parent, it also adds your block to that parent’s allowed children, on the server and in the editor’s inserter.
Ideas
- Feature card: icon from a sidebar field, heading and text as inner blocks.
- Tabs: a Tabs container that only allows Tab children, each Tab holding any content.
- Locked hero: fixed heading + text + buttons template, Lock Template on.
Starting from scratch? See how to create a custom Gutenberg block without React.
