Install
$ agentstack add skill-emersimeon-claude-elementor-kit-files ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
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 theremcp__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.jsonin the project registers an MCP server pointing atwp-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:
- Check whether they're using Local-by-Flywheel or a live host. Setup paths differ.
- Run the bundled setup script at
~/.claude/scripts/setup-elementor-mcp.sh— it handles plugin install, auth wiring, and.mcp.jsongeneration interactively for both flavors.
``bash bash ~/.claude/scripts/setup-elementor-mcp.sh ``
- After the script completes, instruct the user to quit and reopen Claude Code in the project directory so the new
.mcp.jsonis picked up. - 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 theflex_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 unitvhfor full-screen heroespadding/margin: {unit, top, right, bottom, left, isLinked}—isLinked: falsewhen sides differbackground_background: "classic"|"gradient"|"video"— must be set first or other background_* keys are ignoredbackground_overlay_*— separate parallel set for overlays.background_overlay_opacity: {unit:"px", size: 0.5}(yes, the unit ispxeven 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:
// ✓ CORRECT
mcp__elementor__elementor-mcp-add-heading({
post_id: 11,
parent_id: "abc123",
title: "where estates are entrusted",
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 `` in the title:
title: "A quiet practice for an uncommon clientele."
Cormorant Garamond and most luxury serifs have italic variants that auto-load when `` 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-headingwidget (supports inline `` for italic emphasis) - Body copy →
add-text-editorwidget - Images →
add-imagewidget (NOT an `` tag inside an HTML widget) - Buttons / CTAs →
add-buttonwidget (NOT an `` styled as a button) - Layout / spacing →
add-containerwith properflex_*settings (NOT ``s with CSS flex) - Lists →
add-icon-listwidget - Tabs →
add-tabswidget - Accordions / FAQs →
add-accordionwidget - Forms → Fluent Forms shortcode via
add-shortcodewidget - 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.
- Tab/accordion content with rich layout.
add-tabsonly acceptstab_contentas a string of HTML, so a multi-card grid inside a tab MUST be HTML. (But the wrapping Tabs widget itself is still native.) - 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.
- 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."
- Site-wide CSS overrides scoped to a specific Elementor element ID (e.g., styling the tab strip of an
add-tabswidget 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-elementto copy it 3+ more times - Use
update-elementto change the copy/image on each duplicate - Wrap them in a parent Container with
flex_direction: rowandflex_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 — ``-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 **`-only HTML widget**: it contains ONLY a ` block — no markup, no rendered content. Scope every selector to the parent Elementor element ID:
.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;
}
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 ``. 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:
update-global-colors+update-global-typography— establish design tokenscreate-page({title, status: "publish", template: "elementor_canvas"})— Canvas template removes theme header/footer chrome so your design is the only thing on the page- (Via WP-CLI) Set as static front page:
wp option update show_on_front page; wp option update page_on_front - Build sections — outer container → inner content container (boxed, max-width 1360px-ish) → content
- After each section:
get-page-structure(post_id)to verify nesting, or just curl the front page - 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:
list-pagesto find the page they're editingget-page-structure(post_id)to see the current widget tree and grab element IDs- For a specific element they describe ("the hero headline", "the third listing card"), use
find-elementif needed, thenupdate-elementwith only the fields that change - Verify the edit by re-reading
get-page-structureor curling the rendered page - Never delete a section unless they explicitly ask — even when restructuring. Use
move-elementorupdate-elementfirst.
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 existget-global-settings— colors, typography, layout settingsget-page-structure(post_id)— what's on a pageget-element-settings(element_id)— exact settings of one widgetfind-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
- 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.
- Create the header template post. Use
create-pagewithpost_type: "elementor-hf"and a title like "Site Header". Then set the following post meta via WP-CLI or theupdate-elementflow:
ehf_template_type="type_header"(or"type_footer"for footers)display-on-canvas="yes"(displays site-wide; alternative meta keys likeehf_target_include_locationsmay apply for narrower scopes)
- Build the layout. A row container with three children:
- Left: logo (Heading widget with brand name in display serif, OR
Site Logowidget 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
- 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 `` 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):
- Fluent Forms → New Form → pick the Contact Form template (pre-built with Name / Email / Subject / Message) OR start from blank
- (optional) Drag in extra fields — Phone, dropdown, etc.
- **Save
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: emersimeon
- Source: emersimeon/claude-elementor-kit
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.