diff --git a/lib/blocks.php b/lib/blocks.php index 92e89abddd646..bf2dee358c8df 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -60,8 +60,10 @@ function gutenberg_parse_blocks( $content ) { if ( ! has_blocks( $content ) ) { return array( array( - 'attrs' => array(), - 'innerHTML' => $content, + 'blockName' => 'core/freeform', + 'attrs' => array(), + 'innerBlocks' => array(), + 'innerHTML' => $content, ), ); } diff --git a/lib/parser.php b/lib/parser.php index 25d37f3c37b8b..a1fb922936619 100644 --- a/lib/parser.php +++ b/lib/parser.php @@ -259,26 +259,26 @@ private function peg_f1($pre, $bs, $post) { return peg_join_blocks( $pre, $bs, $ private function peg_f2($blockName, $a) { return $a; } private function peg_f3($blockName, $attrs) { return array( - 'blockName' => $blockName, - 'attrs' => $attrs, + 'blockName' => $blockName, + 'attrs' => isset( $attrs ) ? $attrs : array(), 'innerBlocks' => array(), - 'innerHTML' => '', + 'innerHTML' => '', ); } private function peg_f4($s, $children, $e) { list( $innerHTML, $innerBlocks ) = peg_array_partition( $children, 'is_string' ); return array( - 'blockName' => $s['blockName'], - 'attrs' => $s['attrs'], + 'blockName' => $s['blockName'], + 'attrs' => $s['attrs'], 'innerBlocks' => $innerBlocks, - 'innerHTML' => implode( '', $innerHTML ), + 'innerHTML' => implode( '', $innerHTML ), ); } private function peg_f5($blockName, $attrs) { return array( 'blockName' => $blockName, - 'attrs' => $attrs, + 'attrs' => isset( $attrs ) ? $attrs : array(), ); } private function peg_f6($blockName) { @@ -1461,7 +1461,12 @@ function peg_join_blocks( $pre, $tokens, $post ) { $blocks = array(); if ( ! empty( $pre ) ) { - $blocks[] = array( 'attrs' => array(), 'innerHTML' => $pre ); + $blocks[] = array( + 'blockName' => 'core/freeform', + 'attrs' => array(), + 'innerBlocks' => array(), + 'innerHTML' => $pre + ); } foreach ( $tokens as $token ) { @@ -1470,12 +1475,22 @@ function peg_join_blocks( $pre, $tokens, $post ) { $blocks[] = $token; if ( ! empty( $html ) ) { - $blocks[] = array( 'attrs' => array(), 'innerHTML' => $html ); + $blocks[] = array( + 'blockName' => 'core/freeform', + 'attrs' => array(), + 'innerBlocks' => array(), + 'innerHTML' => $html + ); } } if ( ! empty( $post ) ) { - $blocks[] = array( 'attrs' => array(), 'innerHTML' => $post ); + $blocks[] = array( + 'blockName' => 'core/freeform', + 'attrs' => array(), + 'innerBlocks' => array(), + 'innerHTML' => $post + ); } return $blocks; diff --git a/packages/block-serialization-default-parser/parser.php b/packages/block-serialization-default-parser/parser.php index 9ea5b6ab78919..e39ade0ab29d9 100644 --- a/packages/block-serialization-default-parser/parser.php +++ b/packages/block-serialization-default-parser/parser.php @@ -121,6 +121,7 @@ function __construct( $block, $token_start, $token_length, $prev_offset = null, * Parses a document and constructs a list of parsed block objects * * @since 3.8.0 + * @since 4.0.0 returns arrays not objects, all attributes are arrays */ class WP_Block_Parser { /** @@ -244,17 +245,14 @@ function proceed() { */ if ( 0 === $stack_depth ) { if ( isset( $leading_html_start ) ) { - $this->output[] = array( - 'attrs' => array(), - 'innerHTML' => substr( - $this->document, - $leading_html_start, - $start_offset - $leading_html_start - ), - ); + $this->output[] = (array) self::freeform( substr( + $this->document, + $leading_html_start, + $start_offset - $leading_html_start + ) ); } - $this->output[] = new WP_Block_Parser_Block( $block_name, $attrs, array(), '' ); + $this->output[] = (array) new WP_Block_Parser_Block( $block_name, $attrs, array(), '' ); $this->offset = $start_offset + $token_length; return true; } @@ -370,7 +368,7 @@ function next_token() { $namespace = ( isset( $namespace ) && -1 !== $namespace[ 1 ] ) ? $namespace[ 0 ] : 'core/'; $name = $namespace . $matches[ 'name' ][ 0 ]; $has_attrs = isset( $matches[ 'attrs' ] ) && -1 !== $matches[ 'attrs' ][ 1 ]; - $attrs = $has_attrs ? json_decode( $matches[ 'attrs' ][ 0 ] ) : null; + $attrs = $has_attrs ? json_decode( $matches[ 'attrs' ][ 0 ], /* as-associative */ true ) : array(); /* * This state isn't allowed @@ -391,6 +389,19 @@ function next_token() { return array( 'block-opener', $name, $attrs, $started_at, $length ); } + /** + * Returns a new block object for freeform HTML + * + * @internal + * @since 3.9.0 + * + * @param string $innerHTML HTML content of block + * @return WP_Block_Parser_Block freeform block object + */ + static function freeform( $innerHTML ) { + return new WP_Block_Parser_Block( 'core/freeform', array(), array(), $innerHTML ); + } + /** * Pushes a length of text from the input document * to the output list as a freeform block @@ -406,10 +417,7 @@ function add_freeform( $length = null ) { return; } - $this->output[] = array( - 'attrs' => new stdClass(), - 'innerHTML' => substr( $this->document, $this->offset, $length ), - ); + $this->output[] = (array) self::freeform( substr( $this->document, $this->offset, $length ) ); } /** @@ -423,7 +431,7 @@ function add_freeform( $length = null ) { * @param int $token_length byte length of entire block from start of opening token to end of closing token * @param int|null $last_offset last byte offset into document if continuing form earlier output */ - function add_inner_block(WP_Block_Parser_Block $block, $token_start, $token_length, $last_offset = null ) { + function add_inner_block( WP_Block_Parser_Block $block, $token_start, $token_length, $last_offset = null ) { $parent = $this->stack[ count( $this->stack ) - 1 ]; $parent->block->innerBlocks[] = $block; $parent->block->innerHTML .= substr( $this->document, $parent->prev_offset, $token_start - $parent->prev_offset ); @@ -446,16 +454,13 @@ function add_block_from_stack( $end_offset = null ) { : substr( $this->document, $prev_offset ); if ( isset( $stack_top->leading_html_start ) ) { - $this->output[] = array( - 'attrs' => array(), - 'innerHTML' => substr( - $this->document, - $stack_top->leading_html_start, - $stack_top->token_start - $stack_top->leading_html_start - ), - ); + $this->output[] = (array) self::freeform( substr( + $this->document, + $stack_top->leading_html_start, + $stack_top->token_start - $stack_top->leading_html_start + ) ); } - $this->output[] = $stack_top->block; + $this->output[] = (array) $stack_top->block; } } diff --git a/packages/block-serialization-default-parser/src/index.js b/packages/block-serialization-default-parser/src/index.js index a4cec7aecd8ef..fef329298d384 100644 --- a/packages/block-serialization-default-parser/src/index.js +++ b/packages/block-serialization-default-parser/src/index.js @@ -13,6 +13,10 @@ function Block( blockName, attrs, innerBlocks, innerHTML ) { }; } +function Freeform( innerHTML ) { + return Block( 'core/freeform', {}, [], innerHTML ); +} + function Frame( block, tokenStart, tokenLength, prevOffset, leadingHtmlStart ) { return { block, @@ -78,10 +82,7 @@ function proceed() { // in the top-level of the document if ( 0 === stackDepth ) { if ( null !== leadingHtmlStart ) { - output.push( { - attrs: {}, - innerHTML: document.substr( leadingHtmlStart, startOffset - leadingHtmlStart ), - } ); + output.push( Freeform( document.substr( leadingHtmlStart, startOffset - leadingHtmlStart ) ) ); } output.push( Block( blockName, attrs, [], '' ) ); offset = startOffset + tokenLength; @@ -196,7 +197,7 @@ function nextToken() { const namespace = namespaceMatch || 'core/'; const name = namespace + nameMatch; const hasAttrs = !! attrsMatch; - const attrs = hasAttrs ? parseJSON( attrsMatch ) : null; + const attrs = hasAttrs ? parseJSON( attrsMatch ) : {}; // This state isn't allowed // This is an error @@ -223,14 +224,7 @@ function addFreeform( rawLength ) { return; } - // why is this not a Frame? it's because the current grammar - // specifies an object that's different. we can update the - // specification and change here if we want to but for now we - // want this parser to be spec-compliant - output.push( { - attrs: {}, - innerHTML: document.substr( offset, length ), - } ); + output.push( Freeform( document.substr( offset, length ) ) ); } function addInnerBlock( block, tokenStart, tokenLength, lastOffset ) { @@ -253,10 +247,7 @@ function addBlockFromStack( endOffset ) { } if ( null !== leadingHtmlStart ) { - output.push( { - attrs: {}, - innerHTML: document.substr( leadingHtmlStart, tokenStart - leadingHtmlStart ), - } ); + output.push( Freeform( document.substr( leadingHtmlStart, tokenStart - leadingHtmlStart ) ) ); } output.push( block ); diff --git a/packages/block-serialization-spec-parser/grammar.pegjs b/packages/block-serialization-spec-parser/grammar.pegjs index aa1dc1b70a29e..ece4a45600a49 100644 --- a/packages/block-serialization-spec-parser/grammar.pegjs +++ b/packages/block-serialization-spec-parser/grammar.pegjs @@ -71,7 +71,12 @@ if ( ! function_exists( 'peg_join_blocks' ) ) { $blocks = array(); if ( ! empty( $pre ) ) { - $blocks[] = array( 'attrs' => array(), 'innerHTML' => $pre ); + $blocks[] = array( + 'blockName' => 'core/freeform', + 'attrs' => array(), + 'innerBlocks' => array(), + 'innerHTML' => $pre + ); } foreach ( $tokens as $token ) { @@ -80,12 +85,22 @@ if ( ! function_exists( 'peg_join_blocks' ) ) { $blocks[] = $token; if ( ! empty( $html ) ) { - $blocks[] = array( 'attrs' => array(), 'innerHTML' => $html ); + $blocks[] = array( + 'blockName' => 'core/freeform', + 'attrs' => array(), + 'innerBlocks' => array(), + 'innerHTML' => $html + ); } } if ( ! empty( $post ) ) { - $blocks[] = array( 'attrs' => array(), 'innerHTML' => $post ); + $blocks[] = array( + 'blockName' => 'core/freeform', + 'attrs' => array(), + 'innerBlocks' => array(), + 'innerHTML' => $post + ); } return $blocks; @@ -96,8 +111,10 @@ if ( ! function_exists( 'peg_join_blocks' ) ) { function freeform( s ) { return s.length && { + blockName: 'core/freeform', attrs: {}, - innerHTML: s + innerBlocks: [], + innerHTML: s, }; } @@ -180,16 +197,16 @@ Block_Void { /** $blockName, - 'attrs' => $attrs, + 'blockName' => $blockName, + 'attrs' => isset( $attrs ) ? $attrs : array(), 'innerBlocks' => array(), - 'innerHTML' => '', + 'innerHTML' => '', ); ?> **/ return { blockName: blockName, - attrs: attrs, + attrs: attrs || {}, innerBlocks: [], innerHTML: '' }; @@ -202,10 +219,10 @@ Block_Balanced list( $innerHTML, $innerBlocks ) = peg_array_partition( $children, 'is_string' ); return array( - 'blockName' => $s['blockName'], - 'attrs' => $s['attrs'], + 'blockName' => $s['blockName'], + 'attrs' => $s['attrs'], 'innerBlocks' => $innerBlocks, - 'innerHTML' => implode( '', $innerHTML ), + 'innerHTML' => implode( '', $innerHTML ), ); ?> **/ @@ -230,13 +247,13 @@ Block_Start /** $blockName, - 'attrs' => $attrs, + 'attrs' => isset( $attrs ) ? $attrs : array(), ); ?> **/ return { blockName: blockName, - attrs: attrs + attrs: attrs || {} }; } diff --git a/packages/block-serialization-spec-parser/index.js b/packages/block-serialization-spec-parser/index.js index 95a476bc3cbdb..5106a8b87d4e4 100644 --- a/packages/block-serialization-spec-parser/index.js +++ b/packages/block-serialization-spec-parser/index.js @@ -165,16 +165,16 @@ peg$c10 = function(blockName, attrs) { /** $blockName, - 'attrs' => $attrs, + 'blockName' => $blockName, + 'attrs' => isset( $attrs ) ? $attrs : array(), 'innerBlocks' => array(), - 'innerHTML' => '', + 'innerHTML' => '', ); ?> **/ return { blockName: blockName, - attrs: attrs, + attrs: attrs || {}, innerBlocks: [], innerHTML: '' }; @@ -184,10 +184,10 @@ list( $innerHTML, $innerBlocks ) = peg_array_partition( $children, 'is_string' ); return array( - 'blockName' => $s['blockName'], - 'attrs' => $s['attrs'], + 'blockName' => $s['blockName'], + 'attrs' => $s['attrs'], 'innerBlocks' => $innerBlocks, - 'innerHTML' => implode( '', $innerHTML ), + 'innerHTML' => implode( '', $innerHTML ), ); ?> **/ @@ -208,13 +208,13 @@ /** $blockName, - 'attrs' => $attrs, + 'attrs' => isset( $attrs ) ? $attrs : array(), ); ?> **/ return { blockName: blockName, - attrs: attrs + attrs: attrs || {} }; }, peg$c15 = "/wp:", @@ -1498,7 +1498,12 @@ $blocks = array(); if ( ! empty( $pre ) ) { - $blocks[] = array( 'attrs' => array(), 'innerHTML' => $pre ); + $blocks[] = array( + 'blockName' => 'core/freeform', + 'attrs' => array(), + 'innerBlocks' => array(), + 'innerHTML' => $pre + ); } foreach ( $tokens as $token ) { @@ -1507,12 +1512,22 @@ $blocks[] = $token; if ( ! empty( $html ) ) { - $blocks[] = array( 'attrs' => array(), 'innerHTML' => $html ); + $blocks[] = array( + 'blockName' => 'core/freeform', + 'attrs' => array(), + 'innerBlocks' => array(), + 'innerHTML' => $html + ); } } if ( ! empty( $post ) ) { - $blocks[] = array( 'attrs' => array(), 'innerHTML' => $post ); + $blocks[] = array( + 'blockName' => 'core/freeform', + 'attrs' => array(), + 'innerBlocks' => array(), + 'innerHTML' => $post + ); } return $blocks; @@ -1523,8 +1538,10 @@ function freeform( s ) { return s.length && { + blockName: 'core/freeform', attrs: {}, - innerHTML: s + innerBlocks: [], + innerHTML: s, }; }