Shell extraction ignores a third capture device document (tablet), so no shared header/footer parts are extracted

Aperta
#4,638 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
74/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
php, wordpress
Ambito
backend, testing

Direzione di ricerca

Start with ShellExtraction::isResponsiveVariantClass() and CaptureEvidence::DEVICE_DOCUMENT; the issue identifies both the recognition rule and the capture contract to follow. Add a contract test based on tests/contract/capture-variant-plain-page-shell.php that includes desktop, mobile, and tablet documents across three routes. Done means shared header and footer parts include the tablet variant, pages have no inline header or footer, and no shell_retained_* diagnostic appears; check the three existing contracts named in the issue too.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

A third capture device document disables shared header/footer extraction

Data Liberation now emits an additional device document for dual routes (data-blocks-engine-capture-tablet-document, alongside the desktop and mobile documents) through the existing capture contract: CaptureEvidence::DEVICE_DOCUMENT allows any profile id ([a-z][a-z0-9_-]{0,63}). Shell extraction recognizes only the two hardcoded document classes:

// ShellExtraction::isResponsiveVariantClass()
return in_array($class, array(CaptureEvidence::DESKTOP_DOCUMENT_CLASS, CaptureEvidence::MOBILE_DOCUMENT_CLASS), true)
    || 1 === preg_match('/^site-document-variant-[a-z][a-z0-9_-]{0,31}$/', $class);

So the tablet copy of each landmark has no responsive variant class, scopedVariantLandmarks() returns null for every route, absorbResponsiveVariantLandmarks() returns false, and both areas end in wordpress_site_plan_shell_retained_incomplete ("shell candidates do not establish a dominant semantic cluster"). Every page keeps its own inline header and footer instead of binding shared template parts.

Observed

A 4fires.org (Wix) import with SSI 1.33.366 / DLA 0.33.136: 41 pages, all with desktop + mobile + tablet documents, produced no parts/ and the two shell_retained_incomplete diagnostics. Probing the materialized pages: on every route the desktop and mobile SITE_HEADER / SITE_FOOTER landmarks resolve to their variant classes and the SITE_HEADER--data-blocks-engine-capture-tablet copy resolves to null.

Reduced reproduction (trunk 15317e2)

Three routes, identical chrome, block markup injected per route the way tests/contract/capture-variant-plain-page-shell.php does. The only difference between the two runs is the third document class:

desktop+mobile          parts=["footer","header"] pages-with-inline-header=0 retained=[]
desktop+mobile+tablet   parts=["footer"] pages-with-inline-header=3 retained=["wordpress_site_plan_shell_retained_incomplete footer","wordpress_site_plan_shell_retained_incomplete header"]
Repro script
declare(strict_types=1);

require getenv('BE') . '/php-transformer/vendor/autoload.php';

use Automattic\BlocksEngine\PhpTransformer\ArtifactCompiler\ArtifactCompiler;
use Automattic\BlocksEngine\PhpTransformer\Contract\CaptureEvidence;
use Automattic\BlocksEngine\PhpTransformer\WordPressSitePlan\WordPressSitePlan;

// Three routes, each captured as three device documents: desktop, mobile, and
// an additional profile (tablet) declared through the same capture contract.
$tablet = 'data-blocks-engine-capture-tablet-document';
$navigation = '<!-- wp:navigation {"overlayMenu":"never"} --><!-- wp:navigation-link {"label":"Home","url":"/","kind":"custom"} /--><!-- wp:navigation-link {"label":"About","url":"/about/","kind":"custom"} /--><!-- /wp:navigation -->';
$header = static fn(string $class): string => '<!-- wp:group {"className":"' . $class . '","tagName":"header"} --><header class="wp-block-group ' . $class . '"><!-- wp:paragraph --><p><a href="/">Four Fires</a></p><!-- /wp:paragraph -->' . $navigation . '</header><!-- /wp:group -->';
$footer = static fn(string $class): string => '<!-- wp:group {"className":"' . $class . '","tagName":"footer"} --><footer class="wp-block-group ' . $class . '"><!-- wp:paragraph --><p>Four Fires Ministries</p><!-- /wp:paragraph --></footer><!-- /wp:group -->';
$main = static fn(string $title): string => '<!-- wp:group {"tagName":"main"} --><main class="wp-block-group"><!-- wp:heading --><h2 class="wp-block-heading">' . $title . '</h2><!-- /wp:heading --></main><!-- /wp:group -->';
$document = static fn(string $class, string $suffix, string $title): string => '<!-- wp:group {"className":"' . $class . '"} --><div class="wp-block-group ' . $class . '">' . $header('site-header' . $suffix) . $main($title) . $footer('site-footer' . $suffix) . '</div><!-- /wp:group -->';
$capture = static fn(string $title, array $classes): string => implode('', array_map(static fn(string $class, int $i): string => $document($class, 0 === $i ? '' : ' compact', $title), $classes, array_keys($classes)));

