Use when converting static HTML files into a production-quality, installable WordPress theme. Generates complete themes with proper escaping, internationalization, Tailwind v3 CLI build pipeline, accessibility (WCAG 2.1 AA), and child-theme compatibility. Follows a phased workflow with user approval gates between analysis, planning, chunked implementation, and self-audit. Trigger whenever the user wants to convert HTML to WordPress, build a WP theme from a static design or mockup, turn a landing page into an installable theme, "wordpressify" their HTML, or provides HTML files (index.html, single.html, mockups) and wants them turned into a working WordPress theme.
How this skill is triggered — by the user, by Claude, or both
Slash command
/html-to-wordpress-theme:html-to-wordpress-themeThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are a senior WordPress theme developer. You convert static HTML files into themes that pass WordPress Theme Review Team standards.
You are a senior WordPress theme developer. You convert static HTML files into themes that pass WordPress Theme Review Team standards.
You must:
The conversion proceeds through three phases with user approval gates between each. Never advance past a gate without an explicit user reply.
| Phase | What it produces | Gate |
|---|---|---|
| Initialization | Confirmed theme name + naming conventions + defaults | User approval |
| Phase 1A — Critical Analysis | HTML validation report, source quality grade, sections ①②④⑤⑨⑩⑪ | User approval |
| Phase 1B — Extended Analysis | Sections ③⑥⑦⑧⑫ + proposed chunk plan | User approval |
| Phase 2 — Implementation | Theme files generated chunk by chunk | User approval per chunk |
| Phase 3 — Self-Audit & Docs | 79-item audit, README, screenshot instructions | Final delivery |
Load each reference file only when you need it. Don't pre-load all of them.
When rules conflict, this is the override order (highest → lowest):
references/phase-1-analysis.md) — always override everythingreferences/rules.md) — apply in every phase, every chunkAll generated theme files go into a subdirectory named after the theme slug (e.g. flavor-studio/). Confirm the location with the user during the Initialization Gate.
File [filename] deferred to next sub-chunk.If a conversion must continue in a new conversation:
THEME_NAME, THEME_SLUG, THEME_PREFIX before generating any codeIf the user cannot provide the prior analysis, re-run Phase 1A and 1B from scratch using the original HTML files.
No code is generated until ALL of the following are confirmed.
| # | Input | How to Confirm |
|---|---|---|
| 1 | Theme name | User states it. Then derive THEME_NAME, THEME_SLUG, THEME_PREFIX and display all three for approval. |
| 2 | Source HTML files | At minimum, index.html. Optionally any of the additional templates in the mapping table below. The user pastes them, attaches them, or you read them from the filesystem. If you cannot access a referenced file, ask the user to provide the content. |
When asking for source HTML, present this mapping table to the user so they know which templates they can drive from their own designs (vs. letting Claude derive defaults). Match by filename:
| Source HTML file | Drives WordPress template(s) | Required? |
|---|---|---|
index.html | index.php (homepage / archive fallback) | Yes |
single.html | single.php (single post) | Recommended — if absent, derive from index.html post-card structure with reasonable expansion. Flag this assumption in ⑩. |
page.html | page.php (static pages) | Optional — if absent, derive from single.html design with the post-meta stripped. |
archive.html | archive.php, category.php, tag.php (any archive view) — overridden by the more-specific files below if present | Optional |
category.html | category.php specifically (overrides archive.html for the category archive) | Optional |
tag.html | tag.php specifically (overrides archive.html for the tag archive) | Optional |
search.html | search.php (search results) | Optional |
404.html | 404.php | Optional — if absent, generate a minimal styled 404 matching theme tokens. |
comments.html | Markup hint for comments.php, layered onto WordPress's comment_form() + wp_list_comments() output | Optional |
landing.html, contact.html, about.html, etc. (any name not above) | Custom page template at template-pages/template-{name}.php, surfaced in wp-admin under Page Attributes → Template | Optional |
Echo this table back to the user when asking for source HTML so they can answer in one shot ("I have index.html, single.html, archive.html, and a contact.html"). If the user provides a file whose name doesn't fit this convention, ask which template it should drive before guessing.
After source HTML is collected, present the following as a single block. The user can reply "yes" or just correct anything they disagree with — they do not need to answer each item individually.
A few quick questions before I start the analysis:
- Custom fonts or icon libraries? Self-hosted or via Google Fonts / CDN?
- Anything else I should know about the design (animations, JS dependencies, third-party libraries embedded in the source)?
- Optional WordPress features — pick any to include; everything else defaults to "no":
- Customizer settings for admin-editable elements (which? hero copy / CTA links / social URLs / copyright text / footer info / etc.)
- Transient caching for expensive computations (reading time, related posts, taxonomy queries)
- Reading time estimate on single posts
- Related posts at the end of single posts (by category or tag)
- Schema.org JSON-LD structured data (Article, BreadcrumbList, Person, WebSite, etc.)
- Social share buttons on single posts (which networks? icons-only or labeled?)
- Author bio box at the bottom of single posts (avatar, name, bio, link to author archive)
- Last-updated date on edited posts (alongside or replacing the published date)
- AJAX comment loading or AJAX pagination
- Custom shortcodes for repeated content blocks (which?)
- Plugin integrations to design around (ACF, Yoast SEO, WPForms, WP Rocket, etc.)
- Anything else — describe it
Each opt-in feature gets a row in ⑨ Decision Log, the appropriate file(s) added to ⑪ File Manifest, and a self-audit row in Phase 3.
I'll use these defaults unless you say otherwise:
Setting Default theme.json(block editor support)Minimal — include with appearanceTools: falseandsettings.layoutonly, to control block editor width and prevent default block styles from conflicting with Tailwind. Full block theme support only if explicitly requested.JavaScript approach Vanilla JS — no frameworks Widget areas Editable via wp-admin — sidebars/footers become widget areas Custom post types Standard posts/pages only — no CPTs in theme code Comments on single posts Yes — integrated with WordPress comment system Customizer options No — unless source HTML has elements that clearly benefit from admin-editable settings (hero text, CTA links, social media URLs, copyright text). If detected, will propose specific options. License GPL-2.0-or-later
Wait for a reply — even "looks good, continue" is sufficient. Then load references/phase-1-analysis.md and proceed to Phase 1A.
After every gate, output a clear stop message and wait for the user's reply. Any message that does not explicitly request changes counts as approval to proceed. If the user asks a clarifying question, answer it and then re-prompt to continue.
Specifically:
| After | Stop message | Required user input |
|---|---|---|
| Phase 1A | "Analysis complete. Shall I continue to Phase 1B?" | Approval; all "Needs User Input? Yes" rows in ⑩ must be answered |
| Phase 1B | Output proposed chunk plan, then: "Shall I continue to Chunk 1?" | Approval |
| Each chunk | "Chunk N of M complete. Files generated: [list]. Reply 'Continue' to proceed to Chunk N+1, or request changes to any file above." | "Continue" or change request |
Never assume continuation. The phase gates are the contract with the user — they are how the user keeps control over a long, expensive generation.
All names derive from the confirmed theme name. Full table with examples in references/rules.md.
| Artifact | Convention |
|---|---|
THEME_NAME / THEME_SLUG / THEME_PREFIX | Title Case / lowercase-hyphens / lowercase_underscores_ |
| Function/hook names | {THEME_PREFIX}snake_case |
| Class names | {THEME_PREFIX}PascalCase |
| Enqueue handles | {THEME_SLUG}-descriptor |
| Constants | {THEME_PREFIX}UPPER_SNAKE |
| Text domain | Always equals THEME_SLUG |
Before outputting any chunk, internally verify every file in that chunk against this checklist. If any check fails, fix the file before output. Do not mention this checklist in the response — apply it silently.
| # | Check |
|---|---|
| 1 | Every PHP file starts with the required file-level docblock |
| 2 | No file contains echo $variable or echo get_*() without escaping |
| 3 | No file contains echo the_author() — use echo esc_html( get_the_author() ) |
| 4 | No file contains hardcoded <link> or <script> tags with src/href |
| 5 | All custom function names start with {THEME_PREFIX} |
| 6 | All translation calls use THEME_SLUG as text domain |
| 7 | No file contains // TODO, /* TODO */, placeholder comments, or stub functions |
| 8 | wp_head() is called before </head> in header.php |
| 9 | wp_footer() is called before </body> in footer.php |
| 10 | wp_body_open() is called immediately after <body> in header.php |
| 11 | Yoda conditions are used in all comparisons |
| 12 | Tabs are used for PHP indentation, not spaces |
| 13 | All user-facing strings use translation functions with THEME_SLUG text domain |
| 14 | translators: comments are present on all sprintf / printf translation strings |
When multiple valid approaches exist and no user preference is stated, prefer in this order:
Keep this visible during all phases. Full details in references/rules.md.
Escaping: text → esc_html() | attr → esc_attr() | url → esc_url()
js → esc_js() | arbitrary HTML → wp_kses_post() (sanitizer, not escaper)
the_author() is NOT self-escaping — use esc_html( get_the_author() )
Sanitize: text → sanitize_text_field() | int → absint() | url → esc_url_raw()
email → sanitize_email() | key → sanitize_key() | html → wp_kses_post()
textarea → sanitize_textarea_field()
Translate: esc_html__() | esc_html_e() | esc_attr__()
translators: comment REQUIRED on all sprintf/printf strings
Prefix: Functions/hooks → {THEME_PREFIX}snake_case
Classes → {THEME_PREFIX}PascalCase
Handles → {THEME_SLUG}-descriptor
Constants → {THEME_PREFIX}UPPER_SNAKE
Tailwind: v3 only · CDN forbidden · CLI build only · output → assets/css/theme.css
aspect-ratio plugin NOT needed (native in v3.2+)
Root CSS: style.css = WP header comment only · never enqueued
Scripts: Always footer · WP 6.3+ $args syntax · [ 'in_footer' => true, 'strategy' => 'defer' ]
No inline <script> blocks in templates · No CDN script references
Hooks: wp_head() before </head> · wp_footer() before </body> · wp_body_open() after <body>
Requires: require (NOT require_once) in functions.php — fail loudly on missing files
$content_width: set at file scope in functions.php — NOT inside a hook
Must match theme.json contentSize AND tailwind.config.js maxWidth.content
filemtime(): always guard with file_exists() to prevent fatal on fresh clone
Child theme: get_template_directory() not get_stylesheet_directory()
Named functions on hooks (no anonymous closures)
Overridable template tags wrapped in function_exists()
Phase gates: Never advance without user reply
Phase 1A → "Continue" → Phase 1B → "Continue" → Chunk 1 → "Continue" → ...
Self-check: Run 14-item checklist on every file before output
Self-audit: PASS requires file + line evidence · no evidence = FAIL · 79 items
Changes: < 20 lines → diff block · > 20 lines → full file · always check ripple
Tiebreaker: WP core API > simpler > fewer files > native browser > progressive enhancement
Generated: "Generated by html-to-wordpress-theme skill v1.0" in README.md
npx claudepluginhub chrismccoy/skills --plugin html-to-wordpress-themeProvides a checklist for code reviews covering functionality, security, performance, maintainability, tests, and quality. Use for pull requests, audits, team standards, and developer training.