Shell identity: per-render ids and current-item inline style inside navigation labels split the header cluster

Open
#4,395 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@chubes4 is already working on this.

Since Nov 5, 2026.

  • #4432 by @chubes4 — open

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
56/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
php, wordpress
Domain
backend

Research direction

Start by reading withoutCurrentNavigationState(), identityMarkup(), and the existing route-state machinery; the issue says these handle current-state classes and some anchors but miss styles and ids inside serialized navigation labels. Reproduce the two-route case and inspect how header identity and route-specific presentation are handled. Done when the contract test clusters one header, preserves the active underline on its route, and keeps headers with different link labels or URLs separate.

Written by the indexing model from the issue text.

Description

Problem

On a 100-route Web.com SiteBuilder capture (desktop + mobile documents), the shared header is never extracted. Every route's header candidate has a different identity: 99 unique identities for 99 candidates. The plan reports wordpress_site_plan_shell_retained_ambiguous (header) and retained_incomplete (footer).

This follows #4362 / #4373. That work clusters device documents correctly, and it fixes the small fixture and a 2-route slice of the same site.

Evidence

Measured on trunk + #4373 by dumping identity_markup from unlabeledChromeCandidates for four routes. The candidates are the right header-section groups, each about 118 KB.

Comparison Raw identity After removing per-render ids After also removing current-item inline state
blog A vs blog B differ equal equal
home vs services differ differ differ only in the remaining state below

All the remaining differences are per-route values. They sit inside the serialized label HTML of core/navigation-link blocks, or in block anchors:

  1. Per-render element ids: id="id1793815509054" / data-element-id="…" on one route vs id1793815621060 on another. The 13-digit timestamp-like ids are regenerated on every render. They appear in navigation-link label markup and in social-links anchor attributes.
  2. Current-item presentation as inline style: on the active route's item, a nested span carries border-width:0px 0px 4px (the active underline) and border-radius:0px, and another carries a raised z-index (12 vs 9, 14 vs 6). The same item on other routes lacks them.
  3. Capture document class order: the device document's class list is in a different order (… full-screen-view pc-desktop-mode header-exists … vs … header-exists footer-exists pc-desktop-mode).

withoutCurrentNavigationState() / identityMarkup() already normalize current-state classes and some anchors. They do not reach inline styles or ids inside the serialized label attribute, and they don't sort the document-scope class list.

Minimal reproduction

Two routes whose header nav item label wraps nested spans:

  • Each span has a render-generated id / data-element-id that differs per route.
  • The current route's item has style="border-width:0px 0px 4px" on an inner span and a higher z-index on its wrapper.
  • Otherwise the headers are identical.

Expected: one header part. Actual: retained as page content.

Expected

  • Shell identity treats route-state and render-noise inside navigation labels as non-identity:
    • Per-render ids are normalized wherever they occur, including inside navigation-link label HTML.
    • Presentation that only the current route's item carries (it differs between routes exactly where the current item moves) is excluded from identity, the same way current-state classes already are.
  • The extracted part keeps the source's current-item presentation per route through the existing route-state mechanism, so the active underline still shows on the right page.
  • Capture document-scope class lists compare as sets.
  • Reuse withoutCurrentNavigationState / identityMarkup and the existing route-state machinery rather than adding a parallel normalizer.

Acceptance

  • A contract test with the two-route reproduction above: one header part, and each route's page content has no header.
  • In the rendered route, the active item keeps its underline on its own route only.
  • A route whose header differs in real content (a different link label or URL) is still not clustered.
Dominant language
PHP
Stars
25
Forks
3
Avg merge
5h 32m
Merged PRs (30d)
949

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Automattic/blocks-engine

All issues in Automattic/blocks-engine

Similar issues

More PHP issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.