Refactor ACF Composer blocks — evolve blocks along 4 axes: rendering model, field composition, block variants $styles, InnerBlocks adoption; legacy block migration, ACF Composer v2 to v3, block phase classification, atomic vs container, block evolution report, get_block_wrapper_attributes, $styles, $innerBlocks, refactor without breaking existing content, block refactoring report
Scanned 9/11/2026
Install to Claude Code
npx -y skills add hekivo/superpowers-sage --skill block-refactoring --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Block Refactoring?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/hekivo-block-refactoring)More formats (shields.io, HTML) on the badges page.
---
name: superpowers-sage:block-refactoring
description: >
Refactor ACF Composer blocks — evolve blocks along 4 axes: rendering model,
field composition, block variants $styles, InnerBlocks adoption; legacy block
migration, ACF Composer v2 to v3, block phase classification, atomic vs container,
block evolution report, get_block_wrapper_attributes, $styles, $innerBlocks,
refactor without breaking existing content, block refactoring report
user-invocable: true
argument-hint: "<BlockClassName or block-slug>"
---
# Block Refactoring — Evolution of Existing Blocks
Analyze and improve an existing block after its first implementation. Four axes of
evolution: design drift detection, CSS coverage analysis, variation expansion, and
gap/migration detection.
**Announce at start:** "I'm using the block-refactoring skill to evolve the block."
## When to use
- Block shipped in a previous PR and design has evolved since
- CSS bundle includes rules/tokens that are no longer used
- New design tokens exist in `app.css`/`design-tokens.md` that the block could leverage
- Legacy block still uses v1 pattern (`.b-{slug}` class, dual selector, no custom element)
- You suspect implementation diverged from design reference during initial build
## When NOT to use
- **Creating a new block from scratch** → use `/block-scaffolding` instead
- **Project-wide convention audit** → use `/reviewing`
- **Non-block UI component** → Blade components are not ACF blocks
## Input
$ARGUMENTS
Resolve to `{ClassName}` and `{slug}`. If not provided, ask.
---
See [references/evolution-axes.md](references/evolution-axes.md) for the 4 evolution axes.
Refactoring NEVER rebuilds from scratch. For a full re-scaffold, delegate to `/block-scaffolding` as a fallback.
---
## Procedure
### Phase 0 — Resolve block identity and locate files
From the argument, identify:
- `{ClassName}` — e.g. `HeroSection`
- `{slug}` — e.g. `hero-section`
- 5 target files (one may be absent on legacy blocks):
- `app/Blocks/{ClassName}.php`
- `resources/views/blocks/{slug}.blade.php`
- `resources/css/blocks/{slug}.css`
- `resources/js/blocks/{slug}.js` (may not exist — legacy)
- `resources/css/editor.css` (check for `@import './blocks/{slug}.css'`)
Read all present files.
### Phase 0b — Shared component inventory
Glob `resources/views/components/*.blade.php` in the target project (if a path is known, otherwise skip this step).
Build a component inventory table:
| Component slug | File | Likely use |
|---|---|---|
| `section-header` | `section-header.blade.php` | `<x-eyebrow>` + `<h2>` pairing |
| `button` | `button.blade.php` | `<a>` or `<button>` with utility classes |
| `card` | `card.blade.php` | Repeated card structure |
Keep this table in context — G9 in Axis 4 will reference it to report concrete component names instead of generic suggestions.
If `resources/views/components/` does not exist or is empty, note "No shared components found" and proceed.
### Phase 1 — Classify current pattern version
Inspect the view file and the CSS file:
| Signal | Version |
|---|---|
| View has `<block-{slug}>` custom element | **v2** |
| View uses `$attributes->merge()` on a `<section class="b-{slug}">` | **v1** |
| CSS scoped to `block-{slug}` tag selector | **v2** |
| CSS scoped to `.b-{slug}` class selector | **v1** |
| CSS has dual selector `&.is-style-*, .is-style-* &` | **v1** |
| CSS has single selector `.is-style-* block-{slug}` | **v2** |
| JS file at `resources/js/blocks/{slug}.js` | **v2** |
Mark the block's current version (`v1` / `v2` / `mixed`) before proceeding.
---
### AXIS 1 — Design drift detection
**Prerequisites:** a design reference must be available. Check in order:
1. MCP design tool with the project's file open (Pencil / Paper / Figma / Stitch)
2. `docs/plans/*/assets/section-{slug}-ref.png` on disk
3. `docs/plans/*/assets/section-{slug}-spec.md` on disk
If none available, report `drift: NOT_VERIFIED` and skip to Axis 2.
**Execution:**
1. Dispatch `visual-verifier` agent with:
- `url`: current environment's URL for a page rendering the block
- `selector`: `block-{slug}` (v2) or `.b-{slug}` (v1)
- `ref`: the reference path found above
- `spec`: spec file path if available
2. Collect: MATCH | DRIFT | MISSING | FAIL_ARBITRARY_VALUES
3. If DRIFT: capture the exact divergences (typography size, color hex, spacing px) for
Phase 6 report
For detailed axis procedures (CSS coverage, variation expansion, gap checks G1–G8), see [`references/evolution-axes.md`](references/evolution-axes.md).
#### G9. Component reuse gap
Grep the view for co-occurring `<x-eyebrow` and `<h2` inline — these should use
`<x-section-header>` instead. Also grep for `<a` elements carrying button utility
classes (e.g. `btn-`, `rounded-`, `px-`, `py-`, `font-`) — these should be
`<x-button>`.
Each instance where a component from the Phase 0b inventory exists but is not used: flag as IMPROVEMENT, naming the component (e.g., "use `<x-section-header>` instead of inline `<x-eyebrow>` + `<h2>`").
#### G10. CSS custom property cascade not used
**Detection** — check the view for any of:
- `match($tone)` expressions returning Tailwind class strings
(e.g. `match($tone) { 'fg' => 'text-fg', 'dark' => 'text-depth-fg' }`)
- Props declared as `tone="fg"` / `tone="dark"` / `variant="*-dark"` encoding
color context in PHP and passing it to child components
- Hardcoded color utility classes (`text-depth-fg`, `text-identity`, `text-white`)
applied directly on semantic elements (`h2`, `p`, `span`) instead of via
inherited CSS variables
Colors must cascade from custom properties in the block's CSS; the view must not
encode color context via conditional logic or hardcoded utilities.
Each instance is CRITICAL.
**When detected, generate corrected CSS for the Phase 6 report:**
1. Run inline component inventory: glob `resources/views/components/*.blade.php`,
grep each for `var(--)` patterns → build local variable name registry
(same logic as block-scaffolding Phase 0b; runs inline here, not delegated)
2. Read `design-guide.md` `## Tokens → Colors` to determine background context:
- If `design-guide.md` exists at `docs/plans/*/components/*/design-guide.md`
→ apply decision table
- If `design-guide.md` is absent → treat as Ambiguous; generate with
`/* VERIFY: design-guide.md not found — confirm background context */`
3. Apply decision table:
| Token found | Background | CSS action |
|---|---|---|
| `bg-depth`, `bg-primary`, `bg-dark`, `bg-inverse` | Dark | Override cascade vars with `*-on-dark` equivalents |
| `bg-identity`, `bg-sage`, `bg-accent` | Identity (brand color bg) | Override cascade vars with `*-on-identity` equivalents (e.g. `var(--color-identity-fg)`) |
| `bg-bg`, `bg-surface`, `bg-muted`, absent | Light (default) | No override — inherit `:root` defaults |
| Unrecognized token | Ambiguous | Generate with `/* VERIFY: background context unknown */` |
4. Include generated CSS in Phase 6 report (see report-format.md G10 section template)
#### G11. nl2br on non-textarea fields
For each `nl2br(esc_html($var))` call in the view, trace the variable back to its
ACF field definition in `app/Blocks/{ClassName}.php`. If the field uses `addText()`
(single-line text), `nl2br()` is a no-op at best and misleading at worst. Flag as
IMPROVEMENT — remove `nl2br()` or change the field to `addTextarea()` / `addWysiwyg()`.
---
## Phase 6 — Report and propose
See [references/report-format.md](references/report-format.md) for the refactoring report format.
---
## Phase 7 — Apply approved changes
After user approves proposals, apply in order: CSS removals → variation expansions → gap fixes. Run `lando theme-build && lando flush` to verify.
---
## Phase 8 — Verification
Use Playwright MCP to screenshot at canonical width and verify all variations. Then:
```
git commit -m "refactor(blocks): {slug} — {summary of applied changes}"
```
---
## Anti-drift — don't reintroduce
See `/block-scaffolding` anti-drift table — same rules apply during refactor. Every
proposal in Phase 6 should, after applied, produce code that would pass `/block-scaffolding`
as if the block were being created today.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!