diff --git a/src/wp-includes/class-wp-block-parser.php b/src/wp-includes/class-wp-block-parser.php index a38007ae6ad03..543f53691ccb1 100644 --- a/src/wp-includes/class-wp-block-parser.php +++ b/src/wp-includes/class-wp-block-parser.php @@ -343,7 +343,7 @@ public function add_freeform( $length = null ) { */ public 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[] = (array) $this->add_html_attributes_to_block( $block ); + $parent->block->innerBlocks[] = (array) $block; $html = substr( $this->document, $parent->prev_offset, $token_start - $parent->prev_offset ); if ( ! empty( $html ) ) { @@ -385,74 +385,7 @@ public function add_block_from_stack( $end_offset = null ) { ); } - $this->output[] = (array) $this->add_html_attributes_to_block( $stack_top->block ); - } - - private function add_html_attributes_to_block( WP_Block_Parser_Block $block ): WP_Block_Parser_Block { - //phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - if ( ! isset( $block->blockName ) ) { - return $block; - } - - if ( '' === $block->innerHTML ) { - return $block; - } - - $block_registry = WP_Block_Type_Registry::get_instance(); - if ( null === $block_registry ) { - return $block; - } - - $block_type = $block_registry->get_registered( $block->blockName ); - if ( null === $block_type || ! isset( $block_type->attributes ) ) { - return $block; - } - - foreach ( $block_type->attributes as $attribute_name => $attribute ) { - if ( ! isset( $attribute['selector'] ) ) { - continue; - } - if ( ! isset( $block->attrs[ $attribute_name ] ) ) { - $processor = WP_HTML_Processor::create_fragment( $block->innerHTML ); - $selector = $attribute['selector']; - - // This is a workaround for a known unsupported selector in a core block. - if ( 'a:not([download])' === $selector ) { - $selector = 'a'; - } - - foreach ( $processor->select_all( $selector ) as $_ ) { - // This is a workaround for a known unsupported selector in a core block. - if ( - 'a:not([download])' === $attribute['selector'] && - null !== $processor->get_attribute( 'download' ) - ) { - continue; - } - - switch ( $attribute['source'] ) { - case 'attribute': - $attr_value = $processor->get_attribute( $attribute['attribute'] ); - if ( null === $attr_value ) { - continue 2; - } - if ( null === $block->attrs ) { - $block->attrs = array(); - } - // This could be null, string, true, check what JS parser does. - $block->attrs[ $attribute_name ] = $attr_value; - break; - - // @todo see about supporting these. - case 'text': - case 'rich-text': - case 'query': - break; - } - } - } - } - return $block; + $this->output[] = (array) $stack_top->block; } } diff --git a/src/wp-includes/class-wp-block-type.php b/src/wp-includes/class-wp-block-type.php index 6916f6a462981..6e3fde5d87b10 100644 --- a/src/wp-includes/class-wp-block-type.php +++ b/src/wp-includes/class-wp-block-type.php @@ -532,6 +532,76 @@ public function prepare_attributes_for_render( $attributes ) { return $attributes; } + /** + * Adds sourced attributes from the parsed block to the block attributes. + * + * @since TBD + * + * @param array $attributes Original block attributes. + * @param array $parsed_block Parsed block. + * @return array Prepared block attributes. + */ + public function add_sourced_attributes_from_parsed_block( $attributes, $parsed_block ) { + // If there are no attribute definitions for the block type, skip + // processing and return verbatim. + if ( ! isset( $this->attributes ) ) { + return $attributes; + } + + // Sourced attributes are extracted from the block's HTML. If there's no + // HTML, there's nothing to do. + if ( '' === $parsed_block['innerHTML'] ) { + return $attributes; + } + + foreach ( $this->attributes as $attribute_name => $attribute_definition ) { + if ( + ! isset( $attribute_definition['source'] ) || + 'attribute' !== $attribute_definition['source'] || + ! is_string( $attribute_definition['attribute'] ) || + ! isset( $attribute_definition['selector'] ) || + + // @todo what to do if it's in serialized attributes already? Skip for now. + isset( $attributes[ $attribute_name ] ) + ) { + continue; + } + + $processor = WP_HTML_Processor::create_fragment( $parsed_block['innerHTML'] ); + if ( null === $processor ) { + continue; + } + + $selector = $attribute_definition['selector']; + + // This is a workaround for a known unsupported selector in a core block. + if ( 'a:not([download])' === $selector ) { + $selector = 'a'; + } + + foreach ( $processor->select_all( $selector ) as $_ ) { + // This is a workaround for a known unsupported selector in a core block. + if ( + 'a:not([download])' === $attribute_definition['selector'] && + null !== $processor->get_attribute( 'download' ) + ) { + continue; + } + + $value = $processor->get_attribute( $attribute_definition['attribute'] ); + if ( null === $value ) { + continue 2; + } + + // @todo another function validates value types, is that sufficient? + $attributes[ $attribute_name ] = $value; + + } + } + + return $attributes; + } + /** * Sets block type properties. * diff --git a/src/wp-includes/class-wp-block.php b/src/wp-includes/class-wp-block.php index a1c52019c29a5..01edb92cff23d 100644 --- a/src/wp-includes/class-wp-block.php +++ b/src/wp-includes/class-wp-block.php @@ -191,7 +191,8 @@ public function __get( $name ) { array(); if ( ! is_null( $this->block_type ) ) { - $this->attributes = $this->block_type->prepare_attributes_for_render( $this->attributes ); + $this->attributes = $this->block_type->add_sourced_attributes_from_parsed_block( $this->attributes, $this->parsed_block ); + $this->attributes = $this->block_type->prepare_attributes_for_render( $this->attributes, $this->parsed_block ); } return $this->attributes;