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