Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .claude/templates/theme/functions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php
/**
* {{THEME_NAME}} theme functions.
*
* @package {{THEME_SLUG}}
*/

if ( ! defined( 'ABSPATH' ) ) {
exit;
}

add_action( 'after_setup_theme', static function () {
add_theme_support( 'wp-block-styles' );
add_theme_support( 'editor-styles' );
add_theme_support( 'responsive-embeds' );
} );
7 changes: 7 additions & 0 deletions .claude/templates/theme/parts/footer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!-- wp:group {"layout":{"type":"constrained"}} -->
<div class="wp-block-group">
<!-- wp:paragraph -->
<p>© {{SITE_TITLE}}</p>
<!-- /wp:paragraph -->
</div>
<!-- /wp:group -->
6 changes: 6 additions & 0 deletions .claude/templates/theme/parts/header.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<!-- wp:group {"layout":{"type":"constrained"}} -->
<div class="wp-block-group">
<!-- wp:site-title /-->
<!-- wp:navigation /-->
</div>
<!-- /wp:group -->
11 changes: 11 additions & 0 deletions .claude/templates/theme/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
Theme Name: {{THEME_NAME}}
Description: A blank Full Site Editing theme scaffolded by Flavian.
Version: 0.1.0
Requires at least: 6.5
Tested up to: 6.7
Requires PHP: 7.4
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: {{THEME_SLUG}}
*/
16 changes: 16 additions & 0 deletions .claude/templates/theme/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!-- wp:template-part {"slug":"header","tagName":"header"} /-->

<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
<main class="wp-block-group">
<!-- wp:query {"queryId":1,"query":{"perPage":10,"pages":0,"offset":0,"postType":"post","order":"desc","orderBy":"date","inherit":true}} -->
<div class="wp-block-query">
<!-- wp:post-template -->
<!-- wp:post-title {"isLink":true} /-->
<!-- wp:post-excerpt /-->
<!-- /wp:post-template -->
</div>
<!-- /wp:query -->
</main>
<!-- /wp:group -->

<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->
8 changes: 8 additions & 0 deletions .claude/templates/theme/templates/page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<!-- wp:template-part {"slug":"header","tagName":"header"} /-->
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
<main class="wp-block-group">
<!-- wp:post-title {"level":1} /-->
<!-- wp:post-content /-->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->
9 changes: 9 additions & 0 deletions .claude/templates/theme/templates/single.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!-- wp:template-part {"slug":"header","tagName":"header"} /-->
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
<main class="wp-block-group">
<!-- wp:post-title {"level":1} /-->
<!-- wp:post-date /-->
<!-- wp:post-content /-->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->
36 changes: 36 additions & 0 deletions .claude/templates/theme/theme.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"title": "{{THEME_NAME}}",
"settings": {
"appearanceTools": true,
"color": {
"palette": [
{ "slug": "primary", "name": "Primary", "color": "#111827" },
{ "slug": "accent", "name": "Accent", "color": "#2563eb" },
{ "slug": "surface", "name": "Surface", "color": "#ffffff" }
]
},
"typography": {
"fontFamilies": [
{
"slug": "system",
"name": "System",
"fontFamily": "system-ui, -apple-system, Segoe UI, Roboto, sans-serif"
}
]
},
"layout": {
"contentSize": "720px",
"wideSize": "1200px"
}
},
"styles": {
"color": { "background": "var(--wp--preset--color--surface)", "text": "var(--wp--preset--color--primary)" },
"typography": { "fontFamily": "var(--wp--preset--font-family--system)", "lineHeight": "1.6" }
},
"templateParts": [
{ "name": "header", "title": "Header", "area": "header" },
{ "name": "footer", "title": "Footer", "area": "footer" }
]
}
42 changes: 42 additions & 0 deletions .github/workflows/init-wizard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Init Wizard Tests

on:
push:
paths:
- 'scripts/init.mjs'
- 'scripts/init/**'
- 'tests/init/**'
- '.claude/templates/theme/**'
- 'package.json'
- 'pnpm-lock.yaml'
- '.github/workflows/init-wizard.yml'
pull_request:
paths:
- 'scripts/init.mjs'
- 'scripts/init/**'
- 'tests/init/**'
- '.claude/templates/theme/**'
- 'package.json'
- 'pnpm-lock.yaml'
- '.github/workflows/init-wizard.yml'

jobs:
init-wizard:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4
with:
version: 9

- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run init wizard tests
run: pnpm run test:init
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,24 @@ Typical runtime: 5–30 minutes. No manual `theme.json` authoring.
git clone <repository-url>
cd Flavian

# 2. Boot local WordPress (Docker must be running)
cp .env.example .env # edit values before continuing
# 2. Install deps and run the interactive setup wizard
pnpm install
pnpm run init # interactive
# or non-interactive:
pnpm run init -- --yes --name=my-site --theme=blank
```

The wizard writes `.env`, scaffolds a starter theme, optionally stages
WooCommerce, and makes an initial git commit. See
[docs/CLI-WIZARD.md](docs/CLI-WIZARD.md) for all flags and prompts.

```bash
# 3. Boot local WordPress (Docker must be running)
./wordpress-local.sh build # first time only
./wordpress-local.sh start
./wordpress-local.sh install # first time only

