Skip to content

Commit 1cb42e5

Browse files
committed
feat(skill): enhance WordPress Block Pattern Validator with background image attribute handling and validation rules
1 parent 71c45fd commit 1cb42e5

3 files changed

Lines changed: 291 additions & 2 deletions

File tree

.github/skills/wordpress-block-pattern-generator/SKILL.md

Lines changed: 235 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,214 @@ All generated patterns must pass these validation checks:
176176
| Incorrect block type | Content doesn't match | Use correct block (paragraph vs heading) |
177177
| Missing escaping | Security warning | Wrap translations in `esc_html__()` |
178178

179+
## Background Image Conversion (TSX/React to WordPress Blocks)
180+
181+
When converting React/TSX components with background images to WordPress blocks, follow this pattern:
182+
183+
### React/TSX Background Image Pattern
184+
185+
```tsx
186+
// React component with background image
187+
<div
188+
className="header-section"
189+
style={{
190+
backgroundImage: `url(${headerTexture})`,
191+
backgroundRepeat: 'no-repeat',
192+
backgroundSize: 'cover',
193+
backgroundPosition: 'center'
194+
}}
195+
>
196+
{/* Content */}
197+
</div>
198+
```
199+
200+
### WordPress Block Attributes Pattern
201+
202+
Convert the above to WordPress block attributes like this:
203+
204+
**Pattern 1: Standard Background (Simple, No Advanced Effects)**
205+
```html
206+
<!-- wp:group {"style":{"background":{"backgroundImage":{"url":"/wp-content/themes/theme-name/assets/images/header-texture.png","source":"file","title":"header-texture"},"backgroundSize":"cover","backgroundPosition":"center","backgroundRepeat":"no-repeat"}},"layout":{"type":"constrained"}} -->
207+
<div class="wp-block-group" style="background-image:url('/wp-content/themes/theme-name/assets/images/header-texture.png');background-size:cover;background-position:center;background-repeat:no-repeat">
208+
<!-- Content blocks here -->
209+
</div>
210+
<!-- /wp:group -->
211+
```
212+
213+
**Pattern 2: Advanced Background (With Blend Modes, Opacity, Filters)**
214+
```html
215+
<!-- wp:group {"style":{"background":{"backgroundImage":{"url":"/wp-content/themes/theme-name/assets/images/header-texture.png","source":"file","title":"header-texture"},"backgroundSize":"cover","backgroundPosition":"center","backgroundRepeat":"no-repeat"}},"className":"header-main","layout":{"type":"constrained"}} -->
216+
<div class="wp-block-group header-main">
217+
<!-- Empty div for SCSS to target -->
218+
<!-- wp:html -->
219+
<div></div>
220+
<!-- /wp:html -->
221+
222+
<!-- Content blocks here -->
223+
</div>
224+
<!-- /wp:group -->
225+
```
226+
227+
**When to use each pattern:**
228+
- **Pattern 1**: Simple backgrounds without blend modes, opacity, or filters
229+
- Background appears in BOTH block attributes AND HTML inline styles
230+
- Browser renders directly from inline styles
231+
- **Pattern 2**: Advanced effects requiring CSS properties not supported by block attributes
232+
- Background appears ONLY in block attributes (for editor preview)
233+
- NO inline styles in HTML
234+
- SCSS handles all rendering using the empty HTML div
235+
236+
**CRITICAL for Pattern 1:** Background images must be defined in BOTH places:
237+
1. **Block comment attributes** - WordPress editor reads these
238+
2. **HTML inline styles** - Browsers render these
239+
240+
**CRITICAL for Pattern 2:** Background images defined ONLY in block attributes:
241+
1. **Block comment attributes** - WordPress editor reads these for preview
242+
2. **NO HTML inline styles** - SCSS module handles all rendering
243+
3. **Empty HTML div** - SCSS targets this for background + advanced effects
244+
245+
**Why both patterns exist:**
246+
- Pattern 1: Block attributes allow the WordPress editor to display and edit the background, inline styles ensure frontend rendering
247+
- Pattern 2: Block attributes provide editor preview, SCSS provides full control for advanced effects not supported by WordPress
248+
- The validator checks Pattern 1 for matching attributes/styles; Pattern 2 requires manual SCSS setup
249+
250+
**IMPORTANT CONSTRAINT:** Blocks with background images CANNOT have background colors or gradients:
251+
-**WRONG:** `"gradient":"brand-red"` + background image = gradient will be overridden
252+
-**WRONG:** `"backgroundColor":"primary"` + background image = color will be overridden
253+
-**CORRECT:** Use ONLY the background image attribute, no gradient or backgroundColor
254+
-**CORRECT:** If you need color underneath, use CSS in the theme's SCSS files
255+
256+
**Example of WRONG pattern (conflicting background properties):**
257+
```html
258+
<!-- WRONG: Has both gradient and background image -->
259+
<!-- wp:group {"gradient":"brand-red","style":{"background":{"backgroundImage":{...}}}} -->
260+
<div class="wp-block-group has-brand-red-gradient-background has-background">
261+
```
262+
263+
**Example of CORRECT pattern:**
264+
```html
265+
<!-- CORRECT: Only background image, no gradient -->
266+
<!-- wp:group {"style":{"background":{"backgroundImage":{...}}}} -->
267+
<div class="wp-block-group has-background">
268+
```
269+
270+
### Required Background Attribute Structure
271+
272+
```json
273+
{
274+
"style": {
275+
"background": {
276+
"backgroundImage": {
277+
"url": "/wp-content/themes/theme-name/assets/images/image.png",
278+
"source": "file",
279+
"title": "image-name"
280+
},
281+
"backgroundSize": "cover|contain|auto",
282+
"backgroundPosition": "center|top|bottom|left|right",
283+
"backgroundRepeat": "no-repeat|repeat|repeat-x|repeat-y"
284+
}
285+
}
286+
}
287+
```
288+
289+
### Properties NOT Supported by Block Attributes
290+
291+
The following CSS properties cannot be set via WordPress block attributes and must be handled in CSS/SCSS:
292+
293+
- **mix-blend-mode** - Blend mode effects (multiply, screen, overlay, etc.)
294+
- **opacity** - Transparency levels (use CSS)
295+
- **filter** - Visual filters (blur, brightness, contrast, etc.)
296+
- **transform** - Transformations (scale, rotate, translate, etc.)
297+
298+
### Recommended Pattern for Advanced Effects
299+
300+
When you need CSS properties not supported by block attributes (blend modes, opacity, filters), use **Pattern 2** from above:
301+
302+
**WordPress Pattern (Pattern 2 - Advanced):**
303+
```html
304+
<!-- wp:group {"style":{"background":{"backgroundImage":{"url":"/wp-content/themes/theme-name/assets/images/texture.png","source":"file","title":"texture"},"backgroundSize":"cover"}},"className":"header-main"} -->
305+
<div class="wp-block-group header-main">
306+
307+
<!-- wp:html -->
308+
<div></div>
309+
<!-- /wp:html -->
310+
311+
<!-- Content blocks -->
312+
313+
</div>
314+
<!-- /wp:group -->
315+
```
316+
317+
**Key differences from Pattern 1:**
318+
1. NO background inline styles in the HTML div
319+
2. Empty HTML div for SCSS to target
320+
3. Background appears ONLY in block attributes (for editor preview)
321+
322+
**SCSS Module (_header.scss):**
323+
```scss
324+
.header-main {
325+
position: relative;
326+
overflow: hidden;
327+
328+
// Target the empty HTML block div for overlay effects
329+
> div:not(.wp-block-group):first-child {
330+
position: absolute;
331+
top: 0;
332+
right: 0;
333+
bottom: 0;
334+
left: 0;
335+
z-index: 0;
336+
pointer-events: none;
337+
mix-blend-mode: multiply;
338+
opacity: 1;
339+
}
340+
}
341+
```
342+
343+
### Asset Management
344+
345+
1. **Copy assets to theme**: Ensure images referenced in block attributes exist in the theme
346+
```bash
347+
cp source-image.png /wp-content/themes/theme-name/assets/images/
348+
```
349+
350+
2. **Use theme-relative paths**: Always use paths relative to theme root
351+
```
352+
✓ /wp-content/themes/theme-name/assets/images/image.png
353+
✗ http://example.com/wp-content/uploads/image.png (media library)
354+
```
355+
356+
3. **Name assets descriptively**: Use kebab-case for image filenames
357+
```
358+
✓ header-texture.png
359+
✓ hero-background.jpg
360+
✗ image1.png
361+
✗ 59f5f21fc3ab664ddea62e2cde218d15718c0a5b.png
362+
```
363+
364+
### Conversion Checklist
365+
366+
**For Pattern 1 (Simple backgrounds):**
367+
- [ ] Background image copied to theme assets directory
368+
- [ ] Background properties added to block comment attributes
369+
- [ ] Background properties added to HTML div inline styles
370+
- [ ] Image URL uses theme-relative path
371+
- [ ] backgroundSize, backgroundPosition, backgroundRepeat set correctly
372+
- [ ] No backgroundColor or gradient attributes present with background image
373+
374+
**For Pattern 2 (Advanced effects with SCSS):**
375+
- [ ] Background image copied to theme assets directory
376+
- [ ] Background properties added to block comment attributes ONLY
377+
- [ ] NO background properties in HTML div inline styles
378+
- [ ] Empty HTML div added for SCSS to target
379+
- [ ] SCSS module created with background + advanced effects
380+
- [ ] Image URL uses theme-relative path
381+
- [ ] No backgroundColor or gradient attributes present with background image
382+
- [ ] Advanced effects (blend modes, opacity) handled in SCSS
383+
- [ ] Empty HTML div added if overlay effects needed
384+
- [ ] SCSS module targets overlay div correctly
385+
- [ ] Theme rebuilt after SCSS changes
386+
179387
## Related Skills
180388

