run:R W Run
1.67 KB
2026-03-11 16:18:52
R W Run
1.57 KB
2026-03-11 16:18:52
R W Run
4.05 KB
2026-03-11 16:18:52
R W Run
9.2 KB
2026-03-11 16:18:52
R W Run
854 By
2026-03-11 16:18:52
R W Run
6.27 KB
2026-03-11 16:18:52
R W Run
5.81 KB
2026-03-11 16:18:52
R W Run
1.64 KB
2026-03-11 16:18:52
R W Run
5.28 KB
2026-03-11 16:18:52
R W Run
2.67 KB
2026-03-11 16:18:52
R W Run
8.46 KB
2026-03-11 16:18:52
R W Run
1.7 KB
2026-03-11 16:18:52
R W Run
39 KB
2026-03-11 16:18:52
R W Run
4.24 KB
2026-03-11 16:18:52
R W Run
4.52 KB
2026-03-11 16:18:52
R W Run
2.04 KB
2026-03-11 16:18:52
R W Run
2.81 KB
2026-03-11 16:18:52
R W Run
29.08 KB
2026-03-11 16:18:52
R W Run
1011 By
2026-03-11 16:18:52
R W Run
error_log
📄typography.php
1<?php
2/**
3 * Typography block support flag.
4 *
5 * @package WordPress
6 * @since 5.6.0
7 */
8
9/**
10 * Registers the style and typography block attributes for block types that support it.
11 *
12 * @since 5.6.0
13 * @since 6.3.0 Added support for text-columns.
14 * @access private
15 *
16 * @param WP_Block_Type $block_type Block Type.
17 */
18function wp_register_typography_support( $block_type ) {
19 if ( ! ( $block_type instanceof WP_Block_Type ) ) {
20 return;
21 }
22
23 $typography_supports = isset( $block_type->supports['typography'] ) ? $block_type->supports['typography'] : false;
24 if ( ! $typography_supports ) {
25 return;
26 }
27
28 $has_font_family_support = isset( $typography_supports['__experimentalFontFamily'] ) ? $typography_supports['__experimentalFontFamily'] : false;
29 $has_font_size_support = isset( $typography_supports['fontSize'] ) ? $typography_supports['fontSize'] : false;
30 $has_font_style_support = isset( $typography_supports['__experimentalFontStyle'] ) ? $typography_supports['__experimentalFontStyle'] : false;
31 $has_font_weight_support = isset( $typography_supports['__experimentalFontWeight'] ) ? $typography_supports['__experimentalFontWeight'] : false;
32 $has_letter_spacing_support = isset( $typography_supports['__experimentalLetterSpacing'] ) ? $typography_supports['__experimentalLetterSpacing'] : false;
33 $has_line_height_support = isset( $typography_supports['lineHeight'] ) ? $typography_supports['lineHeight'] : false;
34 $has_text_align_support = isset( $typography_supports['textAlign'] ) ? $typography_supports['textAlign'] : false;
35 $has_text_columns_support = isset( $typography_supports['textColumns'] ) ? $typography_supports['textColumns'] : false;
36 $has_text_decoration_support = isset( $typography_supports['__experimentalTextDecoration'] ) ? $typography_supports['__experimentalTextDecoration'] : false;
37 $has_text_transform_support = isset( $typography_supports['__experimentalTextTransform'] ) ? $typography_supports['__experimentalTextTransform'] : false;
38 $has_writing_mode_support = isset( $typography_supports['__experimentalWritingMode'] ) ? $typography_supports['__experimentalWritingMode'] : false;
39
40 $has_typography_support = $has_font_family_support
41 || $has_font_size_support
42 || $has_font_style_support
43 || $has_font_weight_support
44 || $has_letter_spacing_support
45 || $has_line_height_support
46 || $has_text_align_support
47 || $has_text_columns_support
48 || $has_text_decoration_support
49 || $has_text_transform_support
50 || $has_writing_mode_support;
51
52 if ( ! $block_type->attributes ) {
53 $block_type->attributes = array();
54 }
55
56 if ( $has_typography_support && ! array_key_exists( 'style', $block_type->attributes ) ) {
57 $block_type->attributes['style'] = array(
58 'type' => 'object',
59 );
60 }
61
62 if ( $has_font_size_support && ! array_key_exists( 'fontSize', $block_type->attributes ) ) {
63 $block_type->attributes['fontSize'] = array(
64 'type' => 'string',
65 );
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 }
73}
74
75/**
76 * Adds CSS classes and inline styles for typography features such as font sizes
77 * to the incoming attributes array. This will be applied to the block markup in
78 * the front-end.
79 *
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.
83 * @access private
84 *
85 * @param WP_Block_Type $block_type Block type.
86 * @param array $block_attributes Block attributes.
87 * @return array Typography CSS classes and inline styles.
88 */
89function wp_apply_typography_support( $block_type, $block_attributes ) {
90 if ( ! ( $block_type instanceof WP_Block_Type ) ) {
91 return array();
92 }
93
94 $typography_supports = isset( $block_type->supports['typography'] )
95 ? $block_type->supports['typography']
96 : false;
97 if ( ! $typography_supports ) {
98 return array();
99 }
100
101 if ( wp_should_skip_block_supports_serialization( $block_type, 'typography' ) ) {
102 return array();
103 }
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
237 $attributes = array();
238 $classnames = array();
239 $styles = wp_style_engine_get_styles(
240 array( 'typography' => $typography_block_styles ),
241 array( 'convert_vars_to_classnames' => true )
242 );
243
244 if ( ! empty( $styles['classnames'] ) ) {
245 $classnames[] = $styles['classnames'];
246 }
247
248 if ( $has_text_align_support && ! $should_skip_text_align && isset( $block_attributes['style']['typography']['textAlign'] ) ) {
249 $classnames[] = 'has-text-align-' . $block_attributes['style']['typography']['textAlign'];
250 }
251
252 if ( ! empty( $classnames ) ) {
253 $attributes['class'] = implode( ' ', $classnames );
254 }
255
256 if ( ! empty( $styles['css'] ) ) {
257 $attributes['style'] = $styles['css'];
258 }
259
260 return $attributes;
261}
262
263/**
264 * Generates an inline style value for a typography feature e.g. text decoration,
265 * text transform, and font style.
266 *
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 */
279function 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 */
308function wp_render_typography_support( $block_content, $block ) {
309 if ( ! empty( $block['attrs']['fitText'] ) && $block['attrs']['fitText'] && ! is_admin() ) {
310 wp_enqueue_script_module( '@wordpress/block-editor/utils/fit-text-frontend' );
311
312 // Add Interactivity API directives for fit text to work with client-side navigation.
313 if ( ! empty( $block_content ) ) {
314 $processor = new WP_HTML_Tag_Processor( $block_content );
315 if ( $processor->next_tag() ) {
316 if ( ! $processor->get_attribute( 'data-wp-interactive' ) ) {
317 $processor->set_attribute( 'data-wp-interactive', true );
318 }
319 $processor->set_attribute( 'data-wp-context---core-fit-text', 'core/fit-text::{"fontSize":""}' );
320 $processor->set_attribute( 'data-wp-init---core-fit-text', 'core/fit-text::callbacks.init' );
321 $processor->set_attribute( 'data-wp-style--font-size', 'core/fit-text::context.fontSize' );
322 $block_content = $processor->get_updated_html();
323 }
324 }
325 // fitText supersedes any other typography features
326 return $block_content;
327 }
328 if ( ! isset( $block['attrs']['style']['typography']['fontSize'] ) ) {
329 return $block_content;
330 }
331
332 $custom_font_size = $block['attrs']['style']['typography']['fontSize'];
333 $fluid_font_size = wp_get_typography_font_size_value( array( 'size' => $custom_font_size ) );
334
335 /*
336 * Checks that $fluid_font_size does not match $custom_font_size,
337 * which means it's been mutated by the fluid font size functions.
338 */
339 if ( ! empty( $fluid_font_size ) && $fluid_font_size !== $custom_font_size ) {
340 // Replaces the first instance of `font-size:$custom_font_size` with `font-size:$fluid_font_size`.
341 return preg_replace( '/font-size\s*:\s*' . preg_quote( $custom_font_size, '/' ) . '\s*;?/', 'font-size:' . esc_attr( $fluid_font_size ) . ';', $block_content, 1 );
342 }
343
344 return $block_content;
345}
346
347/**
348 * Checks a string for a unit and value and returns an array
349 * consisting of `'value'` and `'unit'`, e.g. array( '42', 'rem' ).
350 *
351 * @since 6.1.0
352 *
353 * @param string|int|float $raw_value Raw size value from theme.json.
354 * @param array $options {
355 * Optional. An associative array of options. Default is empty array.
356 *
357 * @type string $coerce_to Coerce the value to rem or px. Default `'rem'`.
358 * @type int $root_size_value Value of root font size for rem|em <-> px conversion. Default `16`.
359 * @type string[] $acceptable_units An array of font size units. Default `array( 'rem', 'px', 'em' )`;
360 * }
361 * @return array|null An array consisting of `'value'` and `'unit'` properties on success.
362 * `null` on failure.
363 */
364function wp_get_typography_value_and_unit( $raw_value, $options = array() ) {
365 if ( ! is_string( $raw_value ) && ! is_int( $raw_value ) && ! is_float( $raw_value ) ) {
366 _doing_it_wrong(
367 __FUNCTION__,
368 __( 'Raw size value must be a string, integer, or float.' ),
369 '6.1.0'
370 );
371 return null;
372 }
373
374 if ( empty( $raw_value ) ) {
375 return null;
376 }
377
378 // Converts numbers to pixel values by default.
379 if ( is_numeric( $raw_value ) ) {
380 $raw_value = $raw_value . 'px';
381 }
382
383 $defaults = array(
384 'coerce_to' => '',
385 'root_size_value' => 16,
386 'acceptable_units' => array( 'rem', 'px', 'em' ),
387 );
388
389 $options = wp_parse_args( $options, $defaults );
390
391 $acceptable_units_group = implode( '|', $options['acceptable_units'] );
392 $pattern = '/^(\d*\.?\d+)(' . $acceptable_units_group . '){1,1}$/';
393
394 preg_match( $pattern, $raw_value, $matches );
395
396 // Bails out if not a number value and a px or rem unit.
397 if ( ! isset( $matches[1] ) || ! isset( $matches[2] ) ) {
398 return null;
399 }
400
401 $value = $matches[1];
402 $unit = $matches[2];
403
404 /*
405 * Default browser font size. Later, possibly could inject some JS to
406 * compute this `getComputedStyle( document.querySelector( "html" ) ).fontSize`.
407 */
408 if ( 'px' === $options['coerce_to'] && ( 'em' === $unit || 'rem' === $unit ) ) {
409 $value = $value * $options['root_size_value'];
410 $unit = $options['coerce_to'];
411 }
412
413 if ( 'px' === $unit && ( 'em' === $options['coerce_to'] || 'rem' === $options['coerce_to'] ) ) {
414 $value = $value / $options['root_size_value'];
415 $unit = $options['coerce_to'];
416 }
417
418 /*
419 * No calculation is required if swapping between em and rem yet,
420 * since we assume a root size value. Later we might like to differentiate between
421 * :root font size (rem) and parent element font size (em) relativity.
422 */
423 if ( ( 'em' === $options['coerce_to'] || 'rem' === $options['coerce_to'] ) && ( 'em' === $unit || 'rem' === $unit ) ) {
424 $unit = $options['coerce_to'];
425 }
426
427 return array(
428 'value' => round( $value, 3 ),
429 'unit' => $unit,
430 );
431}
432
433/**
434 * Internal implementation of CSS clamp() based on available min/max viewport
435 * width and min/max font sizes.
436 *
437 * @since 6.1.0
438 * @since 6.3.0 Checks for unsupported min/max viewport values that cause invalid clamp values.
439 * @since 6.5.0 Returns early when min and max viewport subtraction is zero to avoid division by zero.
440 * @access private
441 *
442 * @param array $args {
443 * Optional. An associative array of values to calculate a fluid formula
444 * for font size. Default is empty array.
445 *
446 * @type string $maximum_viewport_width Maximum size up to which type will have fluidity.
447 * @type string $minimum_viewport_width Minimum viewport size from which type will have fluidity.
448 * @type string $maximum_font_size Maximum font size for any clamp() calculation.
449 * @type string $minimum_font_size Minimum font size for any clamp() calculation.
450 * @type int $scale_factor A scale factor to determine how fast a font scales within boundaries.
451 * }
452 * @return string|null A font-size value using clamp() on success, otherwise null.
453 */
454function wp_get_computed_fluid_typography_value( $args = array() ) {
455 $maximum_viewport_width_raw = isset( $args['maximum_viewport_width'] ) ? $args['maximum_viewport_width'] : null;
456 $minimum_viewport_width_raw = isset( $args['minimum_viewport_width'] ) ? $args['minimum_viewport_width'] : null;
457 $maximum_font_size_raw = isset( $args['maximum_font_size'] ) ? $args['maximum_font_size'] : null;
458 $minimum_font_size_raw = isset( $args['minimum_font_size'] ) ? $args['minimum_font_size'] : null;
459 $scale_factor = isset( $args['scale_factor'] ) ? $args['scale_factor'] : null;
460
461 // Normalizes the minimum font size in order to use the value for calculations.
462 $minimum_font_size = wp_get_typography_value_and_unit( $minimum_font_size_raw );
463
464 /*
465 * We get a 'preferred' unit to keep units consistent when calculating,
466 * otherwise the result will not be accurate.
467 */
468 $font_size_unit = isset( $minimum_font_size['unit'] ) ? $minimum_font_size['unit'] : 'rem';
469
470 // Normalizes the maximum font size in order to use the value for calculations.
471 $maximum_font_size = wp_get_typography_value_and_unit(
472 $maximum_font_size_raw,
473 array(
474 'coerce_to' => $font_size_unit,
475 )
476 );
477
478 // Checks for mandatory min and max sizes, and protects against unsupported units.
479 if ( ! $maximum_font_size || ! $minimum_font_size ) {
480 return null;
481 }
482
483 // Uses rem for accessible fluid target font scaling.
484 $minimum_font_size_rem = wp_get_typography_value_and_unit(
485 $minimum_font_size_raw,
486 array(
487 'coerce_to' => 'rem',
488 )
489 );
490
491 // Viewport widths defined for fluid typography. Normalize units.
492 $maximum_viewport_width = wp_get_typography_value_and_unit(
493 $maximum_viewport_width_raw,
494 array(
495 'coerce_to' => $font_size_unit,
496 )
497 );
498 $minimum_viewport_width = wp_get_typography_value_and_unit(
499 $minimum_viewport_width_raw,
500 array(
501 'coerce_to' => $font_size_unit,
502 )
503 );
504
505 // Protects against unsupported units in min and max viewport widths.
506 if ( ! $minimum_viewport_width || ! $maximum_viewport_width ) {
507 return null;
508 }
509
510 // Calculates the linear factor denominator. If it's 0, we cannot calculate a fluid value.
511 $linear_factor_denominator = $maximum_viewport_width['value'] - $minimum_viewport_width['value'];
512 if ( empty( $linear_factor_denominator ) ) {
513 return null;
514 }
515
516 /*
517 * Build CSS rule.
518 * Borrowed from https://websemantics.uk/tools/responsive-font-calculator/.
519 */
520 $view_port_width_offset = round( $minimum_viewport_width['value'] / 100, 3 ) . $font_size_unit;
521 $linear_factor = 100 * ( ( $maximum_font_size['value'] - $minimum_font_size['value'] ) / ( $linear_factor_denominator ) );
522 $linear_factor_scaled = round( $linear_factor * $scale_factor, 3 );
523 $linear_factor_scaled = empty( $linear_factor_scaled ) ? 1 : $linear_factor_scaled;
524 $fluid_target_font_size = implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor_scaled)";
525
526 return "clamp($minimum_font_size_raw, $fluid_target_font_size, $maximum_font_size_raw)";
527}
528
529/**
530 * Returns a font-size value based on a given font-size preset.
531 * Takes into account fluid typography parameters and attempts to return a CSS
532 * formula depending on available, valid values.
533 *
534 * @since 6.1.0
535 * @since 6.1.1 Adjusted rules for min and max font sizes.
536 * @since 6.2.0 Added 'settings.typography.fluid.minFontSize' support.
537 * @since 6.3.0 Using layout.wideSize as max viewport width, and logarithmic scale factor to calculate minimum font scale.
538 * @since 6.4.0 Added configurable min and max viewport width values to the typography.fluid theme.json schema.
539 * @since 6.6.0 Deprecated bool argument $should_use_fluid_typography.
540 * @since 6.7.0 Font size presets can enable fluid typography individually, even if it’s disabled globally.
541 *
542 * @param array $preset {
543 * Required. fontSizes preset value as seen in theme.json.
544 *
545 * @type string $name Name of the font size preset.
546 * @type string $slug Kebab-case, unique identifier for the font size preset.
547 * @type string|int|float $size CSS font-size value, including units if applicable.
548 * }
549 * @param bool|array $settings Optional Theme JSON settings array that overrides any global theme settings.
550 * Default is false.
551 * @return string|null Font-size value or null if a size is not passed in $preset.
552 */
553
554
555function wp_get_typography_font_size_value( $preset, $settings = array() ) {
556 if ( ! isset( $preset['size'] ) ) {
557 return null;
558 }
559
560 /*
561 * Catches falsy values and 0/'0'. Fluid calculations cannot be performed on `0`.
562 * Also returns early when a preset font size explicitly disables fluid typography with `false`.
563 */
564 $fluid_font_size_settings = $preset['fluid'] ?? null;
565 if ( false === $fluid_font_size_settings || empty( $preset['size'] ) ) {
566 return $preset['size'];
567 }
568
569 /*
570 * As a boolean (deprecated since 6.6), $settings acts as an override to switch fluid typography "on" (`true`) or "off" (`false`).
571 */
572 if ( is_bool( $settings ) ) {
573 _deprecated_argument( __FUNCTION__, '6.6.0', __( '`boolean` type for second argument `$settings` is deprecated. Use `array()` instead.' ) );
574 $settings = array(
575 'typography' => array(
576 'fluid' => $settings,
577 ),
578 );
579 }
580
581 // Fallback to global settings as default.
582 $global_settings = wp_get_global_settings();
583 $settings = wp_parse_args(
584 $settings,
585 $global_settings
586 );
587
588 $typography_settings = $settings['typography'] ?? array();
589
590 /*
591 * Return early when fluid typography is disabled in the settings, and there
592 * are no local settings to enable it for the individual preset.
593 *
594 * If this condition isn't met, either the settings or individual preset settings
595 * have enabled fluid typography.
596 */
597 if ( empty( $typography_settings['fluid'] ) && empty( $fluid_font_size_settings ) ) {
598 return $preset['size'];
599 }
600
601 $fluid_settings = isset( $typography_settings['fluid'] ) ? $typography_settings['fluid'] : array();
602 $layout_settings = isset( $settings['layout'] ) ? $settings['layout'] : array();
603
604 // Defaults.
605 $default_maximum_viewport_width = '1600px';
606 $default_minimum_viewport_width = '320px';
607 $default_minimum_font_size_factor_max = 0.75;
608 $default_minimum_font_size_factor_min = 0.25;
609 $default_scale_factor = 1;
610 $default_minimum_font_size_limit = '14px';
611
612 // Defaults overrides.
613 $minimum_viewport_width = isset( $fluid_settings['minViewportWidth'] ) ? $fluid_settings['minViewportWidth'] : $default_minimum_viewport_width;
614 $maximum_viewport_width = isset( $layout_settings['wideSize'] ) && ! empty( wp_get_typography_value_and_unit( $layout_settings['wideSize'] ) ) ? $layout_settings['wideSize'] : $default_maximum_viewport_width;
615 if ( isset( $fluid_settings['maxViewportWidth'] ) ) {
616 $maximum_viewport_width = $fluid_settings['maxViewportWidth'];
617 }
618 $has_min_font_size = isset( $fluid_settings['minFontSize'] ) && ! empty( wp_get_typography_value_and_unit( $fluid_settings['minFontSize'] ) );
619 $minimum_font_size_limit = $has_min_font_size ? $fluid_settings['minFontSize'] : $default_minimum_font_size_limit;
620
621 // Try to grab explicit min and max fluid font sizes.
622 $minimum_font_size_raw = isset( $fluid_font_size_settings['min'] ) ? $fluid_font_size_settings['min'] : null;
623 $maximum_font_size_raw = isset( $fluid_font_size_settings['max'] ) ? $fluid_font_size_settings['max'] : null;
624
625 // Font sizes.
626 $preferred_size = wp_get_typography_value_and_unit( $preset['size'] );
627
628 // Protects against unsupported units.
629 if ( empty( $preferred_size['unit'] ) ) {
630 return $preset['size'];
631 }
632
633 /*
634 * Normalizes the minimum font size limit according to the incoming unit,
635 * in order to perform comparative checks.
636 */
637 $minimum_font_size_limit = wp_get_typography_value_and_unit(
638 $minimum_font_size_limit,
639 array(
640 'coerce_to' => $preferred_size['unit'],
641 )
642 );
643
644 // Don't enforce minimum font size if a font size has explicitly set a min and max value.
645 if ( ! empty( $minimum_font_size_limit ) && ( ! $minimum_font_size_raw && ! $maximum_font_size_raw ) ) {
646 /*
647 * If a minimum size was not passed to this function
648 * and the user-defined font size is lower than $minimum_font_size_limit,
649 * do not calculate a fluid value.
650 */
651 if ( $preferred_size['value'] <= $minimum_font_size_limit['value'] ) {
652 return $preset['size'];
653 }
654 }
655
656 // If no fluid max font size is available use the incoming value.
657 if ( ! $maximum_font_size_raw ) {
658 $maximum_font_size_raw = $preferred_size['value'] . $preferred_size['unit'];
659 }
660
661 /*
662 * If no minimumFontSize is provided, create one using
663 * the given font size multiplied by the min font size scale factor.
664 */
665 if ( ! $minimum_font_size_raw ) {
666 $preferred_font_size_in_px = 'px' === $preferred_size['unit'] ? $preferred_size['value'] : $preferred_size['value'] * 16;
667
668 /*
669 * The scale factor is a multiplier that affects how quickly the curve will move towards the minimum,
670 * that is, how quickly the size factor reaches 0 given increasing font size values.
671 * For a - b * log2(), lower values of b will make the curve move towards the minimum faster.
672 * The scale factor is constrained between min and max values.
673 */
674 $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 );
675 $calculated_minimum_font_size = round( $preferred_size['value'] * $minimum_font_size_factor, 3 );
676
677 // Only use calculated min font size if it's > $minimum_font_size_limit value.
678 if ( ! empty( $minimum_font_size_limit ) && $calculated_minimum_font_size <= $minimum_font_size_limit['value'] ) {
679 $minimum_font_size_raw = $minimum_font_size_limit['value'] . $minimum_font_size_limit['unit'];
680 } else {
681 $minimum_font_size_raw = $calculated_minimum_font_size . $preferred_size['unit'];
682 }
683 }
684
685 $fluid_font_size_value = wp_get_computed_fluid_typography_value(
686 array(
687 'minimum_viewport_width' => $minimum_viewport_width,
688 'maximum_viewport_width' => $maximum_viewport_width,
689 'minimum_font_size' => $minimum_font_size_raw,
690 'maximum_font_size' => $maximum_font_size_raw,
691 'scale_factor' => $default_scale_factor,
692 )
693 );
694
695 if ( ! empty( $fluid_font_size_value ) ) {
696 return $fluid_font_size_value;
697 }
698
699 return $preset['size'];
700}
701
702// Register the block support.
703WP_Block_Supports::get_instance()->register(
704 'typography',
705 array(
706 'register_attribute' => 'wp_register_typography_support',
707 'apply' => 'wp_apply_typography_support',
708 )
709);
710