# 3. Open Claude Code and hand it your design
# 4. Open Claude Code and hand it your design
claude
> Convert this Figma design to WordPress: <your-figma-url>
```
Expand Down
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
"phpcs": "phpcs --standard=WordPress",
"phpcbf": "phpcbf --standard=WordPress",
"security-scan": "./scripts/wordpress/security-scan.sh",
"check-standards": "./scripts/wordpress/check-coding-standards.sh"
"check-standards": "./scripts/wordpress/check-coding-standards.sh",
"post-create-project-cmd": [
"@php -r \"if (!is_dir('node_modules')) { echo \\\"Run 'pnpm install' then 'node scripts/init.mjs' to finish setup.\\\\n\\\"; exit(0); } passthru('node scripts/init.mjs');\""
]
}
}
117 changes: 117 additions & 0 deletions docs/CLI-WIZARD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Interactive CLI Setup Wizard

`scripts/init.mjs` bootstraps a Flavian project — it scaffolds a theme, writes `.env`,
optionally stages WooCommerce, and creates an initial git commit. Run it once after
cloning the template (or after `composer create-project`).

## Running the wizard

```bash
# From a fresh clone:
pnpm install
pnpm run init # interactive
pnpm run init -- --yes # non-interactive, all defaults
```

Or directly:

```bash
node scripts/init.mjs
```

## Prompts

| Prompt | Default | Notes |
|---|---|---|
| Project / theme slug | directory basename, slugified | Kebab-case, 2–40 chars, starts with a letter |
| Site title | Title-cased slug | Human-readable, used in `.env` and `theme.json` |
| Theme starter | (you pick) | See below |
| WooCommerce support | `no` | Hidden when starter = `flavian-shop` (auto-enabled) |
| Local dev port | `8080` | 1024–65535 |
| Admin email | `git config user.email` | Falls back to `admin@example.com` |

### Theme starters

| Value | What you get |
|---|---|
| `blank` | Minimal FSE theme copied from `.claude/templates/theme/` with your slug/title substituted |
| `flavian-shop` | The bundled WooCommerce-ready theme, copied and renamed to your slug |
| `figma` | No theme generated. Writes `docs/NEXT-STEPS.md` pointing at the `figma-to-fse-autonomous-workflow` skill |
| `indesign` | Placeholder only — the InDesign-to-FSE pipeline is not yet implemented |

## Non-interactive flags

```
--yes Skip prompts, use defaults / flag values
--name <slug> Project slug
--theme <starter> blank | flavian-shop | figma | indesign
--woo Enable WooCommerce (auto-true for flavian-shop)
--port <n> Local dev port (default 8080)
--email <addr> Admin email
--no-git Skip git init
--help Show usage
```

Examples:

```bash
# Smallest possible run — accept all defaults
node scripts/init.mjs --yes

# Build a WooCommerce-ready shop
node scripts/init.mjs --yes --name=acme-shop --theme=flavian-shop

# Stage a Figma-driven project
node scripts/init.mjs --yes --name=marketing-site --theme=figma
```

## What gets written

A successful run produces:

```
<project>/
├── .env ← from .env.example, with your values
├── themes/<slug>/ ← scaffolded theme (skipped for figma/indesign)
├── docs/NEXT-STEPS.md ← only for figma/indesign starters
└── .git/ ← fresh repo, one commit (unless --no-git)
```

The initial scaffold commit is made with `git commit --no-verify`. The freshly
generated project has no commit hooks installed yet, so the flag is purely
belt-and-braces — it has no effect on the commits *you* make afterward.

## What gets validated

After the apply phase, the wizard runs static checks:

1. `.env` exists and is non-empty
2. `themes/<slug>/theme.json` parses as valid JSON
3. `themes/<slug>/style.css` exists
4. `themes/<slug>/templates/index.html` exists

Steps 2–4 are skipped for `figma` and `indesign` starters since they don't
generate a theme directly.

A verification failure leaves the scaffold in place so you can fix and re-run.

## Testing the wizard

```bash
pnpm run test:init
```

Runs all unit tests under `tests/init/unit/` plus integration smoke tests under
`tests/init/integration/`. The CI job (`.github/workflows/init-wizard.yml`)
runs this on every push/PR that touches the wizard code.

## Known limitations

- The InDesign starter is a placeholder; no pipeline ships yet.
- Re-running the wizard against an existing `themes/<slug>/` directory fails
cleanly — there's no in-place upgrade path.
- Verification is static-only. Docker isn't booted; if Docker is missing or
misconfigured, you'll find out when you run `docker compose up`.
- `--yes` mode does not invoke `@clack/prompts`, so the wizard can run in
CI/test environments without it installed. The interactive mode does require
`pnpm install` to have run first.
Loading
Loading