WordPress Theme Generator

VerifiedCaution

Creates a WordPress theme based on Underscores with Vite, Tailwind CSS v4, Alpine.js, Swiper, and AOS from a source folder.

Sby Skills Guide Bot
DevelopmentIntermediate
107/23/2026
Claude Code
#wordpress#theme-development#underscores#vite#tailwind-css

Recommended for

Our review

This skill generates a complete WordPress theme from the Underscores starter, integrating Vite, Tailwind CSS v4, Alpine.js, Swiper, and AOS, based on an existing source folder.

Strengths

  • Automates the installation and renaming of the Underscores theme
  • Integrates modern tools (Vite, Tailwind, Alpine.js) without manual configuration
  • Handles WooCommerce and Contact Form 7 options through interactive questions
  • Systematically replaces all '_s' occurrences in PHP files

Limitations

  • Requires a very specific source folder structure (src/index.html, src/js/app.js, etc.)
  • Only supports Vite as the build tool
  • Advanced theme customizations after generation are left to the developer
When to use it

Use this skill when you need to create a modern WordPress theme from an existing static HTML/Vite project, with ready-to-use Tailwind CSS integration.

When not to use it

Do not use it if your source project does not follow the expected structure or if you prefer to configure each tool manually.

Security analysis

Caution
Quality score85/100

The skill uses Bash for file operations (clone, sed, rm) within a WordPress theme directory, which is legitimate for theme generation. No malicious or destructive commands are present.

No concerns found

Examples

Generate theme from source folder
Create a WordPress theme using my Vite/Tailwind project located at ./my-design-folder
Full theme generation with WooCommerce
Generate a WordPress theme from the source at /projects/shop-design and include WooCommerce support

name: wp-theme description: Creates a WordPress theme based on Underscores (_s) with Vite + Tailwind CSS v4 + Alpine.js + Swiper + AOS, using a source folder as design reference. Use when building a new WP theme from a static HTML/Vite project. argument-hint: [source-folder-path] disable-model-invocation: true allowed-tools: Bash Read Write Edit Glob Grep Agent AskUserQuestion

WordPress Theme Generator (Underscores + Vite/Tailwind)

You are creating a WordPress theme based on the Underscores (_s) starter theme, integrating a Vite + Tailwind CSS v4 build system from an existing source folder.

Input

