112 * its registered type will be assigned to the block's `context` property. |
112 * its registered type will be assigned to the block's `context` property. |
113 * |
113 * |
114 * @since 5.5.0 |
114 * @since 5.5.0 |
115 * |
115 * |
116 * @param array $block { |
116 * @param array $block { |
117 * A representative array of a single parsed block object. See WP_Block_Parser_Block. |
117 * An associative array of a single parsed block object. See WP_Block_Parser_Block. |
118 * |
118 * |
119 * @type string $blockName Name of block. |
119 * @type string $blockName Name of block. |
120 * @type array $attrs Attributes from block comment delimiters. |
120 * @type array $attrs Attributes from block comment delimiters. |
121 * @type array $innerBlocks List of inner blocks. An array of arrays that |
121 * @type array $innerBlocks List of inner blocks. An array of arrays that |
122 * have the same structure as this one. |
122 * have the same structure as this one. |
138 |
138 |
139 $this->block_type = $registry->get_registered( $this->name ); |
139 $this->block_type = $registry->get_registered( $this->name ); |
140 |
140 |
141 $this->available_context = $available_context; |
141 $this->available_context = $available_context; |
142 |
142 |
|
143 $this->refresh_context_dependents(); |
|
144 } |
|
145 |
|
146 /** |
|
147 * Updates the context for the current block and its inner blocks. |
|
148 * |
|
149 * The method updates the context of inner blocks, if any, by passing down |
|
150 * any context values the block provides (`provides_context`). |
|
151 * |
|
152 * If the block has inner blocks, the method recursively processes them by creating new instances of `WP_Block` |
|
153 * for each inner block and updating their context based on the block's `provides_context` property. |
|
154 * |
|
155 * @since 6.8.0 |
|
156 */ |
|
157 public function refresh_context_dependents() { |
|
158 /* |
|
159 * Merging the `$context` property here is not ideal, but for now needs to happen because of backward compatibility. |
|
160 * Ideally, the `$context` property itself would not be filterable directly and only the `$available_context` would be filterable. |
|
161 * However, this needs to be separately explored whether it's possible without breakage. |
|
162 */ |
|
163 $this->available_context = array_merge( $this->available_context, $this->context ); |
|
164 |
143 if ( ! empty( $this->block_type->uses_context ) ) { |
165 if ( ! empty( $this->block_type->uses_context ) ) { |
144 foreach ( $this->block_type->uses_context as $context_name ) { |
166 foreach ( $this->block_type->uses_context as $context_name ) { |
145 if ( array_key_exists( $context_name, $this->available_context ) ) { |
167 if ( array_key_exists( $context_name, $this->available_context ) ) { |
146 $this->context[ $context_name ] = $this->available_context[ $context_name ]; |
168 $this->context[ $context_name ] = $this->available_context[ $context_name ]; |
147 } |
169 } |
148 } |
170 } |
149 } |
171 } |
150 |
172 |
151 if ( ! empty( $block['innerBlocks'] ) ) { |
173 $this->refresh_parsed_block_dependents(); |
|
174 } |
|
175 |
|
176 /** |
|
177 * Updates the parsed block content for the current block and its inner blocks. |
|
178 * |
|
179 * This method sets the `inner_html` and `inner_content` properties of the block based on the parsed |
|
180 * block content provided during initialization. It ensures that the block instance reflects the |
|
181 * most up-to-date content for both the inner HTML and any string fragments around inner blocks. |
|
182 * |
|
183 * If the block has inner blocks, this method initializes a new `WP_Block_List` for them, ensuring the |
|
184 * correct content and context are updated for each nested block. |
|
185 * |
|
186 * @since 6.8.0 |
|
187 */ |
|
188 public function refresh_parsed_block_dependents() { |
|
189 if ( ! empty( $this->parsed_block['innerBlocks'] ) ) { |
152 $child_context = $this->available_context; |
190 $child_context = $this->available_context; |
153 |
191 |
154 if ( ! empty( $this->block_type->provides_context ) ) { |
192 if ( ! empty( $this->block_type->provides_context ) ) { |
155 foreach ( $this->block_type->provides_context as $context_name => $attribute_name ) { |
193 foreach ( $this->block_type->provides_context as $context_name => $attribute_name ) { |
156 if ( array_key_exists( $attribute_name, $this->attributes ) ) { |
194 if ( array_key_exists( $attribute_name, $this->attributes ) ) { |
157 $child_context[ $context_name ] = $this->attributes[ $attribute_name ]; |
195 $child_context[ $context_name ] = $this->attributes[ $attribute_name ]; |
158 } |
196 } |
159 } |
197 } |
160 } |
198 } |
161 |
199 |
162 $this->inner_blocks = new WP_Block_List( $block['innerBlocks'], $child_context, $registry ); |
200 $this->inner_blocks = new WP_Block_List( $this->parsed_block['innerBlocks'], $child_context, $this->registry ); |
163 } |
201 } |
164 |
202 |
165 if ( ! empty( $block['innerHTML'] ) ) { |
203 if ( ! empty( $this->parsed_block['innerHTML'] ) ) { |
166 $this->inner_html = $block['innerHTML']; |
204 $this->inner_html = $this->parsed_block['innerHTML']; |
167 } |
205 } |
168 |
206 |
169 if ( ! empty( $block['innerContent'] ) ) { |
207 if ( ! empty( $this->parsed_block['innerContent'] ) ) { |
170 $this->inner_content = $block['innerContent']; |
208 $this->inner_content = $this->parsed_block['innerContent']; |
171 } |
209 } |
172 } |
210 } |
173 |
211 |
174 /** |
212 /** |
175 * Returns a value from an inaccessible property. |
213 * Returns a value from an inaccessible property. |
235 * The above example will replace the `title` and `url` attributes of the Image |
273 * The above example will replace the `title` and `url` attributes of the Image |
236 * block with the values of the `text_custom_field` and `url_custom_field` post meta. |
274 * block with the values of the `text_custom_field` and `url_custom_field` post meta. |
237 * |
275 * |
238 * @since 6.5.0 |
276 * @since 6.5.0 |
239 * @since 6.6.0 Handle the `__default` attribute for pattern overrides. |
277 * @since 6.6.0 Handle the `__default` attribute for pattern overrides. |
|
278 * @since 6.7.0 Return any updated bindings metadata in the computed attributes. |
240 * |
279 * |
241 * @return array The computed block attributes for the provided block bindings. |
280 * @return array The computed block attributes for the provided block bindings. |
242 */ |
281 */ |
243 private function process_block_bindings() { |
282 private function process_block_bindings() { |
244 $parsed_block = $this->parsed_block; |
283 $parsed_block = $this->parsed_block; |
282 $updated_bindings[ $attribute_name ] = isset( $bindings[ $attribute_name ] ) |
321 $updated_bindings[ $attribute_name ] = isset( $bindings[ $attribute_name ] ) |
283 ? $bindings[ $attribute_name ] |
322 ? $bindings[ $attribute_name ] |
284 : array( 'source' => 'core/pattern-overrides' ); |
323 : array( 'source' => 'core/pattern-overrides' ); |
285 } |
324 } |
286 $bindings = $updated_bindings; |
325 $bindings = $updated_bindings; |
|
326 /* |
|
327 * Update the bindings metadata of the computed attributes. |
|
328 * This ensures the block receives the expanded __default binding metadata when it renders. |
|
329 */ |
|
330 $computed_attributes['metadata'] = array_merge( |
|
331 $parsed_block['attrs']['metadata'], |
|
332 array( 'bindings' => $bindings ) |
|
333 ); |
287 } |
334 } |
288 |
335 |
289 foreach ( $bindings as $attribute_name => $block_binding ) { |
336 foreach ( $bindings as $attribute_name => $block_binding ) { |
290 // If the attribute is not in the supported list, process next attribute. |
337 // If the attribute is not in the supported list, process next attribute. |
291 if ( ! in_array( $attribute_name, $supported_block_attributes[ $this->name ], true ) ) { |
338 if ( ! in_array( $attribute_name, $supported_block_attributes[ $this->name ], true ) ) { |
297 } |
344 } |
298 |
345 |
299 $block_binding_source = get_block_bindings_source( $block_binding['source'] ); |
346 $block_binding_source = get_block_bindings_source( $block_binding['source'] ); |
300 if ( null === $block_binding_source ) { |
347 if ( null === $block_binding_source ) { |
301 continue; |
348 continue; |
|
349 } |
|
350 |
|
351 // Adds the necessary context defined by the source. |
|
352 if ( ! empty( $block_binding_source->uses_context ) ) { |
|
353 foreach ( $block_binding_source->uses_context as $context_name ) { |
|
354 if ( array_key_exists( $context_name, $this->available_context ) ) { |
|
355 $this->context[ $context_name ] = $this->available_context[ $context_name ]; |
|
356 } |
|
357 } |
302 } |
358 } |
303 |
359 |
304 $source_args = ! empty( $block_binding['args'] ) && is_array( $block_binding['args'] ) ? $block_binding['args'] : array(); |
360 $source_args = ! empty( $block_binding['args'] ) && is_array( $block_binding['args'] ) ? $block_binding['args'] : array(); |
305 $source_value = $block_binding_source->get_value( $source_args, $this, $attribute_name ); |
361 $source_value = $block_binding_source->get_value( $source_args, $this, $attribute_name ); |
306 |
362 |
354 } |
410 } |
355 } |
411 } |
356 |
412 |
357 foreach ( $selectors as $selector ) { |
413 foreach ( $selectors as $selector ) { |
358 // If the parent tag, or any of its children, matches the selector, replace the HTML. |
414 // If the parent tag, or any of its children, matches the selector, replace the HTML. |
359 if ( strcasecmp( $block_reader->get_tag( $selector ), $selector ) === 0 || $block_reader->next_tag( |
415 if ( strcasecmp( $block_reader->get_tag(), $selector ) === 0 || $block_reader->next_tag( |
360 array( |
416 array( |
361 'tag_name' => $selector, |
417 'tag_name' => $selector, |
362 ) |
418 ) |
363 ) ) { |
419 ) ) { |
364 $block_reader->release_bookmark( 'iterate-selectors' ); |
420 $block_reader->release_bookmark( 'iterate-selectors' ); |
486 $pre_render = apply_filters( 'pre_render_block', null, $inner_block->parsed_block, $parent_block ); |
542 $pre_render = apply_filters( 'pre_render_block', null, $inner_block->parsed_block, $parent_block ); |
487 |
543 |
488 if ( ! is_null( $pre_render ) ) { |
544 if ( ! is_null( $pre_render ) ) { |
489 $block_content .= $pre_render; |
545 $block_content .= $pre_render; |
490 } else { |
546 } else { |
491 $source_block = $inner_block->parsed_block; |
547 $source_block = $inner_block->parsed_block; |
|
548 $inner_block_context = $inner_block->context; |
492 |
549 |
493 /** This filter is documented in wp-includes/blocks.php */ |
550 /** This filter is documented in wp-includes/blocks.php */ |
494 $inner_block->parsed_block = apply_filters( 'render_block_data', $inner_block->parsed_block, $source_block, $parent_block ); |
551 $inner_block->parsed_block = apply_filters( 'render_block_data', $inner_block->parsed_block, $source_block, $parent_block ); |
495 |
552 |
496 /** This filter is documented in wp-includes/blocks.php */ |
553 /** This filter is documented in wp-includes/blocks.php */ |
497 $inner_block->context = apply_filters( 'render_block_context', $inner_block->context, $inner_block->parsed_block, $parent_block ); |
554 $inner_block->context = apply_filters( 'render_block_context', $inner_block->context, $inner_block->parsed_block, $parent_block ); |
|
555 |
|
556 /* |
|
557 * The `refresh_context_dependents()` method already calls `refresh_parsed_block_dependents()`. |
|
558 * Therefore the second condition is irrelevant if the first one is satisfied. |
|
559 */ |
|
560 if ( $inner_block->context !== $inner_block_context ) { |
|
561 $inner_block->refresh_context_dependents(); |
|
562 } elseif ( $inner_block->parsed_block !== $source_block ) { |
|
563 $inner_block->refresh_parsed_block_dependents(); |
|
564 } |
498 |
565 |
499 $block_content .= $inner_block->render(); |
566 $block_content .= $inner_block->render(); |
500 } |
567 } |
501 |
568 |
502 ++$index; |
569 ++$index; |
539 foreach ( $this->block_type->view_script_module_ids as $view_script_module_id ) { |
606 foreach ( $this->block_type->view_script_module_ids as $view_script_module_id ) { |
540 wp_enqueue_script_module( $view_script_module_id ); |
607 wp_enqueue_script_module( $view_script_module_id ); |
541 } |
608 } |
542 } |
609 } |
543 |
610 |
|
611 /* |
|
612 * For Core blocks, these styles are only enqueued if `wp_should_load_separate_core_block_assets()` returns |
|
613 * true. Otherwise these `wp_enqueue_style()` calls will not have any effect, as the Core blocks are relying on |
|
614 * the combined 'wp-block-library' stylesheet instead, which is unconditionally enqueued. |
|
615 */ |
544 if ( ( ! empty( $this->block_type->style_handles ) ) ) { |
616 if ( ( ! empty( $this->block_type->style_handles ) ) ) { |
545 foreach ( $this->block_type->style_handles as $style_handle ) { |
617 foreach ( $this->block_type->style_handles as $style_handle ) { |
546 wp_enqueue_style( $style_handle ); |
618 wp_enqueue_style( $style_handle ); |
547 } |
619 } |
548 } |
620 } |