Scaffold a new WordPress theme in packages/themes/.
Create a new WordPress theme in packages/themes/ following the project's established conventions.
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-liteStorefront Lite 2 shop-themeShop Theme 3 modern-storeModern Store
Which would you like to use, or do you have your own preference?
Ask the user for:
Scan packages/themes/ for an existing theme to use as a structural reference.
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
style.css/*
Theme Name: <Theme Name>
Description: <Description>
Version: 1.0.0
Requires at least: 6.4
Requires PHP: 8.4
Author: Dekodeinteraktiv
Text Domain: <theme-slug>
*/
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": {}
}
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.
After creating all files, confirm:
style.css header is valid.composer.json.npm run build # Turbo builds the new theme alongside other packages
composer lint # PHP CodeSniffer
npm run lint # JS + CSS linting