Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions php-transformer/src/HtmlToBlocks/BlockFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ public function create(string $name, array $attrs = array(), array $innerBlocks
*/
private function normalizeAttrsForBlock(string $name, array $attrs): array
{
$attrs = $this->normalizeClassNameAttr($attrs);

if ( in_array($name, array( 'core/group', 'core/columns' ), true) ) {
unset($attrs['style']['dimensions']['maxWidth']);
if ( empty($attrs['style']['dimensions']) ) {
Expand All @@ -85,6 +87,33 @@ private function normalizeAttrsForBlock(string $name, array $attrs): array
return $attrs;
}

/**
* @param array<string, mixed> $attrs
* @return array<string, mixed>
*/
private function normalizeClassNameAttr(array $attrs): array
{
if ( ! is_string($attrs['className'] ?? null) ) {
return $attrs;
}

$classes = array();
foreach ( preg_split('/\s+/', trim($attrs['className'])) ?: array() as $class ) {
if ( '' === $class || GeneratedGutenbergClassPolicy::isGeneratedClassName($class) || in_array($class, $classes, true) ) {
continue;
}
$classes[] = $class;
}

if ( array() === $classes ) {
unset($attrs['className']);
return $attrs;
}

$attrs['className'] = implode(' ', $classes);
return $attrs;
}

/**
* @param array<string, mixed> $attrs
* @return array<string, mixed>
Expand Down
18 changes: 18 additions & 0 deletions php-transformer/tests/contract/run.php
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,24 @@ public function match(DOMElement $element, PatternContext $context): ?array
$assert(str_contains($canonicalWrapperAttrsSerialized, '<h2 class="wp-block-heading has-text-color section-title" style="color:red">Menu</h2>'), 'heading wrappers include canonical and support classes with supported color style');
$assert(str_contains($canonicalWrapperAttrsSerialized, '<p class="card-desc" style="margin-bottom:1rem">Fresh daily.</p>'), 'paragraph wrappers preserve runtime-addressable classes and supported margin style');

$paragraphGeneratedClassLeakResult = ( new HtmlTransformer() )->transform(
'<main><p class="has-text-color has-text-color hero-tagline" style="color:red">Slow roasted daily.</p></main>'
)->toArray();
$paragraphGeneratedClassLeakBlock = $paragraphGeneratedClassLeakResult['blocks'][0] ?? array();
$paragraphGeneratedClassLeakSerialized = (string) ($paragraphGeneratedClassLeakResult['serialized_blocks'] ?? '');
$assert('hero-tagline' === ($paragraphGeneratedClassLeakBlock['attrs']['className'] ?? ''), 'paragraph className strips duplicate generated color classes while preserving custom classes');
$assert(str_contains($paragraphGeneratedClassLeakSerialized, '<p class="has-text-color hero-tagline" style="color:red">Slow roasted daily.</p>'), 'paragraph serialization emits generated has-text-color once before custom classes');
$assert(1 === substr_count($paragraphGeneratedClassLeakSerialized, 'has-text-color'), 'paragraph serialization emits has-text-color exactly once');
$assert('pass' === ($paragraphGeneratedClassLeakResult['source_reports']['wp_block_validity']['status'] ?? ''), 'paragraph with stripped generated className passes generated block validity checks');

$paragraphFactoryGeneratedClassLeakBlock = ( new BlockFactory() )->create('core/paragraph', array(
'content' => 'Slow roasted daily.',
'className' => 'has-text-color has-text-color hero-tagline',
'style' => array('color' => array('text' => 'red')),
));
$assert('hero-tagline' === ($paragraphFactoryGeneratedClassLeakBlock['attrs']['className'] ?? ''), 'BlockFactory strips generated classes from direct paragraph className attrs');
$assert(str_contains((string) ($paragraphFactoryGeneratedClassLeakBlock['innerHTML'] ?? ''), '<p class="has-text-color hero-tagline" style="color:red">Slow roasted daily.</p>'), 'BlockFactory paragraph innerHTML emits a single generated color class');

$paragraphSvgResult = ( new HtmlTransformer() )->transform(
'<main><p class="social-link"><a class="social-link" href="#" aria-label="Follow"><svg viewBox="0 0 10 10" aria-hidden="true"><path d="M0 0h10v10H0z"></path></svg></a></p></main>'
)->toArray();
Expand Down
Loading