Style fidelity: translate source CSS button styling onto native core/button attributes#241
Merged
Merged
Conversation
Imported CTA buttons converted to core/button but carried zero native style attributes (backgroundColor/textColor/style.color/style.border were all empty); the resolved source CSS was only carried as a non-canonical inline style string, so WordPress rendered the buttons with default grey styling after block recovery. This reuses the transformer's existing CSS-rule resolution (mergedPresentationStyle -> matchesCssSelector over <style>/linked CSS) and translates the resolved declarations into native WP block attributes: - Filled buttons get style.color.background + style.color.text and, when declared, style.border.radius/width/style/color, spacing.padding, and typography (-> has-background/has-text-color classes + inline style). - Outline/ghost buttons (transparent background, is-style-outline) get style.border.* + style.color.text and never a background, so they render as a colored outline rather than a bare default outline. - Buttons with no resolvable color/border CSS stay default (no fabricated colors). New ButtonStyleResolver does the generic, theme-independent declaration -> attribute translation; BlockFactory serializes the native style object into canonical has-* classes and inline style. Existing button parity fixtures updated to the native output; added filled/outline/unstyled fixtures. Closes #233 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
chubes4
added a commit
that referenced
this pull request
Jun 28, 2026
Core blocks were emitted with a raw inline `style` STRING attribute
(e.g. wp:paragraph {"style":"color:..."}, wp:group {"style":"padding:..."}).
Core blocks expect a structured `style` OBJECT + `layout`, so the stored HTML
diverged from each block's save() and the editor flagged "unexpected or invalid
content" for nearly every styled element.
Generalize the ButtonStyleResolver approach (#241) to ALL blocks:
- New Style/StyleAttributeMapper translates resolved CSS declarations into the
canonical block style OBJECT (style.typography/color/spacing/border) and
serializes it back to the inline CSS + has-* support classes WordPress emits
in save(), keeping stored markup in sync with the block.
- presentationAttributes() now returns a canonical `style` object (never a
string) plus the `layout` attribute; display:flex|grid folds into `layout`.
- BlockFactory serializes the style object for every block (group, heading,
paragraph, list, quote, columns, icon, ...) via the shared mapper.
- HARD RULE: a raw `style` string is never emitted on a core block. Unmappable
declarations (position, overflow, transform, background images, aspect-ratio,
nav anchor/submenu CSS, ...) are dropped and ride on the preserved className.
- Buttons keep resolving from the raw merged CSS via a threaded resolvedStyle
callback (ButtonStyleResolver unchanged).
- Hidden-state safety (#259): display:none / visibility:hidden / opacity:0 base
states are not frozen onto content-bearing/interactive elements; they are
normalized away and surfaced as a frozen_hidden_state diagnostic finding.
Genuinely decorative / aria-hidden nodes may stay hidden.
Tests:
- New "canonical block style attributes" contract: guard asserting no emitted
core block carries a raw string `style`; positive cases (styled h2/p/div ->
canonical typography/color + layout flex); negative case (unmappable props ->
className, not a raw style string); hidden-nav normalization.
- 15 parity fixtures updated: only the style-attribute SHAPE changed
(raw string -> canonical object / layout / dropped-to-className); content and
structure are unchanged. Full suite green.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.
Closes #233
Problem
Imported CTA buttons convert to
core/buttonand keep their source class, but carry zero native style attributes (backgroundColor/textColor/style.color/style.borderall empty). The resolved source CSS was only carried as a non-canonical inlinestylestring, which WordPress drops on block recovery, so buttons render with the theme default grey styling:is-style-outline) rendered as a bare default outline with no border/text color (the h44 case from the issue comment).Fix (generic, theme-independent)
Reuses the transformer's existing CSS-rule resolution —
mergedPresentationStylealready merges the matched<style>/linked-CSS rules for a button viamatchesCssSelector— and translates those resolved declarations into native WordPresscore/buttonattributes. It keys only off the resolved declarations; no fixture-specific strings.style.color.background+style.color.text; when declared,style.border.radius/width/style/color,style.spacing.padding, andstyle.typography.*. Renders withhas-background/has-text-colorclasses + inline style.is-style-outline, transparent background):style.border.*+style.color.textand never a background, so they render as a colored outline (border + text color), not a bare default outline. Atransparent/nonebackground naturally resolves to no fill, which is what distinguishes outline from filled.This PR is slice 1 (buttons) of the broader style-fidelity workstream; non-button elements are untouched.
Changes
src/HtmlToBlocks/Patterns/ButtonStyleResolver.php— generic declaration -> native-attribute translation.ButtonsPattern.php— resolves the button's CSS into native attributes (preserves existing button conversion +is-style-outlinemapping).BlockFactory.php— serializes the nativestyleobject into canonicalhas-*classes and inline style for both<a>and<button>buttons.HtmlTransformer.php— guard structure-signal stringification against the now-objectstyleattribute.Tests
composer test:canonical— pass.composer parity— pass (128 fixtures, no pass/fail regression).composer test(canonical + parity + packaging) — pass.🤖 Generated with Claude Code