A Claude AI skill that converts any design into production-ready WordPress Elementor templates
SaferSkills independently audited Ak-Elementor-Studio (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
HTML WIDGET = JAVASCRIPT <script> TAGS ONLY.
The html widget has exactly one valid use:
→ Embedding a <script> tag for JavaScript behavior
That is ALL. Nothing else ever goes in the html widget.
Not headings. Not text. Not badges. Not nav links.
Not cards. Not layouts. Not pricing. Not timelines.
Not icons. Not stats. Not ANY visual content.
Every visual element has a native Elementor widget. Use it.1. NO COMMENTS — /* */ and // both break JSON parsing
❌ { /* hero */ "id": "a1b2c3d4" } ✅ { "id": "a1b2c3d4" }
2. NO TRAILING COMMAS
❌ { "a": 1, "b": 2, } ✅ { "a": 1, "b": 2 }
3. IDs = UNIQUE 8-CHAR HEX ONLY
❌ "id": "hero_section" ✅ "id": "a1b2c3d4"
4. EVERY ELEMENT MUST HAVE "elements": []
❌ { "widgetType": "heading", "settings": {} }
✅ { "widgetType": "heading", "settings": {}, "elements": [] }
5. isInner RULE
Direct children of "content": [] → "isInner": false
Containers nested inside containers → "isInner": true
Widgets (inside any container) → "isInner": false
6. HEX COLORS ONLY — never color names
❌ "background_color": "white" ✅ "background_color": "#FFFFFF"Ask all in ONE message. Never skip.
👋 Quick details before I start:
1. SITEMAP — Pages? (I generate one .json per page)
2. ELEMENTOR VERSION — Free or Pro?
Pro: Theme Builder header/footer, custom CSS, sticky, scroll effects
Free: header/footer = regular sections inside each page
3. CUSTOM POST TYPES — Any CPTs?
(Services, Portfolio, Plugins, Team, Testimonials → I'll generate ACF JSON)
4. OUTPUT FORMAT
a) Individual .json files — import one-by-one via Templates → Saved Templates (always works, Free + Pro)
b) Elementor native export ZIP — import via Elementor → Tools → Import Kit (no extra plugin needed)
c) Envato Template Kit ZIP — requires "Template Kit Import" plugin installed on WordPress
d) Individual .json + ACF field group files
5. BRAND — Hex color codes + Google Fonts?
(Or I extract from the design)| Input | Pipeline |
|---|---|
| HTML/CSS/JS | Code Pipeline |
| PNG/JPG/WebP/screenshot/mockup/Figma | Visual Pipeline |
| PDF Pipeline | |
| Words only | Description Pipeline |
| Existing Elementor JSON | Edit Pipeline |
| Mixed | Both pipelines, merged |
| Element | Widget |
|---|---|
| h1 / h2 / h3 / h4 / h5 / h6 | heading |
| Paragraph / body text | text-editor |
| Animated counter (500+, 10K) | counter |
| Progress / skill bar | progress |
| Element | Widget |
|---|---|
| Button / CTA / link-as-button | button |
| FAQ / collapsible rows | accordion |
| Tab navigation | tabs |
| Alert / info banner | alert |
| Element | Widget |
|---|---|
| Photo / image | image |
| YouTube / Vimeo / video | video |
| Image grid | image-gallery |
| Image slider / carousel | image-carousel |
| Element | Widget |
|---|---|
| Icon + title + description | icon-box |
| Bulleted list with icons | icon-list |
| Photo + title + text | image-box |
| Customer quote | testimonial |
| Element | Widget |
|---|---|
| Horizontal line / separator | divider |
| Vertical blank space | spacer |
| Element | Widget |
|---|---|
| Social media icons | social-icons |
| Map embed | google-maps |
| Plugin/form shortcode | shortcode |
Structure: flex container (row, space-between)
└── image widget ← logo
└── icon-list widget ← nav links (set icon to "none", each item = a page link)
OR multiple button widgets (size: xs, style: link/ghost, one per nav item)
└── button widget ← CTA buttonOption A: button widget
text: "FULL-TIME", size: "xs", border_radius: 100px
button_text_color: "#00D4C8", button_background_color: "rgba(0,212,200,0.1)"
no link href (or link to "#")
Option B: alert widget
type: "success" / "info" / "warning"
alert_title: "WordPress Developer"
(style with custom CSS if Pro)Structure: inner container (column, border-left: 2px solid accent)
└── inner container (row, gap: 8px) ← date + status row
└── text-editor widget ← "OCT 2024 — PRESENT"
└── button widget (xs, pill) ← "FULL-TIME" badge
└── heading widget (h3/h4) ← "Senior WordPress & Webflow Developer"
└── text-editor widget ← "InVitro Capital — Cairo, Egypt"
└── text-editor widget ← description paragraph
└── inner container (row, wrap) ← tech tags row
└── button widget (xs, ghost) ← "WordPress"
└── button widget (xs, ghost) ← "Webflow"
└── button widget (xs, ghost) ← "CMS"Structure: styled container (background: #141628, border-radius: 12px, padding: 32px)
└── inner container (row) per info row:
└── text-editor widget ← label "LOCATION" (small, muted)
└── text-editor widget ← value "Cairo, Egypt"
└── inner container (row) per clickable row:
└── text-editor widget ← label "EMAIL"
└── button widget ← "[email protected]" (style: link, href: mailto:)
└── alert widget ← "Currently available" status
└── button widget ← "Book a discovery call" CTAStructure: container (column)
└── text-editor widget ← "SKILL DEPTH" heading
└── per skill: inner container (row)
└── text-editor ← "WP" label
└── progress widget ← percent: 95, type: line, bar_color: accent
└── text-editor ← "Expert" labelStructure: inner container (column, background: #141628, border-radius: 12px, padding: 40px)
└── text-editor widget ← plan tier label
└── heading widget (h2) ← "$99" price
└── text-editor widget ← "/month" period
└── divider widget
└── icon-list widget ← feature list (checkmark icons)
└── button widget ← "Get Started" CTA (full width)Use testimonial widget (handles everything natively):
image: avatar URL, name: "Client Name", title: "CEO, Company"
content: "Quote text here"
OR custom layout:
inner container (column)
└── icon-list widget (1 item, star icon × 5) ← star rating
└── text-editor widget ← quote text
└── inner container (row)
└── image widget (border-radius: 50%) ← avatar
└── inner container (column)
└── heading widget (h5) ← name
└── text-editor widget ← title/companyUse image-carousel widget:
slides: [logo1, logo2, logo3, logo4, logo5]
slides_to_show: 5, autoplay: yes, navigation: none
image_size: mediumColumn 1 (brand col):
└── image widget ← logo
└── text-editor widget ← tagline
└── social-icons widget ← LinkedIn, GitHub, Twitter
Columns 2-4 (link cols):
└── heading widget (h5) ← "Quick Links" / "Services" / "Contact"
└── icon-list widget ← links (icon: none or arrow, one per link)
Bottom bar:
└── container (row, space-between)
└── text-editor ← "© 2025 Abanoub Khalil"
└── text-editor ← privacy / terms links (inline <a> tags)For every element: name it, declare its native widget, explain why. If you considered html widget, apply the JS-only self-check first.
Zero visual content in html widget. Apply the Complete Widget Reference above.
Map CSS → Elementor settings (references/style-map.md). CSS variables → resolve to hex.
Section by section. Validate as you write.
One .json per page. No comments. All IDs unique 8-char hex.
NAVBAR:
Logo: [position / type: image or text]
Nav links: [list each] → icon-list items OR button widgets
CTA button(s): [text / color hex]
Background: [#HEX or transparent]
HERO:
BG: [solid #HEX / gradient #X→#Y Ndeg / image overlay / video]
Layout: [centered / text-left+image-right]
Min-height: [100vh / fixed px]
Elements:
[badge?] → alert widget or button widget (xs, pill)
[h1] → heading widget
[h3/subtitle] → heading widget
[description] → text-editor widget
[CTA buttons] → button widgets
[image] → image widget
SECTION N:
Purpose: [features / stats / about / timeline / contact panel / testimonials / CTA]
Layout: [1-col / 2-col / 3-col / 4-col]
Background: [#HEX]
Per column: list native widget for each element
FOOTER: [N columns, content per column]Extract hex for: primary, secondary, accent, heading text, body text, muted, light bg, dark bg, card bg, border. → Full reference table in references/visual-analysis.md
Heading font, body font, label font — family, weight, desktop/tablet/mobile sizes.
Use container grid in references/section-patterns.md.
Apply Complete Widget Reference. Zero html widgets for visual content.
Section pad: 60-80px standard, 100-120px hero. Card pad: 24-32px. Gap: 20-30px.
## 🔍 Visual Analysis — [Page]
**Pages detected:** [list]
**Style:** [Dark/Light/Bold/Minimal]
| Token | Value |
|---|---|
| Primary | #______ |
| Accent | #______ |
| Heading text | #______ |
| Body text | #______ |
| Background | #______ |
| Heading font | Inter 700 |
**Widget map:**
1. Navbar → image + icon-list + button
2. Hero → alert (badge) + heading + text-editor + button + image
3. Stats → N× counter widgets
4. Timeline → N× [text-editor + button (badge) + heading + text-editor + button row] per entry
5. Contact panel → styled container + text-editor rows + button links + alert + button
6. Footer → image + text-editor + social-icons + icon-list columns
**html widgets used:** [List ONLY <script> JS uses. If none: "None."]
**Assumptions:** [list all approximations]
**⚠️ After import:** replace placeholder images, update nav linksSingle PDF → Visual Pipeline. Multi-page → one template per page. Selectable text → extract exact copy.
Ask page type. Apply Widget Reference. Use defaults: primary #1A1A2E, accent #005AFF, font Inter.
Parse → locate → change → re-output full valid JSON → summarize.
{
"id": "a1b2c3d4",
"elType": "container",
"isInner": false,
"settings": {
"content_width": "full",
"flex_direction": "column",
"flex_align_items": "center",
"flex_justify_content": "flex-start",
"flex_gap": { "unit": "px", "column": "30", "row": "30", "isLinked": true },
"padding": { "unit": "px", "top": "80", "right": "60", "bottom": "80", "left": "60", "isLinked": false },
"padding_tablet": { "unit": "px", "top": "50", "right": "30", "bottom": "50", "left": "30", "isLinked": false },
"padding_mobile": { "unit": "px", "top": "40", "right": "20", "bottom": "40", "left": "20", "isLinked": false },
"background_background": "classic",
"background_color": "#FFFFFF"
},
"elements": []
}{
"id": "b2c3d4e5",
"elType": "container",
"isInner": true,
"settings": {
"width": { "unit": "%", "size": 50 },
"width_tablet": { "unit": "%", "size": 100 },
"width_mobile": { "unit": "%", "size": 100 },
"flex_direction": "column",
"flex_align_items": "flex-start",
"padding": { "unit": "px", "top": "20", "right": "20", "bottom": "20", "left": "20", "isLinked": true }
},
"elements": []
}{
"id": "c3d4e5f6",
"elType": "widget",
"widgetType": "heading",
"isInner": false,
"settings": {},
"elements": []
}Full table in references/style-map.md.
"padding": { "unit": "px", "top": "80", "right": "60", "bottom": "80", "left": "60", "isLinked": false }
"_padding": { "unit": "px", "top": "0", "right": "0", "bottom": "20", "left": "0", "isLinked": false }
"_margin": { "unit": "px", "top": "0", "right": "auto", "bottom": "30", "left": "auto", "isLinked": false }
"typography_typography": "custom", "typography_font_family": "Inter",
"typography_font_size": { "unit": "px", "size": 48 },
"typography_font_size_tablet": { "unit": "px", "size": 36 },
"typography_font_size_mobile": { "unit": "px", "size": 24 },
"typography_font_weight": "700",
"typography_line_height": { "unit": "em", "size": 1.3 },
"typography_letter_spacing": { "unit": "px", "size": -0.5 }
"background_background": "gradient", "background_gradient_type": "linear",
"background_color": "#005AFF", "background_color_b": "#0040CC",
"background_gradient_angle": { "unit": "deg", "size": 135 }
"border_border": "solid",
"border_width": { "unit": "px", "top": "1", "right": "1", "bottom": "1", "left": "1", "isLinked": true },
"border_color": "#E5E7EB",
"border_radius": { "unit": "px", "top": "12", "right": "12", "bottom": "12", "left": "12", "isLinked": true }
"box_shadow_box_shadow_type": "yes",
"box_shadow_box_shadow": { "horizontal": 0, "vertical": 4, "blur": 24, "spread": 0, "color": "rgba(0,0,0,0.08)" }"width": { "unit": "%", "size": 33 },
"width_tablet": { "unit": "%", "size": 50 },
"width_mobile": { "unit": "%", "size": 100 }.json per pageheader.json + footer.json (type: "header" / "footer")⚠️ CRITICAL: Three completely different ZIP formats exist. Using the wrong one causes "Couldn't use the .zip file" in Elementor's importer. Match the format to the method.
Recommended default. No plugins required. Works on any Elementor version.
Steps:
1. Elementor → Templates → Saved Templates → Import Templates (↑ icon)
2. Upload one .json file at a time → Import Now
3. Repeat for each page (global-styles first, then header/footer, then pages)
4. Create a WordPress page → Edit with Elementor
→ folder icon (My Templates) → find template → Insert
Each .json file envelope format (single template):
{
"version": "0.4",
"title": "Page Name",
"type": "page", ← "page" | "header" | "footer" | "kit-styles"
"content": [...], ← the elements array from your page JSON
"page_settings": {},
"settings": {}
}Works via: Elementor → Tools → Import Kit
Does NOT require Template Kit Import plugin.
This is what Elementor exports natively when you use Tools → Export Kit.
⚠️ Do NOT confuse manifest.json with Envato's kit.json — they are different formats.
ZIP structure:
kit-export.zip
├── manifest.json ← required, exact format below
├── ak-header/
│ └── template.json
├── ak-footer/
│ └── template.json
├── ak-home/
│ └── template.json
└── ak-about/
└── template.json (one folder per template, folder name is arbitrary)
manifest.json format:
{
"name": "Kit Name",
"title": "Kit Name",
"description": "...",
"author": "Abanoub Khalil",
"version": "1.0.0",
"elementor_version": "3.0.0",
"created": "2025-01-01",
"thumbnail": "",
"site": "https://akstudio.me",
"plugins": [
{ "name": "Elementor", "slug": "elementor", "pluginFile": "elementor/elementor.php", "version": "3.0.0" },
{ "name": "Elementor Pro", "slug": "elementor-pro", "pluginFile": "elementor-pro/elementor-pro.php", "version": "3.0.0" }
],
"templates": [
{ "name": "Header", "title": "Header", "thumbnail": "", "url": "",
"export_date": "2025-01-01", "source": "", "type": "header", "subtype": "header",
"id": 1001, "author": "Abanoub Khalil", "path": "ak-header/" },
{ "name": "Footer", "title": "Footer", "thumbnail": "", "url": "",
"export_date": "2025-01-01", "source": "", "type": "footer", "subtype": "footer",
"id": 1002, "author": "Abanoub Khalil", "path": "ak-footer/" },
{ "name": "Home", "title": "Home", "thumbnail": "", "url": "",
"export_date": "2025-01-01", "source": "", "type": "page", "subtype": "page",
"id": 1003, "author": "Abanoub Khalil", "path": "ak-home/" }
],
"site-settings": { "settings": {} }
}
Each folder's template.json uses the same envelope as Method 1 above.
Import steps:
1. Elementor → Tools → Import Kit → upload ZIP
2. Select which templates to import → Import
3. Assign header/footer via Theme Builder → Conditions⚠️ ONLY use this format when the client explicitly has the "Template Kit Import" plugin.
⚠️ Do NOT use with Elementor's native Tools → Import — it WILL FAIL with "Couldn't use the .zip file".
Requires plugin: "Template Kit Import" (free, wordpress.org)
Import via: WordPress Admin → Tools → Template Kit → Upload ZIP
ZIP structure:
kit-name.zip
├── kit.json ← Envato manifest (completely different from manifest.json)
└── templates/
├── global-styles.json
├── header.json
├── footer.json
├── home.json
└── about.json
kit.json format:
⚠️ Key is "authorURL" (camelCase) — NOT "author_url" (snake_case will silently break validation)
{
"name": "Kit Name",
"slug": "kit-slug",
"version": "1.0.0",
"author": "Abanoub Khalil",
"authorURL": "https://akstudio.me",
"templates": [
{ "name": "Global Styles", "file": "templates/global-styles.json", "type": "kit-styles", "thumbnail": "" },
{ "name": "Home", "file": "templates/home.json", "type": "page", "thumbnail": "" },
{ "name": "Header", "file": "templates/header.json", "type": "header", "thumbnail": "" },
{ "name": "Footer", "file": "templates/footer.json", "type": "footer", "thumbnail": "" }
],
"requiredPlugins": [
{ "name": "Elementor", "slug": "elementor", "source": "wordpress" }
]
}
Import steps:
1. Install "Template Kit Import" plugin from wordpress.org
2. Tools → Template Kit → Upload Template Kit ZIP File
3. Import Global Kit Styles FIRST (sets colors + fonts site-wide)
4. Import each template in order
5. Pages → Add New → Edit with Elementor → folder icon → View Installed Kit → InsertWhen user asks for a kit ZIP with no plugin context → produce Method 2 (Elementor native export)
When user asks for individual files → produce Method 1 envelopes
When user mentions "Template Kit Import plugin" → produce Method 3 (Envato format)
When in doubt → produce Method 1 — it never failsAlways generate with actual brand values. Import FIRST before any page templates.
{
"title": "Global Kit Styles",
"type": "kit-styles",
"version": "0.4",
"page_settings": {},
"content": [],
"settings": {
"system_colors": [
{ "_id": "primary", "title": "Primary", "color": "#005AFF" },
{ "_id": "secondary", "title": "Secondary", "color": "#1A1A2E" },
{ "_id": "text", "title": "Text", "color": "#08091E" },
{ "_id": "accent", "title": "Accent", "color": "#00C87A" }
],
"custom_colors": [
{ "_id": "c_bg_dark", "title": "BG Dark", "color": "#0A0D1A" },
{ "_id": "c_card", "title": "Card", "color": "#141628" },
{ "_id": "c_muted", "title": "Muted", "color": "#6B7280" },
{ "_id": "c_border", "title": "Border", "color": "#1A1D33" }
],
"system_typography": [
{ "_id": "primary", "title": "Primary",
"typography_typography": "custom", "typography_font_family": "Inter",
"typography_font_weight": "700", "typography_font_size": { "unit": "px", "size": 48 },
"typography_line_height": { "unit": "em", "size": 1.15 },
"typography_letter_spacing": { "unit": "px", "size": -1 } },
{ "_id": "secondary", "title": "Secondary",
"typography_typography": "custom", "typography_font_family": "Inter",
"typography_font_weight": "600", "typography_font_size": { "unit": "px", "size": 24 },
"typography_line_height": { "unit": "em", "size": 1.3 } },
{ "_id": "text", "title": "Text",
"typography_typography": "custom", "typography_font_family": "Inter",
"typography_font_weight": "400", "typography_font_size": { "unit": "px", "size": 16 },
"typography_line_height": { "unit": "em", "size": 1.75 } },
{ "_id": "accent", "title": "Accent",
"typography_typography": "custom", "typography_font_family": "Inter",
"typography_font_weight": "500", "typography_font_size": { "unit": "px", "size": 13 },
"typography_letter_spacing": { "unit": "px", "size": 1 },
"typography_text_transform": "uppercase" }
],
"custom_typography": [],
"default_generic_fonts": "Inter, sans-serif"
}
}<script> JS onlyicon-list or button widgets (NOT html)alert or button (xs, pill) widgets (NOT html)heading + text-editor + button widgets (NOT html)text-editor + button widgets (NOT html)heading + icon-list + button in styled container (NOT html)/* */ or //)id"elements": []"isInner": false"isInner": truehttps://placehold.co/WxH/BGHEX/TEXTHEX?text=Label_tablet + _mobile suffixes on font sizes, padding, widths.json per pageglobal-styles.json with brand colors + fonts⚠️ PRO ONLY:
type: "header" / "footer" | custom_css per element | Scroll/Motion Effects
Popup Builder | Form Widget | Sticky | Dynamic Tags
✅ FREE ALTERNATIVES:
header/footer → container sections inside each page
Forms → shortcode widget + WPForms or CF7
Animations → Entrance Animations (free, Advanced tab)references/widget-map.md — Full JSON schemas for all 22 native widgets + ACF CPT field setsreferences/style-map.md — CSS → Elementor JSON mappings (spacing, typography, backgrounds, overflow, position, overlay)references/visual-analysis.md — Color extraction, typography tree, layout detection for images/PDFsreferences/section-patterns.md — 15+ pre-built section JSON patterns using only native widgetsAK Elementor Studio by Abanoub Khalil — Senior WordPress & Webflow Developer, Cairo, Egypt. 🌐 akstudio.me · 💼 7+ years · Elementor Pro · Webflow · ACF · PHP · GSAP 🏢 InVitro Capital — AllCare.ai, AllRx.ai · 🔧 13+ live freelance projects, Egypt & MENA
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.