181389
- `block-theme-development` - Overall theme development standards
@@ -184,8 +392,33 @@ All generated patterns must pass these validation checks:
184392

185393
## Version
186394

187-
1.2.0
395+
1.5.0
188396

189397
## Last Updated
190398

191-
2026-02-03
399+
2026-02-25
400+
401+
## Changelog
402+
403+
### 1.5.0 (2026-02-25)
404+
- **MAJOR UPDATE**: Documented two distinct patterns for background images
405+
- Pattern 1: Simple backgrounds (attributes + HTML inline styles)
406+
- Pattern 2: Advanced backgrounds with SCSS (attributes only, NO inline styles)
407+
- Added clear guidance on when to use each pattern
408+
- Updated conversion checklist for both patterns
409+
- Clarified that Pattern 2 uses block attributes for editor preview, SCSS for rendering
410+
- Added constraint: Cannot mix background images with backgroundColor or gradient attributes
411+
412+
### 1.4.0 (2026-02-25)
413+
- **CRITICAL UPDATE**: Clarified that background images must be defined in BOTH block attributes AND HTML inline styles
414+
- Added explanation of why both are needed (editor vs. frontend rendering)
415+
- Updated all background image examples to show inline styles
416+
- Updated conversion checklist to include HTML inline styles requirement
417+
- Updated validator to check background image inline styles
418+
419+
### 1.3.0 (2026-02-25)
420+
- Added "Background Image Conversion (TSX/React to WordPress Blocks)" section
421+
- Documented WordPress block attribute structure for background images
422+
- Added guidance on handling advanced CSS effects (blend modes, opacity) in SCSS
423+
- Included asset management best practices
424+
- Added conversion checklist for TSX to WordPress block background images

