From f18f515c0164f0ce693621fade185495b9d556da Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Fri, 26 Jun 2026 23:13:54 -0400 Subject: [PATCH] Preserve navigation runtime targets --- .../src/HtmlToBlocks/HtmlTransformer.php | 18 ++++++++++++++++++ .../Patterns/NavigationPattern.php | 4 ++++ php-transformer/tests/contract/run.php | 16 ++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/php-transformer/src/HtmlToBlocks/HtmlTransformer.php b/php-transformer/src/HtmlToBlocks/HtmlTransformer.php index a1139bb..34fcfbd 100644 --- a/php-transformer/src/HtmlToBlocks/HtmlTransformer.php +++ b/php-transformer/src/HtmlToBlocks/HtmlTransformer.php @@ -391,6 +391,10 @@ private function collectSourceLandmarks(DOMElement $element, array &$counts, arr private function landmarkKindForElement(DOMElement $element): string { $tagName = strtolower($element->tagName); + if ( 'footer' === $tagName && $this->hasAncestorTag($element, array( 'blockquote', 'figure' )) ) { + return ''; + } + if ( in_array($tagName, array( 'header', 'nav', 'main', 'footer' ), true) ) { return 'nav' === $tagName ? 'nav' : $tagName; } @@ -404,6 +408,20 @@ private function landmarkKindForElement(DOMElement $element): string }; } + /** + * @param array $tagNames + */ + private function hasAncestorTag(DOMElement $element, array $tagNames): bool + { + for ( $node = $element->parentNode; $node instanceof DOMElement && 'body' !== strtolower($node->tagName); $node = $node->parentNode ) { + if ( in_array(strtolower($node->tagName), $tagNames, true) ) { + return true; + } + } + + return false; + } + /** * @param array> $blocks * @param array> $sourceProvenance diff --git a/php-transformer/src/HtmlToBlocks/Patterns/NavigationPattern.php b/php-transformer/src/HtmlToBlocks/Patterns/NavigationPattern.php index e388f38..6b17011 100644 --- a/php-transformer/src/HtmlToBlocks/Patterns/NavigationPattern.php +++ b/php-transformer/src/HtmlToBlocks/Patterns/NavigationPattern.php @@ -216,6 +216,10 @@ private function navigationItemAttributes(DOMElement $item, DOMElement $anchor, $itemAttrs = $item->isSameNode($anchor) ? array() : $presentationAttributes($item); $anchorAttrs = $presentationAttributes($anchor); $submenuAttrs = $submenuContainer instanceof DOMElement ? $presentationAttributes($submenuContainer) : array(); + if ( '' === (string) ($itemAttrs['className'] ?? '') && '' !== (string) ($anchorAttrs['className'] ?? '') ) { + $itemAttrs['className'] = $anchorAttrs['className']; + } + return array_filter(array_merge($itemAttrs, $baseAttrs, array( 'anchorClassName' => $anchorAttrs['className'] ?? '', 'anchorStyle' => $anchorAttrs['style'] ?? '', diff --git a/php-transformer/tests/contract/run.php b/php-transformer/tests/contract/run.php index ca693ef..e21c2db 100644 --- a/php-transformer/tests/contract/run.php +++ b/php-transformer/tests/contract/run.php @@ -434,6 +434,15 @@ function serialize_blocks(array $blocks): string $assert(str_contains($footerNavigationSerialized, 'footer-link'), 'footer navigation preserves link classes for styling and script targets'); $assert(str_contains($footerNavigationSerialized, 'social-link'), 'social navigation preserves social link classes for styling and script targets'); +$runtimeTargetNavigation = ( new HtmlTransformer() )->transform( + '', + array('runtime_dom_selectors' => array('.nav-link')) +)->toArray(); +$runtimeTargetNavigationSerialized = (string) ($runtimeTargetNavigation['serialized_blocks'] ?? ''); +$runtimeTargetNavigationItemAttrs = $runtimeTargetNavigation['blocks'][0]['innerBlocks'][0]['attrs'] ?? array(); +$assert('nav-link' === ($runtimeTargetNavigationItemAttrs['className'] ?? ''), 'runtime-target navigation link classes are preserved on navigation item attrs'); +$assert(str_contains($runtimeTargetNavigationSerialized, '