foreach (array('desktop+mobile' => array(CaptureEvidence::DESKTOP_DOCUMENT_CLASS, CaptureEvidence::MOBILE_DOCUMENT_CLASS), 'desktop+mobile+tablet' => array(CaptureEvidence::DESKTOP_DOCUMENT_CLASS, CaptureEvidence::MOBILE_DOCUMENT_CLASS, $tablet)) as $label => $classes) {
    $result = (new ArtifactCompiler())->compile(array('entrypoint' => 'index.html', 'files' => array(
        'index.html' => '<main><h1>Home</h1></main>',
        'about/index.html' => '<main><h1>About</h1></main>',
        'contact/index.html' => '<main><h1>Contact</h1></main>',
    )))->toArray();
    foreach ($result['source_reports']['compiled_site']['pages'] as &$page) $page['block_markup'] = $capture(ucfirst(basename(dirname('/' . $page['source_path'])) ?: 'Home'), $classes);
    unset($page);
    $plan = (new WordPressSitePlan())->fromResult($result);
    $areas = array_column($plan['template_parts'], 'area');
    $retained = array_values(array_filter(array_map(static fn(array $d): string => ($d['code'] ?? '') . ' ' . ($d['area'] ?? ''), $plan['diagnostics']), static fn(string $c): bool => str_contains($c, 'shell_retained')));
    $inline = count(array_filter($plan['pages'], static fn(array $p): bool => str_contains((string) $p['canonical_block_markup'], 'site-header')));
    echo str_pad($label, 24), 'parts=', json_encode($areas), ' pages-with-inline-header=', $inline, ' retained=', json_encode($retained), "\n";
    if (str_contains($label, 'tablet')) {
        $header = array_values(array_filter($plan['template_parts'], static fn(array $p): bool => 'header' === $p['area']))[0]['canonical_block_markup'] ?? '';
        echo '  tablet document in shared header part: ', var_export(str_contains($header, $tablet), true), "\n";
    }
}
Expected

Any capture device document class (data-blocks-engine-capture-<profile>-document, profile per the DEVICE_DOCUMENT grammar) is a responsive document variant for shell extraction, the same as desktop and mobile. With three documents the routes bind one shared header part and one shared footer part that render all three variants, and no page keeps an inline copy, matching the two-document result.

Acceptance
  • A contract test (three routes × desktop/mobile/tablet documents) fails on trunk and passes on the fix: shared header and footer parts exist, each holds the tablet variant, no page retains site-header/site-footer, and no shell_retained_* diagnostic is emitted.
  • The existing two-document contracts (capture-variant-plain-page-shell.php, unlabeled-capture-device-shell.php, viewport-hidden-document-variants.php) still pass.
  • Recognition derives from the capture contract (one helper on CaptureEvidence for "is a device document class") rather than adding a third hardcoded constant.

AI disclosure: filed by Franklin (Claude Opus via Pi/Roadie). Root cause found by probing the 4fires import's materialized pages with ShellExtraction on trunk; the reduced repro was run on trunk.

Lingua principale
PHP
Stelle
25
Fork
3
Merge medio
3h 25m
PR unite (30g)
935

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di Automattic/blocks-engine

Tutte le issue di Automattic/blocks-engine

Issue simili

Altre issue su PHP

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.