.github/skills/wordpress-block-pattern-validator/SKILL.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,45 @@ Note: The validator checks for any HTML comment that doesn't start with `wp:` or
191191
- **Attribute**: `"style":{"border":{"width":"2px","color":"#000"}}`
192192
- **Inline Style**: `border-width:2px;border-color:#000`
193193

194+
### Background Image Attributes
195+
196+
#### Background Image with Properties
197+
- **Attribute**: `"style":{"background":{"backgroundImage":{"url":"/path/to/image.png","source":"file","title":"image"},"backgroundSize":"cover","backgroundPosition":"center","backgroundRepeat":"no-repeat"}}`
198+
- **Inline Style**: `background-image:url('/path/to/image.png');background-size:cover;background-position:center;background-repeat:no-repeat`
199+
- **CRITICAL**: Background images must appear in BOTH block attributes AND HTML inline styles
200+
- **Why**: Block attributes are for the editor, inline styles are for frontend rendering
201+
202+
**IMPORTANT CONSTRAINT:** Blocks with background images CANNOT have background colors or gradients:
203+
- Background images will override any `backgroundColor` or `gradient` attributes
204+
- The validator should flag blocks that have both a background image AND a backgroundColor/gradient attribute
205+
-**ERROR:** `"gradient":"brand-red"` + background image
206+
-**ERROR:** `"backgroundColor":"primary"` + background image
207+
-**VALID:** Only background image attribute present
208+
209+
**Example:**
210+
```html
211+
<!-- Block comment with background attributes -->
212+
<!-- wp:group {"style":{"background":{"backgroundImage":{"url":"/wp-content/themes/theme/assets/images/texture.png","source":"file","title":"texture"},"backgroundSize":"cover"}}} -->
213+
<!-- HTML must have inline styles -->
214+
<div class="wp-block-group has-background" style="background-image:url('/wp-content/themes/theme/assets/images/texture.png');background-size:cover">
215+
```
216+
217+
**Invalid Example (conflicting backgrounds):**
218+
```html
219+
<!-- INVALID: Has both gradient and background image -->
220+
<!-- wp:group {"gradient":"brand-red","style":{"background":{"backgroundImage":{...}}}} -->
221+
<div class="wp-block-group has-brand-red-gradient-background has-background">
222+
<!-- This will fail validation - remove "gradient" attribute -->
223+
```
224+
225+
#### Background Image Properties
226+
- **backgroundImage.url**: Required - Full path to image
227+
- **backgroundImage.source**: Typically `"file"` for theme assets
228+
- **backgroundImage.title**: Optional - Image title/alt description
229+
- **backgroundSize**: `cover`, `contain`, `auto`, or custom value
230+
- **backgroundPosition**: `center`, `top`, `bottom`, `left`, `right`, or custom
231+
- **backgroundRepeat**: `no-repeat`, `repeat`, `repeat-x`, `repeat-y`
232+
194233
### Typography Attributes
195234

196235
#### Font Size

.github/skills/wordpress-block-pattern-validator/validate-patterns.cjs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,23 @@ class WordPressBlockValidator {
186186
styles.push(`color:${this.convertPresetNotation(styleObj.color.text)}`);
187187
}
188188

189+
// Background Image
190+
if (styleObj.background?.backgroundImage) {
191+
const bgImage = styleObj.background.backgroundImage;
192+
if (bgImage.url) {
193+
styles.push(`background-image:url('${bgImage.url}')`);
194+
}
195+
}
196+
if (styleObj.background?.backgroundSize) {
197+
styles.push(`background-size:${styleObj.background.backgroundSize}`);
198+
}
199+
if (styleObj.background?.backgroundPosition) {
200+
styles.push(`background-position:${styleObj.background.backgroundPosition}`);
201+
}
202+
if (styleObj.background?.backgroundRepeat) {
203+
styles.push(`background-repeat:${styleObj.background.backgroundRepeat}`);
204+
}
205+
189206
// Typography
190207
if (styleObj.typography?.fontSize) {
191208
styles.push(`font-size:${this.convertPresetNotation(styleObj.typography.fontSize)}`);

0 commit comments

Comments
 (0)