[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

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

   1  <?php
   2  /**
   3   * Block support flags.
   4   *
   5   * @package WordPress
   6   *
   7   * @since 5.6.0
   8   */
   9  
  10  /**
  11   * Class encapsulating and implementing Block Supports.
  12   *
  13   * @since 5.6.0
  14   *
  15   * @access private
  16   *
  17   * @phpstan-type ApplyCallback callable( WP_Block_Type, array<string, mixed> ): array<string, mixed>
  18   * @phpstan-type RegisterCallback callable( WP_Block_Type ): void
  19   */
  20  #[AllowDynamicProperties]
  21  class WP_Block_Supports {
  22  
  23      /**
  24       * Config.
  25       *
  26       * @since 5.6.0
  27       * @var array
  28       * @phpstan-var array<string, array{
  29       *     name: string,
  30       *     apply?: ApplyCallback,
  31       *     register_attribute?: RegisterCallback,
  32       * }>
  33       */
  34      private $block_supports = array();
  35  
  36      /**
  37       * Tracks the current block to be rendered.
  38       *
  39       * @since 5.6.0
  40       * @var array|null
  41       * @phpstan-var array<string, mixed>|null
  42       */
  43      public static $block_to_render = null;
  44  
  45      /**
  46       * Container for the main instance of the class.
  47       *
  48       * @since 5.6.0
  49       * @var WP_Block_Supports|null
  50       */
  51      private static $instance = null;
  52  
  53      /**
  54       * Utility method to retrieve the main instance of the class.
  55       *
  56       * The instance will be created if it does not exist yet.
  57       *
  58       * @since 5.6.0
  59       *
  60       * @return WP_Block_Supports The main instance.
  61       */
  62  	public static function get_instance() {
  63          self::$instance ??= new self();
  64  
  65          return self::$instance;
  66      }
  67  
  68      /**
  69       * Initializes the block supports. It registers the block supports block attributes.
  70       *
  71       * @since 5.6.0
  72       *
  73       * @return void
  74       */
  75  	public static function init() {
  76          $instance = self::get_instance();
  77          $instance->register_attributes();
  78      }
  79  
  80      /**
  81       * Registers a block support.
  82       *
  83       * @since 5.6.0
  84       *
  85       * @link https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/
  86       *
  87       * @param string $block_support_name   Block support name.
  88       * @param array  $block_support_config Array containing the properties of the block support.
  89       *
  90       * @phpstan-param array{
  91       *     apply?: ApplyCallback,
  92       *     register_attribute?: RegisterCallback,
  93       * } $block_support_config
  94       *
  95       * @return void
  96       */
  97  	public function register( $block_support_name, $block_support_config ) {
  98          $this->block_supports[ $block_support_name ] = array_merge(
  99              $block_support_config,
 100              array( 'name' => $block_support_name )
 101          );
 102      }
 103  
 104      /**
 105       * Generates an array of HTML attributes, such as classes, by applying to
 106       * the given block all of the features that the block supports.
 107       *
 108       * @since 5.6.0
 109       *
 110       * @return string[] Array of HTML attribute values keyed by their name.
 111       */
 112  	public function apply_block_supports() {
 113          if ( ! is_array( self::$block_to_render ) ) {
 114              return array();
 115          }
 116  
 117          $block_type = WP_Block_Type_Registry::get_instance()->get_registered(
 118              self::$block_to_render['blockName']
 119          );
 120  
 121          // If no render_callback, assume styles have been previously handled.
 122          if ( ! $block_type ) {
 123              return array();
 124          }
 125  
 126          $block_attributes = array_key_exists( 'attrs', self::$block_to_render ) && is_array( self::$block_to_render['attrs'] )
 127              ? $block_type->prepare_attributes_for_render( self::$block_to_render['attrs'] )
 128              : array();
 129  
 130          $output = array();
 131          foreach ( $this->block_supports as $block_support_config ) {
 132              if ( ! isset( $block_support_config['apply'] ) ) {
 133                  continue;
 134              }
 135  
 136              $new_attributes = call_user_func(
 137                  $block_support_config['apply'],
 138                  $block_type,
 139                  $block_attributes
 140              );
 141  
 142              if ( ! empty( $new_attributes ) ) {
 143                  foreach ( $new_attributes as $attribute_name => $attribute_value ) {
 144                      if ( ! is_scalar( $attribute_value ) || is_bool( $attribute_value ) ) {
 145                          continue;
 146                      }
 147                      $attribute_value = (string) $attribute_value;
 148                      if ( ! array_key_exists( $attribute_name, $output ) || '' === $output[ $attribute_name ] ) {
 149                          $output[ $attribute_name ] = $attribute_value;
 150                      } else {
 151                          $output[ $attribute_name ] .= " $attribute_value";
 152                      }
 153                  }
 154              }
 155          }
 156  
 157          return $output;
 158      }
 159  
 160      /**
 161       * Registers the block attributes required by the different block supports.
 162       *
 163       * @since 5.6.0
 164       *
 165       * @return void
 166       */
 167  	private function register_attributes() {
 168          $block_registry         = WP_Block_Type_Registry::get_instance();
 169          $registered_block_types = $block_registry->get_all_registered();
 170          foreach ( $registered_block_types as $block_type ) {
 171              if ( ! ( $block_type instanceof WP_Block_Type ) ) {
 172                  continue;
 173              }
 174              if ( ! $block_type->attributes ) {
 175                  $block_type->attributes = array();
 176              }
 177  
 178              foreach ( $this->block_supports as $block_support_config ) {
 179                  if ( ! isset( $block_support_config['register_attribute'] ) ) {
 180                      continue;
 181                  }
 182  
 183                  call_user_func(
 184                      $block_support_config['register_attribute'],
 185                      $block_type
 186                  );
 187              }
 188          }
 189      }
 190  }
 191  
 192  /**
 193   * Generates a string of attributes by applying to the current block being
 194   * rendered all of the features that the block supports.
 195   *
 196   * @since 5.6.0
 197   *
 198   * @param array<string, string|int|float> $extra_attributes Optional. Extra attributes to render on the block wrapper,
 199   *                                                          keyed by attribute name. Values are unescaped strings or
 200   *                                                          numbers. This function escapes them, so do not escape them
 201   *                                                          first. Numbers are cast to strings, and values of other
 202   *                                                          types are ignored. Default empty array.
 203   * @return string String of HTML attributes with escaped values, ready to print inside an HTML tag.
 204   */
 205  function get_block_wrapper_attributes( $extra_attributes = array() ) {
 206      $new_attributes = WP_Block_Supports::get_instance()->apply_block_supports();
 207  
 208      if ( empty( $new_attributes ) && empty( $extra_attributes ) ) {
 209          return '';
 210      }
 211  
 212      // Attribute values are concatenated or overridden depending on the attribute type.
 213      // This is hardcoded on purpose, as we only support a fixed list of attributes.
 214      $attribute_merge_callbacks = array(
 215          'style'      => static function ( $new_attribute, $extra_attribute ) {
 216              $styles = array_filter(
 217                  array(
 218                      rtrim( trim( $new_attribute ), ';' ),
 219                      rtrim( trim( $extra_attribute ), ';' ),
 220                  )
 221              );
 222              return safecss_filter_attr( implode( ';', array_filter( $styles ) ) );
 223          },
 224          'class'      => static function ( $new_attribute, $extra_attribute ) {
 225              $classes = array_merge(
 226                  (array) preg_split( '/\s+/', $extra_attribute, -1, PREG_SPLIT_NO_EMPTY ),
 227                  (array) preg_split( '/\s+/', $new_attribute, -1, PREG_SPLIT_NO_EMPTY )
 228              );
 229              $classes = array_unique( $classes );
 230              return implode( ' ', $classes );
 231          },
 232          'id'         => static function ( $new_attribute, $extra_attribute ) {
 233              return '' !== $extra_attribute ? $extra_attribute : $new_attribute;
 234          },
 235          'aria-label' => static function ( $new_attribute, $extra_attribute ) {
 236              return '' !== $extra_attribute ? $extra_attribute : $new_attribute;
 237          },
 238      );
 239  
 240      // Accept strings and numbers (cast to string); reject other types (bool, null, array, object).
 241      $attributes = array();
 242      foreach ( $attribute_merge_callbacks as $attribute_name => $merge_callback ) {
 243          $new_attribute   = $new_attributes[ $attribute_name ] ?? '';
 244          $extra_attribute = $extra_attributes[ $attribute_name ] ?? '';
 245          $new_attribute   = is_scalar( $new_attribute ) && ! is_bool( $new_attribute ) ? (string) $new_attribute : '';
 246          $extra_attribute = is_scalar( $extra_attribute ) && ! is_bool( $extra_attribute ) ? (string) $extra_attribute : '';
 247  
 248          if ( '' === $new_attribute && '' === $extra_attribute ) {
 249              continue;
 250          }
 251  
 252          $attributes[ $attribute_name ] = $merge_callback( $new_attribute, $extra_attribute );
 253      }
 254  
 255      foreach ( $extra_attributes as $attribute_name => $value ) {
 256          if ( ! isset( $attribute_merge_callbacks[ $attribute_name ] ) && is_scalar( $value ) && ! is_bool( $value ) ) {
 257              $attributes[ $attribute_name ] = (string) $value;
 258          }
 259      }
 260  
 261      if ( empty( $attributes ) ) {
 262          return '';
 263      }
 264  
 265      $normalized_attributes = array();
 266      foreach ( $attributes as $key => $value ) {
 267          $normalized_attributes[] = $key . '="' . esc_attr( $value ) . '"';
 268      }
 269  
 270      return implode( ' ', $normalized_attributes );
 271  }


Generated : Thu Nov 5 08:20:37 2026 Cross-referenced by PHPXref