Add Preprocessor for removing unwanted blocks

[MAILPOET-5591]
This commit is contained in:
Jan Lysý
2023-10-12 18:30:25 +02:00
committed by Jan Lysý
parent c1768fd0b2
commit fe5eabfe49
9 changed files with 103 additions and 10 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -0,0 +1,17 @@
<?php declare(strict_types = 1);
namespace MailPoet\EmailEditor\Engine\Renderer\Preprocessors;
class CleanupPreprocessor implements Preprocessor {
public function preprocess(array $parsedBlocks, array $layoutStyles): array {
foreach ($parsedBlocks as $key => $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);
}
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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);

View File

@ -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([]);
}
}

View File

@ -0,0 +1,57 @@
<?php declare(strict_types = 1);
namespace unit\EmailEditor\Engine\Renderer\Preprocessors;
use MailPoet\EmailEditor\Engine\Renderer\Preprocessors\CleanupPreprocessor;
class CleanupPreprocessorTest extends \MailPoetUnitTest {
private const PARAGRAPH_BLOCK = [
'blockName' => '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);
}
}

View File

@ -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');