PluginProbe
Gutenberg / 19.6.1
Gutenberg v19.6.1
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 12.6.0 All 403 releases
gutenberg / lib / block-supports / typography.php

typography.php in Gutenberg 19.6.1, at lib/block-supports/typography.php

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