0

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?

1

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 );
3
  • Okay, we posted an answer at the same time. Is this better than my solution?
    – Marc
    Feb 18 at 21:36
  • Yes, no or maybe - if you want to know which is better, you can either run your own tests or ask on sites like Stack Overflow...
    – Sally CJ
    Feb 18 at 21:42
  • 1
    Your function is simpler. So yours must be better =) Thank you!
    – Marc
    Feb 18 at 21:42
0

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));

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.