PluginProbe
Gutenberg / 24.1.0
Gutenberg v24.1.0
24.1.0 24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 All 404 releases
← All changes | lib/block-supports/custom-css.php +84 -23 23.2.2 → 24.1.0 View file →
@@ -7,21 +7,34 @@
7 7
8 8 /**
9 9 * Render the custom CSS stylesheet and add class name to block as required.
10 10 *
11 + * @since 7.0.0
12 + *
11 13 * @param array $parsed_block The parsed block.
12 14 * @return array The same parsed block with custom CSS class name added if appropriate.
15 + *
16 + * @phpstan-param array{
17 + * blockName: string|null,
18 + * attrs: array{
19 + * className?: string,
20 + * style?: array{
21 + * css?: string,
22 + * ...
23 + * },
24 + * ...
25 + * },
26 + * ...
27 + * } $parsed_block
13 28 */
14 29 function gutenberg_render_custom_css_support_styles( $parsed_block ) {
15 - $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $parsed_block['blockName'] );
16 -
17 - if ( ! block_has_support( $block_type, 'customCSS', true ) ) {
30 + $custom_css = $parsed_block['attrs']['style']['css'] ?? null;
31 + if ( ! is_string( $custom_css ) || '' === trim( $custom_css ) ) {
18 32 return $parsed_block;
19 33 }
20 34
21 - $custom_css = trim( $parsed_block['attrs']['style']['css'] ?? '' );
22 -
23 - if ( empty( $custom_css ) ) {
35 + $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $parsed_block['blockName'] );
36 + if ( ! block_has_support( $block_type, 'customCSS', true ) ) {
24 37 return $parsed_block;
25 38 }
26 39
27 40 // Validate CSS doesn't contain HTML markup (same validation as global styles REST API).
@@ -29,14 +42,15 @@
29 42 return $parsed_block;
30 43 }
31 44
32 45 // Generate a unique class name for this block instance.
33 - $class_name = wp_unique_id_from_values( $parsed_block, 'wp-custom-css-' );
34 - $updated_class_name = isset( $parsed_block['attrs']['className'] )
35 - ? $parsed_block['attrs']['className'] . " $class_name"
46 + $class_name = wp_unique_id_from_values( $parsed_block, 'wp-custom-css-' );
47 + $existing_class_name = $parsed_block['attrs']['className'] ?? null;
48 + $updated_class_name = is_string( $existing_class_name )
49 + ? "$existing_class_name $class_name"
36 50 : $class_name;
37 51
38 - _wp_array_set( $parsed_block, array( 'attrs', 'className' ), $updated_class_name );
52 + $parsed_block['attrs']['className'] = $updated_class_name;
39 53
40 54 // Process the custom CSS using the same method as global styles.
41 55 $selector = '.' . $class_name;
42 56 $processed_css = WP_Theme_JSON_Gutenberg::process_blocks_custom_css( $custom_css, $selector );
@@ -41,15 +55,25 @@
41 55 $selector = '.' . $class_name;
42 56 $processed_css = WP_Theme_JSON_Gutenberg::process_blocks_custom_css( $custom_css, $selector );
43 57
44 58 if ( ! empty( $processed_css ) ) {
45 - /*
46 - * Register and add inline style for block custom CSS.
47 - * The style depends on global-styles to ensure custom CSS loads after
48 - * and can override global styles.
59 + /**
60 + * Reuse one handle so identical custom CSS is enqueued only once via
61 + * {@see wp_unique_id_from_values()}. Explicitly declare the `wp-block-library`
62 + * dependency so `global-styles` is guaranteed to print after it, preventing
63 + * block default styles from unintentionally overriding global styles.
49 64 */
50 - wp_register_style( 'wp-block-custom-css', false, array( 'global-styles' ) );
51 - wp_add_inline_style( 'wp-block-custom-css', $processed_css );
65 + $handle = 'wp-block-custom-css';
66 + if ( ! wp_style_is( $handle, 'registered' ) ) {
67 + wp_register_style( $handle, false, array( 'wp-block-library', 'global-styles' ) );
68 + }
69 + $after_styles = wp_styles()->get_data( $handle, 'after' );
70 + if ( ! is_array( $after_styles ) ) {
71 + $after_styles = array();
72 + }
73 + if ( ! in_array( $processed_css, $after_styles, true ) ) {
74 + wp_add_inline_style( $handle, $processed_css );
75 + }
52 76 }
53 77
54 78 return $parsed_block;
55 79 }
@@ -55,8 +79,10 @@
55 79 }
56 80
57 81 /**
58 82 * Enqueues the block custom CSS styles.
83 + *
84 + * @since 7.0.0
59 85 */
60 86 function gutenberg_enqueue_block_custom_css() {
61 87 wp_enqueue_style( 'wp-block-custom-css' );
62 88 }
@@ -63,28 +89,51 @@
63 89
64 90 /**
65 91 * Applies the custom CSS class name to the block's rendered HTML.
66 92 *
67 - * The class name is generated in `gutenberg_render_custom_css_support_styles`
93 + * The class name is generated in {@see gutenberg_render_custom_css_support_styles()}
68 94 * and stored in block attributes. This filter adds it to the actual markup.
69 95 *
96 + * @since 7.0.0
97 + *
70 98 * @param string $block_content Rendered block content.
71 99 * @param array $block Block object.
72 - * @return string Filtered block content.
100 + * @return string Filtered block content.
101 + *
102 + * @phpstan-param array{
103 + * attrs: array{
104 + * className?: string,
105 + * ...
106 + * },
107 + * ...
108 + * } $block
73 109 */
74 110 function gutenberg_render_custom_css_class_name( $block_content, $block ) {
75 - $class_string = $block['attrs']['className'] ?? '';
76 - preg_match( '/\bwp-custom-css-\S+\b/', $class_string, $matches );
111 + $class_name_attr = $block['attrs']['className'] ?? null;
112 + $class_name_prefix = 'wp-custom-css-';
113 + if ( ! is_string( $class_name_attr ) || ! str_contains( $class_name_attr, $class_name_prefix ) ) {
114 + return $block_content;
115 + }
77 116
78 - if ( empty( $matches ) ) {
117 + // Parse out the 'wp-custom-css-*' class name added by gutenberg_render_custom_css_support_styles().
118 + $matched_class_name = null;
119 + $token_delimiter = " \t\f\r\n";
120 + $class_token = strtok( $class_name_attr, $token_delimiter );
121 + while ( false !== $class_token ) {
122 + if ( str_starts_with( $class_token, $class_name_prefix ) ) {
123 + $matched_class_name = $class_token;
124 + break;
125 + }
126 + $class_token = strtok( $token_delimiter );
127 + }
128 + if ( null === $matched_class_name ) {
79 129 return $block_content;
80 130 }
81 131
82 132 $tags = new WP_HTML_Tag_Processor( $block_content );
83 -
84 133 if ( $tags->next_tag() ) {
85 134 $tags->add_class( 'has-custom-css' );
86 - $tags->add_class( $matches[0] );
135 + $tags->add_class( $matched_class_name );
87 136 }
88 137
89 138 return $tags->get_updated_html();
90 139 }
@@ -107,8 +156,10 @@
107 156
108 157 /**
109 158 * Registers the style block attribute for block types that support it.
110 159 *
160 + * @since 7.0.0
161 + *
111 162 * @param WP_Block_Type $block_type Block Type.
112 163 */
113 164 function gutenberg_register_custom_css_support( $block_type ) {
114 165 // Setup attributes and styles within that if needed.
@@ -136,8 +187,10 @@
136 187 * Uses WP_Block_Parser::next_token() to scan block tokens and surgically
137 188 * replace only the attribute JSON that changed — no parse_blocks() +
138 189 * serialize_blocks() round-trip needed.
139 190 *
191 + * @since 7.0.0
192 + *
140 193 * @param string $content Post content to filter, expected to be escaped with slashes.
141 194 * @return string Filtered post content with block custom CSS removed.
142 195 */
143 196 function gutenberg_strip_custom_css_from_blocks( $content ) {
@@ -216,8 +269,10 @@
216 269 }
217 270
218 271 /**
219 272 * Adds the filters to strip custom CSS from block content on save.
273 + *
274 + * @since 7.0.0
220 275 * @access private
221 276 */
222 277 function gutenberg_custom_css_kses_init_filters() {
223 278 add_filter( 'content_save_pre', 'gutenberg_strip_custom_css_from_blocks', 8 );
@@ -225,8 +280,10 @@
225 280 }
226 281
227 282 /**
228 283 * Removes the filters that strip custom CSS from block content on save.
284 + *
285 + * @since 7.0.0
229 286 * @access private
230 287 */
231 288 function gutenberg_custom_css_remove_filters() {
232 289 remove_filter( 'content_save_pre', 'gutenberg_strip_custom_css_from_blocks', 8 );
@@ -234,8 +291,10 @@
234 291 }
235 292
236 293 /**
237 294 * Registers the custom CSS content filters if the user does not have the edit_css capability.
295 + *
296 + * @since 7.0.0
238 297 * @access private
239 298 */
240 299 function gutenberg_custom_css_kses_init() {
241 300 gutenberg_custom_css_remove_filters();
@@ -249,8 +308,10 @@
249 308 *
250 309 * This filter is the last being executed on force_filtered_html_on_import.
251 310 * If the input of the filter is true it means we are in an import situation and should
252 311 * enable the custom CSS filters, independently of the user capabilities.
312 + *
313 + * @since 7.0.0
253 314 * @access private
254 315 *
255 316 * @param mixed $arg Input argument of the filter.
256 317 * @return mixed Input argument of the filter.