From c321eb282ebf052cd24d4fd98da2a7b45f29f9a1 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Tue, 23 Apr 2024 19:58:56 +0100 Subject: [PATCH] Refactor renderers to use template JSON --- .../ContentRenderer/BlocksRegistry.php | 29 ++-------- .../ContentRenderer/ContentRenderer.php | 56 ++++++++++--------- .../EmailEditor/Engine/Renderer/Renderer.php | 28 +++++++++- .../Engine/Templates/Templates.php | 43 +++++++++++--- .../Engine/Templates/email-computing-mag.html | 10 ++++ .../Engine/Templates/email-computing-mag.json | 28 ++++++++++ .../EmailEditor/Engine/ThemeController.php | 44 +++++++++++---- .../ContentRenderer/BlocksRegistryTest.php | 4 +- .../Layout/FlexLayoutRendererTest.php | 2 +- 9 files changed, 172 insertions(+), 72 deletions(-) create mode 100644 mailpoet/lib/EmailEditor/Engine/Templates/email-computing-mag.html create mode 100644 mailpoet/lib/EmailEditor/Engine/Templates/email-computing-mag.json diff --git a/mailpoet/lib/EmailEditor/Engine/Renderer/ContentRenderer/BlocksRegistry.php b/mailpoet/lib/EmailEditor/Engine/Renderer/ContentRenderer/BlocksRegistry.php index 728a07ac1a..b9eefdf9f8 100644 --- a/mailpoet/lib/EmailEditor/Engine/Renderer/ContentRenderer/BlocksRegistry.php +++ b/mailpoet/lib/EmailEditor/Engine/Renderer/ContentRenderer/BlocksRegistry.php @@ -2,47 +2,30 @@ namespace MailPoet\EmailEditor\Engine\Renderer\ContentRenderer; -use MailPoet\EmailEditor\Engine\SettingsController; - class BlocksRegistry { /** @var BlockRenderer[] */ private $blockRenderersMap = []; - /** @var SettingsController */ - private $settingsController; - - public function __construct( - SettingsController $settingsController - ) { - $this->settingsController = $settingsController; - } - public function addBlockRenderer(string $blockName, BlockRenderer $renderer): void { $this->blockRenderersMap[$blockName] = $renderer; - add_filter('render_block_' . $blockName, [$this, 'renderBlock'], 10, 2); + } + + public function hasBlockRenderer(string $blockName): bool { + return isset($this->blockRenderersMap[$blockName]); } public function getBlockRenderer(string $blockName): ?BlockRenderer { - return apply_filters('mailpoet_block_renderer_' . $blockName, $this->blockRenderersMap[$blockName] ?? null); + return $this->blockRenderersMap[$blockName] ?? null; } - public function removeAllBlockRendererFilters(): void { + public function removeAllBlockRenderers(): void { foreach (array_keys($this->blockRenderersMap) as $blockName) { $this->removeBlockRenderer($blockName); } } - public function renderBlock($blockContent, $parsedBlock): string { - // Here we could add a default renderer for blocks that don't have a renderer registered - if (!isset($this->blockRenderersMap[$parsedBlock['blockName']])) { - throw new \InvalidArgumentException('Block renderer not found for block ' . $parsedBlock['name']); - } - return $this->blockRenderersMap[$parsedBlock['blockName']]->render($blockContent, $parsedBlock, $this->settingsController); - } - private function removeBlockRenderer(string $blockName): void { unset($this->blockRenderersMap[$blockName]); - remove_filter('render_block_' . $blockName, [$this, 'renderBlock']); } } diff --git a/mailpoet/lib/EmailEditor/Engine/Renderer/ContentRenderer/ContentRenderer.php b/mailpoet/lib/EmailEditor/Engine/Renderer/ContentRenderer/ContentRenderer.php index 8a464e6d8e..60c3447f92 100644 --- a/mailpoet/lib/EmailEditor/Engine/Renderer/ContentRenderer/ContentRenderer.php +++ b/mailpoet/lib/EmailEditor/Engine/Renderer/ContentRenderer/ContentRenderer.php @@ -13,8 +13,6 @@ class ContentRenderer { private ProcessManager $processManager; private SettingsController $settingsController; private ThemeController $themeController; - private $layoutSettings; - private $themeStyles; const CONTENT_STYLES_FILE = 'content.css'; @@ -27,18 +25,44 @@ class ContentRenderer { $this->processManager = $preprocessManager; $this->blocksRegistry = $blocksRegistry; $this->settingsController = $settingsController; - $this->themeController = $themeController; } private function initialize() { - $this->layoutSettings = $this->settingsController->getLayout(); - $this->themeStyles = $this->settingsController->getEmailStyles(); + add_filter('render_block', [$this, 'renderBlock'], 10, 2); add_filter('block_parser_class', [$this, 'blockParser']); add_filter('mailpoet_blocks_renderer_parsed_blocks', [$this, 'preprocessParsedBlocks']); + do_action('mailpoet_blocks_renderer_initialized', $this->blocksRegistry); } + public function render(WP_Post $post, WP_Block_Template $template): string { + $this->setTemplateGlobals($post, $template); + $this->initialize(); + + $renderedHtml = $this->processManager->postprocess(get_the_block_template_html()); + + $this->reset(); + + return $this->inlineStyles($renderedHtml, $post); + } + + public function blockParser() { + return 'MailPoet\EmailEditor\Engine\Renderer\ContentRenderer\BlocksParser'; + } + + public function preprocessParsedBlocks(array $parsedBlocks): array { + return $this->processManager->preprocess($parsedBlocks, $this->settingsController->getLayout(), $this->themeController->getStyles()); + } + + public function renderBlock($blockContent, $parsedBlock) { + if (!$this->blocksRegistry->hasBlockRenderer($parsedBlock['blockName'])) { + return $blockContent; + } + $renderer = $this->blocksRegistry->getBlockRenderer($parsedBlock['blockName']); + return $renderer ? $renderer->render($blockContent, $parsedBlock, $this->settingsController) : $blockContent; + } + private function setTemplateGlobals(WP_Post $post, WP_Block_Template $template) { global $_wp_current_template_content, $_wp_current_template_id; $_wp_current_template_id = $template->id; @@ -51,30 +75,12 @@ class ContentRenderer { * so that we don't interfere with possible post rendering that might happen later. */ private function reset() { - $this->blocksRegistry->removeAllBlockRendererFilters(); + $this->blocksRegistry->removeAllBlockRenderers(); + remove_filter('render_block', [$this, 'renderBlock']); remove_filter('block_parser_class', [$this, 'blockParser']); remove_filter('mailpoet_blocks_renderer_parsed_blocks', [$this, 'preprocessParsedBlocks']); } - public function blockParser() { - return 'MailPoet\EmailEditor\Engine\Renderer\ContentRenderer\BlocksParser'; - } - - public function preprocessParsedBlocks(array $parsedBlocks): array { - return $this->processManager->preprocess($parsedBlocks, $this->layoutSettings, $this->themeStyles); - } - - public function render(WP_Post $post, WP_Block_Template $template): string { - $this->initialize(); - $this->setTemplateGlobals($post, $template); - - $renderedHtml = $this->processManager->postprocess(get_the_block_template_html()); - - $this->reset(); - - return $this->inlineStyles($renderedHtml, $post); - } - /** * @param string $html * @return string diff --git a/mailpoet/lib/EmailEditor/Engine/Renderer/Renderer.php b/mailpoet/lib/EmailEditor/Engine/Renderer/Renderer.php index f267f389ef..4184d4e468 100644 --- a/mailpoet/lib/EmailEditor/Engine/Renderer/Renderer.php +++ b/mailpoet/lib/EmailEditor/Engine/Renderer/Renderer.php @@ -6,17 +6,21 @@ use MailPoet\Config\ServicesChecker; use MailPoet\EmailEditor\Engine\Renderer\ContentRenderer\ContentRenderer; use MailPoet\EmailEditor\Engine\SettingsController; use MailPoet\EmailEditor\Engine\Templates\Templates; +use MailPoet\EmailEditor\Engine\ThemeController; use MailPoet\Util\CdnAssetUrl; use MailPoetVendor\Html2Text\Html2Text; use MailPoetVendor\Pelago\Emogrifier\CssInliner; use WP_Style_Engine; +use WP_Theme_JSON; class Renderer { private SettingsController $settingsController; + private ThemeController $themeController; private ContentRenderer $contentRenderer; private CdnAssetUrl $cdnAssetUrl; private ServicesChecker $servicesChecker; private Templates $templates; + private static WP_Theme_JSON|null $theme = null; const TEMPLATE_FILE = 'template-canvas.php'; const TEMPLATE_STYLES_FILE = 'template-canvas.css'; @@ -26,23 +30,41 @@ class Renderer { ContentRenderer $contentRenderer, CdnAssetUrl $cdnAssetUrl, Templates $templates, - ServicesChecker $servicesChecker + ServicesChecker $servicesChecker, + ThemeController $themeController ) { $this->settingsController = $settingsController; $this->contentRenderer = $contentRenderer; $this->cdnAssetUrl = $cdnAssetUrl; $this->templates = $templates; $this->servicesChecker = $servicesChecker; + $this->themeController = $themeController; + } + + /** + * During rendering, this stores the theme data for the template being rendered. + */ + public static function getTheme() { + return self::$theme; } public function render(\WP_Post $post, string $subject, string $preHeader, string $language, $metaRobots = ''): array { + $templateId = 'mailpoet/mailpoet//' . (get_page_template_slug($post) ?: 'email-general'); + $template = $this->templates->getBlockTemplate($templateId); + $theme = $this->templates->getBlockTheme($templateId); + + // Set the theme for the template. This is merged with base theme.json and core json before rendering. + self::$theme = new WP_Theme_JSON($theme, 'default'); + + $emailStyles = $this->themeController->getStyles(); + $layoutSettings = $this->settingsController->getLayout(); + $templateHtml = $this->contentRenderer->render($post, $template); + ob_start(); $logoHtml = $this->servicesChecker->isPremiumPluginActive() ? '' : 'MailPoet'; - $templateHtml = $this->contentRenderer->render($post, $this->templates->getBlockTemplate('mailpoet/mailpoet//email-general')); include self::TEMPLATE_FILE; $renderedTemplate = (string)ob_get_clean(); - $emailStyles = $this->settingsController->getEmailStyles(); $templateStyles = WP_Style_Engine::compile_css( [ 'background-color' => $emailStyles['color']['background'] ?? 'inherit', diff --git a/mailpoet/lib/EmailEditor/Engine/Templates/Templates.php b/mailpoet/lib/EmailEditor/Engine/Templates/Templates.php index 90a9990cf5..ecd9ccba95 100644 --- a/mailpoet/lib/EmailEditor/Engine/Templates/Templates.php +++ b/mailpoet/lib/EmailEditor/Engine/Templates/Templates.php @@ -12,11 +12,12 @@ class Templates { private $templateDirectory; private $pluginSlug; private $postType; + private $themeJson = []; public function __construct() { - $this->templateDirectory = dirname(__FILE__) . DIRECTORY_SEPARATOR; - $this->pluginSlug = 'mailpoet/mailpoet'; - $this->postType = 'mailpoet_email'; + $this->templateDirectory = dirname(__FILE__) . DIRECTORY_SEPARATOR; + $this->pluginSlug = 'mailpoet/mailpoet'; + $this->postType = 'mailpoet_email'; } public function initialize(): void { @@ -39,6 +40,36 @@ class Templates { } } + public function getBlockTemplate($templateId) { + $templates = $this->getBlockTemplates(); + return $templates[$templateId] ?? null; + } + + public function getBlockTheme($templateId) { + $template_name_parts = explode('//', $templateId); + + if (count($template_name_parts) < 2) { + return false; + } + + list( $templatePrefix, $templateSlug ) = $template_name_parts; + + if ($this->pluginSlug !== $templatePrefix) { + return false; + } + + if (!isset($this->themeJson[$templateSlug])) { + $templatePath = $templateSlug . '.json'; + $jsonFile = $this->templateDirectory . $templatePath; + + if (file_exists($jsonFile)) { + $this->themeJson[$templateSlug] = json_decode((string)file_get_contents($jsonFile), true); + } + } + + return $this->themeJson[$templateSlug]; + } + public function getBlockFileTemplate($return, $templateId, $template_type) { $template_name_parts = explode('//', $templateId); @@ -114,11 +145,6 @@ class Templates { return $block_template; } - public function getBlockTemplate($templateId) { - $templates = $this->getBlockTemplates(); - return $templates[$templateId] ?? null; - } - /** * Gets block templates indexed by ID. */ @@ -127,6 +153,7 @@ class Templates { $this->getBlockTemplateFromFile('email-general.html'), $this->getBlockTemplateFromFile('awesome-one.html'), $this->getBlockTemplateFromFile('awesome-two.html'), + $this->getBlockTemplateFromFile('email-computing-mag.html'), ]; $custom_templates = $this->getCustomBlockTemplates(); $custom_template_ids = wp_list_pluck($custom_templates, 'id'); diff --git a/mailpoet/lib/EmailEditor/Engine/Templates/email-computing-mag.html b/mailpoet/lib/EmailEditor/Engine/Templates/email-computing-mag.html new file mode 100644 index 0000000000..1daef55881 --- /dev/null +++ b/mailpoet/lib/EmailEditor/Engine/Templates/email-computing-mag.html @@ -0,0 +1,10 @@ + +
+ Computing Magazine +
+ + diff --git a/mailpoet/lib/EmailEditor/Engine/Templates/email-computing-mag.json b/mailpoet/lib/EmailEditor/Engine/Templates/email-computing-mag.json new file mode 100644 index 0000000000..cfcb1a1d0d --- /dev/null +++ b/mailpoet/lib/EmailEditor/Engine/Templates/email-computing-mag.json @@ -0,0 +1,28 @@ +{ + "version": 2, + "styles": { + "spacing": { + "blockGap": "16px", + "padding": { + "bottom": "20px", + "left": "20px", + "right": "20px", + "top": "20px" + } + }, + "color": { + "background": "#008282", + "text": "#000000" + }, + "typography": { + "fontFamily": "'Tahoma, Verdana, Segoe, sans-serif'" + }, + "elements": { + "heading": { + "typography": { + "fontFamily": "'Comic Sans MS', 'Marker Felt-Thin', Arial, sans-serif" + } + } + } + } +} diff --git a/mailpoet/lib/EmailEditor/Engine/ThemeController.php b/mailpoet/lib/EmailEditor/Engine/ThemeController.php index 5b67e371d4..f6d3200af9 100644 --- a/mailpoet/lib/EmailEditor/Engine/ThemeController.php +++ b/mailpoet/lib/EmailEditor/Engine/ThemeController.php @@ -2,6 +2,7 @@ namespace MailPoet\EmailEditor\Engine; +use MailPoet\EmailEditor\Engine\Renderer\Renderer; use WP_Theme_JSON; use WP_Theme_JSON_Resolver; @@ -10,19 +11,42 @@ use WP_Theme_JSON_Resolver; * This class is responsible for accessing data defined by the theme.json. */ class ThemeController { - private WP_Theme_JSON $themeJson; + private WP_Theme_JSON $coreTheme; + private WP_Theme_JSON $baseTheme; + + public function __construct() { + $this->coreTheme = WP_Theme_JSON_Resolver::get_core_data(); + $this->baseTheme = new WP_Theme_JSON((array)json_decode((string)file_get_contents(dirname(__FILE__) . '/theme.json'), true), 'default'); + } public function getTheme(): WP_Theme_JSON { - if (isset($this->themeJson)) { - return $this->themeJson; + $theme = new WP_Theme_JSON(); + $theme->merge($this->coreTheme); + $theme->merge($this->baseTheme); + + if (Renderer::getTheme() !== null) { + $theme->merge(Renderer::getTheme()); } - $coreThemeData = WP_Theme_JSON_Resolver::get_core_data(); - $themeJson = (string)file_get_contents(dirname(__FILE__) . '/theme.json'); - $themeJson = json_decode($themeJson, true); - /** @var array $themeJson */ - $coreThemeData->merge(new WP_Theme_JSON($themeJson, 'default')); - $this->themeJson = apply_filters('mailpoet_email_editor_theme_json', $coreThemeData); - return $this->themeJson; + + return apply_filters('mailpoet_email_editor_theme_json', $theme); + } + + /** + * @return array{ + * spacing: array{ + * blockGap: string, + * padding: array{bottom: string, left: string, right: string, top: string} + * }, + * color: array{ + * background: string + * }, + * typography: array{ + * fontFamily: string + * } + * } + */ + public function getStyles(): array { + return $this->getTheme()->get_data()['styles']; } public function getSettings(): array { diff --git a/mailpoet/tests/integration/EmailEditor/Engine/Renderer/ContentRenderer/BlocksRegistryTest.php b/mailpoet/tests/integration/EmailEditor/Engine/Renderer/ContentRenderer/BlocksRegistryTest.php index 7f6ae77c4f..6e7064f997 100644 --- a/mailpoet/tests/integration/EmailEditor/Engine/Renderer/ContentRenderer/BlocksRegistryTest.php +++ b/mailpoet/tests/integration/EmailEditor/Engine/Renderer/ContentRenderer/BlocksRegistryTest.php @@ -41,7 +41,7 @@ class BlocksRegistryTest extends \MailPoetTest { remove_filter('mailpoet_block_renderer_test', $callback); } - public function testItRemovesAllBlockRendererFilters() { + public function testItRemovesAllBlockRenderers() { $renderer = new Text(); verify(has_filter('render_block_test'))->false(); verify(has_filter('render_block_test2'))->false(); @@ -53,7 +53,7 @@ class BlocksRegistryTest extends \MailPoetTest { verify($this->registry->getBlockRenderer('test'))->notNull(); verify($this->registry->getBlockRenderer('test2'))->notNull(); - $this->registry->removeAllBlockRendererFilters(); + $this->registry->removeAllBlockRenderers(); verify(has_filter('render_block_test'))->false(); verify(has_filter('render_block_test2'))->false(); verify($this->registry->getBlockRenderer('test'))->null(); diff --git a/mailpoet/tests/integration/EmailEditor/Engine/Renderer/ContentRenderer/Layout/FlexLayoutRendererTest.php b/mailpoet/tests/integration/EmailEditor/Engine/Renderer/ContentRenderer/Layout/FlexLayoutRendererTest.php index 9cd197503f..b6e800ff4d 100644 --- a/mailpoet/tests/integration/EmailEditor/Engine/Renderer/ContentRenderer/Layout/FlexLayoutRendererTest.php +++ b/mailpoet/tests/integration/EmailEditor/Engine/Renderer/ContentRenderer/Layout/FlexLayoutRendererTest.php @@ -22,7 +22,7 @@ class FlexLayoutRendererTest extends \MailPoetTest { public function _before(): void { parent::_before(); $this->settingsController = $this->diContainer->get(SettingsController::class); - $this->registry = new BlocksRegistry($this->settingsController); + $this->registry = new BlocksRegistry(); $this->renderer = new FlexLayoutRenderer(); $this->registry->addBlockRenderer('dummy/block', new DummyBlockRenderer()); register_block_type('dummy/block', []);