From b1d4ffddf9f19443ab3c0d8439bf3c32115e9ad1 Mon Sep 17 00:00:00 2001 From: Ramon Date: Tue, 11 Oct 2022 07:17:12 +1100 Subject: [PATCH] Fluid typography: convert font size inline style attributes to fluid values (#44764) * This commit ensures that custom font size values that appear in the style attribute of block content are converted to fluid typography (if activated) * Adding comments * Bail early if we don't find a custom font size * Adding tests yo * Updating PHP doc to describe incoming type of $raw_value (string|number) --- lib/block-supports/typography.php | 43 +++++- phpunit/block-supports/typography-test.php | 139 ++++++++++++++++++ .../theme.json | 9 ++ 3 files changed, 188 insertions(+), 3 deletions(-) create mode 100644 phpunit/data/themedir1/block-theme-child-with-fluid-typography/theme.json diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index f84bfd2a74b8f..22dfdba97fbb8 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -228,14 +228,42 @@ function gutenberg_typography_get_css_variable_inline_style( $attributes, $featu return sprintf( '%s:var(--wp--preset--%s--%s);', $css_property, $css_property, $slug ); } +/** + * Renders typography styles/content to the block wrapper. + * + * @param string $block_content Rendered block content. + * @param array $block Block object. + * @return string Filtered block content. + */ +function gutenberg_render_typography_support( $block_content, $block ) { + if ( ! isset( $block['attrs']['style']['typography']['fontSize'] ) ) { + return $block_content; + } + + $custom_font_size = $block['attrs']['style']['typography']['fontSize']; + $fluid_font_size = gutenberg_get_typography_font_size_value( array( 'size' => $custom_font_size ) ); + + /* + * Checks that $fluid_font_size does not match $custom_font_size, + * which means it's been mutated by the fluid font size functions. + */ + if ( ! empty( $fluid_font_size ) && $fluid_font_size !== $custom_font_size ) { + // Replaces the first instance of `font-size:$custom_font_size` with `font-size:$fluid_font_size`. + return preg_replace( '/font-size\s*:\s*' . preg_quote( $custom_font_size, '/' ) . '\s*;?/', 'font-size:' . esc_attr( $fluid_font_size ) . ';', $block_content, 1 ); + } + + return $block_content; + +} + /** * Internal method that checks a string for a unit and value and returns an array consisting of `'value'` and `'unit'`, e.g., [ '42', 'rem' ]. * A raw font size of `value + unit` is expected. If the value is a number, it will convert to `value + 'px'`. * * @access private * - * @param string $raw_value Raw size value from theme.json. - * @param array $options { + * @param string|number $raw_value Raw size value from theme.json. + * @param array $options { * Optional. An associative array of options. Default is empty array. * * @type string $coerce_to Coerce the value to rem or px. Default `'rem'`. @@ -380,9 +408,13 @@ function gutenberg_get_computed_fluid_typography_value( $args = array() ) { * } * @param bool $should_use_fluid_typography An override to switch fluid typography "on". Can be used for unit testing. Default is `false`. * - * @return string Font-size value. + * @return string|null Font-size value or `null` if a size is not passed in $preset. */ function gutenberg_get_typography_font_size_value( $preset, $should_use_fluid_typography = false ) { + if ( ! isset( $preset['size'] ) || empty( $preset['size'] ) ) { + return null; + } + // Check if fluid font sizes are activated. $typography_settings = gutenberg_get_global_settings( array( 'typography' ) ); $should_use_fluid_typography = isset( $typography_settings['fluid'] ) && true === $typography_settings['fluid'] ? true : $should_use_fluid_typography; @@ -452,3 +484,8 @@ function gutenberg_get_typography_font_size_value( $preset, $should_use_fluid_ty 'apply' => 'gutenberg_apply_typography_support', ) ); + +if ( function_exists( 'wp_render_typography_support' ) ) { + remove_filter( 'render_block', 'wp_render_typography_support' ); +} +add_filter( 'render_block', 'gutenberg_render_typography_support', 10, 2 ); diff --git a/phpunit/block-supports/typography-test.php b/phpunit/block-supports/typography-test.php index 0b1cba6c83c80..d21619a3a5286 100644 --- a/phpunit/block-supports/typography-test.php +++ b/phpunit/block-supports/typography-test.php @@ -12,20 +12,59 @@ class WP_Block_Supports_Typography_Test extends WP_UnitTestCase { */ private $test_block_name; + /** + * Stores the current test theme root. + * + * @var string|null + */ + private $theme_root; + + /** + * Caches the original theme directory global value in order + * to restore it in tear down. + * + * @var string|null + */ + private $orig_theme_dir; + /** * Sets up tests. */ public function set_up() { parent::set_up(); + $this->test_block_name = null; + + // Sets up the `wp-content/themes/` directory to ensure consistency when running tests. + $this->theme_root = realpath( __DIR__ . '/../data/themedir1' ); + $this->orig_theme_dir = $GLOBALS['wp_theme_directories']; + $GLOBALS['wp_theme_directories'] = array( WP_CONTENT_DIR . '/themes', $this->theme_root ); + + $theme_root_callback = function () { + return $this->theme_root; + }; + add_filter( 'theme_root', $theme_root_callback ); + add_filter( 'stylesheet_root', $theme_root_callback ); + add_filter( 'template_root', $theme_root_callback ); + + // Clear caches. + wp_clean_themes_cache(); + unset( $GLOBALS['wp_themes'] ); } /** * Tears down tests. */ public function tear_down() { + // Restores the original theme directory setup. + $GLOBALS['wp_theme_directories'] = $this->orig_theme_dir; + wp_clean_themes_cache(); + unset( $GLOBALS['wp_themes'] ); + + // Resets test block name. unregister_block_type( $this->test_block_name ); $this->test_block_name = null; + parent::tear_down(); } @@ -301,6 +340,24 @@ public function data_generate_font_size_preset_fixtures() { 'expected_output' => '28px', ), + 'default_return_value_when_value_is_already_clamped' => array( + 'font_size_preset' => array( + 'size' => 'clamp(21px, 1.3125rem + ((1vw - 7.68px) * 2.524), 42px)', + 'fluid' => false, + ), + 'should_use_fluid_typography' => true, + 'expected_output' => 'clamp(21px, 1.3125rem + ((1vw - 7.68px) * 2.524), 42px)', + ), + + 'default_return_value_with_unsupported_unit' => array( + 'font_size_preset' => array( + 'size' => '1000%', + 'fluid' => false, + ), + 'should_use_fluid_typography' => true, + 'expected_output' => '1000%', + ), + 'return_fluid_value' => array( 'font_size_preset' => array( 'size' => '1.75rem', @@ -382,4 +439,86 @@ public function data_generate_font_size_preset_fixtures() { ), ); } + + /** + * Tests that custom font sizes are converted to fluid values + * in inline block supports styles, + * when "settings.typography.fluid" is set to `true`. + * + * @covers ::gutenberg_render_typography_support + * + * @dataProvider data_generate_replace_inline_font_styles_with_fluid_values_fixtures + * + * @param string $block_content HTML block content. + * @param string $font_size_value The block supports custom font size value. + * @param bool $should_use_fluid_typography An override to switch fluid typography "on". Can be used for unit testing. + * @param string $expected_output Expected value of style property from gutenberg_apply_typography_support(). + */ + public function test_should_replace_inline_font_styles_with_fluid_values( $block_content, $font_size_value, $should_use_fluid_typography, $expected_output ) { + if ( $should_use_fluid_typography ) { + switch_theme( 'block-theme-child-with-fluid-typography' ); + } else { + switch_theme( 'default' ); + } + + $block = array( + 'blockName' => 'core/image', + 'attrs' => array( + 'style' => array( + 'typography' => array( + 'fontSize' => $font_size_value, + ), + ), + ), + ); + $actual = gutenberg_render_typography_support( $block_content, $block ); + + $this->assertSame( $expected_output, $actual ); + } + + /** + * Data provider for test_should_replace_inline_font_styles_with_fluid_values. + * + * @return array + */ + public function data_generate_replace_inline_font_styles_with_fluid_values_fixtures() { + return array( + 'default_return_content' => array( + 'block_content' => '', + 'font_size_value' => '4rem', + 'should_use_fluid_typography' => false, + 'expected_output' => '', + ), + 'return_content_with_replaced_fluid_font_size_inline_style' => array( + 'block_content' => '', + 'font_size_value' => '4rem', + 'should_use_fluid_typography' => true, + 'expected_output' => '', + ), + 'return_content_if_no_inline_font_size_found' => array( + 'block_content' => '

A paragraph inside a group

', + 'font_size_value' => '20px', + 'should_use_fluid_typography' => true, + 'expected_output' => '

A paragraph inside a group

', + ), + 'return_content_css_var' => array( + 'block_content' => '

A paragraph inside a group

', + 'font_size_value' => 'var:preset|font-size|x-large', + 'should_use_fluid_typography' => true, + 'expected_output' => '

A paragraph inside a group

', + ), + 'return_content_with_spaces' => array( + 'block_content' => '

A paragraph inside a group

', + 'font_size_value' => '20px', + 'should_use_fluid_typography' => true, + 'expected_output' => '

A paragraph inside a group

', + ), + 'return_content_with_first_match_replace_only' => array( + 'block_content' => "
\n \n

A paragraph inside a group

", + 'font_size_value' => '1em', + 'should_use_fluid_typography' => true, + 'expected_output' => "
\n \n

A paragraph inside a group

", + ), + ); + } } diff --git a/phpunit/data/themedir1/block-theme-child-with-fluid-typography/theme.json b/phpunit/data/themedir1/block-theme-child-with-fluid-typography/theme.json new file mode 100644 index 0000000000000..93234766eddd2 --- /dev/null +++ b/phpunit/data/themedir1/block-theme-child-with-fluid-typography/theme.json @@ -0,0 +1,9 @@ +{ + "version": 2, + "settings": { + "appearanceTools": true, + "typography": { + "fluid": true + } + } +}