Add definition of default heading font-sizes and renderer support

Initially, I tried to place the definition to theme.json
(It could set it in styles.block.core/heading or styles.elements.h1...)
It was not possible to use theme.json because of the fluid typography
feature which, when enabled for a site, causes font sizes to being
converted to the fluid definition (clamp(x, y, z)) and which
is not usable for an email due to very little client support.

We need to make some changes in Gutenberg to be able to disable the feature.
Currently, the code for generating font sizes in CSS generated from the theme.json
looks directly at the global settings of the site.
[MAILPOET-5740]
This commit is contained in:
Rostislav Wolny
2024-01-19 12:08:39 +01:00
committed by Jan Lysý
parent 6f3ebc10b8
commit b90a35d80a
6 changed files with 82 additions and 18 deletions

View File

@ -70,6 +70,8 @@ class SettingsController {
['css' => $flexEmailLayoutStyles],
];
$settings['styles'] = apply_filters('mailpoet_email_editor_editor_styles', $settings['styles']);
$settings['__experimentalFeatures'] = $themeSettings;
// Enable border radius, color, style and width where possible
$settings['__experimentalFeatures']['border'] = [

View File

@ -9,6 +9,8 @@ class Initializer {
public function initialize(): void {
add_action('mailpoet_blocks_renderer_initialized', [$this, 'registerCoreBlocksRenderers'], 10, 1);
add_filter('mailpoet_email_editor_theme_json', [$this, 'adjustThemeJson'], 10, 1);
add_filter('mailpoet_email_editor_editor_styles', [$this, 'addEditorStyles'], 10, 1);
add_filter('mailpoet_email_renderer_styles', [$this, 'addRendererStyles'], 10, 1);
}
/**
@ -35,4 +37,16 @@ class Initializer {
$editorThemeJson->merge(new \WP_Theme_JSON($themeJson, 'default'));
return $editorThemeJson;
}
public function addEditorStyles(array $styles) {
$declaration = (string)file_get_contents(dirname(__FILE__) . '/styles.css');
$styles[] = ['css' => $declaration];
return $styles;
}
public function addRendererStyles(string $styles) {
$declaration = (string)file_get_contents(dirname(__FILE__) . '/styles.css');
$styles .= $declaration;
return $styles;
}
}

View File

@ -9,7 +9,7 @@ use MailPoet\Util\Helpers;
class Heading implements BlockRenderer {
public function render(string $blockContent, array $parsedBlock, SettingsController $settingsController): string {
$level = $parsedBlock['attrs']['level'] ?? 2; // default level is 2
$blockContent = $this->removePaddingFromElement($blockContent, ['tag_name' => "h{$level}"]);
$blockContent = $this->adjustStyleAttribute($blockContent, $parsedBlock, $settingsController, ['tag_name' => "h{$level}"]);
return str_replace('{heading_content}', $blockContent, $this->getBlockWrapper($parsedBlock, $settingsController));
}
@ -17,7 +17,7 @@ class Heading implements BlockRenderer {
* Based on MJML <mj-text>
*/
private function getBlockWrapper(array $parsedBlock, SettingsController $settingsController): string {
$themeData = $settingsController->getTheme()->get_data();
$availableStylesheets = $settingsController->getAvailableStylesheets();
// Styles for padding need to be set on the wrapping table cell due to support in Outlook
@ -39,10 +39,6 @@ class Heading implements BlockRenderer {
$styles[$property] = $value;
}
if (!isset($styles['font-size'])) {
$styles['font-size'] = $themeData['styles']['typography']['fontSize'];
}
$styles = array_merge($styles, $this->fetchStylesFromBlockAttrs($availableStylesheets, $parsedBlock['attrs']));
return '
@ -113,13 +109,21 @@ class Heading implements BlockRenderer {
}
/**
* 1) We need to remove padding because we render padding on wrapping table cell
* 2) We also need to replace font-size to avoid clamp() because clamp() is not supported in many email clients.
* The font size values is automatically converted to clamp() when WP site theme is configured to use fluid layouts.
* Currently (WP 6.4), there is no way to disable this behavior.
* @param array{tag_name: string, class_name?: string} $tag
*/
private function removePaddingFromElement($blockContent, array $tag): string {
private function adjustStyleAttribute($blockContent, array $parsedBlock, SettingsController $settingsController, array $tag): string {
$html = new \WP_HTML_Tag_Processor($blockContent);
$themeData = $settingsController->getTheme()->get_data();
$fontSize = 'font-size:' . ($parsedBlock['email_attrs']['font-size'] ?? $themeData['styles']['typography']['fontSize']) . ';';
if ($html->next_tag($tag)) {
$elementStyle = $html->get_attribute('style') ?? '';
$elementStyle = preg_replace('/padding.*:.?[0-9]+px;?/', '', $elementStyle);
$elementStyle = preg_replace('/font-size:[^;]+;?/', $fontSize, $elementStyle);
$html->set_attribute('style', $elementStyle);
$blockContent = $html->get_updated_html();
}

View File

@ -0,0 +1,23 @@
h1 {
font-size: 48px;
}
h2 {
font-size: 42px;
}
h3 {
font-size: 36px;
}
h4 {
font-size: 26px;
}
h5 {
font-size: 20px;
}
h6 {
font-size: 13px;
}

View File

@ -20,11 +20,13 @@ class HeadingTest extends \MailPoetTest {
'style' => [
'typography' => [
'textTransform' => 'lowercase',
'fontSize' => '24px',
],
],
],
'email_attrs' => [
'width' => '640px',
'font-size' => '24px',
],
'innerBlocks' => [],
'innerHTML' => '<h1 class="has-pale-cyan-blue-color has-vivid-red-background-color has-text-color has-background">This is Heading 1</h1>',
@ -46,6 +48,7 @@ class HeadingTest extends \MailPoetTest {
$rendered = $this->headingRenderer->render('<h1>This is Heading 1</h1>', $this->parsedHeading, $this->settingsController);
verify($rendered)->stringContainsString('This is Heading 1');
verify($rendered)->stringContainsString('width: 100%;');
verify($rendered)->stringContainsString('font-size:24px;');
verify($rendered)->stringNotContainsString('width:640px;');
}
@ -56,4 +59,9 @@ class HeadingTest extends \MailPoetTest {
verify($rendered)->stringContainsString('text-transform:lowercase;');
verify($rendered)->stringContainsString('text-align:center;');
}
public function testItReplacesFluidFontSizeInContent(): void {
$rendered = $this->headingRenderer->render('<h1 style="font-size:clamp(10px, 20px, 24px)">This is Heading 1</h1>', $this->parsedHeading, $this->settingsController);
verify($rendered)->stringContainsString('font-size:24px');
}
}

View File

@ -22,19 +22,32 @@ class RendererTest extends \MailPoetTest {
'post_content' => '<!-- wp:button --><div class="wp-block-button"><a class="wp-block-button__link has-background wp-element-button">Button</a></div><!-- /wp:button -->',
]);
$rendered = $this->renderer->render($emailPost, 'Subject', '', 'en');
$doc = new \DOMDocument();
$doc->loadHTML($rendered['html']);
$xpath = new \DOMXPath($doc);
$nodes = $xpath->query('//td[contains(@class, "wp-block-button")]');
$button = null;
if (($nodes instanceof \DOMNodeList) && $nodes->length > 0) {
$button = $nodes->item(0);
}
$this->assertInstanceOf(\DOMElement::class, $button);
$this->assertInstanceOf(\DOMDocument::class, $button->ownerDocument);
$buttonHtml = $button->ownerDocument->saveHTML($button);
$buttonHtml = $this->extractBlockHtml($rendered['html'], 'wp-block-button', 'td');
verify($buttonHtml)->stringContainsString('color:#ffffff');
verify($buttonHtml)->stringContainsString('padding:.7em 1.4em');
verify($buttonHtml)->stringContainsString('background:#32373c');
}
public function testItInlinesHeadingFontSize() {
$emailPost = new \WP_Post((object)[
'post_content' => '<!-- wp:heading {"level":1,"style":{"typography":{"fontSize":"large"}}} --><h1 class="wp-block-heading">Hello</h1><!-- /wp:heading -->',
]);
$rendered = $this->renderer->render($emailPost, 'Subject', '', 'en');
$headingHtml = $this->extractBlockHtml($rendered['html'], 'wp-block-heading', 'h1');
verify($headingHtml)->stringContainsString('font-size:48px'); // large is 48px
}
private function extractBlockHtml(string $html, string $blockClass, string $tag): string {
$doc = new \DOMDocument();
$doc->loadHTML($html);
$xpath = new \DOMXPath($doc);
$nodes = $xpath->query('//' . $tag . '[contains(@class, "' . $blockClass . '")]');
$block = null;
if (($nodes instanceof \DOMNodeList) && $nodes->length > 0) {
$block = $nodes->item(0);
}
$this->assertInstanceOf(\DOMElement::class, $block);
$this->assertInstanceOf(\DOMDocument::class, $block->ownerDocument);
return (string)$block->ownerDocument->saveHTML($block);
}
}