| 1 |
# SITE PARTS (Pro) |
| 2 |
If the user asks about a header, footer, 404, single, archive, or search-results, that content lives in a SEPARATE document — not the current page. Call `elementor/list-site-parts` (or `elementor/manage-site-parts` to create) first to get the correct `post_id`, then invoke this tool on that id. This capability requires Elementor Pro; skip when the site-parts tools are not registered. Read [elementor://wordpress/best-practices] for repeating-layout patterns (one single template driven by dynamic data — not N duplicated pages). |
| 3 |
|
| 4 |
# RESOURCES (Read before use) |
| 5 |
- [elementor://wordpress/best-practices] - Opinionated WordPress patterns: repeating layouts, condition scoping, Post Content placement, dynamic tags |
| 6 |
- [elementor://global-classes] - Reusable CSS classes from the active kit, ordered from highest to lowest CSS priority; check FIRST before adding inline styles |
| 7 |
- [elementor://global-variables] - Design tokens from the active kit; use labels in CSS as `var(--label)` or `var(--label, fallback)`; ONLY variables listed here are valid |
| 8 |
- [elementor://interactions/schema] - Native interaction item shape and allowed enums for `interactions` |
| 9 |
- [elementor/list-widget-schemas?summary=true] - Available widget types this tool can configure |
| 10 |
- `elementor/list-assets` - Images, SVG icons, and videos (via `type: "video"`) already in the Media Library; call before placing an `e-image` (for real dimensions and `srcset`), always before an `e-svg` (which needs an uploaded asset to render), and before `e-self-hosted-video` / `e-background-video` when using a library video |
| 11 |
- `elementor/list-components` - Discover reusable widget compositions and the component capabilities available for the current license tier (see COMPONENTS) |
| 12 |
|
| 13 |
# TOOL SUPPORT |
| 14 |
Discover valid `widget_type` values via `elementor/list-widget-schemas?summary=true`. Any type it lists is workable through the same uniform contract (`element_config`, `style`, `classes`, `interactions`); anything it does not list must be edited manually in the Elementor editor. |
| 15 |
|
| 16 |
# WORKFLOW |
| 17 |
1. Check/create global variables via `elementor/manage-global-variable` |
| 18 |
2. Check/create global classes via `elementor/manage-classes` |
| 19 |
3. When component capabilities permit, prefer reusable components for cohesive structures that are repeated or likely to be reused |
| 20 |
4. Build composition (THIS TOOL) - minimal inline styles; attach existing global classes via `classes` |
| 21 |
5. Use returned element IDs for subsequent configuration changes |
| 22 |
|
| 23 |
## CRITICAL: Avoid write conflicts after build-composition |
| 24 |
`manage-elements` is a **read → modify → write** operation on the current document. If you call it after `build-composition` using element IDs from a **prior** `get-page-structure` read, it will restore the old tree and silently overwrite what `build-composition` just saved. |
| 25 |
|
| 26 |
**Rules:** |
| 27 |
- Only use element IDs from the `resolved_xml` in **this tool's response** for any follow-up `manage-elements` calls — never IDs from an earlier read. |
| 28 |
- Prefer adding pseudo-states (`&:hover`, `&:focus`, `&:active`) and breakpoints (`@media (--mobile)`) **inline in the `style` string** during composition, eliminating the need for a follow-up `manage-elements` call entirely. |
| 29 |
|
| 30 |
# COMPONENTS (only when explicitly requested) |
| 31 |
Elementor components are reusable widget compositions; global classes are reusable styles. Do not substitute one for the other. |
| 32 |
|
| 33 |
Call `elementor/list-components` before building a repeated, named, or otherwise reusable structure. Use its `capabilities` response to decide the flow: |
| 34 |
- When `can_add_to_page` is true, reuse a matching component whose `overridable_props` cover the required customization. |
| 35 |
- When no suitable component exists and `can_create` is true, create one through `elementor/manage-component`, then place it. |
| 36 |
- When the required capability is false, build with raw widgets. Do not claim that a component was created or placed. |
| 37 |
|
| 38 |
Place a component as the self-closing leaf tag `<e-component configuration-id="my-hero"/>`. Configure it through `element_config` with `{ component_id, overrides? }`. Override values use the plain-value shape from `origin_prop_schema`; only listed override keys are valid. Components can be mixed with raw widgets. |
| 39 |
|
| 40 |
# XML STRUCTURE |
| 41 |
- Use widget tags: `<e-button configuration-id="btn1"></e-button>` |
| 42 |
- Containers: "e-flexbox", "e-div-block", "e-tabs" |
| 43 |
- **Every element MUST have a unique "configuration-id" attribute** |
| 44 |
- No attributes, classes, IDs, or text nodes in XML |
| 45 |
- Pass the raw XML tags directly as the `xml_structure` string. Do NOT wrap the value in `<![CDATA[ ... ]]>`, code fences, quotes, or any other wrapper — JSON string escaping is the only escaping needed. Wrapping in CDATA turns the whole payload into text and the tool will reject it with `empty_composition`. |
| 46 |
|
| 47 |
## NESTED ELEMENTS |
| 48 |
Some elements have internal tree structures (nesting). When using these elements, you MUST build the FULL tree in XML. |
| 49 |
- Check `llm_guidance.nesting` in widget schemas for structure requirements |
| 50 |
- `llm_guidance.required_direct_children` lists element types that must appear as direct child tags in XML (from widget defaults) |
| 51 |
- `allowed_child_types` lists which element types can be nested inside |
| 52 |
- `allowed_parents` lists which element types this element can be placed inside |
| 53 |
|
| 54 |
# CONFIGURATION |
| 55 |
- Map configuration-id → element_config (props) + style (plain CSS string) + classes (global class labels) |
| 56 |
- **element_config uses plain JSON values** — send scalars and objects exactly as shown in the widget schema. |
| 57 |
- **Prop names must come from the widget schema (use elementor/get-widget-schema tool with the widget type). Unknown/unsupported keys are NOT rejected — they are skipped and reported in `warnings`, and the build still succeeds. Prefer valid keys so props are not silently dropped.** |
| 58 |
- style is a plain CSS string (e.g. `color: red; padding-top: 1rem;`); supports `&:hover`/`&:focus`/`&:active` nesting and `@media(--breakpoint)` blocks (e.g. `@media(--mobile) { font-size: 2rem; }`). The server converts most declarations into native atomic styles. See **Style conversion** below. |
| 59 |
- classes is configuration-id → array of existing global class **labels** from [elementor://global-classes] |
| 60 |
- LINKS: a `link` prop is valid only when the target widget's schema (via `elementor/get-widget-schema`) includes a `link` property. On widgets without it, `link` is skipped and reported in `warnings` (the composition still builds) — wrap the element in a linkable container instead. Plain link shape: `{ "destination": "https://example.com", "isTargetBlank": true, "tag": "a" }` |
| 61 |
- Check `llm_guidance.default_settings` in widget schemas — omit only keys listed there from element_config unless the user explicitly asks to change them |
| 62 |
|
| 63 |
### Style conversion |
| 64 |
The server converts most CSS into **native atomic styles** (breakpoint variants, pseudo-states). Some value shapes fall back to `custom_css`; `animation` and `animation-*` are dropped. |
| 65 |
|
| 66 |
**When easy, prefer native-friendly shapes** (fallbacks are fine when the design needs them): |
| 67 |
- Breakpoints: `@media(--mobile)` — not `@media (max-width: 768px)` |
| 68 |
- Gap: single value `gap: 1rem` — not two-value `gap: 1rem 2rem` / `row-gap` |
| 69 |
- Borders: shorthand `border` / `border-width` — per-side `border-color` / `border-style` may fall back |
| 70 |
- Border-radius: simple values — not elliptical slash form (`10px / 20px`) |
| 71 |
- Transform: `rotate()` / `scale()` / `translate()` — not `matrix()`, `skew()`, `perspective`, `rotate3d` |
| 72 |
- Transition: property list — easing and delay may be dropped |
| 73 |
- Box-shadow: literal values (fully supported) — not `var(...)` inside the shadow |
| 74 |
- Font family & `var()`: one Google Font or one kit variable label — see GLOBAL VARIABLES |
| 75 |
|
| 76 |
**`padding` / `margin` shorthands are supported** — use them; do not split into longhand unnecessarily. |
| 77 |
|
| 78 |
## element_config FORMAT |
| 79 |
Match the widget schema shape: |
| 80 |
- **string / enum / url**: plain string (`"h2"`, `"https://example.com"`) |
| 81 |
- **number**: plain number (`42`) |
| 82 |
- **boolean**: plain boolean (`true`) |
| 83 |
- **text** (`title` on `e-heading`, `paragraph` on `e-paragraph`, `text` on `e-button`): plain string (`"Welcome"`). May contain inline HTML tags for text styling. |
| 84 |
- Example: `"paragraph": "<strong>Contact support</strong> for a <s>free</s> discounted quote — <em>limited time</em> only."` |
| 85 |
- **dynamic** (where schema allows): `{ "name": "<tag from elementor://dynamic-tags>", "settings": { ... } }` — settings use plain values per the tag schema; omit `group` |
| 86 |
- **image**: two forms, `id` and `url` are mutually exclusive — send one, not both: |
| 87 |
- Library asset (from `elementor/list-assets` tool): `{ "src": { "id": 123 }, "size": "full" }`. |
| 88 |
- External URL: `{ "src": { "url": "https://example.com/photo.jpg" }, "size": "full" }` — works. If no library asset fits and no on-brand external image is available, tell the user which images to upload. |
| 89 |
- **svg** (the `svg` prop on `e-svg`): `{ "id": <attachment id from elementor/list-assets with type: "svg"> }`. An external URL on `e-svg` renders an empty div. If no uploaded SVG exists, ask the user to upload one, otherwise omit the icon or use a text label — never fabricate an id. |
| 90 |
- **video** (the `source` prop on `e-self-hosted-video` and `e-background-video`): two forms, `id` and `url` are mutually exclusive — send one, not both: |
| 91 |
- Library asset (from `elementor/list-assets` with `type: "video"`): `{ "id": 123 }` |
| 92 |
- External URL: `{ "url": "https://example.com/clip.mp4" }` |
| 93 |
- NEVER put a raw video URL on a text, link, or `href` prop — a video always goes into `source` on a video widget. |
| 94 |
|
| 95 |
## GLOBAL VARIABLES |
| 96 |
Read [elementor://global-variables] before styling. Create or update via `elementor/manage-global-variable`. Use variable **labels** from that list — not internal ids. |
| 97 |
|
| 98 |
**In `style` (raw CSS):** reference by label only: |
| 99 |
- `color: var(--wc26-gold)` or `color: var(--wc26-gold, #C6A15B)` |
| 100 |
- `font-family: var(--font-heading)` or `font-size: var(--spacing-lg, 1.5rem)` |
| 101 |
- Literal `font-family` values MUST be a single Google Font family name (e.g. `Playfair Display`). NEVER pass fallback stacks (`Inter, sans-serif`) or generic families as the primary value. |
| 102 |
- Do NOT use the internal `e-gv-` id prefix (e.g. `var(--e-gv-wc26-gold)` is wrong; use `var(--wc26-gold)`) |
| 103 |
- Unrecognized variable references fall back to `custom_css` |
| 104 |
|
| 105 |
## GLOBAL CLASSES |
| 106 |
Read [elementor://global-classes] before composing. Create or update via `elementor/manage-classes`. Use `elementor/reorder-classes` when conflicting global class declarations need a priority change. Use class **labels** from that list — not internal ids. |
| 107 |
|
| 108 |
**In `classes` (reference-only):** attach existing global classes by label: |
| 109 |
- Map configuration-id → array of labels (e.g. `"Section Title": ["hero-heading", "text-muted"]`) |
| 110 |
- Create or update classes with `elementor/manage-classes` before referencing them here |
| 111 |
- Global classes are prepended before any local styles from `style`; local styles still win on conflicts |
| 112 |
|
| 113 |
# DYNAMIC TAGS |
| 114 |
- A value can be made dynamic wherever the widget schema allows a dynamic variant (often a union on the prop or a nested field such as an image's `src`). |
| 115 |
- Put the plain dynamic object at that node, in place of the static variant. Read [elementor://dynamic-tags] for allowed tag names and each tag's settings schema. |
| 116 |
- Plain dynamic shape: `{ "name": "<allowed tag>", "settings": { ... } }` |
| 117 |
- Example (image `src`): `"image": { "src": { "name": "<image tag>", "settings": { ... } }, "size": "full" }` |
| 118 |
- The tag's categories must intersect the categories declared by the field (visible in the widget schema's dynamic branch). Pick a tag from [elementor://dynamic-tags] whose category list overlaps. A category mismatch returns an error for that field and skips merging it. |
| 119 |
- Do NOT send `group` (resolved automatically). Populate `settings` strictly per the tag's schema; use `{}` only when it has none. |
| 120 |
|
| 121 |
Note about configuration ids: These names are visible to the end-user, make sure they make sense, related and relevant. |
| 122 |
|
| 123 |
# DESIGN PHILOSOPHY: CONTEXT-DRIVEN CREATIVITY |
| 124 |
|
| 125 |
**Use the user's context aggressively.** Business type, brand personality, target audience, and purpose should drive every design decision. A law firm needs gravitas; a children's app needs playfulness. Don't default to generic. |
| 126 |
|
| 127 |
## SIZING: DEFAULT IS NO SIZE (CRITICAL) |
| 128 |
|
| 129 |
**DO NOT specify height or width unless you have a specific visual reason.** |
| 130 |
|
| 131 |
Flexbox and CSS already handle sizing automatically: |
| 132 |
- Containers grow to fit their content |
| 133 |
- Flex children distribute space via flex properties, not width/height |
| 134 |
- Text elements size to their content |
| 135 |
|
| 136 |
WHEN TO SPECIFY SIZE: |
| 137 |
- min-height on ROOT section for viewport-spanning hero (use min-height, NOT height) |
| 138 |
- max-width for contained content areas (e.g., max-width: 60rem) |
| 139 |
- Explicit aspect ratios for media containers |
| 140 |
|
| 141 |
NEVER SPECIFY: |
| 142 |
- height on nested containers (causes overflow) |
| 143 |
- width on flex children (use flex-basis or gap instead) |
| 144 |
- 100vh on anything except root-level sections |
| 145 |
- Any size "just to be safe" - if unsure, OMIT IT |
| 146 |
|
| 147 |
vh units are VIEWPORT-relative. Nested 100vh inside 100vh = 200vh overflow. |
| 148 |
|
| 149 |
GOOD: `<e-flexbox>content naturally sizes</e-flexbox>` |
| 150 |
BAD: `<e-flexbox style="height:100vh"><e-div-block style="height:100vh">overflow</e-div-block></e-flexbox>` |
| 151 |
|
| 152 |
## Layout Variety (Break the Template) |
| 153 |
- AVOID: Full-width 100vh hero → three columns → testimonials → CTA (every AI does this) |
| 154 |
- VARY heights: Use auto-height sections with generous padding (6rem+). Let content breathe |
| 155 |
- VARY widths: Not everything spans full width. Use contained sections (max-width: 960px) mixed with edge-to-edge |
| 156 |
- ASYMMETRIC grids: 2:1, 1:3, offset layouts. Avoid equal column widths |
| 157 |
- Negative space as design element: Large margins create focus and sophistication |
| 158 |
- Break alignment intentionally: Offset headings, overlapping elements, broken grids |
| 159 |
|
| 160 |
## Visual Depth & Effects |
| 161 |
- Layer elements: Overlapping cards, text over images, floating elements |
| 162 |
- Subtle shadows with color tint (not pure black): `box-shadow: 0 20px 60px rgba(<brand-color-here>, 0.15)` |
| 163 |
- Gradient overlays on images for text readability |
| 164 |
- Border radius variation: Mix sharp (0) and soft (1rem+) corners purposefully |
| 165 |
- Backdrop blur for glassmorphism where appropriate |
| 166 |
- Micro-interactions via CSS: hover transforms, transitions (0.3s ease) |
| 167 |
|
| 168 |
## Typography with Character |
| 169 |
- Display fonts for headlines (from user's brand or contextually appropriate) |
| 170 |
- Size contrast: 4rem+ headlines vs 1rem body. Make hierarchy unmistakable |
| 171 |
- Letter-spacing: Tight for large headlines (-0.02em), loose for small caps (0.1em) |
| 172 |
- Line-height: Tight for headlines (1.1), generous for body (1.6-1.8) |
| 173 |
- Text decoration: Underlines, highlights, gradient text for emphasis |
| 174 |
|
| 175 |
## Color with Purpose |
| 176 |
- Extract palette from user context (brand colors, industry norms, mood) |
| 177 |
- 60-30-10 rule: dominant, secondary, accent |
| 178 |
- Tinted neutrals over pure grays: warm (#faf8f5, #2d2a26) or cool (#f5f7fa, #1e2430) |
| 179 |
- Color blocking: Large colored sections create visual rhythm |
| 180 |
- Gradient directions: Diagonal (135deg, 225deg) feel more dynamic than vertical |
| 181 |
|
| 182 |
## Spacing Strategy |
| 183 |
- Section padding: 6rem-10rem vertical, creating breathing room |
| 184 |
- Rhythm variation: Tight groups (2rem) with generous gaps between (6rem) |
| 185 |
- Use rem/em exclusively for responsive scaling |
| 186 |
- Generous padding on CTAs: min 1rem 2.5rem |
| 187 |
|
| 188 |
# INTERACTIONS |
| 189 |
Attach element interactions via the `interactions` parameter — a record mapping `configuration-id` → array of native-shape interaction items. Read [elementor://interactions/schema] for the full shape and allowed enum values. Send `[]` for a `configuration-id` to clear its interactions. |
| 190 |
|
| 191 |
# HARD CONSTRAINTS |
| 192 |
- Variables ONLY from [elementor://global-variables]; reference **labels** in `style` as `var(--label)` — the `e-gv-` prefix is internal only |
| 193 |
- Classes ONLY from [elementor://global-classes]; reference **labels** in `classes` — internal `g-` ids must not be sent in `classes` |
| 194 |
- SVG widgets require an uploaded attachment: discover one via `elementor/list-assets` with `type: "svg"` and reference it by `id`. External URLs on `e-svg` render an empty div. When none exists, ask the user to upload, otherwise omit the icon or use a text label. |
| 195 |
- Check `llm_guidance` in widget schemas (`default_styles`, nesting, required children) |
| 196 |
|
| 197 |
# MODE |
| 198 |
Redesigning an existing parent? Use `mode: 'replace_children'` with the parent's id — one call replaces its children. Default `'append'` keeps existing content. |
| 199 |
- `append` (default): Insert new elements as children of `parent_id`, preserving existing children. |
| 200 |
- `replace_children`: Remove all direct children of `parent_id` first, then insert new elements. The response includes `removed_element_ids` listing what was removed. |
| 201 |
- When `parent_id: 'document'` + `mode: 'replace_children'`, all top-level elements are removed — use this to redesign the whole page. |
| 202 |
|
| 203 |
# PARAMETERS |
| 204 |
- **post_id**: WordPress post ID of the document to mutate |
| 205 |
- **xml_structure**: Valid XML with configuration-id attributes on every element |
| 206 |
- **element_config**: configuration-id → plain widget settings (see PLAIN element_config FORMAT). For `<e-component>` config-ids the value is `{ component_id, overrides? }` (see COMPONENTS section). |
| 207 |
- **style**: configuration-id → plain CSS string (e.g. `"color: red; padding-top: 1rem;"`). Supports `&:hover`/`&:focus`/`&:active` nesting and `@media(--breakpoint)` blocks (e.g. `@media(--mobile)`). Variables by **label** via `var(--label)` |
| 208 |
- **classes**: configuration-id → list of existing global class **labels** to attach |
| 209 |
- **interactions**: configuration-id → array of native-shape interaction items (see INTERACTIONS section; read [elementor://interactions/schema] for allowed values) |
| 210 |
- **parent_id**: ID of the parent container (omit to insert at document root) |
| 211 |
- **mode**: `'append'` (default) or `'replace_children'` — see MODE section above |
| 212 |
- **dry_run**: If true, validate and return resolved tree without persisting |
| 213 |
|
| 214 |
# EXAMPLE |
| 215 |
Section with heading + button (NO explicit heights - content sizes naturally): |
| 216 |
```json |
| 217 |
{ |
| 218 |
"post_id": 123, |
| 219 |
"xml_structure": "<e-flexbox configuration-id=\"Main Section\"><e-heading configuration-id=\"Section Title\"></e-heading><e-button configuration-id=\"Call to Action\"></e-button></e-flexbox>", |
| 220 |
"element_config": { |
| 221 |
"Section Title": { |
| 222 |
"tag": "h2", |
| 223 |
"title": "Welcome" |
| 224 |
} |
| 225 |
}, |
| 226 |
"style": { |
| 227 |
"Main Section": "padding: 6rem 4rem; background: linear-gradient(135deg, #faf8f5 0%, #f0ebe4 100%); @media(--mobile) { padding: 3rem 1.5rem; }", |
| 228 |
"Section Title": "font-size: 3.5rem; color: #2d2a26; &:hover { color: var(--wc26-gold); } @media(--mobile) { font-size: 2.25rem; } @media(--tablet) { font-size: 2.75rem; }" |
| 229 |
} |
| 230 |
} |
| 231 |
``` |
| 232 |
Note: No height/width specified on any element - flexbox handles layout automatically. |
| 233 |
|
| 234 |
# FURTHER INSTRUCTIONS |
| 235 |
Element IDs in the returned XML represent actual widgets. Use these IDs for subsequent styling or configuration changes. |
| 236 |
|
| 237 |
If components were requested or used, verify that each was created or placed successfully before reporting completion. |
| 238 |
|