Skip to content

Instantly share code, notes, and snippets.

@gaambo
Last active January 26, 2022 08:14
Show Gist options
  • Save gaambo/16c7fb6fd758e4eb72e0f5db3888dd40 to your computer and use it in GitHub Desktop.
Save gaambo/16c7fb6fd758e4eb72e0f5db3888dd40 to your computer and use it in GitHub Desktop.
UPDATE: No longer needed in WP 5.9 // Fixes Bug #51612 in WordPress Core where block filters (pre_render_block and render_block_data) only get called for top level blocks (not for innerBlocks/nested)
<?php
// phpcs:ignoreFile PSR1.Files.SideEffects
namespace CoreFunctionality\BlockEditor;
/**
* Fixes Bug #51612 in WordPress Core
* where block filters (pre_render_block and render_block_data)
* only get called for top level blocks (not for innerBlocks/nested)
*
* Current Workaround is to hook into render_block_data
* and render each innerBlock (recursively) with render_block
* because core doesn't use render_block for innerBlocks but only WP_Block::render
* but pre_render_block and render_block_data only get called in render_block
*
* Changes in render_block/WP_Block have to be monitored and maybe this won't be required in future
*
* @see https://core.trac.wordpress.org/ticket/51612
*/
class BlockFilterWorkaround
{
public function __construct()
{
/**
* hook latest possible priority (= PHP_INT_MAX) so other hooks which change data run first
* our function doesn't change data, it only renders innerBlocks and stores them
*/
add_filter('render_block_data', [$this, 'render_block_data'], PHP_INT_MAX, 2);
}
/**
* Callback for `render_block_data`
*
* @see wp-includes/blocks.php:687
* @param array $block
* @param array $sourceBlock
* @return array filtered block data with rendered inner blocks
*/
public function render_block_data($block, $sourceBlock) // phpcs:ignore PSR1.Methods.CamelCapsMethodName
{
// only run if has innerBlocks, maximum nested block without innerBlocks just returns data
if (isset($block['innerBlocks']) && $block['innerBlocks']) {
$renderedInnerBlocks = [];
/**
* call render_block foreach innerBlock
* this calls pre_render_block and render_block_data for nested blocks
* calling render_block_data on a nested block also
* calls this method again recursively (for inner-innerBlocks)
*/
foreach ($block['innerBlocks'] as $i => $innerBlock) {
$renderedInnerBlocks[] = render_block($innerBlock);
}
$innerBlockIndex = 0;
/**
* on WP_Block::render it checks for all chunks of innerContent
* and if any of these chunks is a string it outputs that string
* instead of calling render on the inner block
* see class-wp-block.php::208-212
*/
foreach ($block['innerContent'] as $i => $innerContent) {
/**
* innerContent has structure of [wrapperDiv, null, endDiv] for most blocks
* therefore only put values in the "null" elements
* see class-wp-block.php::208-212
*/
if (!is_string($innerContent)) {
$block['innerContent'][$i] = $renderedInnerBlocks[$innerBlockIndex++];
}
}
}
return $block;
}
}
new BlockFilterWorkaround();
@gaambo
Copy link
Author

gaambo commented Apr 16, 2021

@gaambo
Copy link
Author

gaambo commented Jan 26, 2022

UPDATE: WordPress 5.9 includes a bug fix, so this workaround is no longer required.
See https://core.trac.wordpress.org/ticket/51612

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment