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
39 changes: 37 additions & 2 deletions php-transformer/src/HtmlToBlocks/HtmlTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -3740,6 +3740,24 @@ private function visualTextWrapperBlockFromElement(DOMElement $element): ?array
return null;
}

// A pure-text styled wrapper whose CSS is typographic only (no box-model
// geometry) round-trips as a single styled `core/paragraph` carrying the
// wrapper class. The `core/group` + default inner paragraph form neither
// inherits the wrapper's typographic scale onto that inner paragraph nor
// suppresses default block spacing, so an eyebrow like `<div class="label">
// The Shop</div>` renders at the wrong size and pushes every following
// block down. The group form is retained only when the wrapper owns
// box-model geometry (padding/border/flex) that a block-level container
// must preserve.
if ( 0 === $this->childElementCount($element) && ! $this->hasBoxModelWrapperStyling($element) ) {
return $this->createBlock(
'core/paragraph',
array_merge($this->presentationAttributes($element), array( 'content' => $content )),
array(),
$element
);
}

return $this->createBlock(
'core/group',
$this->presentationAttributes($element),
Expand All @@ -3748,6 +3766,15 @@ private function visualTextWrapperBlockFromElement(DOMElement $element): ?array
);
}

/**
* Box-model CSS declarations that give a text wrapper block-level geometry
* (padding, border, explicit sizing, or flex/grid layout) which must be
* preserved on a `core/group` rather than flattened onto a paragraph.
*
* @var array<int, string>
*/
private const BOX_MODEL_WRAPPER_PROPERTIES = array( 'display', 'gap', 'padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left', 'border', 'border-color', 'border-radius', 'width', 'height', 'min-width', 'max-width', 'min-height' );

private function hasVisualTextWrapperSignal(DOMElement $element): bool
{
$className = strtolower($this->attr($element, 'class'));
Expand All @@ -3759,8 +3786,16 @@ private function hasVisualTextWrapperSignal(DOMElement $element): bool
return false;
}

$declarations = $this->presentationDeclarations($element);
foreach ( array( 'display', 'gap', 'padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left', 'border', 'border-color', 'border-radius', 'width', 'height', 'min-width', 'max-width', 'min-height' ) as $property ) {
return $this->hasBoxModelWrapperStyling($element);
}

private function hasBoxModelWrapperStyling(DOMElement $element): bool
{
// Read the raw matched declarations rather than the post-projection
// presentation set: box-model properties such as padding are consumed
// into block-supports attributes and would otherwise be invisible here.
$declarations = $this->structuralPresentationDeclarations($element);
foreach ( self::BOX_MODEL_WRAPPER_PROPERTIES as $property ) {
if ( isset($declarations[$property]) && '' !== trim((string) $declarations[$property]) ) {
return true;
}
Expand Down
10 changes: 5 additions & 5 deletions php-transformer/tests/unit/block-style-support-conversion.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,11 @@
$labelResult = ( new HtmlTransformer() )->transform($labelHtml, array('static_css' => $labelCss))->toArray();
$labelMarkup = (string) ($labelResult['serialized_blocks'] ?? '');

$assert(str_contains($labelMarkup, '<div class="wp-block-group tag'), '25: class-owned section badge stays a group wrapper', $labelMarkup);
$assert(str_contains($labelMarkup, '<div class="wp-block-group tier-name'), '26: class-owned card tier label stays a group wrapper', $labelMarkup);
$assert(str_contains($labelMarkup, '<div class="wp-block-group tier-price'), '27: class-owned card price row stays a group wrapper', $labelMarkup);
$assert(str_contains($labelMarkup, '<div class="wp-block-group use-case-result'), '28: class-owned card result row stays a group wrapper', $labelMarkup);
$assert(! str_contains($labelMarkup, '<p class="tier-name"'), '29: card label is not flattened into a paragraph that breaks wrapper CSS', $labelMarkup);
$assert(str_contains($labelMarkup, '<div class="wp-block-group tag'), '25: box-model section badge stays a group wrapper', $labelMarkup);
$assert(str_contains($labelMarkup, '<p class="tier-name">Team</p>'), '26: typography-only card tier label collapses to a styled paragraph so its font scale applies', $labelMarkup);
$assert(str_contains($labelMarkup, '<div class="wp-block-group tier-price'), '27: box-model card price row stays a group wrapper', $labelMarkup);
$assert(str_contains($labelMarkup, '<div class="wp-block-group use-case-result'), '28: box-model card result row stays a group wrapper', $labelMarkup);
$assert(! preg_match('/<!-- wp:group[^>]*"className":"tier-name"/', $labelMarkup), '29: typography-only tier label does not round-trip as a group wrapping a default paragraph', $labelMarkup);

$stackHtml = '<div class="hero-content"><p>Eyebrow</p><h1>Low Tide Table</h1><div></div><p>Local shrimp.</p><div><p>Next Run</p></div><div><a href="#reserve">Reserve</a></div></div>';
$stackResult = ( new HtmlTransformer() )->transform($stackHtml, array())->toArray();
Expand Down
Loading