55 if ( $has_font_size_support && ! array_key_exists( 'fontSize', $block_type->attributes ) ) { |
62 if ( $has_font_size_support && ! array_key_exists( 'fontSize', $block_type->attributes ) ) { |
56 $block_type->attributes['fontSize'] = array( |
63 $block_type->attributes['fontSize'] = array( |
57 'type' => 'string', |
64 'type' => 'string', |
58 ); |
65 ); |
59 } |
66 } |
|
67 |
|
68 if ( $has_font_family_support && ! array_key_exists( 'fontFamily', $block_type->attributes ) ) { |
|
69 $block_type->attributes['fontFamily'] = array( |
|
70 'type' => 'string', |
|
71 ); |
|
72 } |
60 } |
73 } |
61 |
74 |
62 /** |
75 /** |
63 * Adds CSS classes and inline styles for typography features such as font sizes |
76 * Adds CSS classes and inline styles for typography features such as font sizes |
64 * to the incoming attributes array. This will be applied to the block markup in |
77 * to the incoming attributes array. This will be applied to the block markup in |
65 * the front-end. |
78 * the front-end. |
66 * |
79 * |
67 * @since 5.6.0 |
80 * @since 5.6.0 |
|
81 * @since 6.1.0 Used the style engine to generate CSS and classnames. |
|
82 * @since 6.3.0 Added support for text-columns. |
68 * @access private |
83 * @access private |
69 * |
84 * |
70 * @param WP_Block_Type $block_type Block type. |
85 * @param WP_Block_Type $block_type Block type. |
71 * @param array $block_attributes Block attributes. |
86 * @param array $block_attributes Block attributes. |
72 * @return array Typography CSS classes and inline styles. |
87 * @return array Typography CSS classes and inline styles. |
73 */ |
88 */ |
74 function wp_apply_typography_support( $block_type, $block_attributes ) { |
89 function wp_apply_typography_support( $block_type, $block_attributes ) { |
75 if ( ! property_exists( $block_type, 'supports' ) ) { |
90 if ( ! ( $block_type instanceof WP_Block_Type ) ) { |
76 return array(); |
91 return array(); |
77 } |
92 } |
78 |
93 |
79 $typography_supports = _wp_array_get( $block_type->supports, array( 'typography' ), false ); |
94 $typography_supports = isset( $block_type->supports['typography'] ) |
|
95 ? $block_type->supports['typography'] |
|
96 : false; |
80 if ( ! $typography_supports ) { |
97 if ( ! $typography_supports ) { |
81 return array(); |
98 return array(); |
82 } |
99 } |
83 |
100 |
84 if ( wp_should_skip_block_supports_serialization( $block_type, 'typography' ) ) { |
101 if ( wp_should_skip_block_supports_serialization( $block_type, 'typography' ) ) { |
85 return array(); |
102 return array(); |
86 } |
103 } |
87 |
104 |
|
105 $has_font_family_support = isset( $typography_supports['__experimentalFontFamily'] ) ? $typography_supports['__experimentalFontFamily'] : false; |
|
106 $has_font_size_support = isset( $typography_supports['fontSize'] ) ? $typography_supports['fontSize'] : false; |
|
107 $has_font_style_support = isset( $typography_supports['__experimentalFontStyle'] ) ? $typography_supports['__experimentalFontStyle'] : false; |
|
108 $has_font_weight_support = isset( $typography_supports['__experimentalFontWeight'] ) ? $typography_supports['__experimentalFontWeight'] : false; |
|
109 $has_letter_spacing_support = isset( $typography_supports['__experimentalLetterSpacing'] ) ? $typography_supports['__experimentalLetterSpacing'] : false; |
|
110 $has_line_height_support = isset( $typography_supports['lineHeight'] ) ? $typography_supports['lineHeight'] : false; |
|
111 $has_text_align_support = isset( $typography_supports['textAlign'] ) ? $typography_supports['textAlign'] : false; |
|
112 $has_text_columns_support = isset( $typography_supports['textColumns'] ) ? $typography_supports['textColumns'] : false; |
|
113 $has_text_decoration_support = isset( $typography_supports['__experimentalTextDecoration'] ) ? $typography_supports['__experimentalTextDecoration'] : false; |
|
114 $has_text_transform_support = isset( $typography_supports['__experimentalTextTransform'] ) ? $typography_supports['__experimentalTextTransform'] : false; |
|
115 $has_writing_mode_support = isset( $typography_supports['__experimentalWritingMode'] ) ? $typography_supports['__experimentalWritingMode'] : false; |
|
116 |
|
117 // Whether to skip individual block support features. |
|
118 $should_skip_font_size = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontSize' ); |
|
119 $should_skip_font_family = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontFamily' ); |
|
120 $should_skip_font_style = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontStyle' ); |
|
121 $should_skip_font_weight = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontWeight' ); |
|
122 $should_skip_line_height = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'lineHeight' ); |
|
123 $should_skip_text_align = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textAlign' ); |
|
124 $should_skip_text_columns = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textColumns' ); |
|
125 $should_skip_text_decoration = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textDecoration' ); |
|
126 $should_skip_text_transform = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textTransform' ); |
|
127 $should_skip_letter_spacing = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'letterSpacing' ); |
|
128 $should_skip_writing_mode = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'writingMode' ); |
|
129 |
|
130 $typography_block_styles = array(); |
|
131 if ( $has_font_size_support && ! $should_skip_font_size ) { |
|
132 $preset_font_size = array_key_exists( 'fontSize', $block_attributes ) |
|
133 ? "var:preset|font-size|{$block_attributes['fontSize']}" |
|
134 : null; |
|
135 $custom_font_size = isset( $block_attributes['style']['typography']['fontSize'] ) |
|
136 ? $block_attributes['style']['typography']['fontSize'] |
|
137 : null; |
|
138 $typography_block_styles['fontSize'] = $preset_font_size ? $preset_font_size : wp_get_typography_font_size_value( |
|
139 array( |
|
140 'size' => $custom_font_size, |
|
141 ) |
|
142 ); |
|
143 } |
|
144 |
|
145 if ( $has_font_family_support && ! $should_skip_font_family ) { |
|
146 $preset_font_family = array_key_exists( 'fontFamily', $block_attributes ) |
|
147 ? "var:preset|font-family|{$block_attributes['fontFamily']}" |
|
148 : null; |
|
149 $custom_font_family = isset( $block_attributes['style']['typography']['fontFamily'] ) |
|
150 ? wp_typography_get_preset_inline_style_value( $block_attributes['style']['typography']['fontFamily'], 'font-family' ) |
|
151 : null; |
|
152 $typography_block_styles['fontFamily'] = $preset_font_family ? $preset_font_family : $custom_font_family; |
|
153 } |
|
154 |
|
155 if ( |
|
156 $has_font_style_support && |
|
157 ! $should_skip_font_style && |
|
158 isset( $block_attributes['style']['typography']['fontStyle'] ) |
|
159 ) { |
|
160 $typography_block_styles['fontStyle'] = wp_typography_get_preset_inline_style_value( |
|
161 $block_attributes['style']['typography']['fontStyle'], |
|
162 'font-style' |
|
163 ); |
|
164 } |
|
165 |
|
166 if ( |
|
167 $has_font_weight_support && |
|
168 ! $should_skip_font_weight && |
|
169 isset( $block_attributes['style']['typography']['fontWeight'] ) |
|
170 ) { |
|
171 $typography_block_styles['fontWeight'] = wp_typography_get_preset_inline_style_value( |
|
172 $block_attributes['style']['typography']['fontWeight'], |
|
173 'font-weight' |
|
174 ); |
|
175 } |
|
176 |
|
177 if ( $has_line_height_support && ! $should_skip_line_height ) { |
|
178 $typography_block_styles['lineHeight'] = isset( $block_attributes['style']['typography']['lineHeight'] ) |
|
179 ? $block_attributes['style']['typography']['lineHeight'] |
|
180 : null; |
|
181 } |
|
182 |
|
183 if ( $has_text_align_support && ! $should_skip_text_align ) { |
|
184 $typography_block_styles['textAlign'] = isset( $block_attributes['style']['typography']['textAlign'] ) |
|
185 ? $block_attributes['style']['typography']['textAlign'] |
|
186 : null; |
|
187 } |
|
188 |
|
189 if ( $has_text_columns_support && ! $should_skip_text_columns && isset( $block_attributes['style']['typography']['textColumns'] ) ) { |
|
190 $typography_block_styles['textColumns'] = isset( $block_attributes['style']['typography']['textColumns'] ) |
|
191 ? $block_attributes['style']['typography']['textColumns'] |
|
192 : null; |
|
193 } |
|
194 |
|
195 if ( |
|
196 $has_text_decoration_support && |
|
197 ! $should_skip_text_decoration && |
|
198 isset( $block_attributes['style']['typography']['textDecoration'] ) |
|
199 ) { |
|
200 $typography_block_styles['textDecoration'] = wp_typography_get_preset_inline_style_value( |
|
201 $block_attributes['style']['typography']['textDecoration'], |
|
202 'text-decoration' |
|
203 ); |
|
204 } |
|
205 |
|
206 if ( |
|
207 $has_text_transform_support && |
|
208 ! $should_skip_text_transform && |
|
209 isset( $block_attributes['style']['typography']['textTransform'] ) |
|
210 ) { |
|
211 $typography_block_styles['textTransform'] = wp_typography_get_preset_inline_style_value( |
|
212 $block_attributes['style']['typography']['textTransform'], |
|
213 'text-transform' |
|
214 ); |
|
215 } |
|
216 |
|
217 if ( |
|
218 $has_letter_spacing_support && |
|
219 ! $should_skip_letter_spacing && |
|
220 isset( $block_attributes['style']['typography']['letterSpacing'] ) |
|
221 ) { |
|
222 $typography_block_styles['letterSpacing'] = wp_typography_get_preset_inline_style_value( |
|
223 $block_attributes['style']['typography']['letterSpacing'], |
|
224 'letter-spacing' |
|
225 ); |
|
226 } |
|
227 |
|
228 if ( $has_writing_mode_support && |
|
229 ! $should_skip_writing_mode && |
|
230 isset( $block_attributes['style']['typography']['writingMode'] ) |
|
231 ) { |
|
232 $typography_block_styles['writingMode'] = isset( $block_attributes['style']['typography']['writingMode'] ) |
|
233 ? $block_attributes['style']['typography']['writingMode'] |
|
234 : null; |
|
235 } |
|
236 |
88 $attributes = array(); |
237 $attributes = array(); |
89 $classes = array(); |
238 $classnames = array(); |
90 $styles = array(); |
239 $styles = wp_style_engine_get_styles( |
91 |
240 array( 'typography' => $typography_block_styles ), |
92 $has_font_family_support = _wp_array_get( $typography_supports, array( '__experimentalFontFamily' ), false ); |
241 array( 'convert_vars_to_classnames' => true ) |
93 $has_font_size_support = _wp_array_get( $typography_supports, array( 'fontSize' ), false ); |
242 ); |
94 $has_font_style_support = _wp_array_get( $typography_supports, array( '__experimentalFontStyle' ), false ); |
243 |
95 $has_font_weight_support = _wp_array_get( $typography_supports, array( '__experimentalFontWeight' ), false ); |
244 if ( ! empty( $styles['classnames'] ) ) { |
96 $has_letter_spacing_support = _wp_array_get( $typography_supports, array( '__experimentalLetterSpacing' ), false ); |
245 $classnames[] = $styles['classnames']; |
97 $has_line_height_support = _wp_array_get( $typography_supports, array( 'lineHeight' ), false ); |
246 } |
98 $has_text_decoration_support = _wp_array_get( $typography_supports, array( '__experimentalTextDecoration' ), false ); |
247 |
99 $has_text_transform_support = _wp_array_get( $typography_supports, array( '__experimentalTextTransform' ), false ); |
248 if ( $has_text_align_support && ! $should_skip_text_align && isset( $block_attributes['style']['typography']['textAlign'] ) ) { |
100 |
249 $classnames[] = 'has-text-align-' . $block_attributes['style']['typography']['textAlign']; |
101 if ( $has_font_size_support && ! wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontSize' ) ) { |
250 } |
102 $has_named_font_size = array_key_exists( 'fontSize', $block_attributes ); |
251 |
103 $has_custom_font_size = isset( $block_attributes['style']['typography']['fontSize'] ); |
252 if ( ! empty( $classnames ) ) { |
104 |
253 $attributes['class'] = implode( ' ', $classnames ); |
105 if ( $has_named_font_size ) { |
254 } |
106 $classes[] = sprintf( 'has-%s-font-size', _wp_to_kebab_case( $block_attributes['fontSize'] ) ); |
255 |
107 } elseif ( $has_custom_font_size ) { |
256 if ( ! empty( $styles['css'] ) ) { |
108 $styles[] = sprintf( 'font-size: %s;', $block_attributes['style']['typography']['fontSize'] ); |
257 $attributes['style'] = $styles['css']; |
109 } |
|
110 } |
|
111 |
|
112 if ( $has_font_family_support && ! wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontFamily' ) ) { |
|
113 $has_named_font_family = array_key_exists( 'fontFamily', $block_attributes ); |
|
114 $has_custom_font_family = isset( $block_attributes['style']['typography']['fontFamily'] ); |
|
115 |
|
116 if ( $has_named_font_family ) { |
|
117 $classes[] = sprintf( 'has-%s-font-family', _wp_to_kebab_case( $block_attributes['fontFamily'] ) ); |
|
118 } elseif ( $has_custom_font_family ) { |
|
119 // Before using classes, the value was serialized as a CSS Custom Property. |
|
120 // We don't need this code path when it lands in core. |
|
121 $font_family_custom = $block_attributes['style']['typography']['fontFamily']; |
|
122 if ( strpos( $font_family_custom, 'var:preset|font-family' ) !== false ) { |
|
123 $index_to_splice = strrpos( $font_family_custom, '|' ) + 1; |
|
124 $font_family_slug = _wp_to_kebab_case( substr( $font_family_custom, $index_to_splice ) ); |
|
125 $font_family_custom = sprintf( 'var(--wp--preset--font-family--%s)', $font_family_slug ); |
|
126 } |
|
127 $styles[] = sprintf( 'font-family: %s;', $font_family_custom ); |
|
128 } |
|
129 } |
|
130 |
|
131 if ( $has_font_style_support && ! wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontStyle' ) ) { |
|
132 $font_style = wp_typography_get_css_variable_inline_style( $block_attributes, 'fontStyle', 'font-style' ); |
|
133 if ( $font_style ) { |
|
134 $styles[] = $font_style; |
|
135 } |
|
136 } |
|
137 |
|
138 if ( $has_font_weight_support && ! wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontWeight' ) ) { |
|
139 $font_weight = wp_typography_get_css_variable_inline_style( $block_attributes, 'fontWeight', 'font-weight' ); |
|
140 if ( $font_weight ) { |
|
141 $styles[] = $font_weight; |
|
142 } |
|
143 } |
|
144 |
|
145 if ( $has_line_height_support && ! wp_should_skip_block_supports_serialization( $block_type, 'typography', 'lineHeight' ) ) { |
|
146 $has_line_height = isset( $block_attributes['style']['typography']['lineHeight'] ); |
|
147 if ( $has_line_height ) { |
|
148 $styles[] = sprintf( 'line-height: %s;', $block_attributes['style']['typography']['lineHeight'] ); |
|
149 } |
|
150 } |
|
151 |
|
152 if ( $has_text_decoration_support && ! wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textDecoration' ) ) { |
|
153 $text_decoration_style = wp_typography_get_css_variable_inline_style( $block_attributes, 'textDecoration', 'text-decoration' ); |
|
154 if ( $text_decoration_style ) { |
|
155 $styles[] = $text_decoration_style; |
|
156 } |
|
157 } |
|
158 |
|
159 if ( $has_text_transform_support && ! wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textTransform' ) ) { |
|
160 $text_transform_style = wp_typography_get_css_variable_inline_style( $block_attributes, 'textTransform', 'text-transform' ); |
|
161 if ( $text_transform_style ) { |
|
162 $styles[] = $text_transform_style; |
|
163 } |
|
164 } |
|
165 |
|
166 if ( $has_letter_spacing_support && ! wp_should_skip_block_supports_serialization( $block_type, 'typography', 'letterSpacing' ) ) { |
|
167 $letter_spacing_style = wp_typography_get_css_variable_inline_style( $block_attributes, 'letterSpacing', 'letter-spacing' ); |
|
168 if ( $letter_spacing_style ) { |
|
169 $styles[] = $letter_spacing_style; |
|
170 } |
|
171 } |
|
172 |
|
173 if ( ! empty( $classes ) ) { |
|
174 $attributes['class'] = implode( ' ', $classes ); |
|
175 } |
|
176 if ( ! empty( $styles ) ) { |
|
177 $attributes['style'] = implode( ' ', $styles ); |
|
178 } |
258 } |
179 |
259 |
180 return $attributes; |
260 return $attributes; |
181 } |
261 } |
182 |
262 |
183 /** |
263 /** |
184 * Generates an inline style for a typography feature e.g. text decoration, |
264 * Generates an inline style value for a typography feature e.g. text decoration, |
185 * text transform, and font style. |
265 * text transform, and font style. |
186 * |
266 * |
187 * @since 5.8.0 |
267 * Note: This function is for backwards compatibility. |
|
268 * * It is necessary to parse older blocks whose typography styles contain presets. |
|
269 * * It mostly replaces the deprecated `wp_typography_get_css_variable_inline_style()`, |
|
270 * but skips compiling a CSS declaration as the style engine takes over this role. |
|
271 * @link https://github.com/wordpress/gutenberg/pull/27555 |
|
272 * |
|
273 * @since 6.1.0 |
|
274 * |
|
275 * @param string $style_value A raw style value for a single typography feature from a block's style attribute. |
|
276 * @param string $css_property Slug for the CSS property the inline style sets. |
|
277 * @return string A CSS inline style value. |
|
278 */ |
|
279 function wp_typography_get_preset_inline_style_value( $style_value, $css_property ) { |
|
280 // If the style value is not a preset CSS variable go no further. |
|
281 if ( empty( $style_value ) || ! str_contains( $style_value, "var:preset|{$css_property}|" ) ) { |
|
282 return $style_value; |
|
283 } |
|
284 |
|
285 /* |
|
286 * For backwards compatibility. |
|
287 * Presets were removed in WordPress/gutenberg#27555. |
|
288 * A preset CSS variable is the style. |
|
289 * Gets the style value from the string and return CSS style. |
|
290 */ |
|
291 $index_to_splice = strrpos( $style_value, '|' ) + 1; |
|
292 $slug = _wp_to_kebab_case( substr( $style_value, $index_to_splice ) ); |
|
293 |
|
294 // Return the actual CSS inline style value, |
|
295 // e.g. `var(--wp--preset--text-decoration--underline);`. |
|
296 return sprintf( 'var(--wp--preset--%s--%s);', $css_property, $slug ); |
|
297 } |
|
298 |
|
299 /** |
|
300 * Renders typography styles/content to the block wrapper. |
|
301 * |
|
302 * @since 6.1.0 |
|
303 * |
|
304 * @param string $block_content Rendered block content. |
|
305 * @param array $block Block object. |
|
306 * @return string Filtered block content. |
|
307 */ |
|
308 function wp_render_typography_support( $block_content, $block ) { |
|
309 if ( ! isset( $block['attrs']['style']['typography']['fontSize'] ) ) { |
|
310 return $block_content; |
|
311 } |
|
312 |
|
313 $custom_font_size = $block['attrs']['style']['typography']['fontSize']; |
|
314 $fluid_font_size = wp_get_typography_font_size_value( array( 'size' => $custom_font_size ) ); |
|
315 |
|
316 /* |
|
317 * Checks that $fluid_font_size does not match $custom_font_size, |
|
318 * which means it's been mutated by the fluid font size functions. |
|
319 */ |
|
320 if ( ! empty( $fluid_font_size ) && $fluid_font_size !== $custom_font_size ) { |
|
321 // Replaces the first instance of `font-size:$custom_font_size` with `font-size:$fluid_font_size`. |
|
322 return preg_replace( '/font-size\s*:\s*' . preg_quote( $custom_font_size, '/' ) . '\s*;?/', 'font-size:' . esc_attr( $fluid_font_size ) . ';', $block_content, 1 ); |
|
323 } |
|
324 |
|
325 return $block_content; |
|
326 } |
|
327 |
|
328 /** |
|
329 * Checks a string for a unit and value and returns an array |
|
330 * consisting of `'value'` and `'unit'`, e.g. array( '42', 'rem' ). |
|
331 * |
|
332 * @since 6.1.0 |
|
333 * |
|
334 * @param string|int|float $raw_value Raw size value from theme.json. |
|
335 * @param array $options { |
|
336 * Optional. An associative array of options. Default is empty array. |
|
337 * |
|
338 * @type string $coerce_to Coerce the value to rem or px. Default `'rem'`. |
|
339 * @type int $root_size_value Value of root font size for rem|em <-> px conversion. Default `16`. |
|
340 * @type string[] $acceptable_units An array of font size units. Default `array( 'rem', 'px', 'em' )`; |
|
341 * } |
|
342 * @return array|null An array consisting of `'value'` and `'unit'` properties on success. |
|
343 * `null` on failure. |
|
344 */ |
|
345 function wp_get_typography_value_and_unit( $raw_value, $options = array() ) { |
|
346 if ( ! is_string( $raw_value ) && ! is_int( $raw_value ) && ! is_float( $raw_value ) ) { |
|
347 _doing_it_wrong( |
|
348 __FUNCTION__, |
|
349 __( 'Raw size value must be a string, integer, or float.' ), |
|
350 '6.1.0' |
|
351 ); |
|
352 return null; |
|
353 } |
|
354 |
|
355 if ( empty( $raw_value ) ) { |
|
356 return null; |
|
357 } |
|
358 |
|
359 // Converts numbers to pixel values by default. |
|
360 if ( is_numeric( $raw_value ) ) { |
|
361 $raw_value = $raw_value . 'px'; |
|
362 } |
|
363 |
|
364 $defaults = array( |
|
365 'coerce_to' => '', |
|
366 'root_size_value' => 16, |
|
367 'acceptable_units' => array( 'rem', 'px', 'em' ), |
|
368 ); |
|
369 |
|
370 $options = wp_parse_args( $options, $defaults ); |
|
371 |
|
372 $acceptable_units_group = implode( '|', $options['acceptable_units'] ); |
|
373 $pattern = '/^(\d*\.?\d+)(' . $acceptable_units_group . '){1,1}$/'; |
|
374 |
|
375 preg_match( $pattern, $raw_value, $matches ); |
|
376 |
|
377 // Bails out if not a number value and a px or rem unit. |
|
378 if ( ! isset( $matches[1] ) || ! isset( $matches[2] ) ) { |
|
379 return null; |
|
380 } |
|
381 |
|
382 $value = $matches[1]; |
|
383 $unit = $matches[2]; |
|
384 |
|
385 /* |
|
386 * Default browser font size. Later, possibly could inject some JS to |
|
387 * compute this `getComputedStyle( document.querySelector( "html" ) ).fontSize`. |
|
388 */ |
|
389 if ( 'px' === $options['coerce_to'] && ( 'em' === $unit || 'rem' === $unit ) ) { |
|
390 $value = $value * $options['root_size_value']; |
|
391 $unit = $options['coerce_to']; |
|
392 } |
|
393 |
|
394 if ( 'px' === $unit && ( 'em' === $options['coerce_to'] || 'rem' === $options['coerce_to'] ) ) { |
|
395 $value = $value / $options['root_size_value']; |
|
396 $unit = $options['coerce_to']; |
|
397 } |
|
398 |
|
399 /* |
|
400 * No calculation is required if swapping between em and rem yet, |
|
401 * since we assume a root size value. Later we might like to differentiate between |
|
402 * :root font size (rem) and parent element font size (em) relativity. |
|
403 */ |
|
404 if ( ( 'em' === $options['coerce_to'] || 'rem' === $options['coerce_to'] ) && ( 'em' === $unit || 'rem' === $unit ) ) { |
|
405 $unit = $options['coerce_to']; |
|
406 } |
|
407 |
|
408 return array( |
|
409 'value' => round( $value, 3 ), |
|
410 'unit' => $unit, |
|
411 ); |
|
412 } |
|
413 |
|
414 /** |
|
415 * Internal implementation of CSS clamp() based on available min/max viewport |
|
416 * width and min/max font sizes. |
|
417 * |
|
418 * @since 6.1.0 |
|
419 * @since 6.3.0 Checks for unsupported min/max viewport values that cause invalid clamp values. |
|
420 * @since 6.5.0 Returns early when min and max viewport subtraction is zero to avoid division by zero. |
188 * @access private |
421 * @access private |
189 * |
422 * |
190 * @param array $attributes Block's attributes. |
423 * @param array $args { |
191 * @param string $feature Key for the feature within the typography styles. |
424 * Optional. An associative array of values to calculate a fluid formula |
192 * @param string $css_property Slug for the CSS property the inline style sets. |
425 * for font size. Default is empty array. |
193 * @return string CSS inline style. |
426 * |
194 */ |
427 * @type string $maximum_viewport_width Maximum size up to which type will have fluidity. |
195 function wp_typography_get_css_variable_inline_style( $attributes, $feature, $css_property ) { |
428 * @type string $minimum_viewport_width Minimum viewport size from which type will have fluidity. |
196 // Retrieve current attribute value or skip if not found. |
429 * @type string $maximum_font_size Maximum font size for any clamp() calculation. |
197 $style_value = _wp_array_get( $attributes, array( 'style', 'typography', $feature ), false ); |
430 * @type string $minimum_font_size Minimum font size for any clamp() calculation. |
198 if ( ! $style_value ) { |
431 * @type int $scale_factor A scale factor to determine how fast a font scales within boundaries. |
199 return; |
432 * } |
200 } |
433 * @return string|null A font-size value using clamp() on success, otherwise null. |
201 |
434 */ |
202 // If we don't have a preset CSS variable, we'll assume it's a regular CSS value. |
435 function wp_get_computed_fluid_typography_value( $args = array() ) { |
203 if ( strpos( $style_value, "var:preset|{$css_property}|" ) === false ) { |
436 $maximum_viewport_width_raw = isset( $args['maximum_viewport_width'] ) ? $args['maximum_viewport_width'] : null; |
204 return sprintf( '%s:%s;', $css_property, $style_value ); |
437 $minimum_viewport_width_raw = isset( $args['minimum_viewport_width'] ) ? $args['minimum_viewport_width'] : null; |
205 } |
438 $maximum_font_size_raw = isset( $args['maximum_font_size'] ) ? $args['maximum_font_size'] : null; |
206 |
439 $minimum_font_size_raw = isset( $args['minimum_font_size'] ) ? $args['minimum_font_size'] : null; |
207 // We have a preset CSS variable as the style. |
440 $scale_factor = isset( $args['scale_factor'] ) ? $args['scale_factor'] : null; |
208 // Get the style value from the string and return CSS style. |
441 |
209 $index_to_splice = strrpos( $style_value, '|' ) + 1; |
442 // Normalizes the minimum font size in order to use the value for calculations. |
210 $slug = substr( $style_value, $index_to_splice ); |
443 $minimum_font_size = wp_get_typography_value_and_unit( $minimum_font_size_raw ); |
211 |
444 |
212 // Return the actual CSS inline style e.g. `text-decoration:var(--wp--preset--text-decoration--underline);`. |
445 /* |
213 return sprintf( '%s:var(--wp--preset--%s--%s);', $css_property, $css_property, $slug ); |
446 * We get a 'preferred' unit to keep units consistent when calculating, |
|
447 * otherwise the result will not be accurate. |
|
448 */ |
|
449 $font_size_unit = isset( $minimum_font_size['unit'] ) ? $minimum_font_size['unit'] : 'rem'; |
|
450 |
|
451 // Normalizes the maximum font size in order to use the value for calculations. |
|
452 $maximum_font_size = wp_get_typography_value_and_unit( |
|
453 $maximum_font_size_raw, |
|
454 array( |
|
455 'coerce_to' => $font_size_unit, |
|
456 ) |
|
457 ); |
|
458 |
|
459 // Checks for mandatory min and max sizes, and protects against unsupported units. |
|
460 if ( ! $maximum_font_size || ! $minimum_font_size ) { |
|
461 return null; |
|
462 } |
|
463 |
|
464 // Uses rem for accessible fluid target font scaling. |
|
465 $minimum_font_size_rem = wp_get_typography_value_and_unit( |
|
466 $minimum_font_size_raw, |
|
467 array( |
|
468 'coerce_to' => 'rem', |
|
469 ) |
|
470 ); |
|
471 |
|
472 // Viewport widths defined for fluid typography. Normalize units. |
|
473 $maximum_viewport_width = wp_get_typography_value_and_unit( |
|
474 $maximum_viewport_width_raw, |
|
475 array( |
|
476 'coerce_to' => $font_size_unit, |
|
477 ) |
|
478 ); |
|
479 $minimum_viewport_width = wp_get_typography_value_and_unit( |
|
480 $minimum_viewport_width_raw, |
|
481 array( |
|
482 'coerce_to' => $font_size_unit, |
|
483 ) |
|
484 ); |
|
485 |
|
486 // Protects against unsupported units in min and max viewport widths. |
|
487 if ( ! $minimum_viewport_width || ! $maximum_viewport_width ) { |
|
488 return null; |
|
489 } |
|
490 |
|
491 // Calculates the linear factor denominator. If it's 0, we cannot calculate a fluid value. |
|
492 $linear_factor_denominator = $maximum_viewport_width['value'] - $minimum_viewport_width['value']; |
|
493 if ( empty( $linear_factor_denominator ) ) { |
|
494 return null; |
|
495 } |
|
496 |
|
497 /* |
|
498 * Build CSS rule. |
|
499 * Borrowed from https://websemantics.uk/tools/responsive-font-calculator/. |
|
500 */ |
|
501 $view_port_width_offset = round( $minimum_viewport_width['value'] / 100, 3 ) . $font_size_unit; |
|
502 $linear_factor = 100 * ( ( $maximum_font_size['value'] - $minimum_font_size['value'] ) / ( $linear_factor_denominator ) ); |
|
503 $linear_factor_scaled = round( $linear_factor * $scale_factor, 3 ); |
|
504 $linear_factor_scaled = empty( $linear_factor_scaled ) ? 1 : $linear_factor_scaled; |
|
505 $fluid_target_font_size = implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor_scaled)"; |
|
506 |
|
507 return "clamp($minimum_font_size_raw, $fluid_target_font_size, $maximum_font_size_raw)"; |
|
508 } |
|
509 |
|
510 /** |
|
511 * Returns a font-size value based on a given font-size preset. |
|
512 * Takes into account fluid typography parameters and attempts to return a CSS |
|
513 * formula depending on available, valid values. |
|
514 * |
|
515 * @since 6.1.0 |
|
516 * @since 6.1.1 Adjusted rules for min and max font sizes. |
|
517 * @since 6.2.0 Added 'settings.typography.fluid.minFontSize' support. |
|
518 * @since 6.3.0 Using layout.wideSize as max viewport width, and logarithmic scale factor to calculate minimum font scale. |
|
519 * @since 6.4.0 Added configurable min and max viewport width values to the typography.fluid theme.json schema. |
|
520 * @since 6.6.0 Deprecated bool argument $should_use_fluid_typography. |
|
521 * |
|
522 * @param array $preset { |
|
523 * Required. fontSizes preset value as seen in theme.json. |
|
524 * |
|
525 * @type string $name Name of the font size preset. |
|
526 * @type string $slug Kebab-case, unique identifier for the font size preset. |
|
527 * @type string|int|float $size CSS font-size value, including units if applicable. |
|
528 * } |
|
529 * @param bool|array $settings Optional Theme JSON settings array that overrides any global theme settings. |
|
530 * Default is false. |
|
531 * @return string|null Font-size value or null if a size is not passed in $preset. |
|
532 */ |
|
533 |
|
534 |
|
535 function wp_get_typography_font_size_value( $preset, $settings = array() ) { |
|
536 if ( ! isset( $preset['size'] ) ) { |
|
537 return null; |
|
538 } |
|
539 |
|
540 /* |
|
541 * Catches empty values and 0/'0'. |
|
542 * Fluid calculations cannot be performed on 0. |
|
543 */ |
|
544 if ( empty( $preset['size'] ) ) { |
|
545 return $preset['size']; |
|
546 } |
|
547 |
|
548 /* |
|
549 * As a boolean (deprecated since 6.6), $settings acts as an override to switch fluid typography "on" (`true`) or "off" (`false`). |
|
550 */ |
|
551 if ( is_bool( $settings ) ) { |
|
552 _deprecated_argument( __FUNCTION__, '6.6.0', __( '`boolean` type for second argument `$settings` is deprecated. Use `array()` instead.' ) ); |
|
553 $settings = array( |
|
554 'typography' => array( |
|
555 'fluid' => $settings, |
|
556 ), |
|
557 ); |
|
558 } |
|
559 |
|
560 // Fallback to global settings as default. |
|
561 $global_settings = wp_get_global_settings(); |
|
562 $settings = wp_parse_args( |
|
563 $settings, |
|
564 $global_settings |
|
565 ); |
|
566 |
|
567 $typography_settings = isset( $settings['typography'] ) ? $settings['typography'] : array(); |
|
568 $should_use_fluid_typography = ! empty( $typography_settings['fluid'] ); |
|
569 |
|
570 if ( ! $should_use_fluid_typography ) { |
|
571 return $preset['size']; |
|
572 } |
|
573 |
|
574 // $typography_settings['fluid'] can be a bool or an array. Normalize to array. |
|
575 $fluid_settings = is_array( $typography_settings['fluid'] ) ? $typography_settings['fluid'] : array(); |
|
576 $layout_settings = isset( $settings['layout'] ) ? $settings['layout'] : array(); |
|
577 |
|
578 // Defaults. |
|
579 $default_maximum_viewport_width = '1600px'; |
|
580 $default_minimum_viewport_width = '320px'; |
|
581 $default_minimum_font_size_factor_max = 0.75; |
|
582 $default_minimum_font_size_factor_min = 0.25; |
|
583 $default_scale_factor = 1; |
|
584 $default_minimum_font_size_limit = '14px'; |
|
585 |
|
586 // Defaults overrides. |
|
587 $minimum_viewport_width = isset( $fluid_settings['minViewportWidth'] ) ? $fluid_settings['minViewportWidth'] : $default_minimum_viewport_width; |
|
588 $maximum_viewport_width = isset( $layout_settings['wideSize'] ) && ! empty( wp_get_typography_value_and_unit( $layout_settings['wideSize'] ) ) ? $layout_settings['wideSize'] : $default_maximum_viewport_width; |
|
589 if ( isset( $fluid_settings['maxViewportWidth'] ) ) { |
|
590 $maximum_viewport_width = $fluid_settings['maxViewportWidth']; |
|
591 } |
|
592 $has_min_font_size = isset( $fluid_settings['minFontSize'] ) && ! empty( wp_get_typography_value_and_unit( $fluid_settings['minFontSize'] ) ); |
|
593 $minimum_font_size_limit = $has_min_font_size ? $fluid_settings['minFontSize'] : $default_minimum_font_size_limit; |
|
594 |
|
595 // Font sizes. |
|
596 $fluid_font_size_settings = isset( $preset['fluid'] ) ? $preset['fluid'] : null; |
|
597 |
|
598 // A font size has explicitly bypassed fluid calculations. |
|
599 if ( false === $fluid_font_size_settings ) { |
|
600 return $preset['size']; |
|
601 } |
|
602 |
|
603 // Try to grab explicit min and max fluid font sizes. |
|
604 $minimum_font_size_raw = isset( $fluid_font_size_settings['min'] ) ? $fluid_font_size_settings['min'] : null; |
|
605 $maximum_font_size_raw = isset( $fluid_font_size_settings['max'] ) ? $fluid_font_size_settings['max'] : null; |
|
606 |
|
607 // Font sizes. |
|
608 $preferred_size = wp_get_typography_value_and_unit( $preset['size'] ); |
|
609 |
|
610 // Protects against unsupported units. |
|
611 if ( empty( $preferred_size['unit'] ) ) { |
|
612 return $preset['size']; |
|
613 } |
|
614 |
|
615 /* |
|
616 * Normalizes the minimum font size limit according to the incoming unit, |
|
617 * in order to perform comparative checks. |
|
618 */ |
|
619 $minimum_font_size_limit = wp_get_typography_value_and_unit( |
|
620 $minimum_font_size_limit, |
|
621 array( |
|
622 'coerce_to' => $preferred_size['unit'], |
|
623 ) |
|
624 ); |
|
625 |
|
626 // Don't enforce minimum font size if a font size has explicitly set a min and max value. |
|
627 if ( ! empty( $minimum_font_size_limit ) && ( ! $minimum_font_size_raw && ! $maximum_font_size_raw ) ) { |
|
628 /* |
|
629 * If a minimum size was not passed to this function |
|
630 * and the user-defined font size is lower than $minimum_font_size_limit, |
|
631 * do not calculate a fluid value. |
|
632 */ |
|
633 if ( $preferred_size['value'] <= $minimum_font_size_limit['value'] ) { |
|
634 return $preset['size']; |
|
635 } |
|
636 } |
|
637 |
|
638 // If no fluid max font size is available use the incoming value. |
|
639 if ( ! $maximum_font_size_raw ) { |
|
640 $maximum_font_size_raw = $preferred_size['value'] . $preferred_size['unit']; |
|
641 } |
|
642 |
|
643 /* |
|
644 * If no minimumFontSize is provided, create one using |
|
645 * the given font size multiplied by the min font size scale factor. |
|
646 */ |
|
647 if ( ! $minimum_font_size_raw ) { |
|
648 $preferred_font_size_in_px = 'px' === $preferred_size['unit'] ? $preferred_size['value'] : $preferred_size['value'] * 16; |
|
649 |
|
650 /* |
|
651 * The scale factor is a multiplier that affects how quickly the curve will move towards the minimum, |
|
652 * that is, how quickly the size factor reaches 0 given increasing font size values. |
|
653 * For a - b * log2(), lower values of b will make the curve move towards the minimum faster. |
|
654 * The scale factor is constrained between min and max values. |
|
655 */ |
|
656 $minimum_font_size_factor = min( max( 1 - 0.075 * log( $preferred_font_size_in_px, 2 ), $default_minimum_font_size_factor_min ), $default_minimum_font_size_factor_max ); |
|
657 $calculated_minimum_font_size = round( $preferred_size['value'] * $minimum_font_size_factor, 3 ); |
|
658 |
|
659 // Only use calculated min font size if it's > $minimum_font_size_limit value. |
|
660 if ( ! empty( $minimum_font_size_limit ) && $calculated_minimum_font_size <= $minimum_font_size_limit['value'] ) { |
|
661 $minimum_font_size_raw = $minimum_font_size_limit['value'] . $minimum_font_size_limit['unit']; |
|
662 } else { |
|
663 $minimum_font_size_raw = $calculated_minimum_font_size . $preferred_size['unit']; |
|
664 } |
|
665 } |
|
666 |
|
667 $fluid_font_size_value = wp_get_computed_fluid_typography_value( |
|
668 array( |
|
669 'minimum_viewport_width' => $minimum_viewport_width, |
|
670 'maximum_viewport_width' => $maximum_viewport_width, |
|
671 'minimum_font_size' => $minimum_font_size_raw, |
|
672 'maximum_font_size' => $maximum_font_size_raw, |
|
673 'scale_factor' => $default_scale_factor, |
|
674 ) |
|
675 ); |
|
676 |
|
677 if ( ! empty( $fluid_font_size_value ) ) { |
|
678 return $fluid_font_size_value; |
|
679 } |
|
680 |
|
681 return $preset['size']; |
214 } |
682 } |
215 |
683 |
216 // Register the block support. |
684 // Register the block support. |
217 WP_Block_Supports::get_instance()->register( |
685 WP_Block_Supports::get_instance()->register( |
218 'typography', |
686 'typography', |