Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fluid typography: convert font size inline style attributes to fluid values #44764

Merged
merged 5 commits into from
Oct 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 40 additions & 3 deletions lib/block-supports/typography.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Copy link
Member Author

@ramonjd ramonjd Oct 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adamziel 👋 I know you've been looking at anti-patterns for this kind of stuff so just wanted to run it by you.

This lovely line looks at a block's HTML content and searches for a match on font-size: $custom_font_size.

Assuming we can't yet use the HTML_Walker (yet, which I'd love to), do you see any danger here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't love this approach, but I can't see a better one until the walker is merged. I have tried pretty hard to break it and I haven't found a way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for testing this @scruffian

Yeah, I had to scrub my keyboard after writing it it felt so dirty. We'll be able to replace with HTML Walker for the plugin, but not 6.1 just yet 🤞

}

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'`.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 );
139 changes: 139 additions & 0 deletions phpunit/block-supports/typography-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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' => '<h2 class="has-vivid-red-background-color has-background has-link-color" style="margin-top:var(--wp--preset--spacing--60);font-size:4rem;font-style:normal;font-weight:600;letter-spacing:29px;text-decoration:underline;text-transform:capitalize">This is a heading</h2>',
'font_size_value' => '4rem',
'should_use_fluid_typography' => false,
'expected_output' => '<h2 class="has-vivid-red-background-color has-background has-link-color" style="margin-top:var(--wp--preset--spacing--60);font-size:4rem;font-style:normal;font-weight:600;letter-spacing:29px;text-decoration:underline;text-transform:capitalize">This is a heading</h2>',
),
'return_content_with_replaced_fluid_font_size_inline_style' => array(
'block_content' => '<h2 class="has-vivid-red-background-color has-background has-link-color" style="margin-top:var(--wp--preset--spacing--60);font-size:4rem;font-style:normal;font-weight:600;letter-spacing:29px;text-decoration:underline;text-transform:capitalize">This is a heading</h2>',
'font_size_value' => '4rem',
'should_use_fluid_typography' => true,
'expected_output' => '<h2 class="has-vivid-red-background-color has-background has-link-color" style="margin-top:var(--wp--preset--spacing--60);font-size:clamp(3rem, 3rem + ((1vw - 0.48rem) * 5.769), 6rem);font-style:normal;font-weight:600;letter-spacing:29px;text-decoration:underline;text-transform:capitalize">This is a heading</h2>',
),
'return_content_if_no_inline_font_size_found' => array(
'block_content' => '<p class="has-medium-font-size" style="font-style:normal;font-weight:600;letter-spacing:29px;">A paragraph inside a group</p>',
'font_size_value' => '20px',
'should_use_fluid_typography' => true,
'expected_output' => '<p class="has-medium-font-size" style="font-style:normal;font-weight:600;letter-spacing:29px;">A paragraph inside a group</p>',
),
'return_content_css_var' => array(
'block_content' => '<p class="has-medium-font-size" style="font-size:var(--wp--preset--font-size--x-large);">A paragraph inside a group</p>',
'font_size_value' => 'var:preset|font-size|x-large',
'should_use_fluid_typography' => true,
'expected_output' => '<p class="has-medium-font-size" style="font-size:var(--wp--preset--font-size--x-large);">A paragraph inside a group</p>',
),
'return_content_with_spaces' => array(
'block_content' => '<p class="has-medium-font-size" style=" font-size: 20px ; ">A paragraph inside a group</p>',
'font_size_value' => '20px',
'should_use_fluid_typography' => true,
'expected_output' => '<p class="has-medium-font-size" style=" font-size:clamp(15px, 0.9375rem + ((1vw - 7.68px) * 1.803), 30px); ">A paragraph inside a group</p>',
),
'return_content_with_first_match_replace_only' => array(
'block_content' => "<div class=\"wp-block-group\" style=\"font-size:1em\"> \n \n<p style=\"font-size:1em\">A paragraph inside a group</p></div>",
'font_size_value' => '1em',
'should_use_fluid_typography' => true,
'expected_output' => "<div class=\"wp-block-group\" style=\"font-size:clamp(0.75em, 0.75em + ((1vw - 0.48em) * 1.442), 1.5em);\"> \n \n<p style=\"font-size:1em\">A paragraph inside a group</p></div>",
),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"version": 2,
"settings": {
"appearanceTools": true,
"typography": {
"fluid": true
}
}
}