[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> class-wp-block.php (source)

   1  <?php
   2  /**
   3   * Blocks API: WP_Block class
   4   *
   5   * @package WordPress
   6   * @since 5.5.0
   7   */
   8  
   9  /**
  10   * Class representing a parsed instance of a block.
  11   *
  12   * @since 5.5.0
  13   * @property array $attributes
  14   */
  15  #[AllowDynamicProperties]
  16  class WP_Block {
  17  
  18      /**
  19       * Original parsed array representation of block.
  20       *
  21       * @since 5.5.0
  22       * @var array
  23       */
  24      public $parsed_block;
  25  
  26      /**
  27       * Name of block.
  28       *
  29       * @example "core/paragraph"
  30       *
  31       * @since 5.5.0
  32       * @var string|null
  33       */
  34      public $name;
  35  
  36      /**
  37       * Block type associated with the instance.
  38       *
  39       * @since 5.5.0
  40       * @var WP_Block_Type
  41       */
  42      public $block_type;
  43  
  44      /**
  45       * Block context values.
  46       *
  47       * @since 5.5.0
  48       * @var array
  49       */
  50      public $context = array();
  51  
  52      /**
  53       * All available context of the current hierarchy.
  54       *
  55       * @since 5.5.0
  56       * @var array
  57       */
  58      protected $available_context = array();
  59  
  60      /**
  61       * Block type registry.
  62       *
  63       * @since 5.9.0
  64       * @var WP_Block_Type_Registry
  65       */
  66      protected $registry;
  67  
  68      /**
  69       * List of inner blocks (of this same class)
  70       *
  71       * @since 5.5.0
  72       * @var WP_Block_List
  73       */
  74      public $inner_blocks = array();
  75  
  76      /**
  77       * Resultant HTML from inside block comment delimiters after removing inner
  78       * blocks.
  79       *
  80       * @example "...Just <!-- wp:test /--> testing..." -> "Just testing..."
  81       *
  82       * @since 5.5.0
  83       * @var string
  84       */
  85      public $inner_html = '';
  86  
  87      /**
  88       * List of string fragments and null markers where inner blocks were found
  89       *
  90       * @example array(
  91       *   'inner_html'    => 'BeforeInnerAfter',
  92       *   'inner_blocks'  => array( block, block ),
  93       *   'inner_content' => array( 'Before', null, 'Inner', null, 'After' ),
  94       * )
  95       *
  96       * @since 5.5.0
  97       * @var array
  98       */
  99      public $inner_content = array();
 100  
 101      /**
 102       * List of supported block attributes for block bindings.
 103       *
 104       * @since 6.9.0
 105       * @var array
 106       *
 107       * @see WP_Block::process_block_bindings()
 108       */
 109      private const BLOCK_BINDINGS_SUPPORTED_ATTRIBUTES = array(
 110          'core/paragraph' => array( 'content' ),
 111          'core/heading'   => array( 'content' ),
 112          'core/image'     => array( 'id', 'url', 'title', 'alt' ),
 113          'core/button'    => array( 'url', 'text', 'linkTarget', 'rel' ),
 114          'core/post-date' => array( 'datetime' ),
 115      );
 116  
 117      /**
 118       * Constructor.
 119       *
 120       * Populates object properties from the provided block instance argument.
 121       *
 122       * The given array of context values will not necessarily be available on
 123       * the instance itself, but is treated as the full set of values provided by
 124       * the block's ancestry. This is assigned to the private `available_context`
 125       * property. Only values which are configured to consumed by the block via
 126       * its registered type will be assigned to the block's `context` property.
 127       *
 128       * @since 5.5.0
 129       *
 130       * @param array                  $block             {
 131       *     An associative array of a single parsed block object. See WP_Block_Parser_Block.
 132       *
 133       *     @type string|null $blockName    Name of block.
 134       *     @type array       $attrs        Attributes from block comment delimiters.
 135       *     @type array       $innerBlocks  List of inner blocks. An array of arrays that
 136       *                                     have the same structure as this one.
 137       *     @type string      $innerHTML    HTML from inside block comment delimiters.
 138       *     @type array       $innerContent List of string fragments and null markers where inner blocks were found.
 139       * }
 140       * @param array                  $available_context Optional array of ancestry context values.
 141       * @param WP_Block_Type_Registry $registry          Optional block type registry.
 142       */
 143  	public function __construct( $block, $available_context = array(), $registry = null ) {
 144          $this->parsed_block = $block;
 145          $this->name         = $block['blockName'];
 146  
 147          if ( is_null( $registry ) ) {
 148              $registry = WP_Block_Type_Registry::get_instance();
 149          }
 150  
 151          $this->registry = $registry;
 152  
 153          $this->block_type = $registry->get_registered( $this->name );
 154  
 155          $this->available_context = $available_context;
 156  
 157          $this->refresh_context_dependents();
 158      }
 159  
 160      /**
 161       * Updates the context for the current block and its inner blocks.
 162       *
 163       * The method updates the context of inner blocks, if any, by passing down
 164       * any context values the block provides (`provides_context`).
 165       *
 166       * If the block has inner blocks, the method recursively processes them by creating new instances of `WP_Block`
 167       * for each inner block and updating their context based on the block's `provides_context` property.
 168       *
 169       * @since 6.8.0
 170       */
 171  	public function refresh_context_dependents() {
 172          /*
 173           * Merging the `$context` property here is not ideal, but for now needs to happen because of backward compatibility.
 174           * Ideally, the `$context` property itself would not be filterable directly and only the `$available_context` would be filterable.
 175           * However, this needs to be separately explored whether it's possible without breakage.
 176           */
 177          $this->available_context = array_merge( $this->available_context, $this->context );
 178  
 179          if ( ! empty( $this->block_type->uses_context ) ) {
 180              foreach ( $this->block_type->uses_context as $context_name ) {
 181                  if ( array_key_exists( $context_name, $this->available_context ) ) {
 182                      $this->context[ $context_name ] = $this->available_context[ $context_name ];
 183                  }
 184              }
 185          }
 186  
 187          $this->refresh_parsed_block_dependents();
 188      }
 189  
 190      /**
 191       * Updates the parsed block content for the current block and its inner blocks.
 192       *
 193       * This method sets the `inner_html` and `inner_content` properties of the block based on the parsed
 194       * block content provided during initialization. It ensures that the block instance reflects the
 195       * most up-to-date content for both the inner HTML and any string fragments around inner blocks.
 196       *
 197       * If the block has inner blocks, this method initializes a new `WP_Block_List` for them, ensuring the
 198       * correct content and context are updated for each nested block.
 199       *
 200       * @since 6.8.0
 201       */
 202  	public function refresh_parsed_block_dependents() {
 203          if ( ! empty( $this->parsed_block['innerBlocks'] ) ) {
 204              $child_context = $this->available_context;
 205  
 206              if ( ! empty( $this->block_type->provides_context ) ) {
 207                  foreach ( $this->block_type->provides_context as $context_name => $attribute_name ) {
 208                      if ( array_key_exists( $attribute_name, $this->attributes ) ) {
 209                          $child_context[ $context_name ] = $this->attributes[ $attribute_name ];
 210                      }
 211                  }
 212              }
 213  
 214              $this->inner_blocks = new WP_Block_List( $this->parsed_block['innerBlocks'], $child_context, $this->registry );
 215          }
 216  
 217          if ( ! empty( $this->parsed_block['innerHTML'] ) ) {
 218              $this->inner_html = $this->parsed_block['innerHTML'];
 219          }
 220  
 221          if ( ! empty( $this->parsed_block['innerContent'] ) ) {
 222              $this->inner_content = $this->parsed_block['innerContent'];
 223          }
 224      }
 225  
 226      /**
 227       * Returns a value from an inaccessible property.
 228       *
 229       * This is used to lazily initialize the `attributes` property of a block,
 230       * such that it is only prepared with default attributes at the time that
 231       * the property is accessed. For all other inaccessible properties, a `null`
 232       * value is returned.
 233       *
 234       * @since 5.5.0
 235       *
 236       * @param string $name Property name.
 237       * @return array|null Prepared attributes, or null.
 238       */
 239  	public function __get( $name ) {
 240          if ( 'attributes' === $name ) {
 241              $this->attributes = isset( $this->parsed_block['attrs'] ) ?
 242                  $this->parsed_block['attrs'] :
 243                  array();
 244  
 245              if ( ! is_null( $this->block_type ) ) {
 246                  $this->attributes = $this->block_type->prepare_attributes_for_render( $this->attributes );
 247              }
 248  
 249              return $this->attributes;
 250          }
 251  
 252          return null;
 253      }
 254  
 255      /**
 256       * Processes the block bindings and updates the block attributes with the values from the sources.
 257       *
 258       * A block might contain bindings in its attributes. Bindings are mappings
 259       * between an attribute of the block and a source. A "source" is a function
 260       * registered with `register_block_bindings_source()` that defines how to
 261       * retrieve a value from outside the block, e.g. from post meta.
 262       *
 263       * This function will process those bindings and update the block's attributes
 264       * with the values coming from the bindings.
 265       *
 266       * ### Example
 267       *
 268       * The "bindings" property for an Image block might look like this:
 269       *
 270       * ```json
 271       * {
 272       *   "metadata": {
 273       *     "bindings": {
 274       *       "title": {
 275       *         "source": "core/post-meta",
 276       *         "args": { "key": "text_custom_field" }
 277       *       },
 278       *       "url": {
 279       *         "source": "core/post-meta",
 280       *         "args": { "key": "url_custom_field" }
 281       *       }
 282       *     }
 283       *   }
 284       * }
 285       * ```
 286       *
 287       * The above example will replace the `title` and `url` attributes of the Image
 288       * block with the values of the `text_custom_field` and `url_custom_field` post meta.
 289       *
 290       * @since 6.5.0
 291       * @since 6.6.0 Handle the `__default` attribute for pattern overrides.
 292       * @since 6.7.0 Return any updated bindings metadata in the computed attributes.
 293       *
 294       * @return array The computed block attributes for the provided block bindings.
 295       */
 296  	private function process_block_bindings() {
 297          $block_type                 = $this->name;
 298          $parsed_block               = $this->parsed_block;
 299          $computed_attributes        = array();
 300  
 301          $supported_block_attributes =
 302              self::BLOCK_BINDINGS_SUPPORTED_ATTRIBUTES[ $block_type ] ??
 303              array();
 304  
 305          /**
 306           * Filters the supported block attributes for block bindings.
 307           *
 308           * The dynamic portion of the hook name, `$block_type`, refers to the block type
 309           * whose attributes are being filtered.
 310           *
 311           * @since 6.9.0
 312           *
 313           * @param string[] $supported_block_attributes The block's attributes that are supported by block bindings.
 314           */
 315          $supported_block_attributes = apply_filters(
 316              "block_bindings_supported_attributes_{$block_type}",
 317              $supported_block_attributes
 318          );
 319  
 320          // If the block doesn't have the bindings property, isn't one of the supported
 321          // block types, or the bindings property is not an array, return the block content.
 322          if (
 323              empty( $supported_block_attributes ) ||
 324              empty( $parsed_block['attrs']['metadata']['bindings'] ) ||
 325              ! is_array( $parsed_block['attrs']['metadata']['bindings'] )
 326          ) {
 327              return $computed_attributes;
 328          }
 329  
 330          $bindings = $parsed_block['attrs']['metadata']['bindings'];
 331  
 332          /*
 333           * If the default binding is set for pattern overrides, replace it
 334           * with a pattern override binding for all supported attributes.
 335           */
 336          if (
 337              isset( $bindings['__default']['source'] ) &&
 338              'core/pattern-overrides' === $bindings['__default']['source']
 339          ) {
 340              $updated_bindings = array();
 341  
 342              /*
 343               * Build a binding array of all supported attributes.
 344               * Note that this also omits the `__default` attribute from the
 345               * resulting array.
 346               */
 347              foreach ( $supported_block_attributes as $attribute_name ) {
 348                  // Retain any non-pattern override bindings that might be present.
 349                  $updated_bindings[ $attribute_name ] = isset( $bindings[ $attribute_name ] )
 350                      ? $bindings[ $attribute_name ]
 351                      : array( 'source' => 'core/pattern-overrides' );
 352              }
 353              $bindings = $updated_bindings;
 354              /*
 355               * Update the bindings metadata of the computed attributes.
 356               * This ensures the block receives the expanded __default binding metadata when it renders.
 357               */
 358              $computed_attributes['metadata'] = array_merge(
 359                  $parsed_block['attrs']['metadata'],
 360                  array( 'bindings' => $bindings )
 361              );
 362          }
 363  
 364          foreach ( $bindings as $attribute_name => $block_binding ) {
 365              // If the attribute is not in the supported list, process next attribute.
 366              if ( ! in_array( $attribute_name, $supported_block_attributes, true ) ) {
 367                  continue;
 368              }
 369              // If no source is provided, or that source is not registered, process next attribute.
 370              if ( ! isset( $block_binding['source'] ) || ! is_string( $block_binding['source'] ) ) {
 371                  continue;
 372              }
 373  
 374              $block_binding_source = get_block_bindings_source( $block_binding['source'] );
 375              if ( null === $block_binding_source ) {
 376                  continue;
 377              }
 378  
 379              // Adds the necessary context defined by the source.
 380              if ( ! empty( $block_binding_source->uses_context ) ) {
 381                  foreach ( $block_binding_source->uses_context as $context_name ) {
 382                      if ( array_key_exists( $context_name, $this->available_context ) ) {
 383                          $this->context[ $context_name ] = $this->available_context[ $context_name ];
 384                      }
 385                  }
 386              }
 387  
 388              $source_args  = ! empty( $block_binding['args'] ) && is_array( $block_binding['args'] ) ? $block_binding['args'] : array();
 389              $source_value = $block_binding_source->get_value( $source_args, $this, $attribute_name );
 390  
 391              // If the value is not null, process the HTML based on the block and the attribute.
 392              if ( ! is_null( $source_value ) ) {
 393                  $computed_attributes[ $attribute_name ] = $source_value;
 394              }
 395          }
 396  
 397          return $computed_attributes;
 398      }
 399  
 400      /**
 401       * Depending on the block attribute name, replace its value in the HTML based on the value provided.
 402       *
 403       * @since 6.5.0
 404       *
 405       * @param string $block_content  Block content.
 406       * @param string $attribute_name The attribute name to replace.
 407       * @param mixed  $source_value   The value used to replace in the HTML.
 408       * @return string The modified block content.
 409       */
 410  	private function replace_html( string $block_content, string $attribute_name, $source_value ) {
 411          $block_type = $this->block_type;
 412          if ( ! isset( $block_type->attributes[ $attribute_name ]['source'] ) ) {
 413              return $block_content;
 414          }
 415  
 416          // Depending on the attribute source, the processing will be different.
 417          switch ( $block_type->attributes[ $attribute_name ]['source'] ) {
 418              case 'html':
 419              case 'rich-text':
 420                  $block_reader = new WP_HTML_Tag_Processor( $block_content );
 421  
 422                  // TODO: Support for CSS selectors whenever they are ready in the HTML API.
 423                  // In the meantime, support comma-separated selectors by exploding them into an array.
 424                  $selectors = explode( ',', $block_type->attributes[ $attribute_name ]['selector'] );
 425                  // Add a bookmark to the first tag to be able to iterate over the selectors.
 426                  $block_reader->next_tag();
 427                  $block_reader->set_bookmark( 'iterate-selectors' );
 428  
 429                  // TODO: This shouldn't be needed when the `set_inner_html` function is ready.
 430                  // Store the parent tag and its attributes to be able to restore them later in the button.
 431                  // The button block has a wrapper while the paragraph and heading blocks don't.
 432                  if ( 'core/button' === $this->name ) {
 433                      $button_wrapper                 = $block_reader->get_tag();
 434                      $button_wrapper_attribute_names = $block_reader->get_attribute_names_with_prefix( '' );
 435                      $button_wrapper_attrs           = array();
 436                      foreach ( $button_wrapper_attribute_names as $name ) {
 437                          $button_wrapper_attrs[ $name ] = $block_reader->get_attribute( $name );
 438                      }
 439                  }
 440  
 441                  foreach ( $selectors as $selector ) {
 442                      // If the parent tag, or any of its children, matches the selector, replace the HTML.
 443                      if ( strcasecmp( $block_reader->get_tag(), $selector ) === 0 || $block_reader->next_tag(
 444                          array(
 445                              'tag_name' => $selector,
 446                          )
 447                      ) ) {
 448                          $block_reader->release_bookmark( 'iterate-selectors' );
 449  
 450                          // TODO: Use `set_inner_html` method whenever it's ready in the HTML API.
 451                          // Until then, it is hardcoded for the paragraph, heading, and button blocks.
 452                          // Store the tag and its attributes to be able to restore them later.
 453                          $selector_attribute_names = $block_reader->get_attribute_names_with_prefix( '' );
 454                          $selector_attrs           = array();
 455                          foreach ( $selector_attribute_names as $name ) {
 456                              $selector_attrs[ $name ] = $block_reader->get_attribute( $name );
 457                          }
 458                          $selector_markup = "<$selector>" . wp_kses_post( $source_value ) . "</$selector>";
 459                          $amended_content = new WP_HTML_Tag_Processor( $selector_markup );
 460                          $amended_content->next_tag();
 461                          foreach ( $selector_attrs as $attribute_key => $attribute_value ) {
 462                              $amended_content->set_attribute( $attribute_key, $attribute_value );
 463                          }
 464                          if ( 'core/paragraph' === $this->name || 'core/heading' === $this->name ) {
 465                              return $amended_content->get_updated_html();
 466                          }
 467                          if ( 'core/button' === $this->name ) {
 468                              $button_markup  = "<$button_wrapper>{$amended_content->get_updated_html()}</$button_wrapper>";
 469                              $amended_button = new WP_HTML_Tag_Processor( $button_markup );
 470                              $amended_button->next_tag();
 471                              foreach ( $button_wrapper_attrs as $attribute_key => $attribute_value ) {
 472                                  $amended_button->set_attribute( $attribute_key, $attribute_value );
 473                              }
 474                              return $amended_button->get_updated_html();
 475                          }
 476                      } else {
 477                          $block_reader->seek( 'iterate-selectors' );
 478                      }
 479                  }
 480                  $block_reader->release_bookmark( 'iterate-selectors' );
 481                  return $block_content;
 482  
 483              case 'attribute':
 484                  $amended_content = new WP_HTML_Tag_Processor( $block_content );
 485                  if ( ! $amended_content->next_tag(
 486                      array(
 487                          // TODO: build the query from CSS selector.
 488                          'tag_name' => $block_type->attributes[ $attribute_name ]['selector'],
 489                      )
 490                  ) ) {
 491                      return $block_content;
 492                  }
 493                  $amended_content->set_attribute( $block_type->attributes[ $attribute_name ]['attribute'], $source_value );
 494                  return $amended_content->get_updated_html();
 495  
 496              default:
 497                  return $block_content;
 498          }
 499      }
 500  
 501  
 502      /**
 503       * Generates the render output for the block.
 504       *
 505       * @since 5.5.0
 506       * @since 6.5.0 Added block bindings processing.
 507       *
 508       * @global WP_Post $post Global post object.
 509       *
 510       * @param array $options {
 511       *     Optional options object.
 512       *
 513       *     @type bool $dynamic Defaults to 'true'. Optionally set to false to avoid using the block's render_callback.
 514       * }
 515       * @return string Rendered block output.
 516       */
 517  	public function render( $options = array() ) {
 518          global $post;
 519  
 520          /*
 521           * There can be only one root interactive block at a time because the rendered HTML of that block contains
 522           * the rendered HTML of all its inner blocks, including any interactive block.
 523           */
 524          static $root_interactive_block = null;
 525          /**
 526           * Filters whether Interactivity API should process directives.
 527           *
 528           * @since 6.6.0
 529           *
 530           * @param bool $enabled Whether the directives processing is enabled.
 531           */
 532          $interactivity_process_directives_enabled = apply_filters( 'interactivity_process_directives', true );
 533          if (
 534              $interactivity_process_directives_enabled && null === $root_interactive_block && (
 535                  ( isset( $this->block_type->supports['interactivity'] ) && true === $this->block_type->supports['interactivity'] ) ||
 536                  ! empty( $this->block_type->supports['interactivity']['interactive'] )
 537              )
 538          ) {
 539              $root_interactive_block = $this;
 540          }
 541  
 542          $options = wp_parse_args(
 543              $options,
 544              array(
 545                  'dynamic' => true,
 546              )
 547          );
 548  
 549          // Process the block bindings and get attributes updated with the values from the sources.
 550          $computed_attributes = $this->process_block_bindings();
 551          if ( ! empty( $computed_attributes ) ) {
 552              // Merge the computed attributes with the original attributes.
 553              $this->attributes = array_merge( $this->attributes, $computed_attributes );
 554          }
 555  
 556          $is_dynamic    = $options['dynamic'] && $this->name && null !== $this->block_type && $this->block_type->is_dynamic();
 557          $block_content = '';
 558  
 559          if ( ! $options['dynamic'] || empty( $this->block_type->skip_inner_blocks ) ) {
 560              $index = 0;
 561  
 562              foreach ( $this->inner_content as $chunk ) {
 563                  if ( is_string( $chunk ) ) {
 564                      $block_content .= $chunk;
 565                  } else {
 566                      $inner_block  = $this->inner_blocks[ $index ];
 567                      $parent_block = $this;
 568  
 569                      /** This filter is documented in wp-includes/blocks.php */
 570                      $pre_render = apply_filters( 'pre_render_block', null, $inner_block->parsed_block, $parent_block );
 571  
 572                      if ( ! is_null( $pre_render ) ) {
 573                          $block_content .= $pre_render;
 574                      } else {
 575                          $source_block        = $inner_block->parsed_block;
 576                          $inner_block_context = $inner_block->context;
 577  
 578                          /** This filter is documented in wp-includes/blocks.php */
 579                          $inner_block->parsed_block = apply_filters( 'render_block_data', $inner_block->parsed_block, $source_block, $parent_block );
 580  
 581                          /** This filter is documented in wp-includes/blocks.php */
 582                          $inner_block->context = apply_filters( 'render_block_context', $inner_block->context, $inner_block->parsed_block, $parent_block );
 583  
 584                          /*
 585                           * The `refresh_context_dependents()` method already calls `refresh_parsed_block_dependents()`.
 586                           * Therefore the second condition is irrelevant if the first one is satisfied.
 587                           */
 588                          if ( $inner_block->context !== $inner_block_context ) {
 589                              $inner_block->refresh_context_dependents();
 590                          } elseif ( $inner_block->parsed_block !== $source_block ) {
 591                              $inner_block->refresh_parsed_block_dependents();
 592                          }
 593  
 594                          $block_content .= $inner_block->render();
 595                      }
 596  
 597                      ++$index;
 598                  }
 599              }
 600          }
 601  
 602          if ( ! empty( $computed_attributes ) && ! empty( $block_content ) ) {
 603              foreach ( $computed_attributes as $attribute_name => $source_value ) {
 604                  $block_content = $this->replace_html( $block_content, $attribute_name, $source_value );
 605              }
 606          }
 607  
 608          if ( $is_dynamic ) {
 609              $global_post = $post;
 610              $parent      = WP_Block_Supports::$block_to_render;
 611  
 612              WP_Block_Supports::$block_to_render = $this->parsed_block;
 613  
 614              $block_content = (string) call_user_func( $this->block_type->render_callback, $this->attributes, $block_content, $this );
 615  
 616              WP_Block_Supports::$block_to_render = $parent;
 617  
 618              $post = $global_post;
 619          }
 620  
 621          if ( ( ! empty( $this->block_type->script_handles ) ) ) {
 622              foreach ( $this->block_type->script_handles as $script_handle ) {
 623                  wp_enqueue_script( $script_handle );
 624              }
 625          }
 626  
 627          if ( ! empty( $this->block_type->view_script_handles ) ) {
 628              foreach ( $this->block_type->view_script_handles as $view_script_handle ) {
 629                  wp_enqueue_script( $view_script_handle );
 630              }
 631          }
 632  
 633          if ( ! empty( $this->block_type->view_script_module_ids ) ) {
 634              foreach ( $this->block_type->view_script_module_ids as $view_script_module_id ) {
 635                  wp_enqueue_script_module( $view_script_module_id );
 636              }
 637          }
 638  
 639          /*
 640           * For Core blocks, these styles are only enqueued if `wp_should_load_separate_core_block_assets()` returns
 641           * true. Otherwise these `wp_enqueue_style()` calls will not have any effect, as the Core blocks are relying on
 642           * the combined 'wp-block-library' stylesheet instead, which is unconditionally enqueued.
 643           */
 644          if ( ( ! empty( $this->block_type->style_handles ) ) ) {
 645              foreach ( $this->block_type->style_handles as $style_handle ) {
 646                  wp_enqueue_style( $style_handle );
 647              }
 648          }
 649  
 650          if ( ( ! empty( $this->block_type->view_style_handles ) ) ) {
 651              foreach ( $this->block_type->view_style_handles as $view_style_handle ) {
 652                  wp_enqueue_style( $view_style_handle );
 653              }
 654          }
 655  
 656          /**
 657           * Filters the content of a single block.
 658           *
 659           * @since 5.0.0
 660           * @since 5.9.0 The `$instance` parameter was added.
 661           *
 662           * @param string   $block_content The block content.
 663           * @param array    $block         The full block, including name and attributes.
 664           * @param WP_Block $instance      The block instance.
 665           */
 666          $block_content = apply_filters( 'render_block', $block_content, $this->parsed_block, $this );
 667  
 668          /**
 669           * Filters the content of a single block.
 670           *
 671           * The dynamic portion of the hook name, `$name`, refers to
 672           * the block name, e.g. "core/paragraph".
 673           *
 674           * @since 5.7.0
 675           * @since 5.9.0 The `$instance` parameter was added.
 676           *
 677           * @param string   $block_content The block content.
 678           * @param array    $block         The full block, including name and attributes.
 679           * @param WP_Block $instance      The block instance.
 680           */
 681          $block_content = apply_filters( "render_block_{$this->name}", $block_content, $this->parsed_block, $this );
 682  
 683          if ( $root_interactive_block === $this ) {
 684              // The root interactive block has finished rendering. Time to process directives.
 685              $block_content          = wp_interactivity_process_directives( $block_content );
 686              $root_interactive_block = null;
 687          }
 688  
 689          return $block_content;
 690      }
 691  }


Generated : Tue Aug 19 08:20:01 2025 Cross-referenced by PHPXref