AdvancedCustomFields / acf

Advanced Custom Fields
http://advancedcustomfields.com/
835 stars 171 forks source link

ACF breaks the block editor if blocks are rendered inside of an ACF block #837

Open CreativeDive opened 1 year ago

CreativeDive commented 1 year ago

Hey,

I just wanted to let you know that the block editor hangs as soon as you render block content within an ACF block. I suspect this only occurs when inner blocks are present.

I know this bug has been fixed in the past: https://github.com/AdvancedCustomFields/acf/issues/682. But now it doesn't seem to be working anymore.

This error only occurs if the block content has not yet been cached by ACF. That's why I haven't noticed it for a long time.

I think you should know that.

I have now fixed this bug for myself by doing some operations in my ACF blocks render callback function, but I think this bug should also be fixed directly at ACF:

In my callback function:

function my_acf_block_render_callback( $block, $content, $is_preview, $post_id, $wp_block, $context ) {

    //...

    /*
    * HOTFIX: ACF breaks the editor if block content is rendered via do_blocks();
    */

    if( $is_preview && doing_filter('render_block_content_in_editor_filter') ) {
        $block_content = acf_render_blocks_in_editor( $block_content, $content, $wp_block, $block );
        echo $block_content;
        return;
    }

    //...

}

To convert <InnerBlocks> tags to content:

function acf_render_blocks_in_editor( $html, $content, $wp_block, $block ) {

    $content = str_replace( '$', '\$', $content );

    // Wrap content in our acf-inner-container wrapper if necessary.
    if( $wp_block && apply_filters( 'acf/blocks/wrap_frontend_innerblocks', true, $block['name'] ) ) {

        // Check for a class (or className) provided in the template to become the InnerBlocks wrapper class.
        $matches = array();

        $class = 'acf-innerblocks-container';
        if( preg_match( '/<InnerBlocks(?:[^<]+?)(?:class|className)=(?:["\']\W+\s*(?:\w+)\()?["\']([^\'"]+)[\'"]/', $html, $matches ) ) {
            $class = isset( $matches[1] ) ? $matches[1] : 'acf-innerblocks-container';
        }

        $content = '<div class="' . $class . '">' . $content . '</div>';
    }

    return preg_replace( '/<InnerBlocks([\S\s]*?)\/>/', $content, $html );

}

To output rendered block content in the editor:

function get_block_content( $post_id ) {

    $post = get_post( $post_id );
    $content = isset( $post->post_content ) ? $post->post_content : '';

    return do_blocks( $content );

}

add_filter( 'render_block_content_in_editor_filter', 'get_block_content' );
lgladdy commented 1 year ago

Hey @CreativeDive, any chance you could create us a ACF Block as a zipped plugin that shows the issue so we can drop-in something reproducible here please?

lgladdy commented 1 year ago

Also, could you confirm if this introduced with the security changes in WordPress 6.2.2?

CreativeDive commented 1 year ago

@lgladdy I think all you have to do is create a post that uses inner blocks.

Save this post.

Then you need a block that does the following:

$post = get_post( $post_id );// <-- Use the post you just created.
$content = isset( $post->post_content ) ? $post->post_content : '';

echo do_blocks( $content );

View this block in another post or page inside the block editor.

As a result, you should not see the finished rendered block content, but an unsuccessful attempt to convert inner blocks.

In my case, the editor also hangs up.

I would guess that happened before WordPress 6.2.2. But I probably haven't noticed it for a while because ACF caches the block content in the editor. In addition, I have the case in which I only rarely render block content in an ACF block. Now when I re-saved the page which is rendered inside an ACF block I noticed this bug.

Above I have shown a way how I could solve this bug immediately.