How to Use Inner Blocks in Gutenberg

In the previous article, we built a carousel block where we allow uploading multiple images using the MediaUpload component. Though it works perfectly it has some limitations.

  • You can’t easily sort/change the position of images.
  • You can’t add links to your images.

While searching for a solution to these problems I came across core blocks available in Gutenberg. I found that the Gallery block can be used to overcome the above limitations. You can see the working of a Gallery block by simply adding it to the editor.

Apart from Gallery Block, there are a rich set of default blocks available that can be utilized in your custom block development. Each core block comes with its own markup on a frontend which might not suit your requirement. This markup can be modified which I’ll show in the later part of the tutorial.

You can integrate these core blocks with the help of Inner Blocks. The Inner Blocks are nothing but a nested block where you can use multiple blocks inside it.

Having said that, let’s see practically how to build a following section with Inner Blocks where we have a heading, paragraph, and multiple images.

our-partners-section

How to Use Inner Blocks

Inner Blocks are the name of react component available in the “Block Editor” package. In order to use it, you need to import the useInnerBlocksProps hook:

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

Then, using the code below you can easily add core blocks like Heading, Paragraph, and Gallery into your custom block.

import { BaseControl } from '@wordpress/components';

export default function Edit() {
	const innerBlocksProps = useInnerBlocksProps(
		{ className: 'wp-block-gutenberg-artisasnweb-client-logos__content' },
		{
			allowedBlocks: [
				'core/heading', 'core/paragraph', 'core/gallery'
			],
			template: [
				['core/heading', { placeholder: __("Enter heading here...") }],
				['core/paragraph', { placeholder: __("Enter paragraph here...") }],
				['core/gallery', {}],
			],
		},
	);
	return (
		<div { ...useBlockProps() }>
			<BaseControl label={__("Artisans Web - Client Logos")}>
				<div {...innerBlocksProps} />
			</BaseControl>
		</div>
	);
}

As per our section, I’m allowing only required blocks using allowedBlocks prop. If you skip this prop then inner blocks allow you to insert any block which doesn’t make sense for our end goal.

Next, using the template prop, it gives a predefined list of blocks which displays when you add your custom block to the editor. It’s an optional prop. If you don’t specify it, you have to add allowed blocks manually.

Let’s check the editor. You should see your custom block appear something like the below screenshot.

inner-blocks-example

Here, you can add your content. But, it can’t be saved yet. The content of inner blocks is saved in the actual post content. For this, you should use <InnerBlocks.content /> in save() method of index.js file.

import { InnerBlocks } from '@wordpress/block-editor';

registerBlockType( metadata.name, {
	edit: Edit,
	save: () => <InnerBlocks.Content />,
} );

You can now add your content and save it. Next, let’s focus on the frontend part.

Print the Content of Inner Blocks

As I preferred dynamic blocks, inside my render.php template, I have access to a few variables – $attributes, $content, $block and $context. Out of these variables, $content variable holds the value of saved content. So, I can simply print my block content as follows.

<div <?php echo get_block_wrapper_attributes(); ?>>
	<div class="artisansweb-client-logos">
		<?php echo $content; ?>
	</div>
</div>

You’ll get the content generated by the blocks inserted. At this stage, the flow of inner blocks is finished but the work is not done yet.

While working with inner blocks you may see difficulties on the frontend. The inner blocks are allowed to add core blocks and these blocks have their own markup. There is a possibility your frontend is not rendering the way you want because of these default markups. For instance, if you check the frontend of the block we just built, it has a kind of below structure.

<div class="artisansweb-client-logos">
	<h2>Our Partners</h2>
	<p>We are working with some amazing partners.</p>
	<figure class="is-layout-flex wp-block-gallery-6 wp-block-gallery has-nested-images columns-default is-cropped">
		<figure class="wp-block-image size-large">
			<a href="https://google.com" target="_blank" rel="noreferrer noopener">
				<img loading="lazy" decoding="async" width="1024" height="680" src="https://wp-81.local/wp-content/uploads/2023/07/7-1024x680.jpg" alt="" class="wp-image-39" srcset="https://wp-81.local/wp-content/uploads/2023/07/7-1024x680.jpg 1024w, https://wp-81.local/wp-content/uploads/2023/07/7-300x199.jpg 300w, https://wp-81.local/wp-content/uploads/2023/07/7-768x510.jpg 768w, https://wp-81.local/wp-content/uploads/2023/07/7.jpg 1280w" sizes="(max-width: 1024px) 100vw, 1024px">
			</a>
		</figure>
		<figure class="wp-block-image size-large">
			<a href="https://artisansweb.net" target="_blank" rel="noreferrer noopener">
				<img decoding="async" loading="lazy" width="1024" height="682" src="https://wp-81.local/wp-content/uploads/2023/07/11-1024x682.jpg" alt="" class="wp-image-43" srcset="https://wp-81.local/wp-content/uploads/2023/07/11-1024x682.jpg 1024w, https://wp-81.local/wp-content/uploads/2023/07/11-300x200.jpg 300w, https://wp-81.local/wp-content/uploads/2023/07/11-768x512.jpg 768w, https://wp-81.local/wp-content/uploads/2023/07/11.jpg 1280w" sizes="(max-width: 1024px) 100vw, 1024px">
			</a>
		</figure>
	</figure>
