Skip to main content

3 posts tagged with "FSE"

View all tags

Fix FSE Group Block Layout Property Overriding Custom CSS

· 3 min read

TL;DR

WordPress FSE Group blocks with layout property automatically generate is-layout-* CSS classes that have higher specificity than custom CSS, causing size settings to be ignored. Solution: 1) Use "layout":{"type":"default"} in block annotation to avoid extra layout classes; 2) Use !important in CSS to force override; 3) Key: Add padding: 0 !important to clear the Group block's default padding.

Problem

Timeline component year dots should display as 80px circles, but appear as ellipses:

<!-- Size settings in block annotation -->
<!-- wp:group {"style":{"dimensions":{"width":"80px","height":"80px"}},"layout":{"type":"flex",...}} -->
/* Custom CSS */
.cclee-timeline-dot {
width: 80px;
height: 80px;
border-radius: 50%;
}

Neither adjusting CSS nor block attributes fixed the stretched dots.

Root Cause

WordPress FSE Group blocks automatically add layout-related CSS classes based on the layout property:

<div class="wp-block-group cclee-timeline-dot is-layout-flow">

These is-layout-* classes come from WordPress core stylesheets and override custom CSS. Additionally, Group blocks have default padding that increases element dimensions.

Key issues:

  1. layout: {"type": "flex"} generates is-layout-flex class, causing children to be stretched by flexbox
  2. style.dimensions in block annotation becomes inline style, but gets overridden by layout class styles
  3. Group block default padding adds to actual element size

Solution

1. Modify Block Annotation with Default Layout

<!-- wp:group {"className":"cclee-timeline-dot","style":{"border":{"radius":"50%"}},"backgroundColor":"accent","textColor":"base","layout":{"type":"default"}} -->
<div class="wp-block-group cclee-timeline-dot has-base-color has-accent-background-color has-text-color has-background" style="border-radius:50%">

Remove style.dimensions and complex flex layout, use "layout":{"type":"default"} instead.

2. CSS Override + Clear Default Padding

/* Timeline: Fixed circle dot */
.wp-block-group.cclee-timeline-dot {
width: 80px !important;
height: 80px !important;
min-width: 80px !important;
min-height: 80px !important;
flex-shrink: 0 !important;
aspect-ratio: unset !important;
border-radius: 50% !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
align-self: center !important;
box-sizing: border-box !important;
text-align: center !important;
padding: 0 !important; /* Key: clear default padding */
}

.wp-block-group.cclee-timeline-dot p {
margin: 0 !important;
white-space: nowrap !important;
line-height: 1 !important;
overflow: visible !important;
}

3. Use :has() to Control Parent Container

Prevent parent Column from being stretched by flexbox:

.wp-block-columns .wp-block-column:has(.cclee-timeline-dot) {
flex-shrink: 0 !important;
flex-basis: 100px !important;
width: 100px !important;
}

Key Finding

padding: 0 !important is the final solution. Group block's default padding stretches the element—even with width/height set, the actual rendered size exceeds expectations.


Interested in similar solutions? Contact us

Fix WordPress FSE Theme Footer Text Visibility - WCAG Contrast Issue

· 3 min read

While developing a WordPress FSE enterprise theme for a client, I discovered the Footer block text was nearly invisible across multiple Style Variations. This post documents the complete fix process - from WCAG contrast diagnosis to introducing semantic colors and handling global styles override.

TL;DR

Problem: FSE theme's contrast color token has conflicting semantics. In light themes, contrast ≈ light gray ≈ base (white), resulting in Footer contrast ratio of only 1.05:1.

Solution:

  1. Introduce surface semantic color for dark block backgrounds
  2. Delete override styles in wp_global_styles
  3. Add surface definition to all Style Variations

Result: Contrast ratio improved from 1.05:1 to 15.8:1 (WCAG AAA grade).

Problem

Footer block uses backgroundColor="contrast" + textColor="base":

<!-- wp:group {"backgroundColor":"contrast","textColor":"base"} -->
<div class="has-base-color has-contrast-background-color">
Footer content
</div>

Under default theme, Footer text is nearly invisible:

CombinationForegroundBackgroundContrastWCAG
Footer text#ffffff (base)#f8fafc (contrast)1.05:1❌ Fail
Footer link#f59e0b (accent)#f8fafc (contrast)1.78:1❌ Fail

WCAG AA standard requires ≥ 4.5:1 for normal text. Current state is far below standard.

Root Cause Analysis

1. Conflicting contrast Semantics

contrast was designed as "background color that contrasts with base", but semantics conflict across themes:

VariationbasecontrastExpected vs Actual
Default (light)#ffffff white#f8fafc light grayExpected dark, actual light
Tech (dark)#0f0f1a deep black#1e1e2e deep purpleExpected light, actual dark

Footer Pattern assumes contrast is a dark background, but in 5/6 Style Variations it's light.

2. Missing Semantic Color for Dark Blocks

Original design system only had one "contrast" color, without distinguishing:

  • Light contrast blocks (CTA Banner, etc.)
  • Dark contrast blocks (Footer, dark Hero, etc.)

Solution

Step 1: Introduce surface Semantic Color

Add surface token in theme.json for dark block backgrounds:

{
"slug": "surface",
"color": "#0f172a",
"name": "Surface"
}

Step 2: Update All Style Variations

Each variation defines its own surface color (usually equals primary):

// styles/commerce.json
{ "slug": "surface", "color": "#1f2937", "name": "Surface" }

// styles/nature.json
{ "slug": "surface", "color": "#14532d", "name": "Surface" }

// styles/tech.json (dark theme)
{ "slug": "surface", "color": "#1e1e2e", "name": "Surface" }
<!-- wp:group {"backgroundColor":"surface","textColor":"base"} -->
<div class="has-base-color has-surface-background-color">
Footer content
</div>

Step 4: Delete Global Styles Override

Colors still not working after modifying theme.json? Check global styles:

# Check if global styles exist
docker exec wp_cli wp post list --post_type=wp_global_styles --fields=ID,post_title --allow-root

# Delete global styles
docker exec wp_cli wp post delete <ID> --force --allow-root
docker exec wp_cli wp cache flush --allow-root

Reason: color.palette in wp_global_styles completely overrides (not merges) theme.json's palette.

Results

Variationsurface + base ContrastWCAG Grade
Default15.8:1✅ AAA
Commerce13.1:1✅ AAA
Industrial12.6:1✅ AAA
Professional9.9:1✅ AAA
Nature10.8:1✅ AAA
Tech11.5:1✅ AAA

Color Semantics Summary

TokenPurpose
primaryBrand color (Logo, primary button)
secondarySecondary elements
accentCall to action (CTA, links)
basePage main background
contrastLight contrast block background
surfaceDark block background (Footer, dark CTA) ← New

Interested in similar solutions? Get in touch

Fix WordPress FSE Pattern Block Validation Errors - 5 Common Causes

· 4 min read

Encountered frequent Block Pattern validation failures while developing a WordPress FSE theme for a client. This article summarizes 5 common causes and solutions.

TL;DR

Block validation failures are usually caused by one of: undefined color slugs, duplicate JSON keys, Style Variation palette override, HTML attribute mismatch with block comments, or global styles overriding theme.json. Check each one systematically.

Problem

Patterns show a red warning in the editor:

Block contains unexpected or invalid content

After attempting to recover the block, it may work temporarily, but the issue returns after refresh.


Cause 1: Undefined Color Slug

Root Cause

Pattern block attributes reference color slugs that don't exist in theme.json:

<!-- Error: neutral-text doesn't exist -->
<!-- wp:paragraph {"textColor":"neutral-text"} -->
<p class="has-neutral-text-color">...</p>

Solution

  1. Open theme.json and check all colors defined in settings.color.palette
  2. Replace invalid slugs in your Pattern with valid ones
# Batch replacement example
cd patterns/
sed -i 's/"neutral-text"/"neutral-500"/g' *.php
sed -i 's/has-neutral-text-color/has-neutral-500-color/g' *.php

Valid slugs reference: primary, secondary, accent, base, contrast, neutral-50 through neutral-900


Cause 2: Duplicate JSON Key

Root Cause

Block comment JSON has duplicate keys at the same level (common when copy-pasting):

// Error: two style keys
{"style":{"typography":{...}},"style":{"spacing":{...}}}

JSON specification doesn't allow duplicate keys; parser behavior is undefined.

Solution

Merge into a single key:

// Correct
{"style":{"typography":{...},"spacing":{...}}}

Debug command:

# Search for potentially duplicate keys
grep -n ',"style":{' patterns/*.php | head -20

Cause 3: Style Variation Palette Override

Root Cause

color.palette in styles/*.json completely overrides (doesn't merge) the parent theme palette.

When a Pattern references neutral-500, but the current Style Variation doesn't define it, validation fails.

Solution

Each Style Variation must include the complete neutral series:

// styles/ocean.json
{
"version": 3,
"settings": {
"color": {
"palette": [
{ "slug": "primary", "color": "#0d9488", "name": "Primary" },
{ "slug": "secondary", "color": "#0f766e", "name": "Secondary" },
{ "slug": "accent", "color": "#f59e0b", "name": "Accent" },
{ "slug": "base", "color": "#f8fafc", "name": "Base" },
{ "slug": "contrast", "color": "#0f172a", "name": "Contrast" },
{ "slug": "neutral-50", "color": "#fafafa", "name": "Neutral 50" },
{ "slug": "neutral-100", "color": "#f5f5f5", "name": "Neutral 100" },
{ "slug": "neutral-200", "color": "#e5e5e5", "name": "Neutral 200" },
{ "slug": "neutral-300", "color": "#d4d4d4", "name": "Neutral 300" },
{ "slug": "neutral-400", "color": "#a3a3a3", "name": "Neutral 400" },
{ "slug": "neutral-500", "color": "#737373", "name": "Neutral 500" },
{ "slug": "neutral-600", "color": "#525252", "name": "Neutral 600" },
{ "slug": "neutral-700", "color": "#404040", "name": "Neutral 700" },
{ "slug": "neutral-800", "color": "#262626", "name": "Neutral 800" },
{ "slug": "neutral-900", "color": "#171717", "name": "Neutral 900" }
]
}
}
}

Key point: Neutral series color values must match theme.json exactly; only change brand colors.


Cause 4: HTML Attribute Mismatch with Block Comments

Root Cause

This is the most subtle issue. WordPress save function has strict requirements for generated HTML.

Issue 4.1: Incorrect class Order

WordPress generates classes in a fixed order:

has-border-color has-{slug}-border-color has-{slug}-background-color has-background

Wrong order in hand-written HTML causes validation failure.

Issue 4.2: Background Color Attribute Mixing

Background color must use backgroundColor attribute, not style.color.background:

<!-- Error: mixing causes invalid CSS generation -->
<!-- wp:group {"style":{"color":{"background":"#f5f5f5"}}} -->

<!-- Correct -->
<!-- wp:group {"backgroundColor":"neutral-100"} -->

Issue 4.3: Border Style Attribute Order

border-width must come before border-style:

<!-- Correct -->
<div style="border-width:1px;border-style:solid;border-radius:8px;">

Solution

Best practice: Copy block code from the editor, don't hand-write HTML class and style.

  1. Configure the block in the editor
  2. Switch to Code Editor view
  3. Copy the complete block comment + HTML
  4. Paste into Pattern file

Correct example:

<!-- wp:group {"backgroundColor":"accent","borderColor":"neutral-200","style":{"border":{"radius":"8px","width":"1px","style":"solid"}}} -->
<div class="wp-block-group has-border-color has-neutral-200-border-color has-accent-background-color has-background" style="border-width:1px;border-style:solid;border-radius:8px;">
<!-- content -->
</div>
<!-- /wp:group -->

Cause 5: Global Styles Override theme.json

Root Cause

Custom styles saved by Site Editor are stored in wp_global_styles CPT with higher priority than theme.json.

After modifying theme.json, the frontend still shows old values because global styles override theme defaults.

Debug

# Check if global styles exist
wp post list --post_type=wp_global_styles --fields=ID,post_title --allow-root

# View global styles content
wp post get <ID> --fields=post_content --allow-root

Solution

# Delete global styles
wp post delete <ID> --force --allow-root

# Clear cache
wp cache flush --allow-root

Prevention: Avoid using Site Editor for custom styles during development. Manage all configuration through theme.json.


Debug Flow Summary

Block validation failed

├─→ Check if color slugs are defined in theme.json

├─→ Check JSON for duplicate keys

├─→ Check all Style Variations have complete palettes

├─→ Check HTML class/style matches block comments

└─→ Check if wp_global_styles overrides theme.json

Interested in similar projects? Get in touch