Question

I struggle with columns block in my plugin. I try to filter all blocks of the type "heading":

$post = get_post();
$blocks = parse_blocks($post->post_content);
$headings = array_values(array_filter($blocks, function ($block) {
    return $block['blockName'] === 'core/heading';
}));

This returns an array of all heading block. But if the post contains columns the array $blocks is a nested multidimensional array. array_filter does not select blocks nested like this:

}
      [1]=>
      array(5) {
        ["blockName"]=>
        string(11) "core/column"
        ["attrs"]=>
        array(0) {
        }
        ["innerBlocks"]=>
        array(4) {
          [0]=>
          array(5) {
            ["blockName"]=>
            string(12) "core/heading"
            ["attrs"]=>
            array(0) {
            }
            ["innerBlocks"]=>
            array(0) {
            }
            ["innerHTML"]=>
            string(26) "
<h2>HEADING.COLUMN1</h2>
"
            ["innerContent"]=>
            array(1) {
              [0]=>
              string(26) "
<h2>HEADING.COLUMN1</h2>
"
            }
          }

Is there a way to select only heading blocks with parse_blocks or some other clever way?

Was it helpful?

Solution

parse_blocks() simply returns all blocks found in the post content, so for what you're trying to get, you could use a function which calls itself recursively like so:

function my_find_heading_blocks( $blocks ) {
    $list = array();

    foreach ( $blocks as $block ) {
        if ( 'core/heading' === $block['blockName'] ) {
            // add current item, if it's a heading block
            $list[] = $block;
        } elseif ( ! empty( $block['innerBlocks'] ) ) {
            // or call the function recursively, to find heading blocks in inner blocks
            $list = array_merge( $list, my_find_heading_blocks( $block['innerBlocks'] ) );
        }
    }

    return $list;
}

// Sample usage:
$post = get_post();
$blocks = parse_blocks( $post->post_content );
$headings = my_find_heading_blocks( $blocks );

OTHER TIPS

I used this:

function recurse($blocks) {
  $arr = array();

  foreach ($blocks as $block => $innerBlock) {
      if (is_array($innerBlock) ) {
          $arr = array_merge(recurse($innerBlock),$arr);
      } else {
          if ( isset($blocks['blockName']) && $blocks['blockName'] === 'core/heading' && $innerBlock !== 'core/heading')  {       
            $arr[] = $innerBlock;
          }
      }
  }

  return $arr;
}

$headings = array_reverse(recurse($blocks));
Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top