| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
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 string[] $extra_attributes Optional. Array of extra attributes to render on the block wrapper. 199 * @return string String of HTML attributes. 200 */ 201 function get_block_wrapper_attributes( $extra_attributes = array() ) { 202 $new_attributes = WP_Block_Supports::get_instance()->apply_block_supports(); 203 204 if ( empty( $new_attributes ) && empty( $extra_attributes ) ) { 205 return ''; 206 } 207 208 // Attribute values are concatenated or overridden depending on the attribute type. 209 // This is hardcoded on purpose, as we only support a fixed list of attributes. 210 $attribute_merge_callbacks = array( 211 'style' => static function ( $new_attribute, $extra_attribute ) { 212 $styles = array_filter( 213 array( 214 rtrim( trim( $new_attribute ), ';' ), 215 rtrim( trim( $extra_attribute ), ';' ), 216 ) 217 ); 218 return safecss_filter_attr( implode( ';', array_filter( $styles ) ) ); 219 }, 220 'class' => static function ( $new_attribute, $extra_attribute ) { 221 $classes = array_merge( 222 (array) preg_split( '/\s+/', $extra_attribute, -1, PREG_SPLIT_NO_EMPTY ), 223 (array) preg_split( '/\s+/', $new_attribute, -1, PREG_SPLIT_NO_EMPTY ) 224 ); 225 $classes = array_unique( $classes ); 226 return implode( ' ', $classes ); 227 }, 228 'id' => static function ( $new_attribute, $extra_attribute ) { 229 return '' !== $extra_attribute ? $extra_attribute : $new_attribute; 230 }, 231 'aria-label' => static function ( $new_attribute, $extra_attribute ) { 232 return '' !== $extra_attribute ? $extra_attribute : $new_attribute; 233 }, 234 ); 235 236 // Accept strings and numbers (cast to string); reject other types (bool, null, array, object). 237 $attributes = array(); 238 foreach ( $attribute_merge_callbacks as $attribute_name => $merge_callback ) { 239 $new_attribute = $new_attributes[ $attribute_name ] ?? ''; 240 $extra_attribute = $extra_attributes[ $attribute_name ] ?? ''; 241 $new_attribute = is_scalar( $new_attribute ) && ! is_bool( $new_attribute ) ? (string) $new_attribute : ''; 242 $extra_attribute = is_scalar( $extra_attribute ) && ! is_bool( $extra_attribute ) ? (string) $extra_attribute : ''; 243 244 if ( '' === $new_attribute && '' === $extra_attribute ) { 245 continue; 246 } 247 248 $attributes[ $attribute_name ] = $merge_callback( $new_attribute, $extra_attribute ); 249 } 250 251 foreach ( $extra_attributes as $attribute_name => $value ) { 252 if ( ! isset( $attribute_merge_callbacks[ $attribute_name ] ) && is_scalar( $value ) && ! is_bool( $value ) ) { 253 $attributes[ $attribute_name ] = (string) $value; 254 } 255 } 256 257 if ( empty( $attributes ) ) { 258 return ''; 259 } 260 261 $normalized_attributes = array(); 262 foreach ( $attributes as $key => $value ) { 263 $normalized_attributes[] = $key . '="' . esc_attr( $value ) . '"'; 264 } 265 266 return implode( ' ', $normalized_attributes ); 267 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Fri Sep 18 08:20:28 2026 | Cross-referenced by PHPXref |