From 35a4e9bed8699da5e520996d60578da7bff66fc0 Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Wed, 24 Jun 2026 09:45:10 -0400 Subject: [PATCH] Fix navigation dedupe serialization --- .../src/HtmlToBlocks/HtmlTransformer.php | 43 +++++++++++++++++++ php-transformer/tests/contract/run.php | 35 +++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/php-transformer/src/HtmlToBlocks/HtmlTransformer.php b/php-transformer/src/HtmlToBlocks/HtmlTransformer.php index 1f0df5b..f2d6418 100644 --- a/php-transformer/src/HtmlToBlocks/HtmlTransformer.php +++ b/php-transformer/src/HtmlToBlocks/HtmlTransformer.php @@ -307,6 +307,7 @@ private function deduplicateNavigationBlocksRecursive(array $blocks, array &$see if ( ! empty($block['innerBlocks']) && is_array($block['innerBlocks']) ) { $block['innerBlocks'] = $this->deduplicateNavigationBlocksRecursive($block['innerBlocks'], $seen); + $block = $this->reconcileInnerContentChildPlaceholders($block); } if ( 'core/navigation' === ($block['blockName'] ?? '') ) { @@ -329,6 +330,48 @@ private function deduplicateNavigationBlocksRecursive(array $blocks, array &$see return $deduplicated; } + /** + * @param array $block + * @return array + */ + private function reconcileInnerContentChildPlaceholders(array $block): array + { + $innerBlocks = is_array($block['innerBlocks'] ?? null) ? array_values($block['innerBlocks']) : array(); + $innerContent = is_array($block['innerContent'] ?? null) ? array_values($block['innerContent']) : null; + if ( null === $innerContent ) { + return $block; + } + + $placeholderCount = 0; + $firstPlaceholderIndex = null; + $lastPlaceholderIndex = null; + foreach ( $innerContent as $index => $part ) { + if ( null !== $part ) { + continue; + } + + ++$placeholderCount; + $firstPlaceholderIndex ??= $index; + $lastPlaceholderIndex = $index; + } + + if ( count($innerBlocks) === $placeholderCount ) { + return $block; + } + + if ( null === $firstPlaceholderIndex || null === $lastPlaceholderIndex ) { + return $block; + } + + $opening = array_slice($innerContent, 0, $firstPlaceholderIndex); + $closing = array_slice($innerContent, $lastPlaceholderIndex + 1); + $block['innerBlocks'] = $innerBlocks; + $block['innerContent'] = array_merge($opening, array_fill(0, count($innerBlocks), null), $closing); + $block['innerHTML'] = implode('', array_map(static fn ($part): string => null === $part ? '' : (string) $part, array_merge($opening, $closing))); + + return $block; + } + /** * @param array $block */ diff --git a/php-transformer/tests/contract/run.php b/php-transformer/tests/contract/run.php index d58fadf..9b2a5e9 100644 --- a/php-transformer/tests/contract/run.php +++ b/php-transformer/tests/contract/run.php @@ -336,6 +336,41 @@ function serialize_blocks(array $blocks): string $assert(str_contains($asideSerialized, 'sidebar'), 'semantic aside container preserves CSS-addressable sidebar class'); $assert(str_contains($asideSerialized, '