| name | new-theme |
| description | Scaffold a new WordPress theme in packages/themes/. |
Scaffold a New WordPress Theme
Create a new WordPress theme in packages/themes/ following the project's established conventions.
Step 0 — Understand the purpose
Ask the user: "What will this theme do?" — a brief description of the site or project it is for and the design goals it should achieve.
Based on the description, suggest 2–3 slug and name pairs, for example:
Based on your description, here are some suggestions:
| # | Slug | Name |
|---|
| 1 | storefront-lite | Storefront Lite |
| 2 | shop-theme | Shop Theme |
| 3 | modern-store | Modern Store |
Which would you like to use, or do you have your own preference?
- The user may pick one of the suggestions or provide their own slug and name.
- Confirm the final choice before proceeding.
Step 1 — Gather remaining information
Ask the user for:
- Description — one sentence (use the purpose from Step 0 if it already covers this).
- Is it a child theme? — if yes, ask for the parent theme slug.
Scan packages/themes/ for an existing theme to use as a structural reference.
Step 2 — Create the directory structure
packages/themes/<theme-slug>/
├── style.css
├── functions.php
├── index.php (empty — required by WP)
├── theme.json
├── t2.json
├── src/
│ ├── Setup/
│ │ └── ThemeSetup.php
│ ├── view.css (frontend entry point)
│ ├── editor.css (block editor entry point)
│ └── blocks/ (per-block CSS overrides, imported into view.css/editor.css)
├── templates/
│ └── index.html (FSE block template)
├── parts/
│ ├── header.html
│ └── footer.html
├── assets/ (empty — populated by build)
├── package.json
└── composer.json
Step 3 — File contents
style.css
If child theme, add: Template: <parent-theme-slug>
functions.php
<?php
declare( strict_types=1 );
use Dekodeinteraktiv\Theme\<PascalSlug>\Setup\ThemeSetup;
require_once __DIR__ . '/vendor/autoload.php';
ThemeSetup::instance()->hooks();
src/Setup/ThemeSetup.php
<?php
declare( strict_types=1 );
namespace Dekodeinteraktiv\Theme\<PascalSlug>\Setup;
class ThemeSetup {
private static ?self $instance = null;
private function __construct() {}
public static function instance(): self {
return self::$instance ??= new self();
}
public function hooks(): void {
add_action( 'after_setup_theme', [ $this, 'setup' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_assets' ] );
}
public function setup(): void {
load_theme_textdomain( '<theme-slug>', get_template_directory() . '/languages' );
add_theme_support( 'wp-block-styles' );
add_theme_support( 'editor-styles' );
add_editor_style( 'assets/css/editor.css' );
}
public function enqueue_assets(): void {
$script_asset = include get_template_directory() . '/assets/js/theme.asset.php';
wp_enqueue_script(
'<theme-slug>-theme',
get_template_directory_uri() . '/assets/js/theme.js',
$script_asset['dependencies'],
$script_asset['version'],
true
);
$style_asset = include get_template_directory() . '/assets/css/view.asset.php';
wp_enqueue_style(
'<theme-slug>-style',
get_template_directory_uri() . '/assets/css/view.css',
[],
$style_asset['version']
);
}
}
package.json
{
"name": "<theme-slug>",
"private": true,
"version": "1.0.0",
"description": "<Description>",
"scripts": {
"build": "wp-scripts build",
"start": "wp-scripts start",
"test": "echo \"Error: no test specified\" && exit 1",
"clean": "rm -rf node_modules build dist"
},
"devDependencies": {
"@wordpress/scripts": "^27.0.0"
}
}
composer.json
{
"name": "dekodeinteraktiv/<theme-slug>",
"type": "wordpress-theme",
"version": "1.0.0",
"autoload": {
"psr-4": { "Dekodeinteraktiv\\Theme\\<PascalSlug>\\": "src/" }
}
}
theme.json (minimal, extend as needed)
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"appearanceTools": true,
"color": { "palette": [] },
"typography": { "fontFamilies": [] }
},
"styles": {}
}
Step 4 — Wire the theme into the root project
After creating the theme files, register it in the root configuration:
-
Root composer.json — add the theme under "require" using @dev:
{
"require": {
"dekodeinteraktiv/<theme-slug>": "@dev"
}
}
Then run composer update from the project root.
-
Root package.json — add the theme under "devDependencies":
{
"devDependencies": {
"<theme-slug>": "file:packages/themes/<theme-slug>"
}
}
Then run npm install from the project root.
Step 5 — Verify
After creating all files, confirm:
style.css header is valid.
- Namespace in PHP matches the PSR-4 map in
composer.json.
- Run from the project root:
npm run build
composer lint
npm run lint