PluginProbe
Gutenberg / trunk
Gutenberg vtrunk
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.1.1 → trunk 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.