</div>

The good news is you can modify this markup and fit it as per your requirement. It solves the hurdle of using inner blocks in combination with core blocks.

Let’s say you want to modify the markup of the gallery as per the below structure. Here, I’m replacing the figure tag with ul, li format.

<div class="artisansweb-client-logos">
	<h2>Our Partners</h2>
	<p>We are working with some amazing partners.</p>
	<ul>
		<li>
			<a href="https://google.com" target="_blank" rel="noreferrer noopener">
				<img loading="lazy" decoding="async" width="1024" height="680" src="https://wp-81.local/wp-content/uploads/2023/07/7-1024x680.jpg" alt="" class="wp-image-39" srcset="https://wp-81.local/wp-content/uploads/2023/07/7-1024x680.jpg 1024w, https://wp-81.local/wp-content/uploads/2023/07/7-300x199.jpg 300w, https://wp-81.local/wp-content/uploads/2023/07/7-768x510.jpg 768w, https://wp-81.local/wp-content/uploads/2023/07/7.jpg 1280w" sizes="(max-width: 1024px) 100vw, 1024px">
			</a>
		</li>
		<li>
			<a href="https://artisansweb.net" target="_blank" rel="noreferrer noopener">
				<img decoding="async" loading="lazy" width="1024" height="682" src="https://wp-81.local/wp-content/uploads/2023/07/11-1024x682.jpg" alt="" class="wp-image-43" srcset="https://wp-81.local/wp-content/uploads/2023/07/11-1024x682.jpg 1024w, https://wp-81.local/wp-content/uploads/2023/07/11-300x200.jpg 300w, https://wp-81.local/wp-content/uploads/2023/07/11-768x512.jpg 768w, https://wp-81.local/wp-content/uploads/2023/07/11.jpg 1280w" sizes="(max-width: 1024px) 100vw, 1024px">
			</a>
		</li
	</ul>
</div>

Modify the Markup of a Core Gallery Block

You would rarely need to change the markup of the heading and paragraph block. That’s why I’m going to modify the Gallery block’s markup. It can be done using the render_block hook in WordPress. This hook accepts two parameters, the $block_content and Block class instance($block).

As you need to hook into the Gallery block, you should pass the name of the block after the hook name as render_block_${namespace/block}. Let’s see it in action. Add the below code to your main plugin file.

<?php
function artisansweb_modify_gallery_markup( $block_content, $block ) {
	if ( isset( $block['innerBlocks'] ) ) {
		$content = '<ul>';
		foreach ( $block['innerBlocks'] as $innerBlock ) {
			if ( "core/image" == $innerBlock['blockName'] ) {
				$content .= '<li>';
				// regular expression if you're having anchor tag around img element
				preg_match( '/<a(.*?)<\/a>/s', $innerBlock['innerHTML'], $match );

				// regular expression if you're having only img element
				//preg_match( '/<img[^>]*>/i', $innerBlock['innerHTML'], $match );

				$content .= isset( $match[0] ) ? $match[0] : '';
				$content .= '</li>';
			}
		}
		$content .= '</ul>';
		return $content;
	}
    return $block_content;
}
add_filter( 'render_block_core/gallery', 'artisansweb_modify_gallery_markup', 10, 2 );

In the above code, I’m extracting each anchor tag which also includes img tag. This markup is then wrapped into ul, li format.

In your case, you might not be using links to the images. I have also added a commented code for this scenario.

Now if you check the frontend you can see a new markup rendered for your Gallery block.

Finally, add the styling for the frontend into the src/style.scss file. Of course, you can change this styling as per your needs.

.your-selector-here {

	.artisansweb-client-logos {
		h2, p {
			text-align: center;
		}
		ul {
			display: flex;
			justify-content: space-around;
			padding: 0;
			list-style: none;

			li {
				a {
					display: block;
					text-decoration: none;
					transition: transform 0.3s ease;

					&:hover {
						transform: scale(1.1);
					}

					img {
						max-width: 100px;
						max-height: 100px;
						border: 2px solid #ddd;
						border-radius: 50%;
					}
				}
			}
		}
	}
}

Just in case, you want to add a carousel for these images, I already explained adding a carousel in my previous article.

If you liked this article, then please subscribe to our YouTube Channel for video tutorials.

Leave a Reply

Your email address will not be published. Required fields are marked *