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
5 changes: 4 additions & 1 deletion php-transformer/src/ArtifactCompiler/ArtifactCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2012,7 +2012,10 @@ private function compiledSiteReport(array $artifact, string $entryPath, array $d
$shellArtifact['slug'] = 'entry-' . $slug;
}
$partSlugs[(string) $shellArtifact['slug']] = true;
if ( is_string($shellArtifact['inner_block_markup'] ?? null) ) {
if ( is_string($shellArtifact['template_part_block_markup'] ?? null) ) {
$shellArtifact['block_markup'] = $shellArtifact['template_part_block_markup'];
unset($shellArtifact['template_part_block_markup'], $shellArtifact['inner_block_markup']);
} elseif ( is_string($shellArtifact['inner_block_markup'] ?? null) ) {
$shellArtifact['block_markup'] = $shellArtifact['inner_block_markup'];
unset($shellArtifact['inner_block_markup']);
}
Expand Down
6 changes: 6 additions & 0 deletions php-transformer/src/HtmlToBlocks/HtmlTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,11 @@ private function globalShellArtifacts(DOMElement $body, string $source, bool $re
// landmark around an independently converted landmark block.
$blocks = array($this->createBlock('core/group', $wrapperAttrs, $blocks, $child));
$markup = $this->runtime->serializeBlocks($blocks);
$templatePartAttrs = $wrapperAttrs;
unset($templatePartAttrs['tagName']);
$templatePartMarkup = array() === $templatePartAttrs
? $innerMarkup
: $this->runtime->serializeBlocks(array($this->createBlock('core/group', $templatePartAttrs, $blocks[0]['innerBlocks'] ?? array())));
if ( '' === trim($markup) ) {
continue;
}
Expand All @@ -673,6 +678,7 @@ private function globalShellArtifacts(DOMElement $body, string $source, bool $re
'body_format' => 'blocks',
'block_markup' => $markup,
'inner_block_markup' => $innerMarkup,
'template_part_block_markup' => $templatePartMarkup,
'source_selector' => strtolower($child->tagName),
'source_classes' => $this->shellSourceClasses($child),
'source_hash' => hash('sha256', $this->outerHtml($child)),
Expand Down
7 changes: 4 additions & 3 deletions php-transformer/src/WordPressSitePlan/WordPressSitePlan.php
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,8 @@ private function shellCandidates(array $document, AssetReferenceCanonicalizer $r
$classes = array_values(array_filter($candidate['source_classes'] ?? array(), 'is_string'));
sort($classes, SORT_STRING);
$innerMarkup = is_string($candidate['inner_block_markup'] ?? null) ? $this->routeLinks($references->content($candidate['inner_block_markup'], self::value($document, 'source_path')), self::value($document, 'source_path'), $routes) : $markup;
$candidates[] = array('area' => $candidate['area'], 'markup' => $markup, 'inner_markup' => $innerMarkup, 'classes' => $classes);
$templatePartMarkup = is_string($candidate['template_part_block_markup'] ?? null) ? $this->routeLinks($references->content($candidate['template_part_block_markup'], self::value($document, 'source_path')), self::value($document, 'source_path'), $routes) : $innerMarkup;
$candidates[] = array('area' => $candidate['area'], 'markup' => $markup, 'inner_markup' => $innerMarkup, 'template_part_markup' => $templatePartMarkup, 'classes' => $classes);
}
return $candidates;
}
Expand Down Expand Up @@ -317,7 +318,7 @@ private function sharedShells(array $pages, array $reservedSlugs = array(), arra
$sourcePath = $singlePage ? $pages[array_key_first($applicable)]['source_path'] : 'wordpress-site-plan/shared/' . $area;
$placement = $singlePage ? 'entry_shell' : 'shared_shell';
$templateSlugs = $singlePage ? array('front-page') : array('index', 'page', 'front-page');
$partMarkup = $first['markup'];
$partMarkup = $first['template_part_markup'];
$parts[] = array('source_path' => $sourcePath . '#' . $area, 'slug' => $area, 'title' => ucfirst($area), 'post_type' => 'wp_template_part', 'parent_source_path' => '', 'entrypoint' => false, 'area' => $area, 'placement' => array('kind' => $placement, 'source_path' => $sourcePath, 'template_slugs' => $templateSlugs), 'canonical_block_markup' => $partMarkup, 'metadata' => array(), 'document_metadata' => array('source_context' => array('source_path' => $sourcePath . '#' . $area, 'kind' => 'template_part'), 'title' => ucfirst($area), 'title_declaration' => array('order' => 0, 'placement' => 'head'), 'meta' => array(), 'links' => array(), 'scripts' => array()), 'provenance' => array('shell_identity' => $identity), 'reconciliation_identity' => self::identity('template-part', $sourcePath . '#' . $area, 'parts/' . $area . '.html'), 'content_hash' => self::contentHash($partMarkup));
$diagnostics[] = array('code' => $singlePage ? 'wordpress_site_plan_shell_entry_extracted' : 'wordpress_site_plan_shell_extracted', 'severity' => 'info', 'message' => $singlePage ? "Extracted the entry {$area} shell for the front-page template." : "Extracted one semantically equivalent {$area} shell for all pages.", 'area' => $area, 'page_count' => count($applicable));
}
Expand Down Expand Up @@ -491,7 +492,7 @@ private function templates(array $pages, array $parts): array
$markup = static function (string $templateSlug) use ($bound): string {
$before = ''; $after = '';
foreach ($bound as $part) if (in_array($templateSlug, $part['placement']['template_slugs'] ?? array(), true)) {
$reference = '<!-- wp:template-part {"slug":"' . $part['slug'] . '","area":"' . $part['area'] . '"} /-->' . "\n";
$reference = '<!-- wp:template-part {"slug":"' . $part['slug'] . '","area":"' . $part['area'] . '","tagName":"' . $part['area'] . '"} /-->' . "\n";
if ('footer' === $part['area']) $after .= $reference; else $before .= $reference;
}
return $before . '<!-- wp:post-content /-->' . "\n" . $after;
Expand Down
1 change: 1 addition & 0 deletions php-transformer/tests/contract/run.php
Original file line number Diff line number Diff line change
Expand Up @@ -2140,6 +2140,7 @@ public function match(DOMElement $element, PatternContext $context): ?array
$canonicalEntryPage = array_values(array_filter($canonicalShellPlan['pages'] ?? array(), static fn (array $page): bool => 'index.html' === ($page['source_path'] ?? '')))[0] ?? array();
$assert(! str_contains((string) ($canonicalEntryPage['canonical_block_markup'] ?? ''), 'Get started') && str_contains((string) ($canonicalHeaderPart['canonical_block_markup'] ?? ''), 'Get started'), 'canonical entry header is projected only to its shell part, without duplicate post-content chrome');
$assert(str_contains((string) ($canonicalFooterPart['canonical_block_markup'] ?? ''), 'Global footer'), 'canonical entry footer part preserves global footer content');
$assert(! str_contains((string) ($canonicalHeaderPart['canonical_block_markup'] ?? ''), '<header') && ! str_contains((string) ($canonicalFooterPart['canonical_block_markup'] ?? ''), '<footer'), 'canonical shell parts rely on their semantic template-part references instead of nesting duplicate landmarks');
$assert(2 === count(array_filter($canonicalShellPlan['writes'] ?? array(), static fn (array $write): bool => 'theme_template_part' === ($write['kind'] ?? ''))), 'WordPress site plan exposes canonical entry header and footer writes');

$runtimeDependencySite = $compiler->compile(
Expand Down
10 changes: 6 additions & 4 deletions php-transformer/tests/contract/shared-shell-plan.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,17 @@
$nearPages = $pages($nearMatch);
$assert(str_contains($nearPages['index.html']['canonical_block_markup'] ?? '', 'Home') && str_contains($nearPages['about.html']['canonical_block_markup'] ?? '', 'Contact us') && !array_filter($nearMatch['template_parts'], static fn(array $part): bool => 'header' === ($part['area'] ?? null)), 'Route-specific header actions are retained as a near-match instead of being deduplicated.');

$singleResult = (new ArtifactCompiler())->compile(array('entrypoint' => 'index.html', 'files' => array('index.html' => '<header class="solo"><p>Solo</p></header><main>Home</main><footer>Solo footer</footer>')))->toArray();
$singleResult = (new ArtifactCompiler())->compile(array('entrypoint' => 'index.html', 'files' => array('index.html' => '<header id="solo-shell" class="solo" style="border-top:2px solid #111"><p>Solo</p></header><main>Home</main><footer>Solo footer</footer>')))->toArray();
$single = $singleResult['source_reports']['wordpress_site_plan'];
$singleWrites = $writes($single);
$assert(2 === count(array_filter($single['template_parts'], static fn(array $part): bool => 'entry_shell' === ($part['placement']['kind'] ?? null))) && str_contains($singleWrites['templates/front-page.html']['payload']['data'], '"slug":"header"') && !str_contains($singleWrites['templates/page.html']['payload']['data'], '"slug":"header"') && !str_contains($singleWrites['templates/index.html']['payload']['data'], '"slug":"header"'), 'A single-page artifact retains entry-shell behavior and binds chrome only to front-page.');
$assert(2 === count(array_filter($single['template_parts'], static fn(array $part): bool => 'entry_shell' === ($part['placement']['kind'] ?? null))) && str_contains($singleWrites['templates/front-page.html']['payload']['data'], '"slug":"header","area":"header","tagName":"header"') && str_contains($singleWrites['templates/front-page.html']['payload']['data'], '"slug":"footer","area":"footer","tagName":"footer"') && !str_contains($singleWrites['templates/page.html']['payload']['data'], '"slug":"header"') && !str_contains($singleWrites['templates/index.html']['payload']['data'], '"slug":"header"'), 'A single-page artifact binds semantic entry-shell template parts only to front-page.');
$singleHeader = array_values(array_filter($single['template_parts'], static fn(array $part): bool => 'header' === ($part['area'] ?? null)))[0] ?? array();
$assert(str_contains($singleHeader['canonical_block_markup'] ?? '', '"tagName":"header"') && str_contains($singleHeader['canonical_block_markup'] ?? '', 'solo') && str_contains($singleHeader['canonical_block_markup'] ?? '', 'Solo') && !str_contains($pages($single)['index.html']['canonical_block_markup'] ?? '', 'Solo</p>'), 'Single-page entry chrome preserves its semantic landmark and source presentation while removing it from post content.');
$assert(!str_contains($singleHeader['canonical_block_markup'] ?? '', '"tagName":"header"') && !str_contains($singleHeader['canonical_block_markup'] ?? '', '<header') && str_contains($singleHeader['canonical_block_markup'] ?? '', '"className":"solo"') && str_contains($singleHeader['canonical_block_markup'] ?? '', '"anchor":"solo-shell"') && str_contains($singleHeader['canonical_block_markup'] ?? '', 'border-top:2px solid #111') && str_contains($singleHeader['canonical_block_markup'] ?? '', 'Solo') && !str_contains($pages($single)['index.html']['canonical_block_markup'] ?? '', 'Solo</p>'), 'Single-page entry chrome preserves source presentation without nesting a landmark inside the semantic template-part wrapper.');
$compiledHeader = array_values(array_filter($singleResult['source_reports']['compiled_site']['template_parts'] ?? array(), static fn(array $part): bool => 'header' === ($part['area'] ?? null)))[0] ?? array();
$compiledPage = $singleResult['source_reports']['compiled_site']['pages'][0] ?? array();
$assert('entry_shell' === ($compiledHeader['placement']['kind'] ?? null) && !str_contains($compiledHeader['block_markup'] ?? '', '"tagName":"header"') && str_contains($compiledHeader['block_markup'] ?? '', 'Solo') && !str_contains($compiledPage['block_markup'] ?? '', 'Solo</p>'), 'The compiled-site compatibility report retains its established single-page entry shell projection without duplicate page chrome.');
$assert('entry_shell' === ($compiledHeader['placement']['kind'] ?? null) && !str_contains($compiledHeader['block_markup'] ?? '', '"tagName":"header"') && !str_contains($compiledHeader['block_markup'] ?? '', '<header') && str_contains($compiledHeader['block_markup'] ?? '', '"className":"solo"') && str_contains($compiledHeader['block_markup'] ?? '', '"anchor":"solo-shell"') && str_contains($compiledHeader['block_markup'] ?? '', 'border-top:2px solid #111') && str_contains($compiledHeader['block_markup'] ?? '', 'Solo') && !str_contains($compiledPage['block_markup'] ?? '', 'Solo</p>'), 'The compiled-site compatibility report retains source presentation on a non-landmark wrapper without duplicate page chrome.');
$materializedHeader = array_values(array_filter($singleResult['source_reports']['materialization_plan']['template_part_writes'] ?? array(), static fn(array $write): bool => 'header' === ($write['area'] ?? null)))[0] ?? array();
$assert(str_contains($materializedHeader['content'] ?? '', '"className":"solo"') && str_contains($materializedHeader['content'] ?? '', '"anchor":"solo-shell"') && str_contains($materializedHeader['content'] ?? '', 'border-top:2px solid #111') && str_contains($materializedHeader['content'] ?? '', 'Solo') && !str_contains($materializedHeader['content'] ?? '', '"tagName":"header"') && !str_contains($materializedHeader['content'] ?? '', '<header'), 'The v1 materialization projection retains source presentation without nesting a header landmark inside the template-part wrapper.');

$incomplete = (new ArtifactCompiler())->compile(array('entrypoint' => 'index.html', 'files' => array('index.html' => '<header>Shared</header><main>Home</main>', 'about.html' => '<header>Shared</header><main>About</main>', 'contact.html' => '<main>Contact</main>')))->toArray()['source_reports']['wordpress_site_plan'];
$multiple = (new ArtifactCompiler())->compile(array('entrypoint' => 'index.html', 'files' => array('index.html' => '<header>One</header><header>Two</header><main>Home</main>', 'about.html' => '<header>One</header><header>Two</header><main>About</main>')))->toArray()['source_reports']['wordpress_site_plan'];
Expand Down
Loading