Refactor font family rendering using CSS inlining

We don't reset font family on any level, so there is no need to
bubble the setting using a preprocessor and render the inline styles
explicitly in every block.

In this commit, I change how font-family settings are distributed/rendered
in the email renderer. In the new approach, we rely on class names defining font-family
and a generated CSS sheet with font-family definitions.
We apply the font-family CSS by inlining CSS rules for families in the later phase of
rendering after all individual blocks are processed.
[MAILPOET-5740]
This commit is contained in:
Rostislav Wolny
2024-01-11 17:08:12 +01:00
committed by Jan Lysý
parent a7aaf97070
commit e8bb1b5ac0
10 changed files with 38 additions and 47 deletions

View File

@ -12,7 +12,6 @@ class TypographyPreprocessor implements Preprocessor {
private const TYPOGRAPHY_STYLES = [
'color',
'font-size',
'font-family',
'text-decoration',
];
@ -54,9 +53,6 @@ class TypographyPreprocessor implements Preprocessor {
if (isset($block['attrs']['style']['color']['text'])) {
$emailAttrs['color'] = $block['attrs']['style']['color']['text'];
}
if (isset($block['attrs']['fontFamily'])) {
$emailAttrs['font-family'] = $this->getFontFamilyBySlug($block['attrs']['fontFamily']);
}
if (isset($block['attrs']['style']['typography']['fontSize'])) {
$emailAttrs['font-size'] = $block['attrs']['style']['typography']['fontSize'];
}
@ -80,20 +76,6 @@ class TypographyPreprocessor implements Preprocessor {
if (!($block['email_attrs']['font-size'] ?? '')) {
$block['email_attrs']['font-size'] = $contentStyles['typography']['fontSize'];
}
if (!($block['email_attrs']['font-family'] ?? '')) {
$block['email_attrs']['font-family'] = $contentStyles['typography']['fontFamily'];
}
return $block;
}
private function getFontFamilyBySlug(string $slug): ?string {
$themeData = $this->settingsController->getTheme()->get_data();
$fontFamilies = $themeData['settings']['typography']['fontFamilies'] ?? [];
foreach ($fontFamilies as $fontFamily) {
if ($fontFamily['slug'] === $slug) {
return $fontFamily['fontFamily'];
}
}
return null;
}
}

View File

@ -49,6 +49,7 @@ class Renderer {
$renderedBody = $this->renderBlocks($parsedBlocks);
$styles = (string)file_get_contents(dirname(__FILE__) . '/' . self::TEMPLATE_STYLES_FILE);
$styles .= $this->settingsController->getStylesheetForRendering();
$styles = apply_filters('mailpoet_email_renderer_styles', $styles, $post);
$template = (string)file_get_contents(dirname(__FILE__) . '/' . self::TEMPLATE_FILE);

View File

@ -236,4 +236,14 @@ class SettingsController {
/** @var array $themeJson */
return new \WP_Theme_JSON($themeJson);
}
public function getStylesheetForRendering(): string {
$settings = $this->getTheme()->get_settings();
$css = '';
// Font family classes
foreach ($settings['typography']['fontFamilies']['theme'] as $fontFamily) {
$css .= ".has-{$fontFamily['slug']}-font-family { font-family: {$fontFamily['fontFamily']}; } \n";
}
return $css;
}
}

View File

@ -25,7 +25,11 @@ class Button implements BlockRenderer {
return '';
}
$buttonOriginalWrapper = $buttonDom->getElementsByTagName('div')->item(0);
$buttonClasses = $buttonOriginalWrapper instanceof \DOMElement ? $buttonOriginalWrapper->getAttribute('class') : '';
$markup = $this->getMarkup();
$markup = str_replace('{classes}', $buttonClasses, $markup);
// Add Link Text
$markup = str_replace('{linkText}', $buttonLink->textContent ?: '', $markup);
@ -91,8 +95,6 @@ class Button implements BlockRenderer {
// Escaping
$wrapperStyles = array_map('esc_attr', $wrapperStyles);
$linkStyles = array_map('esc_attr', $linkStyles);
// Font family may contain single quotes
$linkStyles['font-family'] = str_replace(''', "'", esc_attr("{$parsedBlock['email_attrs']['font-family']}"));
$markup = str_replace('{linkStyles}', $settingsController->convertStylesToString($linkStyles), $markup);
$markup = str_replace('{wrapperStyles}', $settingsController->convertStylesToString($wrapperStyles), $markup);
@ -103,7 +105,7 @@ class Button implements BlockRenderer {
private function getMarkup(): string {
return '<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:middle;border-collapse:separate;line-height:100%;width:{width};">
<tr>
<td align="center" bgcolor="{backgroundColor}" role="presentation" style="{wrapperStyles}" valign="middle">
<td align="center" class="{classes}" bgcolor="{backgroundColor}" role="presentation" style="{wrapperStyles}" valign="middle">
<a href="{linkUrl}" style="{linkStyles}" target="_blank">{linkText}</a>
</td>
</tr>

View File

@ -42,9 +42,6 @@ class Heading implements BlockRenderer {
if (!isset($styles['font-size'])) {
$styles['font-size'] = $contentStyles['typography']['fontSize'];
}
if (!isset($styles['font-family'])) {
$styles['font-family'] = $contentStyles['typography']['fontFamily'];
}
$styles = array_merge($styles, $this->fetchStylesFromBlockAttrs($availableStylesheets, $parsedBlock['attrs']));

View File

@ -23,9 +23,6 @@ class ListBlock implements BlockRenderer {
if (!isset($styles['font-size'])) {
$styles['font-size'] = $contentStyles['typography']['fontSize'];
}
if (!isset($styles['font-family'])) {
$styles['font-family'] = $contentStyles['typography']['fontFamily'];
}
$html->set_attribute('style', $settingsController->convertStylesToString($styles));
$blockContent = $html->get_updated_html();

View File

@ -41,9 +41,6 @@ class Paragraph implements BlockRenderer {
if (!isset($styles['font-size'])) {
$styles['font-size'] = $contentStyles['typography']['fontSize'];
}
if (!isset($styles['font-family'])) {
$styles['font-family'] = $contentStyles['typography']['fontFamily'];
}
$styles = array_merge($styles, $this->fetchStylesFromBlockAttrs($availableStylesheets, $parsedBlock['attrs'] ?? []));

View File

@ -0,0 +1,19 @@
<?php declare(strict_types = 1);
namespace MailPoet\EmailEditor\Engine;
class SettingsControllerTest extends \MailPoetTest {
/** @var SettingsController */
private $settingsController;
public function _before() {
parent::_before();
$this->settingsController = $this->diContainer->get(SettingsController::class);
}
public function testItGeneratesCssStylesForThemeWithFontFamilies() {
$css = $this->settingsController->getStylesheetForRendering();
verify($css)->stringContainsString('.has-system-sans-serif-font-family');
verify($css)->stringContainsString('.has-system-Serif-font-family');
}
}

View File

@ -150,15 +150,4 @@ class ButtonTest extends \MailPoetTest {
verify($output)->stringContainsString('border-bottom-left-radius:3px;');
verify($output)->stringContainsString('border-bottom-right-radius:4px;');
}
public function testItAllowsSingleQuotesInFontFamilyDefinition(): void {
$settingsControllerMock = $this->createPartialMock(SettingsController::class, ['getEmailContentStyles']);
$settingsControllerMock->method('getEmailContentStyles')->willReturn([
'typography' => [
'fontFamily' => '"Font\'", serif',
],
]);
$output = $this->buttonRenderer->render($this->parsedButton['innerHTML'], $this->parsedButton, $settingsControllerMock);
verify($output)->stringContainsString('&quot;Font\'&quot;, serif');
}
}

View File

@ -81,7 +81,6 @@ class TypographyPreprocessorTest extends \MailPoetUnitTest {
]];
$expectedEmailAttrs = [
'color' => '#aa00dd',
'font-family' => 'Arial',
'font-size' => '12px',
'text-decoration' => 'underline',
];
@ -121,8 +120,8 @@ class TypographyPreprocessorTest extends \MailPoetUnitTest {
$result = $this->preprocessor->preprocess($blocks, []);
$result = $result[0];
verify($result['innerBlocks'])->arrayCount(2);
verify($result['email_attrs'])->equals(['width' => '640px', 'color' => '#000000', 'font-size' => '13px', 'font-family' => 'Arial']);
$defaultFontStyles = ['color' => '#000000', 'font-size' => '13px', 'font-family' => 'Arial'];
verify($result['email_attrs'])->equals(['width' => '640px', 'color' => '#000000', 'font-size' => '13px']);
$defaultFontStyles = ['color' => '#000000', 'font-size' => '13px'];
verify($result['innerBlocks'][0]['email_attrs'])->equals($defaultFontStyles);
verify($result['innerBlocks'][1]['email_attrs'])->equals($defaultFontStyles);
verify($result['innerBlocks'][1]['innerBlocks'][0]['email_attrs'])->equals($defaultFontStyles);
@ -207,12 +206,10 @@ class TypographyPreprocessorTest extends \MailPoetUnitTest {
];
$expectedEmailAttrs1 = [
'color' => '#aa00dd',
'font-family' => 'Arial',
'font-size' => '12px',
];
$expectedEmailAttrs2 = [
'color' => '#cc22aa',
'font-family' => 'Georgia',
'font-size' => '18px',
];
$result = $this->preprocessor->preprocess($blocks, []);
@ -225,7 +222,7 @@ class TypographyPreprocessorTest extends \MailPoetUnitTest {
verify($child1['innerBlocks'][1]['email_attrs'])->equals($expectedEmailAttrs1);
verify($child1['innerBlocks'][1]['innerBlocks'][0]['email_attrs'])->equals($expectedEmailAttrs1);
verify($child2['innerBlocks'])->arrayCount(1);
verify($child2['email_attrs'])->equals(['color' => '#000000', 'font-size' => '13px', 'font-family' => 'Arial']);
verify($child2['email_attrs'])->equals(['color' => '#000000', 'font-size' => '13px']);
verify($child2['innerBlocks'][0]['email_attrs'])->equals($expectedEmailAttrs2);
verify($child2['innerBlocks'][0]['innerBlocks'][0]['email_attrs'])->equals($expectedEmailAttrs2);
}