[ 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          $supported_block_attributes =
 301              self::BLOCK_BINDINGS_SUPPORTED_ATTRIBUTES[ $block_type ] ??
 302              array();
 303  
 304          /**
 305           * Filters the supported block attributes for block bindings.
 306           *
 307           * The dynamic portion of the hook name, `$block_type`, refers to the block type
 308           * whose attributes are being filtered.
 309           *
 310           * @since 6.9.0
 311           *
 312           * @param string[] $supported_block_attributes The block's attributes that are supported by block bindings.
 313           */
 314          $supported_block_attributes = apply_filters(
 315              "block_bindings_supported_attributes_{$block_type}",
 316              $supported_block_attributes
 317          );
 318  
 319          // If the block doesn't have the bindings property, isn't one of the supported
 320          // block types, or the bindings property is not an array, return the block content.
 321          if (
 322              empty( $supported_block_attributes ) ||
 323              empty( $parsed_block['attrs']['metadata']['bindings'] ) ||
 324              ! is_array( $parsed_block['attrs']['metadata']['bindings'] )
 325          ) {
 326              return $computed_attributes;
 327          }
 328  
 329          $bindings = $parsed_block['attrs']['metadata']['bindings'];
 330  
 331          /*
 332           * If the default binding is set for pattern overrides, replace it
 333           * with a pattern override binding for all supported attributes.
 334           */
 335          if (
 336              isset( $bindings['__default']['source'] ) &&
 337              'core/pattern-overrides' === $bindings['__default']['source']
 338          ) {
 339              $updated_bindings = array();
 340  
 341              /*
 342               * Build a binding array of all supported attributes.
 343               * Note that this also omits the `__default` attribute from the
 344               * resulting array.
 345               */
 346              foreach ( $supported_block_attributes as $attribute_name ) {
 347                  // Retain any non-pattern override bindings that might be present.
 348                  $updated_bindings[ $attribute_name ] = isset( $bindings[ $attribute_name ] )
 349                      ? $bindings[ $attribute_name ]
 350                      : array( 'source' => 'core/pattern-overrides' );
 351              }
 352              $bindings = $updated_bindings;
 353              /*
 354               * Update the bindings metadata of the computed attributes.
 355               * This ensures the block receives the expanded __default binding metadata when it renders.
 356               */
 357              $computed_attributes['metadata'] = array_merge(
 358                  $parsed_block['attrs']['metadata'],
 359                  array( 'bindings' => $bindings )
 360              );
 361          }
 362  
 363          foreach ( $bindings as $attribute_name => $block_binding ) {
 364              // If the attribute is not in the supported list, process next attribute.
 365              if ( ! in_array( $attribute_name, $supported_block_attributes, true ) ) {
 366                  continue;
 367              }
 368              // If no source is provided, or that source is not registered, process next attribute.
 369              if ( ! isset( $block_binding['source'] ) || ! is_string( $block_binding['source'] ) ) {
 370                  continue;
 371              }
 372  
 373              $block_binding_source = get_block_bindings_source( $block_binding['source'] );
 374              if ( null === $block_binding_source ) {
 375                  continue;
 376              }
 377  
 378              // Adds the necessary context defined by the source.
 379              if ( ! empty( $block_binding_source->uses_context ) ) {
 380                  foreach ( $block_binding_source->uses_context as $context_name ) {
 381                      if ( array_key_exists( $context_name, $this->available_context ) ) {
 382                          $this->context[ $context_name ] = $this->available_context[ $context_name ];
 383                      }
 384                  }
 385              }
 386  
 387              $source_args  = ! empty( $block_binding['args'] ) && is_array( $block_binding['args'] ) ? $block_binding['args'] : array();
 388              $source_value = $block_binding_source->get_value( $source_args, $this, $attribute_name );
 389  
 390              // If the value is not null, process the HTML based on the block and the attribute.
 391              if ( ! is_null( $source_value ) ) {
 392                  $computed_attributes[ $attribute_name ] = $source_value;
 393              }
 394          }
 395  
 396          return $computed_attributes;
 397      }
 398  
 399      /**
 400       * Depending on the block attribute name, replace its value in the HTML based on the value provided.
 401       *
 402       * @since 6.5.0
 403       *
 404       * @param string $block_content  Block content.
 405       * @param string $attribute_name The attribute name to replace.
 406       * @param mixed  $source_value   The value used to replace in the HTML.
 407       * @return string The modified block content.
 408       */
 409  	private function replace_html( string $block_content, string $attribute_name, $source_value ) {
 410          $block_type = $this->block_type;
 411          if ( ! isset( $block_type->attributes[ $attribute_name ]['source'] ) ) {
 412              return $block_content;
 413          }
 414  
 415          // Depending on the attribute source, the processing will be different.
 416          switch ( $block_type->attributes[ $attribute_name ]['source'] ) {
 417              case 'html':
 418              case 'rich-text':
 419                  $block_reader = self::get_block_bindings_processor( $block_content );
 420  
 421                  // TODO: Support for CSS selectors whenever they are ready in the HTML API.
 422                  // In the meantime, support comma-separated selectors by exploding them into an array.
 423                  $selectors = explode( ',', $block_type->attributes[ $attribute_name ]['selector'] );
 424                  // Add a bookmark to the first tag to be able to iterate over the selectors.
 425                  $block_reader->next_tag();
 426                  $block_reader->set_bookmark( 'iterate-selectors' );
 427  
 428                  foreach ( $selectors as $selector ) {
 429                      // If the parent tag, or any of its children, matches the selector, replace the HTML.
 430                      if ( strcasecmp( $block_reader->get_tag(), $selector ) === 0 || $block_reader->next_tag(
 431                          array(
 432                              'tag_name' => $selector,
 433                          )
 434                      ) ) {
 435                          // TODO: Use `WP_HTML_Processor::set_inner_html` method once it's available.
 436                          $block_reader->release_bookmark( 'iterate-selectors' );
 437                          $block_reader->replace_rich_text( wp_kses_post( $source_value ) );
 438                          return $block_reader->get_updated_html();
 439                      } else {
 440                          $block_reader->seek( 'iterate-selectors' );
 441                      }
 442                  }
 443                  $block_reader->release_bookmark( 'iterate-selectors' );
 444                  return $block_content;
 445  
 446              case 'attribute':
 447                  $amended_content = new WP_HTML_Tag_Processor( $block_content );
 448                  if ( ! $amended_content->next_tag(
 449                      array(
 450                          // TODO: build the query from CSS selector.
 451                          'tag_name' => $block_type->attributes[ $attribute_name ]['selector'],
 452                      )
 453                  ) ) {
 454                      return $block_content;
 455                  }
 456                  $amended_content->set_attribute( $block_type->attributes[ $attribute_name ]['attribute'], $source_value );
 457                  return $amended_content->get_updated_html();
 458  
 459              default:
 460                  return $block_content;
 461          }
 462      }
 463  
 464  	private static function get_block_bindings_processor( string $block_content ) {
 465          $internal_processor_class = new class('', WP_HTML_Processor::CONSTRUCTOR_UNLOCK_CODE) extends WP_HTML_Processor {
 466              /**
 467               * Replace the rich text content between a tag opener and matching closer.
 468               *
 469               * When stopped on a tag opener, replace the content enclosed by it and its
 470               * matching closer with the provided rich text.
 471               *
 472               * @param string $rich_text The rich text to replace the original content with.
 473               * @return bool True on success.
 474               */
 475  			public function replace_rich_text( $rich_text ) {
 476                  if ( $this->is_tag_closer() || ! $this->expects_closer() ) {
 477                      return false;
 478                  }
 479  
 480                  $depth = $this->get_current_depth();
 481  
 482                  $this->set_bookmark( '_wp_block_bindings_tag_opener' );
 483                  // The bookmark names are prefixed with `_` so the key below has an extra `_`.
 484                  $tag_opener = $this->bookmarks['__wp_block_bindings_tag_opener'];
 485                  $start      = $tag_opener->start + $tag_opener->length;
 486                  $this->release_bookmark( '_wp_block_bindings_tag_opener' );
 487  
 488                  // Find matching tag closer.
 489                  while ( $this->next_token() && $this->get_current_depth() >= $depth ) {
 490                  }
 491  
 492                  $this->set_bookmark( '_wp_block_bindings_tag_closer' );
 493                  $tag_closer  = $this->bookmarks['__wp_block_bindings_tag_closer'];
 494                  $end         = $tag_closer->start;
 495                  $this->release_bookmark( '_wp_block_bindings_tag_closer' );
 496  
 497                  $this->lexical_updates[] = new WP_HTML_Text_Replacement(
 498                      $start,
 499                      $end - $start,
 500                      $rich_text
 501                  );
 502  
 503                  return true;
 504              }
 505          };
 506  
 507          return $internal_processor_class::create_fragment( $block_content );
 508      }
 509  
 510      /**
 511       * Generates the render output for the block.
 512       *
 513       * @since 5.5.0
 514       * @since 6.5.0 Added block bindings processing.
 515       *
 516       * @global WP_Post $post Global post object.
 517       *
 518       * @param array $options {
 519       *     Optional options object.
 520       *
 521       *     @type bool $dynamic Defaults to 'true'. Optionally set to false to avoid using the block's render_callback.
 522       * }
 523       * @return string Rendered block output.
 524       */
 525  	public function render( $options = array() ) {
 526          global $post;
 527  
 528          /*
 529           * There can be only one root interactive block at a time because the rendered HTML of that block contains
 530           * the rendered HTML of all its inner blocks, including any interactive block.
 531           */
 532          static $root_interactive_block = null;
 533          /**
 534           * Filters whether Interactivity API should process directives.
 535           *
 536           * @since 6.6.0
 537           *
 538           * @param bool $enabled Whether the directives processing is enabled.
 539           */
 540          $interactivity_process_directives_enabled = apply_filters( 'interactivity_process_directives', true );
 541          if (
 542              $interactivity_process_directives_enabled && null === $root_interactive_block && (
 543                  ( isset( $this->block_type->supports['interactivity'] ) && true === $this->block_type->supports['interactivity'] ) ||
 544                  ! empty( $this->block_type->supports['interactivity']['interactive'] )
 545              )
 546          ) {
 547              $root_interactive_block = $this;
 548          }
 549  
 550          $options = wp_parse_args(
 551              $options,
 552              array(
 553                  'dynamic' => true,
 554              )
 555          );
 556  
 557          // Process the block bindings and get attributes updated with the values from the sources.
 558          $computed_attributes = $this->process_block_bindings();
 559          if ( ! empty( $computed_attributes ) ) {
 560              // Merge the computed attributes with the original attributes.
 561              $this->attributes = array_merge( $this->attributes, $computed_attributes );
 562          }
 563  
 564          $is_dynamic    = $options['dynamic'] && $this->name && null !== $this->block_type && $this->block_type->is_dynamic();
 565          $block_content = '';
 566  
 567          if ( ! $options['dynamic'] || empty( $this->block_type->skip_inner_blocks ) ) {
 568              $index = 0;
 569  
 570              foreach ( $this->inner_content as $chunk ) {
 571                  if ( is_string( $chunk ) ) {
 572                      $block_content .= $chunk;
 573                  } else {
 574                      $inner_block  = $this->inner_blocks[ $index ];
 575                      $parent_block = $this;
 576  
 577                      /** This filter is documented in wp-includes/blocks.php */
 578                      $pre_render = apply_filters( 'pre_render_block', null, $inner_block->parsed_block, $parent_block );
 579  
 580                      if ( ! is_null( $pre_render ) ) {
 581                          $block_content .= $pre_render;
 582                      } else {
 583                          $source_block        = $inner_block->parsed_block;
 584                          $inner_block_context = $inner_block->context;
 585  
 586                          /** This filter is documented in wp-includes/blocks.php */
 587                          $inner_block->parsed_block = apply_filters( 'render_block_data', $inner_block->parsed_block, $source_block, $parent_block );
 588  
 589                          /** This filter is documented in wp-includes/blocks.php */
 590                          $inner_block->context = apply_filters( 'render_block_context', $inner_block->context, $inner_block->parsed_block, $parent_block );
 591  
 592                          /*
 593                           * The `refresh_context_dependents()` method already calls `refresh_parsed_block_dependents()`.
 594                           * Therefore the second condition is irrelevant if the first one is satisfied.
 595                           */
 596                          if ( $inner_block->context !== $inner_block_context ) {
 597                              $inner_block->refresh_context_dependents();
 598                          } elseif ( $inner_block->parsed_block !== $source_block ) {
 599                              $inner_block->refresh_parsed_block_dependents();
 600                          }
 601  
 602                          $block_content .= $inner_block->render();
 603                      }
 604  
 605                      ++$index;
 606                  }
 607              }
 608          }
 609  
 610          if ( ! empty( $computed_attributes ) && ! empty( $block_content ) ) {
 611              foreach ( $computed_attributes as $attribute_name => $source_value ) {
 612                  $block_content = $this->replace_html( $block_content, $attribute_name, $source_value );
 613              }
 614          }
 615  
 616          if ( $is_dynamic ) {
 617              $global_post = $post;
 618              $parent      = WP_Block_Supports::$block_to_render;
 619  
 620              WP_Block_Supports::$block_to_render = $this->parsed_block;
 621  
 622              $block_content = (string) call_user_func( $this->block_type->render_callback, $this->attributes, $block_content, $this );
 623  
 624              WP_Block_Supports::$block_to_render = $parent;
 625  
 626              $post = $global_post;
 627          }
 628  
 629          if ( ( ! empty( $this->block_type->script_handles ) ) ) {
 630              foreach ( $this->block_type->script_handles as $script_handle ) {
 631                  wp_enqueue_script( $script_handle );
 632              }
 633          }
 634  
 635          if ( ! empty( $this->block_type->view_script_handles ) ) {
 636              foreach ( $this->block_type->view_script_handles as $view_script_handle ) {
 637                  wp_enqueue_script( $view_script_handle );
 638              }
 639          }
 640  
 641          if ( ! empty( $this->block_type->view_script_module_ids ) ) {
 642              foreach ( $this->block_type->view_script_module_ids as $view_script_module_id ) {
 643                  wp_enqueue_script_module( $view_script_module_id );
 644              }
 645          }
 646  
 647          /*
 648           * For Core blocks, these styles are only enqueued if `wp_should_load_separate_core_block_assets()` returns
 649           * true. Otherwise these `wp_enqueue_style()` calls will not have any effect, as the Core blocks are relying on
 650           * the combined 'wp-block-library' stylesheet instead, which is unconditionally enqueued.
 651           */
 652          if ( ( ! empty( $this->block_type->style_handles ) ) ) {
 653              foreach ( $this->block_type->style_handles as $style_handle ) {
 654                  wp_enqueue_style( $style_handle );
 655              }
 656          }
 657  
 658          if ( ( ! empty( $this->block_type->view_style_handles ) ) ) {
 659              foreach ( $this->block_type->view_style_handles as $view_style_handle ) {
 660                  wp_enqueue_style( $view_style_handle );
 661              }
 662          }
 663  
 664          /**
 665           * Filters the content of a single block.
 666           *
 667           * @since 5.0.0
 668           * @since 5.9.0 The `$instance` parameter was added.
 669           *
 670           * @param string   $block_content The block content.
 671           * @param array    $block         The full block, including name and attributes.
 672           * @param WP_Block $instance      The block instance.
 673           */
 674          $block_content = apply_filters( 'render_block', $block_content, $this->parsed_block, $this );
 675  
 676          /**
 677           * Filters the content of a single block.
 678           *
 679           * The dynamic portion of the hook name, `$name`, refers to
 680           * the block name, e.g. "core/paragraph".
 681           *
 682           * @since 5.7.0
 683           * @since 5.9.0 The `$instance` parameter was added.
 684           *
 685           * @param string   $block_content The block content.
 686           * @param array    $block         The full block, including name and attributes.
 687           * @param WP_Block $instance      The block instance.
 688           */
 689          $block_content = apply_filters( "render_block_{$this->name}", $block_content, $this->parsed_block, $this );
 690  
 691          if ( $root_interactive_block === $this ) {
 692              // The root interactive block has finished rendering. Time to process directives.
 693              $block_content          = wp_interactivity_process_directives( $block_content );
 694              $root_interactive_block = null;
 695          }
 696  
 697          return $block_content;
 698      }
 699  }


Generated : Tue Sep 9 08:20:04 2025 Cross-referenced by PHPXref