Skip to main content

elementor-mcp

Helps with WordPress + Elementor work via the elementor-mcp MCP server — building new pages, editing existing ones, inspecting site state, or exploring what's possible. Asks what the user wants before acting. Use when the user references the Elementor MCP, invokes `/elementor-mcp`, or runs `mcp__elementor__elementor-mcp-*` tools. Also covers initial install of the MCP Adapter + elementor-mcp plugins, app-password auth wiring, schema-loading discipline, and the widget-vs-HTML decision tree. SKIP for Bricks, Divi, Beaver Builder, or non-Elementor WordPress builds.

Source facts

Repository
emersimeon/claude-elementor-kit
Last source activity
April 28, 2026 at 21:54
Detected SKILL.md language
English
Stars
85
Forks
26

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
2 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
elementor-mcp
description
Helps with WordPress + Elementor work via the elementor-mcp MCP server — building new pages, editing existing ones, inspecting site state, or exploring what's possible. Asks what the user wants before acting. Use when the user references the Elementor MCP, invokes `/elementor-mcp`, or runs `mcp__elementor__elementor-mcp-*` tools. Also covers initial install of the MCP Adapter + elementor-mcp plugins, app-password auth wiring, schema-loading discipline, and the widget-vs-HTML decision tree. SKIP for Bricks, Divi, Beaver Builder, or non-Elementor WordPress builds.
# Elementor MCP Skill You are operating against a WordPress site with the **elementor-mcp** server (`https://github.com/msrbuilds/elementor-mcp`) connected via the WordPress MCP Adapter. This skill captures everything I learned the hard way the first time through, so subsequent sessions start at expertise level. ## 🛑 First Action Protocol — ASK BEFORE DOING **When this skill is invoked, do not start running tools. Ask the user what they want first.** If the user's invocation message *already* contains a clear task — *"build me a hero section from `index.html`"*, *"show me my current global colors"*, *"change the burgundy to navy"* — proceed with that task directly. Otherwise *(invocations like `/elementor-mcp` alone, or "use the Elementor MCP" with no follow-up)*, **respond with this menu and wait for the user to pick:** ``` What would you like to do with your Elementor site? 1. Build — create new pages or sections from a design 2. Edit — change something on an existing page 3. Reference — inspect current state (pages, colors, fonts, content) 4. Explore — show me what's possible / what can the MCP do here ``` Do **not** silently default to "build" — that's the most destructive action and forces a path the user may not want. Wait for the user to choose 1/2/3/4 *(or describe their task in their own words)* before invoking any MCP tool other than the harmless read-only ones at the bottom of this section. ### Read-only "smoke test" calls that are always safe to run When the user picks any option, you can run these **before** asking follow-up questions, since they help frame the next response: - `mcp__elementor__elementor-mcp-list-pages` — confirms auth + lists what's there - `mcp__elementor__elementor-mcp-get-global-settings` — current colors/fonts kit That's it for unprompted tool calls. **Anything that creates, modifies, or deletes data requires the user to have explicitly asked for it.** ## When this skill applies - The user mentions Elementor MCP, types `/elementor-mcp`, or says "use the Elementor MCP" - A `.mcp.json` in the project registers an MCP server pointing at `wp-json/mcp/elementor-mcp-server` - The user asks to build, edit, inspect, or troubleshoot an Elementor page - Tools beginning with `mcp__elementor__elementor-mcp-*` are available ## First-session setup (when MCP not yet connected) If the user has a WordPress site but no `.mcp.json` and no `elementor` MCP loaded: 1. **Check whether they're using Local-by-Flywheel or a live host.** Setup paths differ. 2. **Run the bundled setup script** at `~/.claude/scripts/setup-elementor-mcp.sh` — it handles plugin install, auth wiring, and `.mcp.json` generation interactively for both flavors. ```bash bash ~/.claude/scripts/setup-elementor-mcp.sh ``` 3. After the script completes, instruct the user to **quit and reopen Claude Code in the project directory** so the new `.mcp.json` is picked up. 4. On reopen, the deferred MCP tools will be exposed via ToolSearch — load the ones you need with `select:` queries. If something fails, see "Setup gotchas" below. ## Working session conventions ### Always do this first ``` mcp__elementor__elementor-mcp-list-pages # confirms auth + lists existing pages mcp__elementor__elementor-mcp-get-global-settings # see existing colors/fonts kit mcp__elementor__elementor-mcp-get-container-schema # ground truth on flex_* key names ``` The container schema is large (~50KB). Read it once, then write down the keys you'll use in your reply text so you don't need to re-fetch it. Critical keys: - `flex_direction`, `flex_justify_content`, `flex_align_items`, `flex_gap`, `flex_wrap` — note the **`flex_` prefix** on justify/align (issue #32 was about these being written under wrong keys in older versions) - `content_width: "boxed"|"full"` + `boxed_width: {unit, size, sizes}` - `min_height: {unit, size, sizes}` — use unit `vh` for full-screen heroes - `padding`/`margin: {unit, top, right, bottom, left, isLinked}` — `isLinked: false` when sides differ - `background_background: "classic"|"gradient"|"video"` — must be set first or other background_* keys are ignored - `background_overlay_*` — separate parallel set for overlays. `background_overlay_opacity: {unit:"px", size: 0.5}` (yes, the unit is `px` even for opacity — quirk of the schema) ### Widget call convention — flat params, NOT nested in `settings` This bit me hard the first time. The `add-*` shortcut tools take their settings as **top-level parameters**, not inside a `settings: {}` object: ```js // ✓ CORRECT mcp__elementor__elementor-mcp-add-heading({ post_id: 11, parent_id: "abc123", title: "where estates <em>are entrusted</em>", header_size: "h1", title_color: "#FFFFFF", typography_typography: "custom", // ← required to enable typography typography_font_family: "Cormorant Garamond", typography_font_size: {size: 110, unit: "px"}, typography_font_weight: "300", typography_line_height: {size: 0.98, unit: "em"}, }) // ✗ WRONG — silently fails or returns "title is required" mcp__elementor__elementor-mcp-add-heading({ post_id: 11, parent_id: "abc123", settings: {title: "...", typography_font_family: "..."} }) ``` `add-container` is the **exception** — it takes a `settings: {}` object. Don't generalize from one to the other. ### Always set `typography_typography: "custom"` Without this, the other typography_* keys are ignored. Same applies to `css_filters_css_filter: "custom"` for image filters, etc. — these "enable" flags are how Elementor knows you want to override defaults. ### Italic emphasis pattern Display headings often need a single italic-emphasized word. Don't use a separate widget — just inline `<em>` in the title: ```js title: "A <em>quiet</em> practice for an <em>uncommon</em> clientele." ``` Cormorant Garamond and most luxury serifs have italic variants that auto-load when `<em>` appears. Confirm via the rendered page; if italics fail, the global typography needs the italic variant explicitly enabled. ## The widget-vs-HTML decision — DEFAULT TO NATIVE WIDGETS > 🚨 **CRITICAL ANTI-PATTERN — read this first.** > > **Do NOT paste an entire HTML page into one HTML widget.** Do NOT build a homepage that is "1 container with 3 HTML widgets inside." That is not building with Elementor — that is using Elementor as a wrapper around a static webpage. The user **cannot edit it** in the Elementor visual editor, **cannot reuse the design tokens**, and **cannot iterate** on it without going back to source code. > > If you find yourself thinking *"I'll just dump this section as HTML, it's faster,"* **STOP.** Break it into native widgets. ### Always default to native widgets For every section the user wants, build it from native Elementor widgets: - **Headings** → `add-heading` widget *(supports inline `<em>` for italic emphasis)* - **Body copy** → `add-text-editor` widget - **Images** → `add-image` widget *(NOT an `<img>` tag inside an HTML widget)* - **Buttons / CTAs** → `add-button` widget *(NOT an `<a>` styled as a button)* - **Layout / spacing** → `add-container` with proper `flex_*` settings *(NOT `<div>`s with CSS flex)* - **Lists** → `add-icon-list` widget - **Tabs** → `add-tabs` widget - **Accordions / FAQs** → `add-accordion` widget - **Forms** → Fluent Forms shortcode via `add-shortcode` widget - **Nav menu in headers** → UAE Nav Menu widget *(`uael-nav-menu`)* ### When HTML widget IS allowed *(narrow list — exceptions only)* Only reach for an HTML widget in these specific cases. **Anything not on this list goes through native widgets.** 1. **Tab/accordion content with rich layout.** `add-tabs` only accepts `tab_content` as a string of HTML, so a multi-card grid inside a tab MUST be HTML. *(But the wrapping Tabs widget itself is still native.)* 2. **Decorative-only flourishes** with no native equivalent — a thin gold rule with a CSS-pseudo-element flourish, an animated underline that grows on hover, a gradient overlay on a child element. **Even then, prefer to pair it with a native widget rather than replacing one.** 3. **Form HTML as a flagged placeholder** when no real form plugin is wired up yet — and you must explicitly tell the user "form is visual only, doesn't capture submissions." 4. **Site-wide CSS overrides** scoped to a specific Elementor element ID *(e.g., styling the tab strip of an `add-tabs` widget that the widget controls don't expose)*. These should be small style blocks, not whole sections of markup. ### What about card grids of 4+ items? Earlier versions of this skill said "use one HTML widget for card grids — it's faster than 50 widget calls." That advice was wrong because it led to non-editable pages. **The correct path for card grids:** - Build the first card with native widgets *(Container → Image → Heading → Text Editor → Button)* - Use `duplicate-element` to copy it 3+ more times - Use `update-element` to change the copy/image on each duplicate - Wrap them in a parent Container with `flex_direction: row` and `flex_wrap: wrap` This is more widget calls, yes, but the result is a **real Elementor card grid** the user can edit, restyle globally, or reuse as a template. ### Cross-widget styling — `<style>`-only HTML widgets When you need to style a native widget from outside (e.g., overriding the Tabs widget tab strip styles that the widget controls don't expose), use a **`<style>`-only HTML widget**: it contains ONLY a `<style>` block — no markup, no rendered content. Scope every selector to the parent Elementor element ID: ```html <style> .elementor-element-f8d1545 .elementor-tab-title { text-transform: uppercase !important; letter-spacing: .26em !important; } .elementor-element-f8d1545 .elementor-tab-title.elementor-active { border-bottom-color: #171615 !important; } </style> ``` The `f8d1545` is the `element_id` returned when you created the tabs widget. Always grab and remember these IDs — they're the only stable selector across page reloads. > ⚠️ **An HTML widget used for cross-widget styling MUST contain only `<style>`.** If you find yourself adding HTML markup *(divs, anchors, spans with text content)* alongside the style block, you're falling back into the anti-pattern at the top of this section. Stop. That markup belongs in native widgets. ## When the user asks to BUILD — building order > Use this section only when the user has explicitly asked you to build something. Do not run this flow on a bare `/elementor-mcp` invocation. For a new page, build top-down section by section, in small commits, verifying after each: 1. `update-global-colors` + `update-global-typography` — establish design tokens 2. `create-page({title, status: "publish", template: "elementor_canvas"})` — Canvas template removes theme header/footer chrome so your design is the only thing on the page 3. (Via WP-CLI) Set as static front page: `wp option update show_on_front page; wp option update page_on_front <id>` 4. Build sections — outer container → inner content container (boxed, max-width 1360px-ish) → content 5. After each section: `get-page-structure(post_id)` to verify nesting, or just curl the front page 6. **Pause for human review** before building header/footer (which use Header Footer Elementor templates, a different flow) ## When the user asks to EDIT Approach existing pages surgically — don't rebuild what you don't have to: 1. `list-pages` to find the page they're editing 2. `get-page-structure(post_id)` to see the current widget tree and grab element IDs 3. For a specific element they describe ("the hero headline", "the third listing card"), use `find-element` if needed, then `update-element` with only the fields that change 4. Verify the edit by re-reading `get-page-structure` or curling the rendered page 5. **Never delete a section unless they explicitly ask** — even when restructuring. Use `move-element` or `update-element` first. ## When the user asks to REFERENCE / INSPECT Read-only tools, no writes. Useful for "show me", "tell me", "what's", "list" requests: - `list-pages` — what pages exist - `get-global-settings` — colors, typography, layout settings - `get-page-structure(post_id)` — what's on a page - `get-element-settings(element_id)` — exact settings of one widget - `find-element(post_id, ...)` — locate a widget by content/type Format the response as a clear summary, not a JSON dump. The user wants understanding, not raw data. ## When the user asks to EXPLORE / "what can you do?" Give a short menu *(don't dump all 75 tools)*. Point them at the four modes from the First Action Protocol with concrete examples: - *"Build a homepage from this HTML mockup"* → mode 1 - *"Make the hero text 20% smaller"* → mode 2 - *"Show me what colors are currently set globally"* → mode 3 - *"What pages exist on the site?"* → mode 3 Then ask which mode they want. ## Header/Footer notes The MCP plugin's `create-theme-template` tool requires **Elementor Pro**. With Elementor Free, headers and footers are built using **Ultimate Addons for Elementor (UAE)** by Brainstorm Force (the kit's setup wizard auto-installs this; alternatively the lighter **Header Footer Elementor (HFE)** plugin from the same company also works — both share the same `elementor-hf` post type). ### Building a site-wide header 1. **Create the WordPress menu first.** Tell the user to go to WP Admin → Appearance → Menus, name it (e.g. "Main"), add the pages they want, and save. The MCP cannot create WP nav menus directly — this step is a one-minute manual action. 2. **Create the header template post.** Use `create-page` with `post_type: "elementor-hf"` and a title like "Site Header". Then set the following post meta via WP-CLI or the `update-element` flow: - `ehf_template_type` = `"type_header"` (or `"type_footer"` for footers) - `display-on-canvas` = `"yes"` (displays site-wide; alternative meta keys like `ehf_target_include_locations` may apply for narrower scopes) 3. **Build the layout.** A row container with three children: - **Left:** logo (Heading widget with brand name in display serif, OR `Site Logo` widget if UAE is installed) - **Center:** **UAE Nav Menu widget** (`uael-nav-menu`) pointed at the WordPress menu by name. UAE's nav menu widget is **free** and handles mobile hamburger, dropdowns, hover states, active-page highlighting automatically — much cleaner than rendering nav as raw HTML. - **Right:** Button widget with "Contact" or "Get In Touch" CTA 4. **Verify display.** After building, instruct the user to check WP Admin → Appearance → Header Footer Builder → confirm the Display On rule is set to "Entire Website." ### When UAE Nav Menu isn't available If only HFE (the lighter plugin) is installed without UAE: use the Shortcode widget calling `[wp_nav_menu menu="Main" container=""]` — WordPress's built-in shortcode renders the menu as a real `<ul>` with all the right classes for active-page highlighting and responsive styling. **Do not** fall back to manually listing the menu items inside an HTML widget — that hard-codes the navigation in two places (the WP menu AND the Elementor template) which means future menu edits won't reflect in the header. Always render the menu through `[wp_nav_menu]` or the UAE widget. ### Footer pattern Identical post type (`elementor-hf`) but `ehf_template_type = "type_footer"`. Layout is typically a 4-column container (brand block + 3 link columns) on a dark background, with a bottom row containing copyright + social icons. ### Forms — Fluent Forms (the recommended path) Elementor's native Form widget is Pro. The kit's wizard auto-installs **Fluent Forms** as the free workaround. The flow is split: the user builds the form, then Claude wires it into the page and styles it. #### The split — what Claude does vs. what the user does **The user does (manual, ~2-3 min in WP Admin):** 1. **Fluent Forms → New Form** → pick the *Contact Form* template *(pre-built with Name / Email / Subject / Message)* OR start from blank 2. *(optional)* Drag in extra fields — Phone, dropdown, etc. 3. **Save Form** — note the form ID at the top of the page (usually `1` for the first form) 4. **Settings → Email Notifications** → confirm the To address (default: `{admin_email}`) **Claude does:** 1. Replace any placeholder form (HTML widget) in the contact section with `add-shortcode` widget containing `[fluentform id="<ID>"]` 2. Add a small `<style>` block (in an HTML widget alongside, NOT replacing the shortcode widget) that scopes Fluent Forms styling to match the site's design #### Wiring the form ```js // Drop the shortcode widget where the form should appear mcp__elementor__elementor-mcp-add-shortcode({ post_id: <page_id>, parent_id: <contact_section_container_id>,
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub