Breeze Theme Editor - Theme Developer Guide
Version: 1.0
Last Updated: 2026-01-09
This guide explains how to add Theme Editor support to your Breeze theme.
Table of Contents
- Quick Start
- File Structure
- Configuration Format
- Field Types Reference
- Field Properties
- Color Palette System
- Validation Rules
- Theme Inheritance
- Best Practices
- Examples
- Troubleshooting
Quick Start
Step 1: Create Configuration File
Create etc/theme_editor/settings.json in your theme root:
your-theme/
└── etc/
└── theme_editor/
└── settings.json
Step 2: Basic Configuration
{
"version": "1.0",
"sections": [
{
"id": "colors",
"name": "Colors",
"description": "Customize theme colors",
"icon": "palette",
"order": 1,
"settings": [
{
"id": "primary_color",
"label": "Primary Color",
"type": "color",
"default": "#1979c3",
"css_var": "--primary-color",
"description": "Main brand color"
}
]
}
]
}
Step 3: Test
- Clear Magento cache:
bin/magento cache:clean - Open frontend with
?breeze_theme_editor=1 - Your settings should appear in the panel
File Structure
your-theme/
├── etc/
│ └── theme_editor/
│ ├── settings.json # Main configuration
│ └── presets/ # Optional presets
│ ├── default.json
│ └── dark-mode.json
└── web/
└── css/
└── source/
└── _theme-variables.less # Your CSS variables
Configuration Format
Root Structure
{
"version": "1.0", // Required: Config version
"extends": "Parent/Theme", // Optional: Inherit from parent theme
"sections": [] // Required: Array of sections
}
Section Structure
{
"id": "unique_section_id", // Required: Unique identifier
"name": "Section Name", // Required: Display name
"description": "Description", // Optional: Section description
"icon": "palette", // Optional: Material icon name
"order": 1, // Optional: Display order (default: 999)
"settings": [] // Required: Array of fields
}
Material Icons
Common icons: palette, format_paint, text_fields, view_column, image, settings, code, link
Full list: https://fonts.google.com/icons
Field Types Reference
1. COLOR - Color Picker
Purpose: Select colors with live preview
{
"id": "primary_color",
"label": "Primary Color",
"type": "color",
"default": "#1979c3",
"css_var": "--primary-color",
"format": "hex",
"description": "Main brand color",
"help_text": "Used for buttons, links, and accents"
}
Features:
- Visual color picker
- HEX input (#RRGGBB or #RGB)
- Configurable output format (HEX or RGB)
- Automatic format conversion
Format Property
Property: format
Type: String
Values: "hex" | "rgb" | "auto"
Required: No
Controls the CSS output format for color values.
Format Options:
"hex"(Breeze 3.0) - Default for new themes{ "id": "text_color", "type": "color", "default": "#111827", "css_var": "--text-color", "format": "hex" }CSS Output:
:root { --text-color: #111827; }Use for: Modern themes using
color: var(--text-color)"rgb"(Breeze 2.0) - For legacy themes{ "id": "text_color", "type": "color", "default": "#111827", "css_var": "--text-color", "format": "rgb" }CSS Output:
:root { --text-color: 17, 24, 39; /* RGB format */ }Use for: Legacy themes using
color: rgb(var(--text-color))"auto"- Smart detection{ "id": "text_color", "type": "color", "default": "255, 0, 0", "css_var": "--text-color", "format": "auto" }Behavior: Detects format from
defaultvalue- If
defaultis HEX → outputs HEX - If
defaultis RGB → outputs RGB
- If
Default Format:
- If
formatis not specified ANDdefaultexists →"auto" - If
formatis not specified AND nodefault→"hex"
Migration Guide (Breeze 2.0 → 3.0):
If your theme uses rgb(var()) syntax in CSS:
// Old Breeze 2.0 CSS
.button {
color: rgb(var(--button-color));
background: rgba(var(--bg-color), 0.5);
}
You MUST add "format": "rgb" to your color fields:
{
"id": "button_color",
"type": "color",
"format": "rgb", // ← ADD THIS
"css_var": "--button-color"
}
For new Breeze 3.0 themes using direct var():
// New Breeze 3.0 CSS
.button {
color: var(--button-color);
background: color-mix(in srgb, var(--bg-color) 50%, transparent);
}
Use "format": "hex" (or omit for default):
{
"id": "button_color",
"type": "color",
"format": "hex", // ← Optional (default)
"css_var": "--button-color"
}
Palette Property
Property: palette
Type: String
Required: No
Enables “Quick Select” color picker with predefined palette colors.
Example:
{
"id": "text_color",
"label": "Text Color",
"type": "color",
"default": "#111827",
"css_var": "--text-color",
"palette": "default",
"format": "hex"
}
Behavior:
- Displays color swatches from the specified palette
- Users can click palette colors for instant selection
- Palette colors are defined in the
palettessection (see Color Palette System) - Users can still manually enter custom colors
When to use:
- ✅ For theme colors that should match brand palette
- ✅ To provide quick access to predefined color schemes
- ✅ To maintain color consistency across the theme
- ❌ Not needed for completely custom color fields
Notes:
- Palette color references (e.g.,
--color-brand-primary) always output asvar()regardless of format - User input is accepted in any format (HEX or RGB) and automatically converted
- Supports both
#FF0000and#F00HEX formats - See Color Palette System section for palette configuration
2. TEXT - Single Line Input
Purpose: Short text values (widths, margins, custom values)
{
"id": "container_width",
"label": "Container Width",
"type": "text",
"default": "1280px",
"css_var": "--container-width",
"placeholder": "e.g. 1280px",
"description": "Maximum content width"
}
Properties:
placeholder- Placeholder textpattern- Regex validation patternvalidationMessage- Custom error messageminLength- Minimum charactersmaxLength- Maximum characters
Example with Validation:
{
"id": "custom_margin",
"type": "text",
"pattern": "^\\d+(px|rem|em|%)$",
"validationMessage": "Must be a valid CSS unit (e.g. 10px, 1rem)",
"placeholder": "10px"
}
3. TEXTAREA - Multi-line Input
Purpose: Custom CSS, scripts, large text blocks
{
"id": "custom_css",
"label": "Custom CSS",
"type": "textarea",
"default": "/* Your custom styles */",
"rows": 10,
"description": "Additional CSS code",
"help_text": "Will be injected into <style> tag"
}
Properties:
rows- Number of visible rows (default: 5)placeholder- Placeholder textmaxLength- Maximum characters
Security:
- CSS comments
/* */are automatically escaped to/ * * / - Prevents breaking CSS output
4. NUMBER - Numeric Input
Purpose: Precise numeric values
{
"id": "grid_columns",
"label": "Grid Columns",
"type": "number",
"default": "4",
"min": "1",
"max": "12",
"step": "1",
"css_var": "--grid-columns",
"description": "Number of product columns"
}
Properties:
min- Minimum valuemax- Maximum valuestep- Increment step (default: 1)
Validation:
- Automatic min/max validation
- Must be numeric
5. RANGE - Slider Input
Purpose: Visual slider for numeric ranges
{
"id": "text_opacity",
"label": "Text Opacity",
"type": "range",
"default": "1",
"min": "0",
"max": "1",
"step": "0.1",
"unit": "",
"css_var": "--text-opacity",
"description": "Transparency level"
}
Properties:
min- Minimum value (required)max- Maximum value (required)step- Slider step (required)unit- Display unit (e.g. “px”, “ms”, “%”)
UI:
- Visual slider with live value display
- Shows: “0.8” or “800ms” (with unit)
6. SELECT - Dropdown
Purpose: Choose from predefined options
{
"id": "layout_type",
"label": "Layout Type",
"type": "select",
"default": "boxed",
"css_var": "--layout-type",
"options": [
{"value": "boxed", "label": "Boxed Layout"},
{"value": "full", "label": "Full Width"},
{"value": "fluid", "label": "Fluid"}
],
"description": "Page layout style"
}
Properties:
options- Array of {value, label} objects (required)
Notes:
- First option is NOT automatically selected
- Must specify
defaultvalue
7. TOGGLE - On/Off Switch
Purpose: Boolean settings
{
"id": "sticky_header",
"label": "Sticky Header",
"type": "toggle",
"default": true,
"css_var": "--header-sticky",
"description": "Fix header on scroll"
}
CSS Output:
:root {
--header-sticky: 1; /* true → 1, false → 0 */
}
Notes:
true→ “1”false→ “0”- Can be used in CSS
calc()oropacity
8. CODE - Code Editor
Purpose: Code snippets with syntax highlighting (future: Monaco editor)
{
"id": "custom_js",
"label": "Custom JavaScript",
"type": "code",
"default": "// Your code here",
"rows": 15,
"description": "Custom JavaScript code",
"help_text": "Use with caution"
}
Properties:
rows- Editor height (default: 10)language- Future: syntax highlighting language
Current Limitations:
- Currently renders as textarea (Monaco integration planned)
- CSS comments are escaped for security
9. FONT_PICKER - Font Selector
Purpose: Choose fonts with preview
{
"id": "body_font",
"label": "Body Font",
"type": "font_picker",
"default": "Open Sans",
"css_var": "--font-family-base",
"options": [
{"value": "Open Sans", "label": "Open Sans"},
{"value": "Roboto", "label": "Roboto"},
{"value": "Georgia", "label": "Georgia"},
{"value": "Courier New", "label": "Courier New"}
],
"description": "Main text font"
}
Features:
- Font preview in dropdown
- Automatic fallback fonts:
- Sans-serif fonts → adds
, sans-serif - Serif fonts → adds
, serif(Georgia, Times, Garamond, etc.) - Monospace fonts → adds
, monospace(Courier, Monaco, Consolas, etc.)
- Sans-serif fonts → adds
CSS Output:
:root {
--font-family-base: "Open Sans", sans-serif;
--font-heading: "Georgia", serif;
--font-code: "Courier New", monospace;
}
Supported Serif Fonts: Georgia, Times New Roman, Times, Garamond, Palatino, Baskerville, Didot, Bodoni, Cambria, serif
Supported Monospace Fonts: Courier New, Courier, Monaco, Consolas, Lucida Console, monospace
10. COLOR_SCHEME - Scheme Selector
Purpose: Predefined color schemes (Light/Dark/Auto)
{
"id": "color_mode",
"label": "Color Scheme",
"type": "color_scheme",
"default": "auto",
"css_var": "--color-scheme",
"schemes": [
{
"value": "light",
"label": "Light Mode",
"colors": ["#ffffff", "#f5f5f5", "#e0e0e0"],
"description": "Light color scheme"
},
{
"value": "dark",
"label": "Dark Mode",
"colors": ["#1a1a1a", "#2d2d2d", "#404040"],
"description": "Dark color scheme"
},
{
"value": "auto",
"label": "Auto",
"colors": ["#ffffff", "#1a1a1a"],
"description": "Follow system preference"
}
]
}
Properties:
schemes- Array of scheme definitions- Each scheme:
value- Scheme IDlabel- Display namecolors- Preview colors (3 swatches)description- Tooltip text
UI:
- Visual cards with color preview
- Radio button selection
11. SOCIAL_LINKS - Social Media URLs
Purpose: Manage social media profile links
{
"id": "social_profiles",
"label": "Social Media Links",
"type": "social_links",
"default": "{}",
"platforms": [
{"code": "facebook", "label": "Facebook", "icon": "f"},
{"code": "twitter", "label": "Twitter/X", "icon": "𝕏"},
{"code": "instagram", "label": "Instagram", "icon": "📷"},
{"code": "linkedin", "label": "LinkedIn", "icon": "in"},
{"code": "youtube", "label": "YouTube", "icon": "▶"}
],
"description": "Your social media profiles"
}
Value Format (JSON):
{
"facebook": "https://facebook.com/yourpage",
"twitter": "https://twitter.com/yourhandle",
"instagram": "https://instagram.com/yourprofile"
}
Features:
- Multiple platform inputs in one field
- Each platform has icon and placeholder
- Stored as JSON object
- Empty fields are omitted
Default Platforms: Facebook, Twitter, Instagram, LinkedIn, YouTube, Pinterest, TikTok
12. ICON_SET_PICKER - Icon Library Selector
Purpose: Choose icon library for theme
{
"id": "icon_library",
"label": "Icon Set",
"type": "icon_set_picker",
"default": "material",
"options": [
{
"value": "material",
"label": "Material Icons",
"preview": "★",
"description": "Google Material Design icons"
},
{
"value": "fontawesome",
"label": "Font Awesome",
"preview": "",
"description": "Font Awesome 6"
},
{
"value": "feather",
"label": "Feather Icons",
"preview": "⚡",
"description": "Simple and clean"
}
]
}
Properties:
options- Array of icon set definitions- Each option:
value- Icon set IDlabel- Display namepreview- Icon preview characterdescription- Tooltip
UI:
- Visual cards with icon preview
- Radio button selection
13. IMAGE_UPLOAD - Image Upload with URL
Purpose: Upload images or provide image URLs
{
"id": "logo",
"label": "Logo Image",
"type": "image_upload",
"default": "",
"css_var": "--logo-url",
"description": "Upload logo or enter URL",
"params": {
"acceptTypes": "image/*",
"maxSize": 2048
}
}
Properties:
params.acceptTypes- Accepted file types (default:"image/*")params.maxSize- Maximum file size in KB (default: 2048)
Features:
- File upload with preview
- URL input option
- Base64 encoding for uploaded files
- Client-side validation
- Remove button to clear image
Value Format:
- URL:
"https://example.com/logo.png" - Data URL:
"data:image/png;base64,iVBORw0KG..."
CSS Output:
:root {
--logo-url: https://example.com/logo.png;
}
Usage in CSS:
.header-logo {
background-image: url(var(--logo-url));
}
Notes:
- Uploaded files are stored as base64 data URLs
- For production, consider using Magento media storage
- Data URLs increase CSS file size
14. SPACING - 4-Sided Spacing Control
Purpose: Control padding or margin with individual sides
{
"id": "container_padding",
"label": "Container Padding",
"type": "spacing",
"default": {
"top": 20,
"right": 20,
"bottom": 20,
"left": 20,
"unit": "px",
"linked": true
},
"css_var": "--container-padding",
"description": "Inner spacing",
"params": {
"unit": "px",
"allowedUnits": ["px", "rem", "em", "%"],
"min": 0,
"max": 100,
"step": 1,
"linkedByDefault": true
}
}
Properties:
params.unit- Default unit (default:"px")params.allowedUnits- Available units (default:["px", "rem", "em", "%"])params.min- Minimum value (default: 0)params.max- Maximum value (default: 100)params.step- Input step (default: 1)params.linkedByDefault- Link all sides initially (default: true)
Features:
- Visual 4-sided input (top, right, bottom, left)
- Link/unlink button to sync all sides
- Unit selector dropdown
- Number inputs with min/max validation
Value Format (JSON):
{
"top": 20,
"right": 20,
"bottom": 20,
"left": 20,
"unit": "px",
"linked": true
}
CSS Output:
:root {
--container-padding: 20px; /* All sides same */
--header-margin: 10px 20px; /* top/bottom, left/right */
--section-padding: 10px 20px 30px 40px; /* All different */
}
Shorthand Logic:
- All same:
20px - Top/Bottom + Left/Right:
10px 20px - Top + Left/Right + Bottom:
10px 20px 30px - All different:
10px 20px 30px 40px
Usage Examples:
.container {
padding: var(--container-padding);
}
.section {
margin: var(--section-margin);
}
15. REPEATER - Dynamic List of Items
Purpose: Create repeating groups of fields (slideshows, testimonials, features)
{
"id": "features",
"label": "Features List",
"type": "repeater",
"default": [],
"description": "Add feature items",
"params": {
"min": 0,
"max": 10,
"addButtonLabel": "Add Feature",
"itemLabel": "Feature",
"collapsible": true,
"sortable": true
},
"fields": [
{
"code": "title",
"label": "Title",
"type": "text",
"required": true,
"placeholder": "Feature name"
},
{
"code": "description",
"label": "Description",
"type": "textarea",
"placeholder": "Describe the feature"
},
{
"code": "icon",
"label": "Icon",
"type": "text",
"placeholder": "Icon name"
},
{
"code": "enabled",
"label": "Enabled",
"type": "toggle",
"default": true
}
]
}
Properties:
fields- Array of sub-field definitions (required)params.min- Minimum items (default: 0)params.max- Maximum items (default: 10)params.addButtonLabel- Button text (default: “Add Item”)params.itemLabel- Item title prefix (default: “Item”)params.collapsible- Allow collapsing items (default: true)params.sortable- Allow reordering (default: true)
Supported Sub-Field Types:
text- Single line inputurl- URL inputtextarea- Multi-line inputnumber- Numeric inputselect- Dropdown with optionstoggle- Checkbox/switch
Features:
- Add/remove items dynamically
- Collapsible items to save space
- Drag-and-drop reordering (basic)
- Each item has numbered header
- Min/max validation
- Remove button per item
Value Format (JSON array):
[
{
"title": "Fast Performance",
"description": "Lightning-fast page loads",
"icon": "speed",
"enabled": true
},
{
"title": "Mobile First",
"description": "Responsive on all devices",
"icon": "mobile",
"enabled": true
}
]
CSS Output:
:root {
--features: [{...}, {...}]; /* JSON string, escaped */
}
Notes:
- Repeater fields typically don’t output to CSS directly
- Use in JavaScript/PHP to render dynamic content
- Access via GraphQL API or custom logic
- Not suitable for CSS variables (use for data storage)
Example Sub-Field Configuration:
{
"fields": [
{
"code": "link_text",
"label": "Link Text",
"type": "text",
"required": true
},
{
"code": "link_url",
"label": "URL",
"type": "url",
"required": true
},
{
"code": "target",
"label": "Open in",
"type": "select",
"options": [
{"value": "_self", "label": "Same Tab"},
{"value": "_blank", "label": "New Tab"}
],
"default": "_self"
}
]
}
Field Properties
Common Properties
All field types support these properties:
{
"id": "field_id", // Required: Unique ID within section
"label": "Field Label", // Required: Display label
"type": "text", // Required: Field type
"default": "value", // Optional: Default value
"css_var": "--css-variable", // Optional: CSS custom property name
"description": "Short text", // Optional: Help text below label
"help_text": "Detailed help", // Optional: Tooltip on (i) icon
"placeholder": "Hint...", // Optional: Input placeholder
"required": false, // Optional: Required field (default: false)
"important": false // Optional: Add !important to CSS (default: false)
}
Property Details
id (string, required)
- Unique identifier within section
- Lowercase, alphanumeric + underscore
- Used in database and GraphQL
- Example:
primary_color,grid_columns
label (string, required)
- Display name in UI
- Can include emoji:
"🎨 Primary Color" - Keep concise (2-4 words)
type (string, required)
- See Field Types Reference
- Supported:
color,text,textarea,number,range,select,toggle,code,font_picker,color_scheme,social_links,icon_set_picker,image_upload,spacing,repeater
default (mixed, optional)
- Default value when field is empty
- Type depends on field type:
color:"#FF0000"or"rgb(255, 0, 0)"text/textarea/code:"string"number/range:"123"or"1.5"toggle:trueorfalseselect/font_picker/icon_set_picker:"option_value"-
color_scheme:"light""dark""auto" social_links:"{}"image_upload:"https://example.com/image.png"or""spacing:{"top": 20, "right": 20, "bottom": 20, "left": 20, "unit": "px", "linked": true}repeater:[](empty array)
css_var (string, optional)
- CSS custom property name
- Must start with
-- - Example:
--primary-color,--font-size-base - If omitted, field value is stored but NOT output to CSS
CSS Output:
:root {
--primary-color: 25, 121, 195;
}
description (string, optional)
- Short help text displayed below label
- 1-2 sentences max
- Example:
"Main brand color for buttons and links"
help_text (string, optional)
- Detailed help text in tooltip
- Click (i) icon to show
- Can be longer, include examples
- Example:
"Accepts HEX (#FF0000), RGB (255, 0, 0), or color names"
placeholder (string, optional)
- Input placeholder text
- For:
text,textarea,code,number - Example:
"1280px","Enter value..."
required (boolean, optional, default: false)
- Mark field as required
- Validation error if empty
- Red asterisk (*) in UI
important (boolean, optional, default: false)
- Add
!importantflag to CSS - Use sparingly (for overrides)
CSS Output:
:root {
--primary-color: 255, 0, 0 !important;
}
16. Presets - Pre-configured Templates
Presets allow theme developers to provide ready-to-use style templates that users can apply with one click. Think of them as “starter kits” for different design variations.
What are Presets?
- Read-only templates defined by theme developer in
settings.json - Quick styling - apply multiple settings at once
- Not saved as separate entities - they update Draft values
- User flow: Select → Preview → Apply → Edit (optional) → Publish
Preset vs Publication
| Feature | Preset | Publication |
|---|---|---|
| Source | Static JSON in theme | Dynamic DB records |
| Created by | Theme developer | User (via UI) |
| Modifiable | No (code only) | Yes (via UI) |
| Versioning | No | Yes (full history) |
| Purpose | Starting templates | Saved versions |
Configuration
Add presets array to your settings.json:
{
"version": "1.0",
"sections": [...],
"presets": [
{
"id": "dark-mode",
"name": "🌙 Dark Mode",
"description": "Complete dark color scheme with high contrast",
"settings": {
"colors.primary_color": "#3b82f6",
"colors.text_color": "rgb(243, 244, 246)",
"colors.background": "#0d0d0d",
"colors.link_color": "rgb(96, 165, 250)"
}
},
{
"id": "minimal-clean",
"name": "✨ Minimal Clean",
"description": "Clean light theme with generous spacing",
"settings": {
"layout.container_width": "1024px",
"layout.grid_gap": "1.5rem",
"colors.primary_color": "#ffffff"
}
}
]
}
Preset Structure
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | Unique preset identifier (kebab-case) |
name |
string | Yes | Display name in UI (can include emoji) |
description |
string | No | Short description (1-2 sentences) |
settings |
object | Yes | Key-value pairs of settings to apply |
Settings Format
Use dot notation for setting keys:
"settings": {
"section_code.field_code": "value"
}
Examples:
{
"colors.primary_color": "#1a1a1a",
"typography.font_family": "Roboto",
"layout.sidebar_width": "250px",
"spacing.container_padding": "2rem"
}
Important: Section code must match your sections[].id and field code must match sections[].settings[].id.
User Flow
- User opens Panel → sees “Apply Preset” dropdown
- Selects preset → expanded view shows:
- Description
- Warning: “This will change N settings”
- Clicks “Apply Preset”:
- If no unsaved changes → applies immediately
- If unsaved changes exist → shows dialog:
- Merge: Keep my changes, apply preset to unchanged fields
- Overwrite: Discard my changes, use all preset values
- Values applied to Draft → fields update, live preview refreshes
- User can:
- Continue editing fields
- Save Draft
- Publish changes
Best Practices
1. Provide 2-4 Presets Maximum
Too many options = decision paralysis. Focus on key variations:
- Light/Dark mode
- Minimal/Detailed style
- Accessibility preset
2. Use Descriptive Names
✅ Good: “🌙 Dark Mode”, “♿ High Contrast”, “✨ Minimal Clean” ❌ Bad: “Preset 1”, “Theme 2”, “Option B”
3. Write Clear Descriptions
Explain what it does and why user might want it:
{
"description": "Complete dark color scheme with high contrast for better readability in low-light conditions. Perfect for night browsing."
}
4. Only Include Essential Settings
Don’t change everything - focus on settings that define the preset’s character:
{
"dark-mode": {
"settings": {
// ✅ Core colors that define dark mode
"colors.background": "#0d0d0d",
"colors.text": "rgb(243, 244, 246)",
"colors.primary": "#3b82f6"
// ❌ Don't include unrelated settings like sidebar_width
}
}
}
5. Test All Presets
- Apply each preset on clean Draft
- Verify all values apply correctly
- Check live preview updates
- Test with existing unsaved changes (merge vs overwrite)
Complete Example
{
"version": "1.0",
"sections": [
{
"id": "colors",
"name": "Colors",
"settings": [
{
"id": "background",
"label": "Background Color",
"type": "color",
"default": "#ffffff",
"css_var": "--bg-color"
},
{
"id": "text",
"label": "Text Color",
"type": "color",
"default": "rgb(17, 24, 39)",
"css_var": "--text-color"
},
{
"id": "primary",
"label": "Primary Color",
"type": "color",
"default": "#1979c3",
"css_var": "--primary-color"
}
]
}
],
"presets": [
{
"id": "dark-mode",
"name": "🌙 Dark Mode",
"description": "Dark color scheme for night browsing with reduced eye strain",
"settings": {
"colors.background": "#0d0d0d",
"colors.text": "rgb(243, 244, 246)",
"colors.primary": "#3b82f6"
}
},
{
"id": "high-contrast",
"name": "♿ High Contrast",
"description": "Maximum contrast for accessibility and users with visual impairments",
"settings": {
"colors.background": "#000000",
"colors.text": "rgb(255, 255, 255)",
"colors.primary": "#ffff00"
}
},
{
"id": "light-minimal",
"name": "✨ Light Minimal",
"description": "Clean light theme with soft colors and minimal distractions",
"settings": {
"colors.background": "#fafafa",
"colors.text": "rgb(55, 65, 81)",
"colors.primary": "#6b7280"
}
}
]
}
GraphQL API
Query Presets:
query {
breezeThemeEditorPresets(storeId: 1, themeId: 21) {
id
name
description
}
}
Apply Preset:
mutation {
applyBreezeThemeEditorPreset(input: {
storeId: 1
themeId: 21
presetId: "dark-mode"
status: DRAFT
overwriteExisting: false # Merge mode
}) {
success
message
appliedCount
values {
sectionCode
fieldCode
value
}
}
}
Troubleshooting
Presets not showing in UI
- Check JSON syntax with
python3 -m json.tool settings.json - Verify
presetsis top-level array (same level assections) - Clear Magento cache:
bin/magento cache:clean
Preset applies but fields don’t update
- Check section/field codes match exactly (case-sensitive)
- Verify fields exist in
sections[].settings[] - Check browser console for JavaScript errors
“Setting not found” error
Error: colors.primary_color not found
Fix: Verify colors section exists with primary_color field:
{
"sections": [
{
"id": "colors", // Must match "colors" in preset
"settings": [
{
"id": "primary_color" // Must match "primary_color"
}
]
}
]
}
Color Palette System
Color palettes provide a centralized way to define and manage theme colors. Users can quickly select colors from predefined palettes when editing COLOR fields.
Palette Structure
Palettes are defined in the palettes section at the root level of settings.json:
{
"version": "1.0",
"sections": [...],
"palettes": {
"default": {
"id": "default",
"label": "Default Color Palette",
"description": "Professional color system",
"groups": {
"brand": {
"id": "brand",
"label": "Brand Colors",
"description": "Primary brand identity colors",
"colors": [
{
"id": "primary",
"label": "Primary",
"description": "Main brand color",
"css_var": "--color-brand-primary",
"default": "#1979c3"
}
]
}
}
}
}
}
Palette Properties
Palette Object
id(String, required) - Unique palette identifierlabel(String, required) - Display namedescription(String) - Palette descriptiongroups(Object, required) - Color groups
Group Object
id(String, required) - Unique group identifierlabel(String, required) - Display namedescription(String) - Group descriptioncolors(Array, required) - Color definitions
Color Object
id(String, required) - Unique color identifierlabel(String, required) - Display namedescription(String) - Color usage descriptioncss_var(String, required) - CSS variable name (e.g.,--color-brand-primary)default(String, required) - Default HEX color value
Complete Palette Example
{
"palettes": {
"default": {
"id": "default",
"label": "Default Color Palette",
"description": "Professional color system for theme customization",
"groups": {
"brand": {
"id": "brand",
"label": "Brand Colors",
"description": "Primary brand identity colors",
"colors": [
{
"id": "primary",
"label": "Primary",
"description": "Main brand color for buttons and key elements",
"css_var": "--color-brand-primary",
"default": "#1979c3"
},
{
"id": "secondary",
"label": "Secondary",
"description": "Supporting brand color",
"css_var": "--color-brand-secondary",
"default": "#111827"
},
{
"id": "accent",
"label": "Accent",
"description": "Highlight color for links",
"css_var": "--color-brand-accent",
"default": "#1d4ed8"
}
]
},
"neutral": {
"id": "neutral",
"label": "Neutral Colors",
"description": "Grayscale palette",
"colors": [
{
"id": "0",
"label": "White",
"description": "Pure white",
"css_var": "--color-neutral-0",
"default": "#ffffff"
},
{
"id": "900",
"label": "Gray 900",
"description": "Darkest gray",
"css_var": "--color-neutral-900",
"default": "#111827"
}
]
},
"state": {
"id": "state",
"label": "State Colors",
"description": "Semantic colors for UI feedback",
"colors": [
{
"id": "success",
"label": "Success",
"description": "Positive actions",
"css_var": "--color-state-success",
"default": "#10b981"
},
{
"id": "error",
"label": "Error",
"description": "Errors and warnings",
"css_var": "--color-state-error",
"default": "#ef4444"
}
]
}
}
}
}
}
Using Palettes in Color Fields
Reference a palette in COLOR field configuration:
{
"id": "text_color",
"label": "Text Color",
"type": "color",
"default": "#111827",
"css_var": "--text-color",
"palette": "default",
"description": "Main text color"
}
Result: Users will see color swatches from the “default” palette when editing this field.
Referencing Palette Colors
Users can select a palette color, which creates a CSS variable reference:
User Action: Click on “Primary” color from palette
Stored Value: --color-brand-primary
CSS Output:
:root {
--text-color: var(--color-brand-primary);
}
Benefits:
- ✅ Changing palette color updates all referencing fields
- ✅ Maintains color consistency across theme
- ✅ Easier theme customization with predefined schemes
Best Practices
1. Group Related Colors
"groups": {
"brand": {...}, // Primary brand colors
"neutral": {...}, // Grays and backgrounds
"state": {...}, // Success, error, warning
"accent": {...} // Highlights and special elements
}
2. Use Descriptive IDs
// ❌ Bad
"id": "color1"
// ✅ Good
"id": "primary"
3. Provide Clear Descriptions
{
"id": "primary",
"label": "Primary",
"description": "Main brand color for buttons and key elements",
"css_var": "--color-brand-primary",
"default": "#1979c3"
}
4. CSS Variable Naming Convention
--color-{group}-{id}
Examples:
--color-brand-primary
--color-neutral-900
--color-state-success
5. Recommended Neutral Scale
"neutral": {
"colors": [
{"id": "0", "default": "#ffffff"}, // White
{"id": "50", "default": "#f9fafb"}, // Lightest
{"id": "100", "default": "#f3f4f6"},
{"id": "200", "default": "#e5e7eb"},
{"id": "300", "default": "#d1d5db"},
{"id": "400", "default": "#9ca3af"},
{"id": "500", "default": "#6b7280"}, // Base
{"id": "600", "default": "#4b5563"},
{"id": "700", "default": "#374151"},
{"id": "800", "default": "#1f2937"},
{"id": "900", "default": "#111827"} // Darkest
]
}
Multiple Palettes
You can define multiple palettes for different color schemes:
{
"palettes": {
"default": {
"id": "default",
"label": "Light Theme Palette",
"groups": {...}
},
"dark": {
"id": "dark",
"label": "Dark Theme Palette",
"groups": {...}
},
"highcontrast": {
"id": "highcontrast",
"label": "High Contrast Palette",
"groups": {...}
}
}
}
Usage:
{
"id": "bg_color",
"type": "color",
"palette": "dark",
"css_var": "--bg-color"
}
Palette Color Format
Important: Palette colors always output in HEX format regardless of field’s format property:
/* Palette definition */
--color-brand-primary: #1979c3; /* Always HEX */
/* Field using palette reference */
--text-color: var(--color-brand-primary); /* Reference, not converted */
If a field has format: "rgb" but user selects a palette color, the output will be:
--my-field: var(--color-brand-primary); /* NOT converted to RGB */
Validation Rules
Built-in Validation
COLOR Type
{
"type": "color",
"default": "#FF0000"
}
- Rule: Must be HEX format
#RRGGBBor#RGB - Error: “Invalid color format. Expected HEX color (e.g. #FF0000)”
NUMBER/RANGE Type
{
"type": "number",
"min": "1",
"max": "12",
"default": "4"
}
- Rules:
- Must be numeric
- Value ≥
min(if specified) - Value ≤
max(if specified)
- Errors:
- “Value must be a number”
- “Value must be at least {min}”
- “Value must not exceed {max}”
TEXT/TEXTAREA Type
Length Validation:
{
"type": "text",
"minLength": 3,
"maxLength": 50
}
- Rules:
- Length ≥
minLength - Length ≤
maxLength
- Length ≥
- Errors:
- “Text must be at least {minLength} characters”
- “Text must not exceed {maxLength} characters”
Pattern Validation:
{
"type": "text",
"pattern": "^\\d+(px|rem|em|%)$",
"validationMessage": "Must be a valid CSS unit (e.g. 10px, 1rem)"
}
- Rule: Value must match regex
pattern - Error: Custom message from
validationMessage
Required Validation
{
"required": true
}
- Rule: Value cannot be empty
- Error: “Field {fieldCode} is required”
Custom Validation
For complex validation, use pattern + validationMessage:
Example: URL Validation
{
"id": "logo_url",
"type": "text",
"pattern": "^https?:\\/\\/.+",
"validationMessage": "Must be a valid URL starting with http:// or https://"
}
Example: Hex Color (alternative)
{
"id": "custom_hex",
"type": "text",
"pattern": "^#[0-9A-Fa-f]{6}$",
"validationMessage": "Must be a 6-digit HEX color (e.g. #FF0000)"
}
Theme Inheritance
Parent Theme Extension
Extend parent theme configuration:
Parent Theme (Parent/Theme/etc/theme_editor/settings.json):
{
"version": "1.0",
"sections": [
{
"id": "colors",
"name": "Colors",
"settings": [
{
"id": "primary_color",
"type": "color",
"default": "#1979c3",
"css_var": "--primary-color"
}
]
}
]
}
Child Theme (Child/Theme/etc/theme_editor/settings.json):
{
"version": "1.0",
"extends": "Parent/Theme",
"sections": [
{
"id": "colors",
"settings": [
{
"id": "secondary_color",
"type": "color",
"default": "#ff6b6b",
"css_var": "--secondary-color"
}
]
},
{
"id": "custom_section",
"name": "Custom Settings",
"settings": [...]
}
]
}
Result:
- Child inherits ALL parent sections and fields
- Child can ADD new sections
- Child can ADD fields to existing sections
- Child CANNOT override/remove parent fields
Inheritance Rules
- Sections: Merged by
id- Parent sections are included
- Child sections are added
- If
idmatches, settings are merged
- Settings: Merged by
id- Parent settings are included
- Child settings are added
- If
idmatches, child value is used (override)
- Values: Child can override parent defaults
- Even without redefining field
- Stored per theme in database
Best Practices
1. Naming Conventions
Section IDs:
- Lowercase, underscore-separated
- Descriptive:
colors,typography,layout,header,footer - Avoid generic names:
section1,misc
Field IDs:
- Lowercase, underscore-separated
- Be specific:
primary_button_colornotcolor1 - Include context:
header_bg_colornotbg_color
CSS Variables:
- Use semantic names:
--primary-colornot--color-1 - Follow convention:
--component-property-modifier--button-primary-bg--text-base-size--header-height-mobile
2. Section Organization
Logical Grouping:
{
"sections": [
{"id": "colors", "order": 1}, // Visual first
{"id": "typography", "order": 2}, // Then typography
{"id": "layout", "order": 3}, // Then structure
{"id": "header", "order": 4}, // Then components
{"id": "footer", "order": 5},
{"id": "advanced", "order": 99} // Advanced last
]
}
Section Size:
- 5-10 fields per section (ideal)
- Max 20 fields (split if larger)
- Use
descriptionto explain section purpose
3. Default Values
Always Provide Defaults:
{
"id": "primary_color",
"default": "#1979c3" // ✅ Good
}
Match CSS Defaults:
// _theme-variables.less
@primary-color: #1979c3;
{
"id": "primary_color",
"default": "#1979c3" // ✅ Matches LESS
}
Use Real Values:
{"default": "TBD"} // ❌ Bad
{"default": "#1979c3"} // ✅ Good
4. CSS Variables
Use Breeze Variables:
{
"id": "primary_color",
"css_var": "--primary" // ✅ Breeze standard
}
Breeze uses RGB format:
:root {
--primary: 25, 121, 195;
}
.button {
background: rgb(var(--primary));
border-color: rgba(var(--primary), 0.5);
}
Avoid Direct Colors:
{
"css_var": "--button-bg-hex" // ❌ Not Breeze style
}
5. Help Text
Description (short):
{
"description": "Main brand color for buttons and links"
}
Help Text (detailed):
{
"help_text": "This color is used for:\n- Primary buttons (Add to Cart, Checkout)\n- Text links\n- Focus states\n- Hover effects"
}
Examples in Help:
{
"help_text": "Accepts values like: 10px, 1rem, 2em, 5%"
}
6. Field Order
Visual Preview First:
{
"settings": [
{"id": "bg_color", "type": "color"}, // Visual
{"id": "text_color", "type": "color"}, // Visual
{"id": "padding", "type": "range"}, // Semi-visual
{"id": "custom_class", "type": "text"} // Technical last
]
}
7. Testing
Before Release:
- ✅ Test all field types render correctly
- ✅ Verify CSS output with
?breeze_theme_editor=1&debug=1 - ✅ Test default values match existing design
- ✅ Validate inheritance if using parent theme
- ✅ Check mobile/tablet responsiveness
- ✅ Test GraphQL queries work
- ✅ Verify draft/publish workflow
Common Issues:
- Missing
css_var→ field stores but doesn’t output CSS - Wrong
defaulttype → validation errors - Duplicate
id→ only last field shows - Missing
extends→ inheritance doesn’t work
Examples
Example 1: Complete Color Section
{
"id": "colors",
"name": "🎨 Colors",
"description": "Customize your theme colors",
"icon": "palette",
"order": 1,
"settings": [
{
"id": "primary_color",
"label": "Primary Color",
"type": "color",
"default": "#1979c3",
"css_var": "--primary",
"description": "Main brand color",
"help_text": "Used for buttons, links, and accents. Supports HEX format (#FF0000)"
},
{
"id": "secondary_color",
"label": "Secondary Color",
"type": "color",
"default": "#6c757d",
"css_var": "--secondary",
"description": "Secondary actions and elements"
},
{
"id": "success_color",
"label": "Success Color",
"type": "color",
"default": "#28a745",
"css_var": "--success",
"description": "Success messages and states"
},
{
"id": "error_color",
"label": "Error Color",
"type": "color",
"default": "#dc3545",
"css_var": "--error",
"description": "Error messages and validation"
},
{
"id": "text_color",
"label": "Text Color",
"type": "color",
"default": "#212529",
"css_var": "--text-color",
"description": "Main body text color"
},
{
"id": "link_color",
"label": "Link Color",
"type": "color",
"default": "#007bff",
"css_var": "--link-color",
"description": "Hyperlink color"
}
]
}
Example 2: Color Format Options (Breeze 2.0 vs 3.0)
{
"id": "color_formats",
"name": "🎨 Color Format Examples",
"description": "Different color format configurations",
"icon": "palette",
"order": 1,
"settings": [
{
"id": "modern_color_hex",
"label": "Modern Color (HEX)",
"type": "color",
"default": "#1979c3",
"css_var": "--modern-color",
"format": "hex",
"description": "Breeze 3.0 - outputs HEX format",
"help_text": "Use with: color: var(--modern-color)"
},
{
"id": "legacy_color_rgb",
"label": "Legacy Color (RGB)",
"type": "color",
"default": "#1979c3",
"css_var": "--legacy-color",
"format": "rgb",
"description": "Breeze 2.0 - outputs RGB format",
"help_text": "Use with: color: rgb(var(--legacy-color))"
},
{
"id": "auto_hex",
"label": "Auto-detect HEX",
"type": "color",
"default": "#ff5722",
"css_var": "--auto-hex",
"format": "auto",
"description": "Auto-detects HEX from default value"
},
{
"id": "auto_rgb",
"label": "Auto-detect RGB",
"type": "color",
"default": "255, 87, 34",
"css_var": "--auto-rgb",
"format": "auto",
"description": "Auto-detects RGB from default value"
},
{
"id": "no_format_with_default",
"label": "No Format Property (with default)",
"type": "color",
"default": "#4caf50",
"css_var": "--no-format-default",
"description": "Defaults to 'auto' → detects HEX"
},
{
"id": "no_format_no_default",
"label": "No Format Property (no default)",
"type": "color",
"css_var": "--no-format-no-default",
"description": "Defaults to 'hex' when no default exists"
}
]
}
Expected CSS Output:
:root {
--modern-color: #1979c3; /* format: hex */
--legacy-color: 25, 121, 195; /* format: rgb */
--auto-hex: #ff5722; /* format: auto (detected HEX) */
--auto-rgb: 255, 87, 34; /* format: auto (detected RGB) */
--no-format-default: #4caf50; /* no format + default → auto → HEX */
--no-format-no-default: #somevalue; /* no format + no default → hex */
}
Example 3: Complete Configuration with Palette and Presets
This example shows a full settings.json with color palette, multiple field types, and presets:
{
"version": "1.0",
"sections": [
{
"id": "colors",
"name": "🎨 Colors",
"description": "Theme color customization",
"icon": "palette",
"order": 1,
"settings": [
{
"id": "text_color",
"label": "Text Color",
"type": "color",
"default": "#111827",
"description": "Main text color across the site",
"css_var": "--base-color",
"palette": "default",
"format": "hex"
},
{
"id": "primary_button_color",
"label": "Primary Button Color",
"type": "color",
"default": "#1979c3",
"description": "Color for primary action buttons",
"css_var": "--button-primary-bg",
"palette": "default",
"format": "hex"
},
{
"id": "link_color",
"label": "Link Color",
"type": "color",
"default": "#1d4ed8",
"description": "Clickable links color",
"css_var": "--link-color",
"palette": "default",
"format": "hex"
}
]
}
],
"palettes": {
"default": {
"id": "default",
"label": "Default Color Palette",
"description": "Professional color system for theme customization",
"groups": {
"brand": {
"id": "brand",
"label": "Brand Colors",
"description": "Primary brand identity colors",
"colors": [
{
"id": "primary",
"label": "Primary",
"description": "Main brand color for buttons and key elements",
"css_var": "--color-brand-primary",
"default": "#1979c3"
},
{
"id": "secondary",
"label": "Secondary",
"description": "Supporting brand color for headers and emphasis",
"css_var": "--color-brand-secondary",
"default": "#111827"
},
{
"id": "accent",
"label": "Accent",
"description": "Highlight color for links and interactive elements",
"css_var": "--color-brand-accent",
"default": "#1d4ed8"
}
]
},
"neutral": {
"id": "neutral",
"label": "Neutral Colors",
"description": "Grayscale palette for backgrounds, borders, and text",
"colors": [
{
"id": "0",
"label": "White",
"description": "Pure white",
"css_var": "--color-neutral-0",
"default": "#ffffff"
},
{
"id": "100",
"label": "Gray 100",
"description": "Very light gray",
"css_var": "--color-neutral-100",
"default": "#f3f4f6"
},
{
"id": "500",
"label": "Gray 500",
"description": "Base gray",
"css_var": "--color-neutral-500",
"default": "#6b7280"
},
{
"id": "900",
"label": "Gray 900",
"description": "Darkest gray - almost black",
"css_var": "--color-neutral-900",
"default": "#111827"
}
]
},
"state": {
"id": "state",
"label": "State Colors",
"description": "Semantic colors for UI feedback",
"colors": [
{
"id": "success",
"label": "Success",
"description": "Positive actions and confirmations",
"css_var": "--color-state-success",
"default": "#10b981"
},
{
"id": "error",
"label": "Error",
"description": "Errors and destructive actions",
"css_var": "--color-state-error",
"default": "#ef4444"
}
]
}
}
}
},
"presets": [
{
"id": "dark-mode",
"name": "🌙 Dark Mode",
"description": "Complete dark color scheme with high contrast",
"settings": {
"colors.text_color": "#f3f4f6",
"colors.primary_button_color": "#3b82f6",
"colors.link_color": "#60a5fa"
}
},
{
"id": "high-contrast",
"name": "♿ High Contrast",
"description": "Maximum contrast for accessibility",
"settings": {
"colors.text_color": "#000000",
"colors.primary_button_color": "#dc2626",
"colors.link_color": "#0000ff"
}
}
]
}
Key Features:
- ✅ Color fields with
palette: "default"property - ✅ Full palette definition with 3 groups (brand, neutral, state)
- ✅ Users can click palette colors for quick selection
- ✅ Two presets that apply multiple color changes at once
- ✅ All colors use
format: "hex"for Breeze 3.0 compatibility
User Experience:
- User opens Theme Editor
- Clicks on “Text Color” field
- Sees color picker + palette swatches
- Can click any palette color (e.g., “Gray 900”)
- Field value becomes
--color-neutral-900(palette reference) - Or user can enter custom HEX color
CSS Output:
:root {
/* Palette colors (only if modified from defaults) */
--color-brand-primary: #1979c3;
--color-neutral-900: #111827;
/* Field values */
--base-color: var(--color-neutral-900); /* User selected from palette */
--button-primary-bg: #1979c3; /* User entered custom HEX */
--link-color: var(--color-brand-accent); /* User selected from palette */
}
Example 4: Typography Section
{
"id": "typography",
"name": "✍️ Typography",
"description": "Font settings",
"icon": "text_fields",
"order": 2,
"settings": [
{
"id": "body_font",
"label": "Body Font",
"type": "font_picker",
"default": "Open Sans",
"css_var": "--font-family-base",
"options": [
{"value": "Open Sans", "label": "Open Sans"},
{"value": "Roboto", "label": "Roboto"},
{"value": "Lato", "label": "Lato"},
{"value": "Georgia", "label": "Georgia (Serif)"}
],
"description": "Main text font"
},
{
"id": "heading_font",
"label": "Heading Font",
"type": "font_picker",
"default": "Montserrat",
"css_var": "--font-family-heading",
"options": [
{"value": "Montserrat", "label": "Montserrat"},
{"value": "Playfair Display", "label": "Playfair Display"},
{"value": "Raleway", "label": "Raleway"}
],
"description": "Headings font (H1-H6)"
},
{
"id": "base_font_size",
"label": "Base Font Size",
"type": "range",
"default": "16",
"min": "12",
"max": "20",
"step": "1",
"unit": "px",
"css_var": "--font-size-base",
"description": "Body text size"
},
{
"id": "line_height",
"label": "Line Height",
"type": "range",
"default": "1.5",
"min": "1",
"max": "2",
"step": "0.1",
"css_var": "--line-height-base",
"description": "Text line spacing"
}
]
}
Example 3: Layout Section with Validation
{
"id": "layout",
"name": "📐 Layout",
"description": "Page structure settings",
"icon": "view_column",
"order": 3,
"settings": [
{
"id": "container_width",
"label": "Container Width",
"type": "select",
"default": "1280px",
"css_var": "--container-max-width",
"options": [
{"value": "960px", "label": "Narrow (960px)"},
{"value": "1140px", "label": "Standard (1140px)"},
{"value": "1280px", "label": "Wide (1280px)"},
{"value": "1536px", "label": "Extra Wide (1536px)"},
{"value": "100%", "label": "Full Width"}
],
"description": "Maximum content width"
},
{
"id": "custom_container_width",
"label": "Custom Container Width",
"type": "text",
"placeholder": "e.g. 1400px",
"pattern": "^\\d+(px|rem|em|%)$",
"validationMessage": "Must be a valid CSS unit (e.g. 1400px, 90rem)",
"description": "Override with custom value",
"help_text": "Leave empty to use predefined width from dropdown above"
},
{
"id": "grid_columns",
"label": "Product Grid Columns",
"type": "number",
"default": "4",
"min": "2",
"max": "6",
"step": "1",
"css_var": "--product-grid-columns",
"description": "Products per row (desktop)"
},
{
"id": "grid_gap",
"label": "Grid Gap",
"type": "range",
"default": "24",
"min": "0",
"max": "48",
"step": "4",
"unit": "px",
"css_var": "--product-grid-gap",
"description": "Space between products"
}
]
}
Example 4: Advanced Section
{
"id": "advanced",
"name": "⚙️ Advanced",
"description": "Custom code and advanced settings",
"icon": "code",
"order": 99,
"settings": [
{
"id": "custom_css",
"label": "Custom CSS",
"type": "textarea",
"default": "/* Add your custom styles here */",
"rows": 15,
"description": "Additional CSS code",
"help_text": "Will be injected into theme CSS. Use with caution."
},
{
"id": "enable_animations",
"label": "Enable Animations",
"type": "toggle",
"default": true,
"css_var": "--animations-enabled",
"description": "Smooth transitions and effects"
},
{
"id": "animation_duration",
"label": "Animation Speed",
"type": "range",
"default": "300",
"min": "0",
"max": "1000",
"step": "50",
"unit": "ms",
"css_var": "--animation-duration",
"description": "How fast animations play"
}
]
}
Example 5: Social Links
{
"id": "social",
"name": "🔗 Social Media",
"description": "Social media links",
"icon": "share",
"order": 10,
"settings": [
{
"id": "social_links",
"label": "Social Media Profiles",
"type": "social_links",
"default": "{}",
"platforms": [
{"code": "facebook", "label": "Facebook", "icon": "f"},
{"code": "twitter", "label": "Twitter / X", "icon": "𝕏"},
{"code": "instagram", "label": "Instagram", "icon": "📷"},
{"code": "linkedin", "label": "LinkedIn", "icon": "in"},
{"code": "youtube", "label": "YouTube", "icon": "▶"},
{"code": "pinterest", "label": "Pinterest", "icon": "P"}
],
"description": "Enter your social media profile URLs",
"help_text": "Leave empty to hide a platform. Links will appear in footer."
},
{
"id": "show_social_icons",
"label": "Show Social Icons",
"type": "toggle",
"default": true,
"description": "Display social media icons in footer"
}
]
}
Troubleshooting
Field Not Showing
Problem: Field doesn’t appear in Theme Editor panel
Solutions:
- ✅ Check
idis unique within section - ✅ Verify JSON syntax is valid
- ✅ Clear cache:
bin/magento cache:clean - ✅ Check browser console for JS errors
- ✅ Verify
typeis supported
CSS Not Generated
Problem: Field value doesn’t appear in CSS output
Solutions:
- ✅ Add
css_varproperty - ✅ Verify
css_varstarts with-- - ✅ Check value is not empty
- ✅ Verify value is not same as
default - ✅ View CSS output:
?breeze_theme_editor=1&breeze_theme_editor_debug=1
Validation Errors
Problem: Cannot save field value
Solutions:
- ✅ Check
min/maxfor number/range - ✅ Verify
patternregex is correct (escape backslashes:\\d) - ✅ Check
requiredfields are filled - ✅ For color: use HEX format
#RRGGBB - ✅ Check browser console for detailed error
Inheritance Not Working
Problem: Parent theme fields not showing
Solutions:
- ✅ Verify
extendsvalue matches parent theme path - ✅ Check parent theme has
etc/theme_editor/settings.json - ✅ Clear cache after changing
extends - ✅ Verify parent theme is registered in Magento
Performance Issues
Problem: Panel loads slowly with many fields
Solutions:
- ✅ Split large sections (max 20 fields per section)
- ✅ Use
orderto organize sections logically - ✅ Avoid unnecessary
help_text(loads on demand) - ✅ Optimize field types (use
selectinstead oftextfor predefined values)
FAQ
Can I add custom field types?
No - currently only built-in types are supported. Planned for v2.0.
Can I use media files (images)?
Not yet - image_upload field type is planned (Task 1.1.3).
How do I test my configuration?
- Create
settings.json - Clear cache:
bin/magento cache:clean - Open frontend with
?breeze_theme_editor=1 - Check panel on right side
Where are values stored?
- Database table:
breeze_theme_editor_value - Per theme + per store + per status (draft/published)
- Accessible via GraphQL
Can I export/import settings?
Yes - via GraphQL mutations:
breezeThemeEditorExportSettingsbreezeThemeEditorImportSettings
How do I create presets?
Add presets array to your settings.json:
{
"version": "1.0",
"sections": [...],
"presets": [
{
"id": "dark-mode",
"name": "🌙 Dark Mode",
"description": "Dark color scheme for night browsing",
"settings": {
"colors.primary_color": "#3b82f6",
"colors.text_color": "rgb(243, 244, 246)",
"colors.background": "#0d0d0d"
}
}
]
}
See Section 16: Presets for complete documentation.
Version History
- 1.1 (2026-01-13) - Presets Feature
- Added Section 16: Presets documentation
- 3 new field types: IMAGE_UPLOAD, SPACING, REPEATER (v1.0.5)
- Preset UI implementation
- Updated FAQ with preset examples
- 1.0 (2026-01-09) - Initial documentation
- 12 field types documented
- Validation rules
- Theme inheritance
- Examples and best practices
Support
- Issues: GitHub Issues
- Documentation: This file
- GraphQL API: See
etc/schema.graphqls
Happy theming! 🎨