Skip to content

feat(renderer-blade): compile WP block-supports into wrapper attributes - #457

Merged
ViewFromTheBox merged 5 commits into
release/1.0from
feature/keystone-50-block-supports
May 16, 2026
Merged

ViewFromTheBox merged 5 commits into
release/1.0from
feature/keystone-50-block-supports

Conversation

@ViewFromTheBox

@ViewFromTheBox ViewFromTheBox commented May 16, 2026 •

Copy link
Copy Markdown
Member

Closes Keystone #50.

The problem

Edit a block's background color (or alignment, padding, font size, border radius, etc.) in the editor → save → reload the public front-end → change is invisible. The block-attribute compilation that WP core's apply_block_supports() does server-side wasn't ported into renderer-blade. Block partials only emitted tagName / layout.type / className; every other persisted attribute was dropped on the floor.

What this MR does

  • New BlockSupports helper (packages/visual-editor-renderer-blade/src/Support/BlockSupports.php) compiles a block's attributes into the canonical wrapper-attribute triple (classes[], style, id) matching WP core's serializers.
  • Covers every block-support category WP core emits: align, textAlign, color (palette + custom + gradient), spacing (padding/margin/blockGap), border (radius/color/style/width root + per-side), typography (palette + custom for fontSize/fontFamily/fontWeight/fontStyle/lineHeight/letterSpacing/textTransform/textDecoration), className, anchor. Also expands var:preset|... shorthand into real var(--wp--preset--…) references.
  • A thin wrapperAttrs() helper returns the ready-to-splice attribute string each Blade partial needs: <{{ $tag }}{!! BlockSupports::wrapperAttrs($attributes, ['wp-block-group']) !!}>.
  • All 43 core/* and artisanpack/* partials updated to delegate to BlockSupports instead of hand-rolling className / align subsets. Block-specific quirks (e.g. core/spacer's height, core/cover's minHeight, core/button's wrapper-vs-link supports split) stay in the partial and merge with the compiled output.

core/button note

The visual block-supports (color, border, spacing, typography) now land on the inner <a> / <span> so theme.json's styles.elements.button targeting .wp-element-button actually picks up the slug-based class set. The outer wrapper carries only align / className / anchor. Mirrors WP core.

Tests

  • 39 new unit tests on BlockSupports::compile and wrapperAttrs covering each block-supports category, palette-vs-custom priority, preset-reference expansion, slug normalization, anchor sanitization, and the legacy style: "default" defensive case for core/separator.
  • 7 new integration tests on BlockRenderer proving the rendered HTML output now carries the canonical class / style / id markers.
  • All 555 existing renderer-blade tests continue to pass. All 1037 JS tests still pass.

Test plan

  • vendor/bin/pest --compact — 555/555 PHP green locally.
  • npx vitest run — 1037/1037 JS green locally.
  • Manual: change a block's background color in the editor on jmwd-default, save, verify the front-end renders the new color.
  • Manual: change a block's alignment to Wide / Full, save, verify the front-end constrains / expands the block correctly.
  • Manual: regression sweep on the seeded home page — buttons, headings, lists, quotes, columns, footer all still render correctly.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Centralized block support: a shared renderer now emits consistent wrapper attributes (classes, styles, id) for blocks.
  • Improvements

    • Numerous core blocks now produce cleaner, deduplicated class and inline-style output and more consistent wrapper markup.
    • Layout-size tokens now generate root CSS variables and alignment rules for wide/full layouts.
  • Tests

    • Expanded unit and feature tests for block-support compilation, wrapper attributes, and layout token output.

Review Change Stack

Closes Keystone #50.

The front-end renderer's block partials only emitted `tagName`,
`layout.type`, and `className` on each wrapper element. Block-support
attributes — `align`, `backgroundColor`, `textColor`, `style.color.*`,
`style.spacing.*`, `style.border.*`, `style.typography.*`, `fontSize`,
`fontFamily`, `borderColor`, `anchor`, etc. — got persisted by the
editor but never reached the rendered HTML. The result was a closed
authoring loop: change a block's background in the editor → save →
front-end shows the un-customized version because no class / inline
style carried the change.

This commit ports WordPress core's server-side `apply_block_supports()`
behavior into a reusable `BlockSupports` helper, then updates every
block partial to use it.

## `BlockSupports::compile`

Walks the attribute tree and returns `['classes' => string[], 'style'
=> string, 'id' => ?string]`. Coverage parity with WP core's
block-supports modules:

- `align` → `align{wide|full|left|center|right}` class. The left /
  center / right values also emit `has-text-align-{value}` so text
  blocks (paragraph, heading) and container blocks share the same
  attribute path.
- `textAlign` → `has-text-align-{left|center|right|justify}` class
  (not inline `text-align: …` — matches WP).
- `color`: palette slugs (`backgroundColor`, `textColor`, `gradient`)
  → `has-{slug}-*` classes plus the `has-background` /
  `has-text-color` markers. Custom values under `style.color.*`
  → inline declarations + the same marker classes. Slug wins over
  custom when both are set (mirrors WP serialization priority).
- `spacing`: `style.spacing.padding` / `style.spacing.margin` as a
  single string (all sides) or per-side object; `blockGap` as
  `--wp--style--block-gap` custom property or per-axis row-gap /
  column-gap.
- `border`: radius (string or per-corner object), per-side / root
  color, style, width. Auto-adds `border-style: solid` when width or
  per-side value is set without an explicit style — same fallback WP
  serializes.
- `typography`: palette slugs (`fontSize` → `has-{slug}-font-size`
  + `has-defined-font-size`, `fontFamily` →
  `has-{slug}-font-family`); custom values for `fontSize`,
  `fontFamily`, `fontWeight`, `fontStyle`, `lineHeight`,
  `letterSpacing`, `textTransform`, `textDecoration`.
- `className` → user-supplied class string appended verbatim
  (whitespace-tokenized; deduped at the end).
- `anchor` → sanitized `id` attribute.
- `var:preset|{taxonomy}|{slug}` references in `style.*` strings
  expand to `var(--wp--preset--{kebab-path})`.

A `wrapperAttrs(attributes, baseClasses)` helper returns the
ready-to-splice attribute string each partial uses:

    <{{ $tag }}{!! BlockSupports::wrapperAttrs( $attributes, [ 'wp-block-group' ] ) !!}>

## Partials updated

Every core/* and artisanpack/* partial now delegates wrapper-attribute
compilation to `BlockSupports`. Block-specific quirks (e.g.
`core/list`'s `start` / `reversed` attributes, `core/spacer`'s
`height`, `core/cover`'s `minHeight`, `core/button`'s wrapper-vs-link
split) stay in the partial and merge with the compiled output where
needed.

`core/button` specifically: the visual block-supports (color, border,
spacing, typography) land on the inner `<a>` / `<span>` so that
`theme.json`'s `styles.elements.button` targeting `.wp-element-button`
actually picks up the slug-based class set. The outer wrapper carries
only `align` / `className` / `anchor`. Mirrors WP core.

## Tests

- 39 new unit tests on `BlockSupports::compile` and `wrapperAttrs`
  covering each block-supports category, palette-vs-custom priority,
  preset-reference expansion, slug normalization, anchor
  sanitization, and the legacy `style: "default"` (core/separator)
  defensive case.
- 7 new integration tests on `BlockRenderer` proving the rendered
  HTML output now carries the canonical class / style / id markers
  for custom backgrounds, palette slugs, alignment, padding,
  typography, anchor, and the `core/button` wrapper-vs-link split.
- All 555 existing renderer-blade PHP tests continue to pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 16, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 38ebe0b4-d25e-4361-8401-9dad0de05ccb

📥 Commits

Reviewing files that changed from the base of the PR and between 848c9af and e5f395e.

📒 Files selected for processing (2)
  • packages/visual-editor-renderer-blade/src/Support/BlockSupports.php
  • packages/visual-editor-renderer-blade/tests/Unit/BlockSupportsTest.php
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/visual-editor-renderer-blade/tests/Unit/BlockSupportsTest.php
  • packages/visual-editor-renderer-blade/src/Support/BlockSupports.php

📝 Walkthrough

Walkthrough

Adds BlockSupports (compile + wrapperAttrs), migrates Blade block templates to use it for wrapper attributes or compiled styles/ids, extends ThemeJsonTokensCompiler to emit layout custom properties and alignment rules, and adds tests covering compile/wrapperAttrs and renderer output.

Changes

Block Supports Compiler & Template Refactoring

Layer / File(s) Summary
BlockSupports compiler implementation
packages/visual-editor-renderer-blade/src/Support/BlockSupports.php, packages/visual-editor-renderer-blade/tests/Unit/BlockSupportsTest.php
New BlockSupports class implements compilation for align, textAlign, colors, spacing, border, typography, className, anchor, and preset expansion. Exposes compile(array): array and wrapperAttrs(array, array): string.
Simple wrapperAttrs template migrations
packages/visual-editor-renderer-blade/resources/views/blocks/core/{audio,code,details,embed,file,gallery,group,heading,image,list-item,list,navigation-link,navigation-submenu,navigation,paragraph,post-author,post-content,post-date,post-excerpt,post-featured-image,post-title,preformatted,pullquote,quote,row,search,site-logo,site-tagline,site-title,stack,table,verse,video}.blade.php, packages/visual-editor-renderer-blade/resources/views/blocks/artisanpack/callout.blade.php
Many Blade templates updated to import BlockSupports, compute minimal baseClasses where needed, and render wrapper attributes via BlockSupports::wrapperAttrs() instead of manual class/style concatenation.
Complex compile() + wrapperAttrs migrations
packages/visual-editor-renderer-blade/resources/views/blocks/core/{column,cover,media-text,spacer}.blade.php
Templates that merge block-specific inline styles (flex-basis, min-height, grid-template-columns, height) now call BlockSupports::compile($attributes) to obtain classes/style/id and combine those outputs with block-local styles/ids before emitting wrapper attributes.
Special-case migrations
packages/visual-editor-renderer-blade/resources/views/blocks/core/{block,button,separator,template-part,buttons}.blade.php
Templates with special wrapper needs updated: button routes color supports to inner link element, block retains data-ve-pattern-ref while using wrapperAttrs, separator normalizes legacy style strings into modern class markers, template-part combines data-ve-* attributes with compiled wrapper attributes, and buttons whitelists justifyContent.
Theme JSON layout tokens
packages/visual-editor-renderer-blade/src/Services/ThemeJsonTokensCompiler.php
Compiler now emits --wp--style--global--content-size / --wp--style--global--wide-size custom properties and generates .alignwide/.alignfull rules conditionally from settings.layout.
Integration & unit tests
packages/visual-editor-renderer-blade/tests/Unit/BlockRendererTest.php, packages/visual-editor-renderer-blade/tests/Unit/BlockSupportsTest.php, packages/visual-editor-renderer-blade/tests/Unit/ThemeJsonTokensCompilerTest.php, packages/visual-editor-renderer-blade/tests/Feature/BlocksStylesComponentTest.php
New and updated tests assert BlockSupports outputs (classes/style/id), rendered HTML contains expected block-support markers/styles, and ThemeJsonTokensCompiler layout rules are generated and ordered correctly.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through blades with tidy paws,
I gathered classes, styles, and laws,
A compiler stitched each wrapper's thread,
Templates cleaner, tests well-fed,
I left a tiny carrot-shaped CSS clause.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main change: adding a BlockSupports feature that compiles WordPress block-supports into wrapper attributes for Blade templates.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/keystone-50-block-supports

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/visual-editor-renderer-blade/resources/views/blocks/core/buttons.blade.php`:
- Around line 4-10: $justify is taken directly from
$attributes['layout']['justifyContent'] and interpolated into the class token
(used in $baseClasses), so validate and normalise it first: trim and cast to
string, then check against an allowlist of permitted tokens (e.g.,
'left','center','right','space-between','space-around','space-evenly' or your
theme's allowed values) and only use the value if it exists in that allowlist;
otherwise fall back to the safe default ('left' or the existing fallback).
Update the logic that sets $justify and the $baseClasses entry to use the
validated token instead of the raw input.

In `@packages/visual-editor-renderer-blade/src/Support/BlockSupports.php`:
- Around line 451-489: The code currently adds inline typography styles from
style.typography even when slug-based attributes exist, so update the loop in
BlockSupports (where $mappings is iterated) to skip generating inline styles for
'fontSize' and 'fontFamily' when the corresponding slug variables
($fontSizeSlug, $fontFamilySlug) are non-empty; i.e., before computing $value
for an $attrKey, if $attrKey is 'fontSize' and $fontSizeSlug !== '' (or if
$attrKey is 'fontFamily' and $fontFamilySlug !== ''), continue the loop so the
slug-based class (created with self::slugify and stringAttr) wins over the
custom inline style produced via self::expandPresetReference.

In `@packages/visual-editor-renderer-blade/tests/Unit/BlockRendererTest.php`:
- Around line 583-597: The test verifies the inner <a> has the color class but
doesn't assert the outer wrapper lacks it; update the test in BlockRendererTest
(the it(...) block using makeBlock, $tree and makeRenderer()->render) to add a
negative assertion that the wrapper div with class "wp-block-button" does NOT
contain "has-accent-background-color" (use the same expect($html) pattern style,
e.g. expect($html)->not->toMatch with a regex targeting the outer div wrapper),
so the contract "color on the inner link, not the outer wrapper" is enforced.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 43d1f5cf-b45c-4471-87f1-6981b6e67dda

📥 Commits

Reviewing files that changed from the base of the PR and between 7b611c8 and ef22aad.

📒 Files selected for processing (47)
  • packages/visual-editor-renderer-blade/resources/views/blocks/artisanpack/callout.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/audio.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/block.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/button.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/buttons.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/code.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/column.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/columns.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/cover.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/details.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/embed.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/file.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/gallery.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/group.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/heading.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/image.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/list-item.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/list.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/media-text.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/navigation-link.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/navigation-submenu.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/navigation.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/paragraph.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/post-author.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/post-content.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/post-date.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/post-excerpt.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/post-featured-image.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/post-title.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/preformatted.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/pullquote.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/quote.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/row.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/search.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/separator.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/site-logo.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/site-tagline.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/site-title.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/spacer.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/stack.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/table.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/template-part.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/verse.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/video.blade.php
  • packages/visual-editor-renderer-blade/src/Support/BlockSupports.php
  • packages/visual-editor-renderer-blade/tests/Unit/BlockRendererTest.php
  • packages/visual-editor-renderer-blade/tests/Unit/BlockSupportsTest.php

Comment thread packages/visual-editor-renderer-blade/src/Support/BlockSupports.php
@ViewFromTheBox ViewFromTheBox moved this from Backlog to In Review in ArtisanPack UI Overview May 16, 2026
ViewFromTheBox and others added 2 commits May 16, 2026 16:28
…ffect at the page root

The block partials emit `alignwide` / `alignfull` classes on each
block now (per the parent commit), but no CSS rule converts those
classes into actual widths when the block sits at the page root.
WordPress-FSE wraps post content in `.wp-block-post-content` so
that `.is-layout-constrained > .alignwide` matches; our renderer
output lands directly inside the consumer's `<main>` / template
wrapper with no such parent marker, so the alignment classes
ride on the section but no CSS sizes it.

`ThemeJsonTokensCompiler` now emits two additional pieces alongside
the `--wp--preset--*` palette tokens it already produces:

- `--wp--style--global--content-size` and
  `--wp--style--global--wide-size` custom properties pulled from
  `theme.json` `settings.layout`. Matches WP's own variable names.

- Layout rules targeting `.wp-block-group.is-layout-constrained.alignwide`
  → `max-width: var(--wp--style--global--wide-size); margin: auto`
  and `.wp-block-group.is-layout-constrained.alignfull`
  → `max-width: none`. The rules target the constrained group's own
  classes, not a parent-relative selector, so they apply whether the
  group sits at the page root or inside another container — which is
  what the user's symptom needed.

The default case (constrained group without an alignment override)
is left alone so themes that already style children-of-constrained
directly aren't double-constrained.

`alignfull` is emitted whenever ANY layout key is configured, since
full-bleed is the same regardless of `wideSize` and authors can
toggle it on without the renderer caring whether the theme happened
to declare `wideSize`.

Updated the BlocksStylesComponent "no recognized tokens" test to
use `settings.border` instead of `settings.layout`, since layout is
now a recognized category.

Tests: 5 new unit tests on `ThemeJsonTokensCompiler` covering the
custom properties, the alignwide rule, the alignfull rule, the
no-layout-omission case, and the root-presets-plus-layout-rules
composition. 560/560 PHP green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ment respects content-size

Continuing on Keystone #50. The prior commit made `alignwide` /
`alignfull` work on constrained groups at the page root, but a
section with `align="none"` (the default) still stretched full-
width — there was no rule giving "unaligned at root" a content-
size constraint. In WP-FSE this is handled by wrapping page
content in `<main class="wp-block-post-content is-layout-constrained">`
so that `.is-layout-constrained > :not(.alignwide):not(.alignfull)`
matches the default case.

Mirror that in the renderer: `ThemeJsonTokensCompiler` now emits
three additional rules scoped to a `.wp-block-post-content.is-layout-constrained`
container:

- `> :where(:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright))`
  → `max-width: var(--wp--style--global--content-size); margin: auto`
- `> .alignwide` → `max-width: var(--wp--style--global--wide-size); margin: auto`
- `> .alignfull` → `max-width: none`

The container class is opt-in. Themes add `class="wp-block-post-content
is-layout-constrained"` to whichever wrapper element holds their page
content (typically `<main>`) and the children get the canonical
alignment behavior. Themes that don't add it keep the old "container
is full-bleed unless aligned" behavior — the opt-in avoids clashing
with header / footer wrappers that are intentionally full-width.

The block-level rules (rule set A — `.wp-block-group.is-layout-constrained.alignwide`
etc.) continue to ship alongside the post-content rules (rule set B)
so authors can pick whichever pattern fits their template.

Tests: 1 new unit test pinning the three post-content child rules.
561/561 PHP green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/visual-editor-renderer-blade/tests/Unit/ThemeJsonTokensCompilerTest.php (1)

160-163: ⚡ Quick win

Strengthen child-rule assertions to verify behavior, not just selector presence.

This test can still pass if selectors exist but declarations regress. Assert key declarations (max-width/margin) for the .wp-block-post-content child rules too.

Suggested test hardening
 		expect( $css )
 			->toContain( '.wp-block-post-content.is-layout-constrained > :where(:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright))' )
 			->toContain( '.wp-block-post-content.is-layout-constrained > .alignwide' )
-			->toContain( '.wp-block-post-content.is-layout-constrained > .alignfull' );
+			->toContain( '.wp-block-post-content.is-layout-constrained > .alignfull' )
+			->toContain( 'max-width: var(--wp--style--global--content-size);' )
+			->toContain( 'max-width: var(--wp--style--global--wide-size);' )
+			->toContain( 'max-width: none;' )
+			->toContain( 'margin-left: auto;' )
+			->toContain( 'margin-right: auto;' );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/visual-editor-renderer-blade/tests/Unit/ThemeJsonTokensCompilerTest.php`
around lines 160 - 163, The current assertions only check selector presence in
ThemeJsonTokensCompilerTest (variable $css) but not the declarations; update the
test to assert that the child-rule selectors for
'.wp-block-post-content.is-layout-constrained >
:where(:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright))',
'.wp-block-post-content.is-layout-constrained > .alignwide' and
'.wp-block-post-content.is-layout-constrained > .alignfull' include the expected
declarations (e.g. contain 'max-width' and the appropriate 'margin' rules) by
adding assertions against $css that look for those declaration strings alongside
the selector checks so the test verifies behavior, not just selector presence.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@packages/visual-editor-renderer-blade/tests/Unit/ThemeJsonTokensCompilerTest.php`:
- Around line 160-163: The current assertions only check selector presence in
ThemeJsonTokensCompilerTest (variable $css) but not the declarations; update the
test to assert that the child-rule selectors for
'.wp-block-post-content.is-layout-constrained >
:where(:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright))',
'.wp-block-post-content.is-layout-constrained > .alignwide' and
'.wp-block-post-content.is-layout-constrained > .alignfull' include the expected
declarations (e.g. contain 'max-width' and the appropriate 'margin' rules) by
adding assertions against $css that look for those declaration strings alongside
the selector checks so the test verifies behavior, not just selector presence.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2f21a762-4528-4a1c-805d-4a537c4cc53e

📥 Commits

Reviewing files that changed from the base of the PR and between 2469fa9 and f262d6e.

📒 Files selected for processing (2)
  • packages/visual-editor-renderer-blade/src/Services/ThemeJsonTokensCompiler.php
  • packages/visual-editor-renderer-blade/tests/Unit/ThemeJsonTokensCompilerTest.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/visual-editor-renderer-blade/src/Services/ThemeJsonTokensCompiler.php

@ViewFromTheBox
ViewFromTheBox marked this pull request as ready for review May 16, 2026 21:41
Three findings:

- `core/buttons` partial — `layout.justifyContent` was concatenated
  into a class token without validation. Whitelist against WP's
  enum (`left`, `center`, `right`, `space-between`, `space-around`,
  `space-evenly`, `stretch`); anything outside falls back to `left`
  (WP's own default). Closes the path that let an authored block
  smuggle arbitrary class tokens through the stored attribute.
- `BlockSupports::applyTypography` — slug-over-custom precedence
  for `fontSize` / `fontFamily`. The class path already emitted
  `has-{slug}-font-size` from the slug attribute; the loop was
  still emitting the inline `font-size: …` declaration from
  `style.typography.fontSize` when both were set. Inline style
  would win the cascade and override the slug class, contradicting
  the documented priority that mirrors the color path's behavior.
  Skip the inline declaration when the slug is present.
- `core/button` renderer test — added the missing negative
  assertion that the outer `<div class="wp-block-button">`
  wrapper does NOT carry the color class. The test title
  ("color on the inner link, NOT the outer wrapper") now pins
  both sides of the contract.
- New buttons-justification whitelist regression test pins the
  fallback behavior + the legitimate value path-through.

Tests: 563/563 PHP green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/visual-editor-renderer-blade/src/Support/BlockSupports.php`:
- Around line 403-433: The current fallback unconditionally adds a global
'border-style: solid' when any side or root reports width/style, which causes
side-only widths to render full boxes; modify the logic in BlockSupports.php to
emit side-specific fallbacks instead: while iterating the sides in the loop that
sets $hasSideWidthOrStyle, track which specific sides have a width but no
explicit style (e.g. push side names into a $sidesNeedingStyle array when you
see a width and no style for that side), preserve existing behavior for root
declarations using $hasRootWidthOrStyle, and then change the final fallback
block so that if $hasRootWidthOrStyle is true you keep the existing global
fallback using self::styleListContains('border-style:'), but if only
side-specific sides require a fallback, append 'border-{side}-style: solid' for
each side in $sidesNeedingStyle (rather than adding a global 'border-style:
solid').
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 921d18cf-a899-4110-8142-780e021c8baf

📥 Commits

Reviewing files that changed from the base of the PR and between f262d6e and 848c9af.

📒 Files selected for processing (4)
  • packages/visual-editor-renderer-blade/resources/views/blocks/core/buttons.blade.php
  • packages/visual-editor-renderer-blade/src/Support/BlockSupports.php
  • packages/visual-editor-renderer-blade/tests/Unit/BlockRendererTest.php
  • packages/visual-editor-renderer-blade/tests/Unit/BlockSupportsTest.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/visual-editor-renderer-blade/tests/Unit/BlockSupportsTest.php

Comment thread packages/visual-editor-renderer-blade/src/Support/BlockSupports.php Outdated
The border fallback in `BlockSupports::applyBorder` unconditionally
appended a root `border-style: solid` whenever ANY side or root
reported a width or style. That turned on the untouched edges with
browser-default widths: a top-only border declared as
`style.border.top.width: 2px` rendered as a full box instead of a
single top line.

Fix is per-side: while iterating sides, track which specific sides
have a width without an explicit style; afterward emit
`border-{side}-style: solid` only for those sides. The root-level
fallback still fires when the ROOT declaration set width or style,
since whole-box semantics are correct in that case.

Tests:
- Reworked the existing per-side test to assert the per-side fallback
  AND the absence of the global one.
- Added a multi-side regression so two sides each get their own
  fallback and the untouched two stay untouched.
- Added an explicit-per-side-style case proving the fallback skips
  when the user supplied a style.

All 565 PHP tests green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

1 participant