diff --git a/mailpoet/lib/DI/ContainerConfigurator.php b/mailpoet/lib/DI/ContainerConfigurator.php index ef0633d742..9a15c82082 100644 --- a/mailpoet/lib/DI/ContainerConfigurator.php +++ b/mailpoet/lib/DI/ContainerConfigurator.php @@ -336,6 +336,7 @@ class ContainerConfigurator implements IContainerConfigurator { $container->autowire(\MailPoet\EmailEditor\Engine\EmailEditor::class)->setPublic(true); $container->autowire(\MailPoet\EmailEditor\Engine\EmailApiController::class)->setPublic(true); $container->autowire(\MailPoet\EmailEditor\Engine\SettingsController::class)->setPublic(true); + $container->autowire(\MailPoet\EmailEditor\Engine\Renderer\Preprocessors\CleanupPreprocessor::class)->setPublic(true); $container->autowire(\MailPoet\EmailEditor\Engine\Renderer\Preprocessors\TopLevelPreprocessor::class)->setPublic(true); $container->autowire(\MailPoet\EmailEditor\Engine\Renderer\Renderer::class)->setPublic(true); $container->autowire(\MailPoet\EmailEditor\Engine\Renderer\BlocksRenderer::class)->setPublic(true); diff --git a/mailpoet/lib/EmailEditor/Engine/Renderer/PreprocessManager.php b/mailpoet/lib/EmailEditor/Engine/Renderer/PreprocessManager.php index 1e4570f6ef..46b4f110c1 100644 --- a/mailpoet/lib/EmailEditor/Engine/Renderer/PreprocessManager.php +++ b/mailpoet/lib/EmailEditor/Engine/Renderer/PreprocessManager.php @@ -2,6 +2,7 @@ namespace MailPoet\EmailEditor\Engine\Renderer; +use MailPoet\EmailEditor\Engine\Renderer\Preprocessors\CleanupPreprocessor; use MailPoet\EmailEditor\Engine\Renderer\Preprocessors\Preprocessor; use MailPoet\EmailEditor\Engine\Renderer\Preprocessors\TopLevelPreprocessor; @@ -10,18 +11,21 @@ class PreprocessManager { private $preprocessors = []; public function __construct( + CleanupPreprocessor $cleanupPreprocessor, TopLevelPreprocessor $topLevelPreprocessor ) { + $this->registerPreprocessor($cleanupPreprocessor); $this->registerPreprocessor($topLevelPreprocessor); } /** * @param array $parsedBlocks + * @param array{width: int, background: string, padding: array{bottom: int, left: int, right: int, top: int}} $layoutStyles * @return array */ - public function preprocess(array $parsedBlocks): array { + public function preprocess(array $parsedBlocks, array $layoutStyles): array { foreach ($this->preprocessors as $preprocessor) { - $parsedBlocks = $preprocessor->preprocess($parsedBlocks); + $parsedBlocks = $preprocessor->preprocess($parsedBlocks, $layoutStyles); } return $parsedBlocks; } diff --git a/mailpoet/lib/EmailEditor/Engine/Renderer/Preprocessors/CleanupPreprocessor.php b/mailpoet/lib/EmailEditor/Engine/Renderer/Preprocessors/CleanupPreprocessor.php new file mode 100644 index 0000000000..23049b05e2 --- /dev/null +++ b/mailpoet/lib/EmailEditor/Engine/Renderer/Preprocessors/CleanupPreprocessor.php @@ -0,0 +1,17 @@ + $block) { + // https://core.trac.wordpress.org/ticket/45312 + // \WP_Block_Parser::parse_blocks() sometimes add a block with name null that can cause unexpected spaces in rendered content + // This behavior was reported as an issue, but it was closed as won't fix + if ($block['blockName'] === null) { + unset($parsedBlocks[$key]); + } + } + return array_values($parsedBlocks); + } +} diff --git a/mailpoet/lib/EmailEditor/Engine/Renderer/Preprocessors/Preprocessor.php b/mailpoet/lib/EmailEditor/Engine/Renderer/Preprocessors/Preprocessor.php index 594878c8ca..4f342156a6 100644 --- a/mailpoet/lib/EmailEditor/Engine/Renderer/Preprocessors/Preprocessor.php +++ b/mailpoet/lib/EmailEditor/Engine/Renderer/Preprocessors/Preprocessor.php @@ -3,5 +3,5 @@ namespace MailPoet\EmailEditor\Engine\Renderer\Preprocessors; interface Preprocessor { - public function preprocess(array $parsedBlocks): array; + public function preprocess(array $parsedBlocks, array $layoutStyles): array; } diff --git a/mailpoet/lib/EmailEditor/Engine/Renderer/Preprocessors/TopLevelPreprocessor.php b/mailpoet/lib/EmailEditor/Engine/Renderer/Preprocessors/TopLevelPreprocessor.php index 0badd517f3..86b7b87a48 100644 --- a/mailpoet/lib/EmailEditor/Engine/Renderer/Preprocessors/TopLevelPreprocessor.php +++ b/mailpoet/lib/EmailEditor/Engine/Renderer/Preprocessors/TopLevelPreprocessor.php @@ -18,7 +18,7 @@ class TopLevelPreprocessor implements Preprocessor { * But for rendering purposes it is more convenient to have them wrapped in a single column. * This method walks through the first level of blocks and wraps non column blocks into a single column. */ - public function preprocess(array $parsedBlocks): array { + public function preprocess(array $parsedBlocks, array $layoutStyles): array { $wrappedParsedBlocks = []; $nonColumnsBlocksBuffer = []; foreach ($parsedBlocks as $block) { diff --git a/mailpoet/lib/EmailEditor/Engine/Renderer/Renderer.php b/mailpoet/lib/EmailEditor/Engine/Renderer/Renderer.php index 5e6857f1ac..cc3bc7803d 100644 --- a/mailpoet/lib/EmailEditor/Engine/Renderer/Renderer.php +++ b/mailpoet/lib/EmailEditor/Engine/Renderer/Renderer.php @@ -42,7 +42,7 @@ class Renderer { $parser = new \WP_Block_Parser(); $parsedBlocks = $parser->parse($post->post_content); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps - $parsedBlocks = $this->preprocessManager->preprocess($parsedBlocks); + $parsedBlocks = $this->preprocessManager->preprocess($parsedBlocks, $this->stylesController->getEmailLayoutStyles()); $renderedBody = $this->blocksRenderer->render($parsedBlocks); $styles = (string)file_get_contents(dirname(__FILE__) . '/' . self::TEMPLATE_STYLES_FILE); diff --git a/mailpoet/tests/unit/EmailEditor/Engine/Renderer/PreprocessManagerTest.php b/mailpoet/tests/unit/EmailEditor/Engine/Renderer/PreprocessManagerTest.php index 530314f301..3b431f834a 100644 --- a/mailpoet/tests/unit/EmailEditor/Engine/Renderer/PreprocessManagerTest.php +++ b/mailpoet/tests/unit/EmailEditor/Engine/Renderer/PreprocessManagerTest.php @@ -3,18 +3,32 @@ namespace unit\EmailEditor\Engine\Renderer; use MailPoet\EmailEditor\Engine\Renderer\PreprocessManager; +use MailPoet\EmailEditor\Engine\Renderer\Preprocessors\CleanupPreprocessor; use MailPoet\EmailEditor\Engine\Renderer\Preprocessors\TopLevelPreprocessor; class PreprocessManagerTest extends \MailPoetUnitTest { public function testItCallsPreprocessorsProperly(): void { + $layoutStyles = [ + 'width' => 600, + 'background' => '#ffffff', + 'padding' => [ + 'bottom' => 0, + 'left' => 0, + 'right' => 0, + 'top' => 0, + ], + ]; $topLevel = $this->createMock(TopLevelPreprocessor::class); $topLevel->expects($this->once())->method('preprocess')->willReturn([]); + $cleanup = $this->createMock(CleanupPreprocessor::class); + $cleanup->expects($this->once())->method('preprocess')->willReturn([]); + $secondPreprocessor = $this->createMock(TopLevelPreprocessor::class); $secondPreprocessor->expects($this->once())->method('preprocess')->willReturn([]); - $preprocessManager = new PreprocessManager($topLevel); + $preprocessManager = new PreprocessManager($cleanup, $topLevel); $preprocessManager->registerPreprocessor($secondPreprocessor); - expect($preprocessManager->preprocess([]))->equals([]); + expect($preprocessManager->preprocess([], $layoutStyles))->equals([]); } } diff --git a/mailpoet/tests/unit/EmailEditor/Engine/Renderer/Preprocessors/CleanupPreprocessorTest.php b/mailpoet/tests/unit/EmailEditor/Engine/Renderer/Preprocessors/CleanupPreprocessorTest.php new file mode 100644 index 0000000000..a253cdb4cb --- /dev/null +++ b/mailpoet/tests/unit/EmailEditor/Engine/Renderer/Preprocessors/CleanupPreprocessorTest.php @@ -0,0 +1,57 @@ + 'core/paragraph', + 'attrs' => [], + 'innerHTML' => 'Paragraph content', + ]; + + private const COLUMNS_BLOCK = [ + 'blockName' => 'core/columns', + 'attrs' => [], + 'innerBlocks' => [[ + 'blockName' => 'core/column', + 'attrs' => [], + 'innerBlocks' => [], + ]], + ]; + + /** @var CleanupPreprocessor */ + private $preprocessor; + + public function _before() { + parent::_before(); + $this->preprocessor = new CleanupPreprocessor(); + } + + public function testItRemovesUnwantedBlocks(): void { + $blocks = [ + self::COLUMNS_BLOCK, + ['blockName' => null, 'attrs' => [], 'innerHTML' => "\r\n"], + self::PARAGRAPH_BLOCK, + ]; + $result = $this->preprocessor->preprocess($blocks, []); + expect($result)->count(2); + expect($result[0])->equals(self::COLUMNS_BLOCK); + expect($result[1])->equals(self::PARAGRAPH_BLOCK); + } + + public function testItPreservesAllRelevantBlocks(): void { + $blocks = [ + self::COLUMNS_BLOCK, + self::PARAGRAPH_BLOCK, + self::COLUMNS_BLOCK, + ]; + $result = $this->preprocessor->preprocess($blocks, []); + expect($result)->count(3); + expect($result[0])->equals(self::COLUMNS_BLOCK); + expect($result[1])->equals(self::PARAGRAPH_BLOCK); + expect($result[2])->equals(self::COLUMNS_BLOCK); + } +} diff --git a/mailpoet/tests/unit/EmailEditor/Engine/Renderer/Preprocessors/TopLevelPreprocessorTest.php b/mailpoet/tests/unit/EmailEditor/Engine/Renderer/Preprocessors/TopLevelPreprocessorTest.php index b3dfd3ad1b..7d417e2636 100644 --- a/mailpoet/tests/unit/EmailEditor/Engine/Renderer/Preprocessors/TopLevelPreprocessorTest.php +++ b/mailpoet/tests/unit/EmailEditor/Engine/Renderer/Preprocessors/TopLevelPreprocessorTest.php @@ -32,7 +32,7 @@ class TopLevelPreprocessorTest extends \MailPoetUnitTest { public function testItWrapsSingleTopLevelBlockIntoColumns() { $parsedDocument = [$this->paragraphBlock]; - $result = $this->preprocessor->preprocess($parsedDocument); + $result = $this->preprocessor->preprocess($parsedDocument, []); verify($result[0]['blockName'])->equals('core/columns'); verify($result[0]['innerBlocks'][0]['blockName'])->equals('core/column'); verify($result[0]['innerBlocks'][0]['innerBlocks'][0]['blockName'])->equals('core/paragraph'); @@ -41,14 +41,14 @@ class TopLevelPreprocessorTest extends \MailPoetUnitTest { public function testItDoesntWrapColumns() { $parsedDocumentWithMultipleColumns = [$this->columnsBlock, $this->columnsBlock]; - $result = $this->preprocessor->preprocess($parsedDocumentWithMultipleColumns); + $result = $this->preprocessor->preprocess($parsedDocumentWithMultipleColumns, []); verify($result)->equals($parsedDocumentWithMultipleColumns); } public function testItWrapsTopLevelBlocksSpreadBetweenColumns() { $parsedDocument = [$this->paragraphBlock, $this->columnsBlock, $this->paragraphBlock, $this->paragraphBlock]; // We expect to wrap top level paragraph blocks into columns so the result should three columns blocks - $result = $this->preprocessor->preprocess($parsedDocument); + $result = $this->preprocessor->preprocess($parsedDocument, []); verify($result)->arrayCount(3); // First columns contain columns with one paragraph block verify($result[0]['innerBlocks'][0]['blockName'])->equals('core/column');