WordPress / gutenberg

The Block Editor project for WordPress and beyond. Plugin is available from the official repository.
https://wordpress.org/gutenberg/
Other
10.48k stars 4.18k forks source link

The `render_block` filter does now work on HTML blocks that are not inside of container blocks #64420

Open ndiego opened 2 months ago

ndiego commented 2 months ago

Description

This is a strange one that was reported by a user of the Block Visibility plugin. The user was trying to add visibility conditions, which are controlled by attributes and applied using render_block filter, to HTML blocks inside of a block template. They were getting different results based on where the block was placed.

After digging into this, I discovered that if an HTML block is not contained within another block, such as a Group block, anything you apply using the render_block filter is not respected. This situation seems relatively rare, and I imagine it only happens in block themes where the HTML block can be added to the root of a block template.

Step-by-step reproduction instructions

  1. Open the Site Editor and add an HTML block to the very top of a template, perhaps the Single Posts template. Ensure that it is not inside another block.
  2. Confirm that the HTML content is displayed on the front end.
  3. Next add the code below to the functions.php file of your theme.
  4. Confirm that the word "testing" does not appear on the front end.
  5. Now wrap the HTML block in a Group block.
  6. Confirm that the word "testing" now appears on the front end.
function append_testing_to_html_block( $block_content, $block ) {
    // Check if the block is an HTML block and has content.
    if ( 'core/html' === $block['blockName'] && $block_content ) {
        // Append the word "testing" to the block content.
        $block_content .= ' testing';
    }

    return $block_content;
}
add_filter( 'render_block', 'append_testing_to_html_block', 10, 2 );

Screenshots, screen recording, code snippet

No container Inside Group block
image image

Environment info

Please confirm that you have searched existing issues in the repo.

Please confirm that you have tested with all plugins deactivated except Gutenberg.

t-hamano commented 2 months ago

I was able to reproduce this issue.

I found that for some reason, when an HTML block is inserted into the root of a template, template part, pattern, etc., it isn't saved as a block, but rather as just a string:

HTML Contents

<!-- wp:paragraph -->
<p>Paragraph Block</p>
<!-- /wp:paragraph -->

This causes $block['blockName'] to be null in the render_block hook, which doesn't work properly.

Inside the post editor or a container block, it is correctly saved as an HTML block, like this:

<!-- wp:html -->
Custom HTML
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Paragraph Block</p>
<!-- /wp:paragraph -->

I'm not sure if this is intended, but it seems like a bug to me.

talldan commented 2 months ago

I found that for some reason, when an HTML block is inserted into the root of a template, template part, pattern, etc., it isn't saved as a block, but rather as just a string:

Its how the block marked as the freeform handler works. When parsing, any content that doesn't have a block delimeter comment is marked as 'freeform' and is handled by the block marked as the freeform handler (see setFreeformContentHandlerName) as a way to make that content editable.

Traditionally the freeform block has been the classic block (so that classic editor content that doesn't have block delimiters works in the block editor), but in the site editor it's the HTML block (if you run wp.blocks.getFreeformContentHandlerName() in the site editor it'll return core/html). The classic block doesn't really make sense in the site editor, as it's main purpose is for migration of classic content and as an onboarding ramp to blocks, but the classic editor was never able write site level content so there's no need for it.

I'd say it is intended in a way, but it's imperfect that user added HTML blocks also lack the block delimiter. I think the reason for this is to preserve any existing raw html in its original form.