Catégories
Développement WordPress

How to extend has_block() function to also check for Gutenberg reusable blocks

It’s been almost three years now that the block editor has been part of WordPress and we all got used to developing with this new editor, Gutenberg.

Convinced of the principle of reusable blocks, I started to work on a plugin dedicated to this feature. In September 2019, I released a plugin called Reusable Blocks Extended, which allows website developers/editors to perform a pseudo full-site editing experience. I updated this plugin before the release of WordPress 5.5 to take into account Block Patterns (with a one-click conversion tool), and it was noticed by WP Tavern ♥️

Nonetheless, reusable blocks are a powerful feature that has remained somewhat on the fringes of Gutenberg developments.

For example, we have has_block(), a useful PHP function for people who develop websites that work with Gutenberg. It allows to check whether a specific block is contained in a series of blocks (this series of blocks is generally the content of a publication written in the block editor).

But… this function doesn’t take into account the content of any existing reusable block.

Here is a function to use instead of has_block(). You just need to put it into your custom theme or your child theme. Then, you can use the has_block_including_reusables() function instead of has_block(). It will return the same results than has_block(), excepts that it also retrieves reusable blocks.

If you want to support my open source work, you can buy me a beer 🍺 or leave a kind comment below 🥰

I’d really like to see this enhancement merged into the existing has_block() Core function, so hopefully this workaround won’t be useful anymore in a near future 🙂

Here is the full code of the function:

/**
 * Determines whether a $post or a string contains a specific block type,
 * including blocks that are included in reusable blocks.
 *
 * @author Jb Audras – @audrasjb on socials.
 *
 * @param string                  $block_name Full Block type to look for.
 * @param int|string|WP_Post|null $post Optional. Post content, post ID, or post object. Defaults to global $post.
 * @return bool Whether the post content contains the specified block.
 */
function has_block_including_reusables( $block_name, $post = false ) {

	if ( ! has_blocks( $post ) ) {
		return false;
	}

	$post = ( ! $post ) ? get_the_ID() : $post;

	if ( $post ) {

		// This is for regular blocks
		if ( has_block( $block_name, $post ) ) {
			return true;
		}

		// This is for reusable blocks
		if ( has_block( 'block', $post ) ) {

			$content = get_post_field( 'post_content', $post );
			$blocks = parse_blocks( $content );

			if ( ! is_array( $blocks ) || empty( $blocks ) ) {
				return false;
			}

			if ( false === strpos( $block_name, '/' ) ) {
				$block_name = 'core/' . $block_name;
			}

			foreach ( $blocks as $block ) {
				if ( $block['blockName'] === 'core/block' && ! empty( $block['attrs']['ref'] ) ) {
					if ( has_block( $block_name, $block['attrs']['ref'] ) ) {
					   return true;
					}
				}
			}
		}
	}
	return false;
}

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.