Repository navigation
fix(php-transformer): preserve associated label hosts and their static attributes - #2637
Merged
Merged
Conversation
(cherry picked from commit 39ce819ecfd2e52aa7b357f810d1e674fd8ce98e)
(cherry picked from commit fcd49a281481704545bf3eb36eed052b77c3c968)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Preserves explicitly associated external
<label for>hosts as editable native label blocks instead of lowering them tocore/paragraph, and keeps their passive static attributes so authored selectors still match their real subject.AuthoredLabelBlockGenerator(consumer-namespaced companion block) owns external labels with a nonemptyforand no nested controls. Static save keeps the<label>host,for,id, classes and inline declarations with no extra wrapper; the editor is standardRichText+useBlockProps.sourceAttributesmap for passive metadata (data-*/aria-*in the canonical name pattern,lang,dir,hidden,role,title,tabindex).Support/SourceAttributecentralizes the selector-identity names and declared-event vocabulary shared byDocumentRootAttributes,SourceDom::eventMetadata, PHP label projection and the generated editor/save filter. Event handlers,data-wp-*directives, URL/executable attributes and attempts to override owned fields are rejected in both PHP and the registered JS save filter.SourceAttributeSubjectsproves when data predicates resolve to a retained label/document-root host, so the author-selector preparer keeps the original predicates instead of minting captured-stateblocks-engine-attribute-*markers.FormControlClassifier::isExternalAssociatedLabel. Unassociated prose labels keep their paragraph role; wrapping labels and form-owned controls keep their existing contracts.Fixes #1617.
Root cause
ReadableFormControlBlockConverteremitted external labels as an escapedcore/paragraph, so neither the<label>host nor itsforassociation survived. Type, adjacent-sibling, checked-state and pseudo-element selectors lost their subject. Core can't host this natively:core/paragraphalways saves<p>, andcore/groupaccepts a label tag but dropsfor/htmlForfrom its attribute schema. A follow-up review also found that the first label host saved only for/id/classes/style, solabel[data-role=caption]{…}lost its subject whendata-rolewas discarded.Before / after
input + label association and adjacency survive compilation). The first label host failsreviewer reproduction preserves the actual data-role subject.data-rolemutation, expanded/negated predicates, native label click, body context mutation, opposite-order click), Gutenberg-saved markup and the real WordPress document canvas exactly match the source. The comparison covers attribute names/values, association, checked state, label/input boxes, painted text-range boxes, font metrics, paint, pseudo-elementattr()content and outline. At rest the label is red 20px/24px at 390, red 22px/28px at 768 and green 24px/30px at 1440. Clicking each label toggles its intended native checkbox.tests/unit/associated-label.php(24 assertions),tests/unit/associated-label-static-attributes.php(41 assertions), andpackages/blocks-engine/src/wp/__tests__/associated-label-save-validity.test.ts(Core capability gap, registered companion parse/save/reopen validity, hostile save maps, browser/native parity).UBC evidence
This came from the fresh UBC residual-owner audit, where form/filter labels lost their source subject and checked-state paint. The fixtures reproduce that source structure in a neutral form. Full 21-route UBC acceptance is not claimed by this PR.
Verification (rebased on current
trunk)composer validate --strict: passcomposer test(PHP 8.3, 2G): passcomposer test:packaging: passtools/visual-paritynpm test: passtypecheck, focused label test,test:bundle,test:svg-decode) passed on the candidate before the rebase. CI re-runs it here.AI disclosure
AI-assisted under Chris Huber's direction. OpenAI GPT-6.1-sol, working through OpenCode, did the diagnosis, implementation and verification of both commits. Anthropic Claude (Opus), also through OpenCode, rebased onto current trunk, re-verified, and wrote this PR. Chris Huber directed the work and authorized landing.