diff --git a/php-transformer/src/HtmlToBlocks/Patterns/ColumnsPattern.php b/php-transformer/src/HtmlToBlocks/Patterns/ColumnsPattern.php index 54abfd09..9a9509d5 100644 --- a/php-transformer/src/HtmlToBlocks/Patterns/ColumnsPattern.php +++ b/php-transformer/src/HtmlToBlocks/Patterns/ColumnsPattern.php @@ -94,12 +94,38 @@ private function looksLikeColumnsContainer(DOMElement $element): bool return false; } + // A genuinely vertical flex container (display:flex with + // flex-direction: column / column-reverse) lays its children out in a + // vertical stack. Emitting core/columns would render them horizontally — + // the wrong direction. Decline here so the host transformer routes the + // element to a vertical core/group instead, preserving its classes and + // styles. Horizontal flex (row / row-reverse / default) and grid layouts + // are unaffected, so legitimate horizontal columns are never disturbed. + if ( $this->isVerticalFlexContainer($style) ) { + return false; + } + return (bool) preg_match('/(?:^|[\s_-])columns?(?:$|[\s_-])/', $className) || ( $this->looksLikeSplitLayout($element) && 1 < $this->directElementChildCount($element) ) || ( $this->looksLikeDocumentationLayout($element) && $this->hasSidebarAndContentChildren($element) ) || preg_match('/(?:^|;)\s*(?:display\s*:\s*(?:inline-)?flex|grid-template-columns\s*:)/', $style); } + /** + * True when the resolved style declares a flex container whose main axis is + * vertical (flex-direction: column / column-reverse). flex-direction only has + * meaning on a flex container, so both display:flex and the column direction + * are required before redirecting away from horizontal columns. + */ + private function isVerticalFlexContainer(string $style): bool + { + if ( ! preg_match('/(?:^|;)\s*display\s*:\s*(?:inline-)?flex\b/', $style) ) { + return false; + } + + return (bool) preg_match('/(?:^|;)\s*flex-direction\s*:\s*column(?:-reverse)?\b/', $style); + } + private function looksLikeSplitLayout(DOMElement $element): bool { $name = strtolower(trim($this->attr($element, 'class') . ' ' . $this->attr($element, 'id'))); diff --git a/php-transformer/src/HtmlToBlocks/Style/StyleResolutionTrait.php b/php-transformer/src/HtmlToBlocks/Style/StyleResolutionTrait.php index ebf9dc56..3679d79e 100644 --- a/php-transformer/src/HtmlToBlocks/Style/StyleResolutionTrait.php +++ b/php-transformer/src/HtmlToBlocks/Style/StyleResolutionTrait.php @@ -419,6 +419,18 @@ private function layoutAttribute(DOMElement $element, string $mergedStyle = ''): $style = strtolower('' !== trim($mergedStyle) ? $mergedStyle : $this->attr($element, 'style')); if ( preg_match('/(?:^|;)\s*display\s*:\s*(inline-)?flex\b/', $style) ) { + // flex-direction: column / column-reverse is a vertical main axis. A + // core/group flex layout defaults to a horizontal Row, so the + // orientation must be made explicit or the children render + // side-by-side instead of stacked. Row / row-reverse / default flex + // keeps the implicit horizontal orientation. + if ( preg_match('/(?:^|;)\s*flex-direction\s*:\s*column(?:-reverse)?\b/', $style) ) { + return array( + 'type' => 'flex', + 'orientation' => 'vertical', + ); + } + return array( 'type' => 'flex' ); } if ( preg_match('/(?:^|;)\s*display\s*:\s*(inline-)?grid\b/', $style) ) { diff --git a/php-transformer/tests/fixtures/parity/html-horizontal-flex-stays-columns.json b/php-transformer/tests/fixtures/parity/html-horizontal-flex-stays-columns.json new file mode 100644 index 00000000..a41510a6 --- /dev/null +++ b/php-transformer/tests/fixtures/parity/html-horizontal-flex-stays-columns.json @@ -0,0 +1,33 @@ +{ + "schema": "blocks-engine/php-transformer/parity-fixture/v1", + "name": "html-horizontal-flex-stays-columns", + "description": "A flex container with the default (row) main axis is a genuine horizontal layout, so it stays a core/columns block. Guards that the flex-direction:column redirect never disturbs legitimate horizontal column layouts.", + "source_reference": { + "repo": "php-transformer", + "path": "tests/fixtures/parity/html-horizontal-flex-stays-columns.json", + "notes": "Same display:flex container shape as the vertical fixture but without flex-direction:column. The ColumnsPattern flex-direction guard does not fire, so the horizontal columns layout is preserved unchanged." + }, + "legacy_comparison": { + "skip": true, + "reason": "Covers current PHP transformer columns recognizer behavior; no downstream legacy comparison." + }, + "operation": "html_transformer.transform", + "input": { + "content": "
one
two