class-wp-block-supports.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <?php
  2. /**
  3. * Block support flags.
  4. *
  5. * @package WordPress
  6. *
  7. * @since 5.6.0
  8. */
  9. /**
  10. * Class encapsulating and implementing Block Supports.
  11. *
  12. * @since 5.6.0
  13. *
  14. * @access private
  15. */
  16. #[AllowDynamicProperties]
  17. class WP_Block_Supports {
  18. /**
  19. * Config.
  20. *
  21. * @since 5.6.0
  22. * @var array
  23. */
  24. private $block_supports = array();
  25. /**
  26. * Tracks the current block to be rendered.
  27. *
  28. * @since 5.6.0
  29. * @var array
  30. */
  31. public static $block_to_render = null;
  32. /**
  33. * Container for the main instance of the class.
  34. *
  35. * @since 5.6.0
  36. * @var WP_Block_Supports|null
  37. */
  38. private static $instance = null;
  39. /**
  40. * Utility method to retrieve the main instance of the class.
  41. *
  42. * The instance will be created if it does not exist yet.
  43. *
  44. * @since 5.6.0
  45. *
  46. * @return WP_Block_Supports The main instance.
  47. */
  48. public static function get_instance() {
  49. if ( null === self::$instance ) {
  50. self::$instance = new self();
  51. }
  52. return self::$instance;
  53. }
  54. /**
  55. * Initializes the block supports. It registers the block supports block attributes.
  56. *
  57. * @since 5.6.0
  58. */
  59. public static function init() {
  60. $instance = self::get_instance();
  61. $instance->register_attributes();
  62. }
  63. /**
  64. * Registers a block support.
  65. *
  66. * @since 5.6.0
  67. *
  68. * @link https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/
  69. *
  70. * @param string $block_support_name Block support name.
  71. * @param array $block_support_config Array containing the properties of the block support.
  72. */
  73. public function register( $block_support_name, $block_support_config ) {
  74. $this->block_supports[ $block_support_name ] = array_merge(
  75. $block_support_config,
  76. array( 'name' => $block_support_name )
  77. );
  78. }
  79. /**
  80. * Generates an array of HTML attributes, such as classes, by applying to
  81. * the given block all of the features that the block supports.
  82. *
  83. * @since 5.6.0
  84. *
  85. * @return string[] Array of HTML attributes.
  86. */
  87. public function apply_block_supports() {
  88. $block_type = WP_Block_Type_Registry::get_instance()->get_registered(
  89. self::$block_to_render['blockName']
  90. );
  91. // If no render_callback, assume styles have been previously handled.
  92. if ( ! $block_type || empty( $block_type ) ) {
  93. return array();
  94. }
  95. $block_attributes = array_key_exists( 'attrs', self::$block_to_render )
  96. ? self::$block_to_render['attrs']
  97. : array();
  98. $output = array();
  99. foreach ( $this->block_supports as $block_support_config ) {
  100. if ( ! isset( $block_support_config['apply'] ) ) {
  101. continue;
  102. }
  103. $new_attributes = call_user_func(
  104. $block_support_config['apply'],
  105. $block_type,
  106. $block_attributes
  107. );
  108. if ( ! empty( $new_attributes ) ) {
  109. foreach ( $new_attributes as $attribute_name => $attribute_value ) {
  110. if ( empty( $output[ $attribute_name ] ) ) {
  111. $output[ $attribute_name ] = $attribute_value;
  112. } else {
  113. $output[ $attribute_name ] .= " $attribute_value";
  114. }
  115. }
  116. }
  117. }
  118. return $output;
  119. }
  120. /**
  121. * Registers the block attributes required by the different block supports.
  122. *
  123. * @since 5.6.0
  124. */
  125. private function register_attributes() {
  126. $block_registry = WP_Block_Type_Registry::get_instance();
  127. $registered_block_types = $block_registry->get_all_registered();
  128. foreach ( $registered_block_types as $block_type ) {
  129. if ( ! property_exists( $block_type, 'supports' ) ) {
  130. continue;
  131. }
  132. if ( ! $block_type->attributes ) {
  133. $block_type->attributes = array();
  134. }
  135. foreach ( $this->block_supports as $block_support_config ) {
  136. if ( ! isset( $block_support_config['register_attribute'] ) ) {
  137. continue;
  138. }
  139. call_user_func(
  140. $block_support_config['register_attribute'],
  141. $block_type
  142. );
  143. }
  144. }
  145. }
  146. }
  147. /**
  148. * Generates a string of attributes by applying to the current block being
  149. * rendered all of the features that the block supports.
  150. *
  151. * @since 5.6.0
  152. *
  153. * @param string[] $extra_attributes Optional. Array of extra attributes to render on the block wrapper.
  154. * @return string String of HTML attributes.
  155. */
  156. function get_block_wrapper_attributes( $extra_attributes = array() ) {
  157. $new_attributes = WP_Block_Supports::get_instance()->apply_block_supports();
  158. if ( empty( $new_attributes ) && empty( $extra_attributes ) ) {
  159. return '';
  160. }
  161. // This is hardcoded on purpose.
  162. // We only support a fixed list of attributes.
  163. $attributes_to_merge = array( 'style', 'class' );
  164. $attributes = array();
  165. foreach ( $attributes_to_merge as $attribute_name ) {
  166. if ( empty( $new_attributes[ $attribute_name ] ) && empty( $extra_attributes[ $attribute_name ] ) ) {
  167. continue;
  168. }
  169. if ( empty( $new_attributes[ $attribute_name ] ) ) {
  170. $attributes[ $attribute_name ] = $extra_attributes[ $attribute_name ];
  171. continue;
  172. }
  173. if ( empty( $extra_attributes[ $attribute_name ] ) ) {
  174. $attributes[ $attribute_name ] = $new_attributes[ $attribute_name ];
  175. continue;
  176. }
  177. $attributes[ $attribute_name ] = $extra_attributes[ $attribute_name ] . ' ' . $new_attributes[ $attribute_name ];
  178. }
  179. foreach ( $extra_attributes as $attribute_name => $value ) {
  180. if ( ! in_array( $attribute_name, $attributes_to_merge, true ) ) {
  181. $attributes[ $attribute_name ] = $value;
  182. }
  183. }
  184. if ( empty( $attributes ) ) {
  185. return '';
  186. }
  187. $normalized_attributes = array();
  188. foreach ( $attributes as $key => $value ) {
  189. $normalized_attributes[] = $key . '="' . esc_attr( $value ) . '"';
  190. }
  191. return implode( ' ', $normalized_attributes );
  192. }