# SITE PARTS (Pro) 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). # RESOURCES (Read before use) - [elementor://wordpress/best-practices] - Opinionated WordPress patterns: repeating layouts, condition scoping, Post Content placement, dynamic tags - [elementor://global-classes] - Reusable CSS classes from the active kit, ordered from highest to lowest CSS priority; check FIRST before adding inline styles - [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 - [elementor://interactions/schema] - Native interaction item shape and allowed enums for `interactions` - [elementor/list-widget-schemas?summary=true] - Available widget types this tool can configure - `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 - `elementor/list-components` - Discover reusable widget compositions and the component capabilities available for the current license tier (see COMPONENTS) # TOOL SUPPORT 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. # WORKFLOW 1. Check/create global variables via `elementor/manage-global-variable` 2. Check/create global classes via `elementor/manage-classes` 3. When component capabilities permit, prefer reusable components for cohesive structures that are repeated or likely to be reused 4. Read the schema via `elementor/get-widget-schema` for every element type you will use, including basic containers like `e-div-block` and `e-flexbox` — their `llm_guidance.default_styles` shape the layout 5. Build composition (THIS TOOL) - minimal inline styles; attach existing global classes via `classes` 6. Use returned element IDs for subsequent configuration changes ## CRITICAL: Avoid write conflicts after build-composition `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. **Rules:** - 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. - 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. # ID RULES `build-composition` uses two different identifiers. Do not mix them. ## configuration-id (you choose; input only) Use the XML attribute `configuration-id` on **every** element tag in `xml_structure` (including nested elements). This is the only allowed attribute on widget tags — no `id`, `class`, or other attributes. | Rule | Detail | |------|--------| | Uniqueness | Each `configuration-id` value must appear at most once in the `xml_structure` string for this call. Duplicates fail validation (`elementor_duplicate_configuration_id`). | | Map keys | Keys in `element_config`, `style`, `classes`, and `interactions` must match a `configuration-id` in `xml_structure` **exactly** (case-sensitive string). Extra map keys with no matching element are ignored. Elements without map entries are still created. | | Allowed values | Any non-empty string valid as a quoted XML attribute value (letters, numbers, spaces, hyphens, etc.). | | Navigator title | The server copies the value into the element's `editor_settings.title`, so it is visible to the user in the editor — use human-readable labels. | | Scope | Per request only. A `configuration-id` from an earlier call does not refer to the same widget later; it is not a persisted element id. | ## Element id (server assigns; output and follow-up) Never put element ids in `xml_structure`. The server generates a **new** id for every inserted element (including all descendants) on each successful save. | Rule | Detail | |------|--------| | Format | Server-generated lowercase hexadecimal string (one new id per inserted element). | | Where to read | After a non-`dry_run` call: `resolved_xml` (each tag gains an `id="..."` attribute) and `root_element_ids` (top-level inserts). `dry_run` does not assign ids. | | Reuse vs create | **Create:** every element in this composition gets a fresh server id — do not invent or recycle ids in input. **Reuse:** `parent_id` must be an existing container element id in the document (from `elementor/get-page-structure` or from `resolved_xml` of a prior save on this document). Use `document` (or omit `parent_id`) for root-level insertion. | | Follow-up edits | For `elementor/manage-elements`, use only element ids from **this** response's `resolved_xml` (see write-conflict rules above). Never substitute a `configuration-id` where an element id is required. | ## component_id (inside `element_config` for `` only) Integer post id of a reusable component from `elementor/list-components`. This is neither a `configuration-id` nor an element id. # COMPONENTS (only when explicitly requested) Elementor components are reusable widget compositions; global classes are reusable styles. Do not substitute one for the other. Call `elementor/list-components` before building a repeated, named, or otherwise reusable structure. Use its `capabilities` response to decide the flow: - When `can_add_to_page` is true, reuse a matching component whose `overridable_props` cover the required customization. - When no suitable component exists and `can_create` is true, create one through `elementor/manage-component`, then place it. - When the required capability is false, build with raw widgets. Do not claim that a component was created or placed. Place a component as the self-closing leaf tag ``. 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. # XML STRUCTURE - Use widget tags: `` - Containers: "e-flexbox", "e-div-block", "e-tabs" - Every element needs a unique `configuration-id` — see **ID RULES** - No other attributes, classes, element ids, or text nodes in XML - Multiple root elements are allowed. Every opening tag needs exactly one matching closing tag (or use a self-closing tag); a stray or missing closing tag fails the whole call with `invalid_xml`, even on `dry_run` - Pass the raw XML tags directly as the `xml_structure` string. Do NOT wrap the value in ``, 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`. ## NESTED ELEMENTS Some elements have internal tree structures (nesting). When using these elements, you MUST build the FULL tree in XML. - Check `llm_guidance.nesting` in widget schemas for structure requirements - `llm_guidance.required_direct_children` lists element types that must appear as direct child tags in XML (from widget defaults) - `allowed_child_types` lists which element types can be nested inside - `allowed_parents` lists which element types this element can be placed inside # CONFIGURATION - Map configuration-id → element_config (props) + style (plain CSS string) + classes (global class labels) - **element_config uses plain JSON values** — send scalars and objects exactly as shown in the widget schema. - **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.** - 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. - classes is configuration-id → array of existing global class **labels** from [elementor://global-classes] - 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" }` - Check `llm_guidance.default_settings` in widget schemas — omit only keys listed there from element_config unless the user explicitly asks to change them ### Style conversion 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. **When easy, prefer native-friendly shapes** (fallbacks are fine when the design needs them): - Breakpoints: `@media(--mobile)` — not `@media (max-width: 768px)` - Gap: single value `gap: 1rem` — not two-value `gap: 1rem 2rem` / `row-gap` - Borders: shorthand `border` / `border-width` — per-side `border-color` / `border-style` may fall back - Border-radius: simple values — not elliptical slash form (`10px / 20px`) - Transform: `rotate()` / `scale()` / `translate()` — not `matrix()`, `skew()`, `perspective`, `rotate3d` - Transition: property list — easing and delay may be dropped - Box-shadow: literal values (fully supported) — not `var(...)` inside the shadow - Font family & `var()`: one Google Font or one kit variable label — see GLOBAL VARIABLES **`padding` / `margin` shorthands are supported** — use them; do not split into longhand unnecessarily. ## element_config FORMAT Match the widget schema shape: - **string / enum / url**: plain string (`"h2"`, `"https://example.com"`) - **number**: plain number (`42`) - **boolean**: plain boolean (`true`) - **text** (`title` on `e-heading`, `paragraph` on `e-paragraph`, `text` on `e-button`): plain string (`"Welcome"`). May contain inline HTML tags for text styling. - Example: `"paragraph": "Contact support for a free discounted quote — limited time only."` - **dynamic** (where schema allows): `{ "name": "", "settings": { ... } }` — settings use plain values per the tag schema; omit `group` - **image**: two forms, `id` and `url` are mutually exclusive — send one, not both: - Library asset (from `elementor/list-assets` tool): `{ "src": { "id": 123 }, "size": "full" }`. Don't send `alt` with `id`; library images render the attachment's Media Library alt text, so ask the user to update it there if it's missing. - 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. - **svg** (the `svg` prop on `e-svg`): `{ "id": }`. 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. - **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: - Library asset (from `elementor/list-assets` with `type: "video"`): `{ "id": 123 }` - External URL: `{ "url": "https://example.com/clip.mp4" }` - NEVER put a raw video URL on a text, link, or `href` prop — a video always goes into `source` on a video widget. ## GLOBAL VARIABLES Read [elementor://global-variables] before styling. Create or update via `elementor/manage-global-variable`. Use variable **labels** from that list — not internal ids. **In `style` (raw CSS):** reference by label only: - `color: var(--wc26-gold)` or `color: var(--wc26-gold, #C6A15B)` - `font-family: var(--font-heading)` or `font-size: var(--spacing-lg, 1.5rem)` - 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. - Do NOT use the internal `e-gv-` id prefix (e.g. `var(--e-gv-wc26-gold)` is wrong; use `var(--wc26-gold)`) - Unrecognized variable references fall back to `custom_css` ## GLOBAL CLASSES 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. **In `classes` (reference-only):** attach existing global classes by label: - Map configuration-id → array of labels (e.g. `"Section Title": ["hero-heading", "text-muted"]`) - Create or update classes with `elementor/manage-classes` before referencing them here - Global classes are prepended before any local styles from `style`; local styles still win on conflicts # DYNAMIC TAGS - 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`). - 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. - Plain dynamic shape: `{ "name": "", "settings": { ... } }` - Example (image `src`): `"image": { "src": { "name": "", "settings": { ... } }, "size": "full" }` - 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. - Do NOT send `group` (resolved automatically). Populate `settings` strictly per the tag's schema; use `{}` only when it has none. # DESIGN PHILOSOPHY: CONTEXT-DRIVEN CREATIVITY **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. ## SIZING: DEFAULT IS NO SIZE (CRITICAL) **DO NOT specify height or width unless you have a specific visual reason.** Flexbox and CSS already handle sizing automatically: - Containers grow to fit their content - Flex children distribute space via flex properties, not width/height - Text elements size to their content WHEN TO SPECIFY SIZE: - min-height on ROOT section for viewport-spanning hero (use min-height, NOT height) - max-width for contained content areas (e.g., max-width: 60rem) - Explicit aspect ratios for media containers NEVER SPECIFY: - height on nested containers (causes overflow) - width on flex children (use flex-basis or gap instead) - 100vh on anything except root-level sections - Any size "just to be safe" - if unsure, OMIT IT vh units are VIEWPORT-relative. Nested 100vh inside 100vh = 200vh overflow. GOOD: `content naturally sizes` BAD: `overflow` ## Layout Variety (Break the Template) - AVOID: Full-width 100vh hero → three columns → testimonials → CTA (every AI does this) - VARY heights: Use auto-height sections with generous padding (6rem+). Let content breathe - VARY widths: Not everything spans full width. Use contained sections (max-width: 960px) mixed with edge-to-edge - ASYMMETRIC grids: 2:1, 1:3, offset layouts. Avoid equal column widths - Negative space as design element: Large margins create focus and sophistication - Break alignment intentionally: Offset headings, overlapping elements, broken grids ## Visual Depth & Effects - Layer elements: Overlapping cards, text over images, floating elements - Subtle shadows with color tint (not pure black): `box-shadow: 0 20px 60px rgba(, 0.15)` - Gradient overlays on images for text readability - Border radius variation: Mix sharp (0) and soft (1rem+) corners purposefully - Backdrop blur for glassmorphism where appropriate - Micro-interactions via CSS: hover transforms, transitions (0.3s ease) ## Typography with Character - Display fonts for headlines (from user's brand or contextually appropriate) - Size contrast: 4rem+ headlines vs 1rem body. Make hierarchy unmistakable - Letter-spacing: Tight for large headlines (-0.02em), loose for small caps (0.1em) - Line-height: Tight for headlines (1.1), generous for body (1.6-1.8) - Text decoration: Underlines, highlights, gradient text for emphasis ## Color with Purpose - Extract palette from user context (brand colors, industry norms, mood) - 60-30-10 rule: dominant, secondary, accent - Tinted neutrals over pure grays: warm (#faf8f5, #2d2a26) or cool (#f5f7fa, #1e2430) - Color blocking: Large colored sections create visual rhythm - Gradient directions: Diagonal (135deg, 225deg) feel more dynamic than vertical ## Spacing Strategy - Section padding: 6rem-10rem vertical, creating breathing room - Rhythm variation: Tight groups (2rem) with generous gaps between (6rem) - Use rem/em exclusively for responsive scaling - Generous padding on CTAs: min 1rem 2.5rem # INTERACTIONS 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. # HARD CONSTRAINTS - Variables ONLY from [elementor://global-variables]; reference **labels** in `style` as `var(--label)` — the `e-gv-` prefix is internal only - Classes ONLY from [elementor://global-classes]; reference **labels** in `classes` — internal `g-` ids must not be sent in `classes` - 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. - Check `llm_guidance` in widget schemas (`default_styles`, nesting, required children) # MODE Redesigning an existing parent? Use `mode: 'replace_children'` with the parent's id — one call replaces its children. Default `'append'` keeps existing content. - `append` (default): Insert new elements as children of `parent_id`, preserving existing children. - `replace_children`: Remove all direct children of `parent_id` first, then insert new elements. The response includes `removed_element_ids` listing what was removed. - When `parent_id: 'document'` + `mode: 'replace_children'`, all top-level elements are removed — use this to redesign the whole page. # PARAMETERS - **post_id**: WordPress post ID of the document to mutate - **xml_structure**: Valid XML with configuration-id attributes on every element - **element_config**: configuration-id → plain widget settings (see PLAIN element_config FORMAT). For `` config-ids the value is `{ component_id, overrides? }` (see COMPONENTS section). - **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)` - **classes**: configuration-id → list of existing global class **labels** to attach - **interactions**: configuration-id → array of native-shape interaction items (see INTERACTIONS section; read [elementor://interactions/schema] for allowed values) - **parent_id**: ID of the parent container (omit to insert at document root) - **mode**: `'append'` (default) or `'replace_children'` — see MODE section above - **dry_run**: If true, validate and return resolved tree without persisting # EXAMPLE Section with heading + button (NO explicit heights - content sizes naturally): ```json { "post_id": 123, "xml_structure": "", "element_config": { "Section Title": { "tag": "h2", "title": "Welcome" } }, "style": { "Main Section": "padding: 6rem 4rem; background: linear-gradient(135deg, #faf8f5 0%, #f0ebe4 100%); @media(--mobile) { padding: 3rem 1.5rem; }", "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; }" } } ``` Note: No height/width specified on any element - flexbox handles layout automatically. # FURTHER INSTRUCTIONS Use server-assigned element ids from `resolved_xml` for follow-up work — see **ID RULES**. If components were requested or used, verify that each was created or placed successfully before reporting completion.