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