The user provides a source folder path as $ARGUMENTS. This folder contains:

  • src/index.html — Static HTML template for the home page
  • src/js/app.js — Main JS entry point (Alpine.js, Swiper, AOS)
  • src/css/app.css — Main CSS with Tailwind v4 config, theme tokens, custom utilities
  • src/css/*.css — Additional CSS modules
  • public/img/ — Static images
  • vite.config.js — Vite configuration
  • package.json — Dependencies

Step 0: Gather Information

Before starting, you MUST ask the user these questions using AskUserQuestion:

Question 1: Theme Name

Ask: "What should the theme name be? (used for the folder name, function prefixes, and text domain)"

  • This will be used as: folder name, function prefix (e.g., mytheme_setup), text domain, and version constant (e.g., MYTHEME_VERSION)

Question 2: Theme Metadata

Ask: "What are the theme details?"

  • Theme URI (website URL)
  • Author name
  • Author URI

Question 3: WooCommerce Support

Ask: "Do you want to include WooCommerce support from Underscores?"

  • Options: "Yes — Include WooCommerce integration (inc/woocommerce.php, WooCommerce CSS)" or "No — Skip WooCommerce support"
  • If YES: Keep inc/woocommerce.php, copy WooCommerce CSS files from source (woocommerce.css, custom-woocommerce.css, custom-booking.css), uncomment WooCommerce imports in app.css, and keep the conditional require in functions.php
  • If NO: Delete inc/woocommerce.php, woocommerce.css from theme root, and remove the WooCommerce conditional require from functions.php

Question 4: Contact Form 7 Support

Ask: "Do you want to include Contact Form 7 CSS support?"

  • If YES: Copy contactForm7.css and uncomment its import in app.css
  • If NO: Skip copying contactForm7.css

Step 1: Read the Source

Read and analyze the source folder provided:

  1. Read src/index.html — Identify all sections (header, banner, content sections, footer)
  2. Read src/js/app.js — Understand JS initialization (Alpine, Swiper instances, AOS, scroll handlers)
  3. Read src/css/app.css — Get theme tokens, custom utilities, imports
  4. Read src/css/*.css — All additional CSS modules
  5. Read vite.config.js — Build configuration
  6. Read package.json — Dependencies
  7. List public/img/ — Available images

Step 2: Clone Underscores

Clone the Underscores starter theme into the WordPress themes directory:

cd "wp-content/themes" && git clone https://github.com/Automattic/_s.git {theme-name}

Then immediately remove the .git directory:

rm -rf "wp-content/themes/{theme-name}/.git"

Step 3: Rename _s to Theme Name

Replace ALL references of _s with the theme name. This is a multi-pattern replacement:

# In all PHP files:
find . -name "*.php" -exec sed -i "s/'_s'/'{theme-name}'/g" {} +
find . -name "*.php" -exec sed -i "s/\"_s\"/\"{theme-name}\"/g" {} +
find . -name "*.php" -exec sed -i "s/_s_/{theme-name}_/g" {} +
find . -name "*.php" -exec sed -i "s/_s-/{theme-name}-/g" {} +
find . -name "*.php" -exec sed -i "s/ _s/ {theme-name}/g" {} +

CRITICAL: The above sed commands do NOT catch _S_VERSION (uppercase). You MUST also:

find . -name "*.php" -exec sed -i "s/_S_VERSION/{THEME-NAME}_VERSION/g" {} +

Where {THEME-NAME}_VERSION uses the uppercase version of the theme name (e.g., MYTHEME_VERSION).

VERIFY with: grep -r "_S_VERSION" . and grep -r "_s" . --include="*.php" — both should return empty.

Step 4: Clean Up Underscores Files

Delete files that will be replaced by the Vite build system:

rm -rf sass/
rm -f style-rtl.css js/customizer.js js/navigation.js
rm -f composer.json phpcs.xml.dist .eslintrc .stylelintrc.json
rm -f README.md LICENSE
rmdir js/ 2>/dev/null

If WooCommerce support was declined, also:

rm -f inc/woocommerce.php woocommerce.css

Step 5: Copy Source Files

mkdir -p src/js src/css public/img
cp {source}/src/js/app.js src/js/app.js
cp {source}/src/css/*.css src/css/
cp {source}/public/img/* public/img/
cp {source}/pnpm-lock.yaml ./

Step 6: Create Build System Files

package.json

Write the same package.json as the source with only dev and build scripts.

vite.config.js

Write the Vite config adapted for WordPress (no index.html):

CRITICAL: Use rollupOptions.input as an OBJECT { app: 'js/app.js' }, NOT a string. A string causes the dev server to fail with "failed to resolve rollupOptions.input".

import { defineConfig } from 'vite';
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
    root: './src',
    publicDir: '../public',
    build: {
        manifest: true,
        outDir: '../dist',
        emptyOutDir: true,
        assetsDir: 'assets',
        rollupOptions: {
            input: { app: 'js/app.js' },
            output: {
                assetFileNames: (assetInfo) => {
                    const info = assetInfo.names[0].split('.')
                    let extType = info[info.length - 1]
                    if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) {
                        extType = 'img'
                    } else if (/woff|woff2/.test(extType)) {
                        extType = 'css'
                    }
                    return `assets/${extType}/[name]-[hash][extname]`
                },
                chunkFileNames: 'assets/js/[name]-[hash].js',
                entryFileNames: 'assets/js/[name]-[hash].js',
            },
        },
    },
    server: { strictPort: true, port: 3000, cors: true },
    plugins: [tailwindcss()],
    resolve: { alias: { '@': '/src/js' } },
});

.gitignore

/node_modules
/dist
.DS_Store

Step 7: Configure Tailwind CSS v4 Source Scanning

CRITICAL: Tailwind CSS v4 only scans files inside Vite's root (./src) by default. PHP templates are OUTSIDE src/, so Tailwind won't detect their classes and the CSS output will be incomplete.

In src/css/app.css, modify the Tailwind import to include the theme folder:

@import "tailwindcss" source("../../../{theme-name}");

The source() path is relative to the CSS file and must point to the theme's root directory so Tailwind scans all PHP files.

Step 8: Rewrite style.css

Replace ALL content with only the theme metadata header (no CSS rules):

/*
Theme Name: {Theme Display Name}
Theme URI: {theme-uri}
Author: {author}
Author URI: {author-uri}
Description: {description}
Version: 1.0.0
Tested up to: 6.7
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: LICENSE
Text Domain: {theme-name}
Tags: custom-menu, featured-images, threaded-comments, translation-ready
*/

Step 9: Rewrite functions.php

Replace the {theme-name}_scripts() function with a Vite asset loader:

  1. Define version constant: define('{THEME_NAME}_VERSION', '1.0.0');
  2. Keep: {theme-name}_setup(), register_nav_menus, theme supports, widget registration, all require statements for inc/ files
  3. Remove: The old wp_enqueue_style for style.css, wp_style_add_data for RTL, wp_enqueue_script for navigation.js
  4. Add {theme-name}_vite_assets():
    • If VITE_DEV constant is true: enqueue scripts from http://localhost:3000/
    • Else: read dist/.vite/manifest.json, enqueue hashed CSS/JS from manifest entry js/app.js
  5. Add script_loader_tag filter: Add type="module" to Vite script tags
  6. Add Google Fonts enqueue: Raleway (or whatever font the source uses)
  7. If NO WooCommerce: Remove the if (class_exists('WooCommerce')) require block

Step 10: Rewrite header.php

Convert the <header> section from src/index.html to WordPress PHP:

  • <!doctype html><html <?php language_attributes(); ?>>
  • <head> with wp_head(), Google Fonts preconnect links
  • <body <?php body_class('font-sans antialiased leading-loose'); ?> x-data="{ showMenu: false }">
  • <?php wp_body_open(); ?>
  • Logo: <img src="<?php echo esc_url(get_theme_file_uri('dist/img/{logo}')); ?>">
  • Desktop nav: wp_nav_menu(['theme_location' => 'menu-1', 'container' => false, 'menu_class' => '{desktop-menu-classes}'])
  • Mobile hamburger button with Alpine.js @click
  • Mobile nav: second wp_nav_menu() inside Alpine container

Step 11: Rewrite footer.php

Convert the <footer> section from src/index.html to WordPress PHP:

  • All static content from the source footer
  • Images with get_theme_file_uri('dist/img/...')
  • Dynamic year: <?php echo esc_html(wp_date('Y')); ?>
  • <?php wp_footer(); ?> before </body>
  • Close </body></html>

Step 12: Create front-page.php

Create a new file with all content sections from src/index.html (everything between header and footer):

<?php get_header(); ?>
<!-- All sections from index.html -->
<?php get_footer(); ?>

All image paths: ./img/X becomes <?php echo esc_url(get_theme_file_uri('dist/img/X')); ?> All inline style background images: url('<?php echo esc_url(get_theme_file_uri('dist/img/X')); ?>')

Step 13: Build & Verify

cd "wp-content/themes/{theme-name}"
pnpm install
pnpm build

Verify:

  1. dist/.vite/manifest.json exists with entry for js/app.js containing css array
  2. dist/assets/css/ and dist/assets/js/ contain hashed files
  3. dist/img/ contains all images from public/img/

Step 14: Post-Setup Instructions

Tell the user:

  1. Activate the theme in WP Admin > Appearance > Themes
  2. Create a page and set it as static front page in Settings > Reading
  3. Create a menu in Appearance > Menus and assign to "Primary"
  4. For development: add define('VITE_DEV', true); to wp-config.php and run pnpm dev
  5. For production: run pnpm build (remove or set VITE_DEV to false)

Important Rules

  • Always use esc_url() for image URLs and esc_html() for text output in PHP templates
  • Keep ALL Underscores template files (index.php, page.php, single.php, archive.php, search.php, 404.php, comments.php, sidebar.php, template-parts/) — only rename prefixes
  • The inc/ directory files (template-tags.php, template-functions.php, customizer.php, custom-header.php) are kept and renamed
  • Use get_theme_file_uri() for all asset paths (not get_template_directory_uri())
  • The Vite manifest path is dist/.vite/manifest.json (Vite 5+ places it inside .vite/ subfolder)
Related skills