Files
WP-LIT-MCP/src/Integrations/Divi/BlockTree/Serializer.php
T

74 lines
2.1 KiB
PHP

<?php
declare(strict_types=1);
namespace LIT\MCP\Integrations\Divi\BlockTree;
/**
* Turns a Document back into block markup. Unchanged blocks reuse their original
* delimiters; changed or new blocks get delimiters generated exactly like WordPress'
* get_comment_delimited_block_content() / serialize_block_attributes() do, which also
* yields the escaping Divi expects inside $variable(…)$ payloads (" → ").
*/
final class Serializer
{
/** serialize_block_attributes() replacements (WordPress 7.0). */
private const ESCAPES = [
'\\\\' => '\\u005c',
'--' => '\\u002d\\u002d',
'<' => '\\u003c',
'>' => '\\u003e',
'&' => '\\u0026',
'\\"' => '\\u0022',
];
public static function document(Document $document): string
{
return self::parts($document->parts());
}
public static function block(Block $block): string
{
$open = $block->rawOpen() ?? self::opener($block);
if ($block->isVoid()) {
return $open;
}
return $open . self::parts($block->parts()) . ($block->rawClose() ?? self::closer($block));
}
/** @param array<string, mixed> $attrs */
public static function attributes(array $attrs): string
{
return strtr(Json::encode($attrs), self::ESCAPES);
}
private static function opener(Block $block): string
{
$attrs = $block->attrs() === [] ? '' : self::attributes($block->attrs()) . ' ';
return '<!-- wp:' . self::serializedName($block->name()) . ' ' . $attrs . ($block->isVoid() ? '/-->' : '-->');
}
private static function closer(Block $block): string
{
return '<!-- /wp:' . self::serializedName($block->name()) . ' -->';
}
private static function serializedName(string $name): string
{
return str_starts_with($name, 'core/') ? substr($name, 5) : $name;
}
/** @param list<string|Block> $parts */
private static function parts(array $parts): string
{
$out = '';
foreach ($parts as $part) {
$out .= $part instanceof Block ? self::block($part) : $part;
}
return $out;
}
}