PluginProbe
Gutenberg / 23.5.3
Gutenberg v23.5.3
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 12.6.0 7.4.0 All 402 releases
gutenberg / lib / block-supports / elements.php

elements.php in Gutenberg 23.5.3, at lib/block-supports/elements.php

287 lines 9.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Elements styles block support.
4 *
5 * @package gutenberg
6 */
7
8 /**
9 * Update the block content with elements class names.
10 *
11 * @deprecated 6.6.0 Use `gutenberg_render_elements_class_name` instead.
12 *
13 * @param string $block_content Rendered block content.
14 * @return string Filtered block content.
15 */
16 function gutenberg_render_elements_support( $block_content ) {
17 _deprecated_function( __FUNCTION__, '6.6.0', 'gutenberg_render_elements_class_name' );
18 return $block_content;
19 }
20
21 /**
22 * Determines whether an elements class name should be added to the block.
23 *
24 * @param array $block Block object.
25 * @param array $options Per element type options e.g. whether to skip serialization.
26 *
27 * @return boolean Whether the block needs an elements class name.
28 */
29 function gutenberg_should_add_elements_class_name( $block, $options ) {
30 if ( ! isset( $block['attrs']['style']['elements'] ) ) {
31 return false;
32 }
33
34 $element_color_properties = array(
35 'button' => array(
36 'skip' => $options['button']['skip'] ?? false,
37 'paths' => array(
38 array( 'button', 'color', 'text' ),
39 array( 'button', 'color', 'background' ),
40 array( 'button', 'color', 'gradient' ),
41 ),
42 ),
43 'link' => array(
44 'skip' => $options['link']['skip'] ?? false,
45 'paths' => array(
46 array( 'link', 'color', 'text' ),
47 array( 'link', ':hover', 'color', 'text' ),
48 ),
49 ),
50 'heading' => array(
51 'skip' => $options['heading']['skip'] ?? false,
52 'paths' => array(
53 array( 'heading', 'color', 'text' ),
54 array( 'heading', 'color', 'background' ),
55 array( 'heading', 'color', 'gradient' ),
56 array( 'h1', 'color', 'text' ),
57 array( 'h1', 'color', 'background' ),
58 array( 'h1', 'color', 'gradient' ),
59 array( 'h2', 'color', 'text' ),
60 array( 'h2', 'color', 'background' ),
61 array( 'h2', 'color', 'gradient' ),
62 array( 'h3', 'color', 'text' ),
63 array( 'h3', 'color', 'background' ),
64 array( 'h3', 'color', 'gradient' ),
65 array( 'h4', 'color', 'text' ),
66 array( 'h4', 'color', 'background' ),
67 array( 'h4', 'color', 'gradient' ),
68 array( 'h5', 'color', 'text' ),
69 array( 'h5', 'color', 'background' ),
70 array( 'h5', 'color', 'gradient' ),
71 array( 'h6', 'color', 'text' ),
72 array( 'h6', 'color', 'background' ),
73 array( 'h6', 'color', 'gradient' ),
74 ),
75 ),
76 );
77
78 $elements_style_attributes = $block['attrs']['style']['elements'];
79
80 foreach ( $element_color_properties as $element_config ) {
81 if ( $element_config['skip'] ) {
82 continue;
83 }
84
85 foreach ( $element_config['paths'] as $path ) {
86 if ( null !== _wp_array_get( $elements_style_attributes, $path, null ) ) {
87 return true;
88 }
89 }
90 }
91
92 return false;
93 }
94
95 /**
96 * Render the elements stylesheet and adds elements class name to block as required.
97 *
98 * In the case of nested blocks we want the parent element styles to be rendered before their descendants.
99 * This solves the issue of an element (e.g.: link color) being styled in both the parent and a descendant:
100 * we want the descendant style to take priority, and this is done by loading it after, in DOM order.
101 *
102 * @since 6.6.0 Element block support class and styles are generated via the `render_block_data` filter instead of `pre_render_block`
103 *
104 * @param array $parsed_block The parsed block.
105 *
106 * @return array The same parsed block with elements classname added if appropriate.
107 */
108 function gutenberg_render_elements_support_styles( $parsed_block ) {
109 /*
110 * The generation of element styles and classname were moved to the
111 * `render_block_data` filter in 6.6.0 to avoid filtered attributes
112 * breaking the application of the elements CSS class.
113 *
114 * @link https://github.com/WordPress/gutenberg/pull/59535
115 *
116 * The change in filter means, the argument types for this function
117 * have changed and require deprecating.
118 */
119 if ( is_string( $parsed_block ) ) {
120 _deprecated_argument(
121 __FUNCTION__,
122 '6.6.0',
123 __( 'Use as a `pre_render_block` filter is deprecated. Use with `render_block_data` instead.', 'gutenberg' )
124 );
125 }
126
127 $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $parsed_block['blockName'] );
128 $element_block_styles = $parsed_block['attrs']['style']['elements'] ?? null;
129
130 if ( ! $element_block_styles ) {
131 return $parsed_block;
132 }
133
134 $skip_link_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'link' );
135 $skip_heading_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'heading' );
136 $skip_button_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'button' );
137 $skips_all_element_color_serialization = $skip_link_color_serialization &&
138 $skip_heading_color_serialization &&
139 $skip_button_color_serialization;
140
141 if ( $skips_all_element_color_serialization ) {
142 return $parsed_block;
143 }
144
145 $options = array(
146 'button' => array( 'skip' => $skip_button_color_serialization ),
147 'link' => array( 'skip' => $skip_link_color_serialization ),
148 'heading' => array( 'skip' => $skip_heading_color_serialization ),
149 );
150
151 if ( ! gutenberg_should_add_elements_class_name( $parsed_block, $options ) ) {
152 return $parsed_block;
153 }
154
155 $class_name = wp_get_elements_class_name( $parsed_block );
156 $updated_class_name = isset( $parsed_block['attrs']['className'] ) ? $parsed_block['attrs']['className'] . " $class_name" : $class_name;
157
158 _wp_array_set( $parsed_block, array( 'attrs', 'className' ), $updated_class_name );
159
160 // Generate element styles based on selector and store in style engine for enqueuing.
161 $element_types = array(
162 'button' => array(
163 'selector' => ".$class_name .wp-element-button, .$class_name .wp-block-button__link",
164 'skip' => $skip_button_color_serialization,
165 ),
166 'link' => array(
167 // :where(:not) matches theme.json selector.
168 'selector' => ".$class_name a:where(:not(.wp-element-button))",
169 'hover_selector' => ".$class_name a:where(:not(.wp-element-button)):hover",
170 'skip' => $skip_link_color_serialization,
171 ),
172 'heading' => array(
173 'selector' => ".$class_name h1, .$class_name h2, .$class_name h3, .$class_name h4, .$class_name h5, .$class_name h6",
174 'skip' => $skip_heading_color_serialization,
175 'elements' => array( 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ),
176 ),
177 );
178
179 foreach ( $element_types as $element_type => $element_config ) {
180 if ( $element_config['skip'] ) {
181 continue;
182 }
183
184 $element_style_object = _wp_array_get( $element_block_styles, array( $element_type ), null );
185
186 // Process primary element type styles.
187 if ( $element_style_object ) {
188 gutenberg_style_engine_get_styles(
189 $element_style_object,
190 array(
191 'selector' => $element_config['selector'],
192 'context' => 'block-supports',
193 )
194 );
195
196 if ( isset( $element_style_object[':hover'] ) ) {
197 gutenberg_style_engine_get_styles(
198 $element_style_object[':hover'],
199 array(
200 'selector' => $element_config['hover_selector'],
201 'context' => 'block-supports',
202 )
203 );
204 }
205 }
206
207 // Process related elements e.g. h1-h6 for headings.
208 if ( isset( $element_config['elements'] ) ) {
209 foreach ( $element_config['elements'] as $element ) {
210 $element_style_object = _wp_array_get( $element_block_styles, array( $element ), null );
211
212 if ( $element_style_object ) {
213 gutenberg_style_engine_get_styles(
214 $element_style_object,
215 array(
216 'selector' => ".$class_name $element",
217 'context' => 'block-supports',
218 )
219 );
220 }
221 }
222 }
223 }
224
225 return $parsed_block;
226 }
227
228 /**
229 * Ensure the elements block support class name generated, and added to
230 * block attributes, in the `render_block_data` filter gets applied to the
231 * block's markup.
232 *
233 * @see gutenberg_render_elements_support_styles
234 *
235 * @param string $block_content Rendered block content.
236 * @param array $block Block object.
237 * @return string Filtered block content.
238 *
239 * @phpstan-param array{
240 * attrs: array{
241 * className?: string,
242 * ...
243 * },
244 * ...
245 * } $block
246 */
247 function gutenberg_render_elements_class_name( $block_content, $block ) {
248 $class_name_attr = $block['attrs']['className'] ?? null;
249 $class_name_prefix = 'wp-elements-';
250 if ( ! is_string( $class_name_attr ) || ! str_contains( $class_name_attr, $class_name_prefix ) ) {
251 return $block_content;
252 }
253
254 // Parse out the 'wp-elements-*' class name.
255 $matched_class_name = null;
256 $token_delimiter = " \t\f\r\n";
257 $class_token = strtok( $class_name_attr, $token_delimiter );
258 while ( false !== $class_token ) {
259 if ( str_starts_with( $class_token, $class_name_prefix ) ) {
260 $matched_class_name = $class_token;
261 break;
262 }
263 $class_token = strtok( $token_delimiter );
264 }
265 if ( null === $matched_class_name ) {
266 return $block_content;
267 }
268
269 $tags = new WP_HTML_Tag_Processor( $block_content );
270 if ( $tags->next_tag() ) {
271 $tags->add_class( $matched_class_name );
272 }
273
274 return $tags->get_updated_html();
275 }
276
277 // Remove deprecated WordPress core filters.
278 remove_filter( 'render_block', 'wp_render_elements_support', 10 );
279 remove_filter( 'pre_render_block', 'wp_render_elements_support_styles', 10 );
280
281 // Remove WordPress core filters to avoid rendering duplicate elements stylesheet & attaching classes twice.
282 remove_filter( 'render_block', 'wp_render_elements_class_name', 10 );
283 remove_filter( 'render_block_data', 'wp_render_elements_support_styles', 10 );
284
285 add_filter( 'render_block', 'gutenberg_render_elements_class_name', 10, 2 );
286 add_filter( 'render_block_data', 'gutenberg_render_elements_support_styles', 10, 1 );
287