From 8eae8f038aaf68d4b0901d73e7569b8793480fab Mon Sep 17 00:00:00 2001 From: Bappi Date: Fri, 10 Jul 2026 08:43:40 +1000 Subject: [PATCH 1/2] Wire the Keel (Total Business Theme) base into the ClaudeToWP pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the FSE/Tailwind base-theme with the Keel hybrid-classic theme (slug tbt), and re-point the scaffolder, packager, and visual-check gates to it. - base-theme/: swap FSE/Tailwind starter for the tbt Keel theme (PHP template hierarchy + hooks + server-rendered blocks; theme.json as the only token source; no Tailwind, no .html templates). - new-site.sh: clone base-theme -> sites/ and rewrite tbt->slug per RENAME.md (text domain, tbt_/Tbt_/TBT_ prefixes, block namespace, CSS vars), rename the .pot, fix .wp-env.json, then npm install && build. - package-site.sh: build with wp-scripts and stage a runtime-only zip (ships /build; excludes block source, tooling, bin/, examples/, docs). - visual-check re-point (REBUILD.md §11): - lint-theme: Keel CSS/markup paths + leftover-Tailwind and raw-value/token-enforcement checks. - seed: create + assign a nav menu (classic nav needs one). - assert: config-driven mobile-nav (classic dropdown, not FSE overlay). - style-diff: add --extract mode emitting the porting manifest. - validate-blocks: SSR rewrite (block.json/render.php validity, php -l, zero render-time PHP errors; drop the isValid check). - ledger/example.json: updated sequence, boot notes, Keel selectors. - Docs: CLAUDE.md rewritten as the Keel pipeline playbook; README architecture/quick-start/gates updated. Verified end-to-end: scaffolded a sample slug (0 residual tbt, correct build namespace, clean php -l), packaged a runtime-only zip, and ran the re-pointed gates against a live wp-now render (seed incl. menu creation, assert incl. classic mobile-nav, validate-blocks, style-diff --extract). Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 386 +- README.md | 424 +- base-theme/.editorconfig | 21 + base-theme/.gitignore | 10 + base-theme/.stylelintrc.json | 6 + base-theme/.wp-env.json | 15 + base-theme/404.php | 25 + base-theme/CLAUDE.md | 103 + base-theme/DECISIONS.md | 59 + base-theme/RENAME.md | 144 + base-theme/RUBRIC.md | 48 + base-theme/SPEC.md | 445 + base-theme/archive.php | 39 + base-theme/assets/css/base.css | 43 + base-theme/assets/css/theme.css | 451 + base-theme/assets/css/woocommerce.css | 273 + .../fonts/inter/InterVariable-Italic.woff2 | Bin 0 -> 387976 bytes .../assets/fonts/inter/InterVariable.woff2 | Bin 0 -> 352240 bytes base-theme/assets/fonts/inter/OFL.txt | 92 + base-theme/assets/js/navigation.js | 16 + base-theme/bin/import-sample-products.php | 74 + base-theme/bin/package.sh | 43 + base-theme/bin/phpcs.sh | 42 + base-theme/bin/responsive-shots.mjs | 27 + base-theme/bin/screenshot.mjs | 21 + base-theme/bin/theme-check.php | 84 + base-theme/bin/verify.sh | 229 + base-theme/blocks/product-showcase/block.json | 41 + base-theme/blocks/product-showcase/edit.js | 82 + base-theme/blocks/product-showcase/index.js | 12 + base-theme/blocks/product-showcase/render.php | 69 + base-theme/blocks/product-showcase/style.scss | 125 + base-theme/blocks/product-showcase/view.js | 32 + base-theme/comments.php | 53 + base-theme/composer.json | 21 +- base-theme/composer.lock | 288 +- .../blocks/category-showcase/block.json | 29 + .../blocks/category-showcase/edit.js | 47 + .../blocks/category-showcase/index.js | 12 + .../blocks/category-showcase/render.php | 67 + .../blocks/category-showcase/style.scss | 52 + base-theme/examples/tbt-child/functions.php | 35 + base-theme/examples/tbt-child/package.json | 15 + .../tbt-child/patterns/store-intro.php | 25 + base-theme/examples/tbt-child/style.css | 18 + base-theme/examples/tbt-child/theme.json | 40 + base-theme/footer.php | 25 + base-theme/front-page.php | 37 + base-theme/functions.php | 144 +- base-theme/header.php | 33 + base-theme/inc/blocks.php | 33 + base-theme/inc/enqueue.php | 52 + base-theme/inc/hooks.php | 166 + base-theme/inc/setup.php | 85 + base-theme/inc/template-tags.php | 109 + base-theme/inc/woocommerce.php | 92 + base-theme/index.php | 30 + base-theme/js/editor.js | 33 - base-theme/languages/tbt.pot | 417 + base-theme/package-lock.json | 25434 ++++++++++++++++ base-theme/package.json | 30 +- base-theme/page.php | 23 + base-theme/parts/footer.html | 18 - base-theme/parts/header.html | 16 - base-theme/parts/mini-cart.html | 7 - base-theme/patterns/cta.php | 32 - base-theme/patterns/features.php | 60 - base-theme/patterns/hero-cta.php | 35 + base-theme/patterns/hero.php | 47 - base-theme/patterns/product-grid.php | 22 + base-theme/phpcs.xml.dist | 37 +- base-theme/readme.txt | 116 +- base-theme/screenshot.png | Bin 22491 -> 72368 bytes base-theme/search.php | 44 + base-theme/searchform.php | 22 + base-theme/single.php | 30 + base-theme/src/css/app.css | 21 - base-theme/style.css | 31 +- base-theme/tailwind.config.js | 39 - base-theme/template-parts/content-none.php | 23 + base-theme/template-parts/content.php | 74 + base-theme/template-parts/entry-meta.php | 15 + base-theme/template-parts/navigation.php | 46 + base-theme/template-parts/site-branding.php | 26 + base-theme/templates/404.html | 17 - base-theme/templates/archive-product.html | 36 - base-theme/templates/archive.html | 31 - base-theme/templates/index.html | 28 - base-theme/templates/page.html | 9 - base-theme/templates/single-product.html | 17 - base-theme/templates/single.html | 37 - base-theme/theme.json | 260 +- base-theme/woocommerce/content-product.php | 32 + scripts/new-site.sh | 127 +- scripts/package-site.sh | 78 +- scripts/visual-check/assert.mjs | 44 +- scripts/visual-check/example.json | 43 +- scripts/visual-check/ledger.mjs | 10 +- scripts/visual-check/lint-theme.mjs | 175 +- scripts/visual-check/seed.mjs | 26 + scripts/visual-check/style-diff.mjs | 50 + scripts/visual-check/validate-blocks.mjs | 175 +- 102 files changed, 31291 insertions(+), 1591 deletions(-) create mode 100644 base-theme/.editorconfig create mode 100644 base-theme/.gitignore create mode 100644 base-theme/.stylelintrc.json create mode 100644 base-theme/.wp-env.json create mode 100644 base-theme/404.php create mode 100644 base-theme/CLAUDE.md create mode 100644 base-theme/DECISIONS.md create mode 100644 base-theme/RENAME.md create mode 100644 base-theme/RUBRIC.md create mode 100644 base-theme/SPEC.md create mode 100644 base-theme/archive.php create mode 100644 base-theme/assets/css/base.css create mode 100644 base-theme/assets/css/theme.css create mode 100644 base-theme/assets/css/woocommerce.css create mode 100644 base-theme/assets/fonts/inter/InterVariable-Italic.woff2 create mode 100644 base-theme/assets/fonts/inter/InterVariable.woff2 create mode 100644 base-theme/assets/fonts/inter/OFL.txt create mode 100644 base-theme/assets/js/navigation.js create mode 100644 base-theme/bin/import-sample-products.php create mode 100755 base-theme/bin/package.sh create mode 100755 base-theme/bin/phpcs.sh create mode 100644 base-theme/bin/responsive-shots.mjs create mode 100644 base-theme/bin/screenshot.mjs create mode 100644 base-theme/bin/theme-check.php create mode 100755 base-theme/bin/verify.sh create mode 100644 base-theme/blocks/product-showcase/block.json create mode 100644 base-theme/blocks/product-showcase/edit.js create mode 100644 base-theme/blocks/product-showcase/index.js create mode 100644 base-theme/blocks/product-showcase/render.php create mode 100644 base-theme/blocks/product-showcase/style.scss create mode 100644 base-theme/blocks/product-showcase/view.js create mode 100644 base-theme/comments.php create mode 100644 base-theme/examples/tbt-child/blocks/category-showcase/block.json create mode 100644 base-theme/examples/tbt-child/blocks/category-showcase/edit.js create mode 100644 base-theme/examples/tbt-child/blocks/category-showcase/index.js create mode 100644 base-theme/examples/tbt-child/blocks/category-showcase/render.php create mode 100644 base-theme/examples/tbt-child/blocks/category-showcase/style.scss create mode 100644 base-theme/examples/tbt-child/functions.php create mode 100644 base-theme/examples/tbt-child/package.json create mode 100644 base-theme/examples/tbt-child/patterns/store-intro.php create mode 100644 base-theme/examples/tbt-child/style.css create mode 100644 base-theme/examples/tbt-child/theme.json create mode 100644 base-theme/footer.php create mode 100644 base-theme/front-page.php create mode 100644 base-theme/header.php create mode 100644 base-theme/inc/blocks.php create mode 100644 base-theme/inc/enqueue.php create mode 100644 base-theme/inc/hooks.php create mode 100644 base-theme/inc/setup.php create mode 100644 base-theme/inc/template-tags.php create mode 100644 base-theme/inc/woocommerce.php create mode 100644 base-theme/index.php delete mode 100644 base-theme/js/editor.js create mode 100644 base-theme/languages/tbt.pot create mode 100644 base-theme/package-lock.json create mode 100644 base-theme/page.php delete mode 100644 base-theme/parts/footer.html delete mode 100644 base-theme/parts/header.html delete mode 100644 base-theme/parts/mini-cart.html delete mode 100644 base-theme/patterns/cta.php delete mode 100644 base-theme/patterns/features.php create mode 100644 base-theme/patterns/hero-cta.php delete mode 100644 base-theme/patterns/hero.php create mode 100644 base-theme/patterns/product-grid.php create mode 100644 base-theme/search.php create mode 100644 base-theme/searchform.php create mode 100644 base-theme/single.php delete mode 100644 base-theme/src/css/app.css delete mode 100644 base-theme/tailwind.config.js create mode 100644 base-theme/template-parts/content-none.php create mode 100644 base-theme/template-parts/content.php create mode 100644 base-theme/template-parts/entry-meta.php create mode 100644 base-theme/template-parts/navigation.php create mode 100644 base-theme/template-parts/site-branding.php delete mode 100644 base-theme/templates/404.html delete mode 100644 base-theme/templates/archive-product.html delete mode 100644 base-theme/templates/archive.html delete mode 100644 base-theme/templates/index.html delete mode 100644 base-theme/templates/page.html delete mode 100644 base-theme/templates/single-product.html delete mode 100644 base-theme/templates/single.html create mode 100644 base-theme/woocommerce/content-product.php diff --git a/CLAUDE.md b/CLAUDE.md index 6b1f9e8..45fc36e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,275 +1,203 @@ -# Claude Design → WordPress (ClaudeToWP) +# Claude Design → WordPress (ClaudeToWP) — Keel pipeline Turns a **Claude design** (HTML/Tailwind, or a Claude Design React/JSX bundle) into an -upload-ready **WordPress FSE block theme** (WooCommerce-capable). Claude is the converter: -it emits `theme.json` tokens, a ported stylesheet, native-block **patterns** (one per -section and one per full page), and template parts. The client assembles pages by inserting -the page patterns. +upload-ready **WordPress theme** built on **Keel** — a lean **hybrid-classic** base theme +(PHP template hierarchy + a named hook system + server-rendered React blocks; `theme.json` +tokens as the single source of truth; **no Tailwind**, no FSE `.html` templates). Claude is +the converter: it maps the design's real computed styles into `theme.json` tokens + scoped +CSS, ports each section to a **server-rendered block** or a **pattern**, and composes a +full-page pattern per page. The client creates a Page, inserts the pattern, edits block +attributes in the normal editor. + +> The base theme (`base-theme/`, slug `tbt`, display "Total Business Theme") is authoritative +> for **theme internals** — read `base-theme/CLAUDE.md`, `base-theme/SPEC.md`, and +> `base-theme/RENAME.md`. THIS file governs the **pipeline** around it (clone → convert → +> gate → package). On any conflict about the theme itself, the base-theme docs win. ## Non-negotiables (break one ⇒ the delivery is not done) 1. **Pixel-perfect, every page.** Reproduce the design exactly — layout, type, spacing, - colour, and POSITION — for *every* page (home, about, services, contact, booking, - shop…), not just home. "Close" is a fail. -2. **Native blocks only — never `wp:html` for content.** The whole point of a theme is that - the client can edit it. (§Conversion) -3. **Fidelity comes from the design's real CSS**, ported into `src/css/app.css` — not from - utilities or guesswork. Read the actual source. (§Use the design's real source) -4. **Page content lives in the Page, not the template** — full-page pattern + content-only - editor; no `front-page.html`, no baked `page-{slug}.html`. (§Page-content model) + colour, and POSITION — for *every* page, not just home. "Close" is a fail. Fidelity comes + from the design's **real computed styles** (§Porting), not guesswork. +2. **Agent-native editability.** Sections are **server-rendered blocks** (editable + attributes) or patterns of native blocks — never `wp:html` for content. The client must be + able to edit it. +3. **`theme.json` is the only token source.** Colours, fluid type, spacing, widths. Component + CSS consumes `--wp--preset--*`; **no raw hex/px where a token exists** (lint-enforced). +4. **Page content lives in the Page**, not the template — full-page pattern inserted into + `post_content`; `page.php` is title-less (designs carry their own hero). 5. **The DONE ledger must print `RESULT: DONE` before you say "done."** Measure, don't eyeball. (§The DONE gate) -6. **Theme-review grade**: Theme Check + WPCS clean, text-domain == slug, escaped output, - GPL, no hotlinked assets. (§Theme-review) +6. **Theme-review grade**: PHPCS (WordPress-Extra + Docs + WPThemeReview + PHPCompatibility) + and Theme Check clean; text-domain == slug; escaped output; GPL; no hotlinked assets. -When the user reports a problem, REPRODUCE AND MEASURE it before answering — never argue -from a proxy (a passing script, a computed `font-family`, a mismatch %). That is exactly -how the font-weight bug shipped. When a gate flags something, decide real-bug vs -gate-false-positive and fix the right one — NEVER loosen a gate to pass a real bug. +When the user reports a problem, REPRODUCE AND MEASURE it before answering — never argue from +a proxy (a passing script, a computed `font-family`, a mismatch %). When a gate flags +something, decide real-bug vs gate-false-positive and fix the right one — **NEVER loosen a +gate to pass a real bug.** ## Layout & build loop ``` -base-theme/ Reusable starter block theme. Clone per client; NEVER edit in place. -scripts/new-site.sh Clones base-theme -> sites/ (rewrites text-domain + prefix to slug). +base-theme/ The Keel base theme. Clone per client; NEVER edit in place. +scripts/new-site.sh Clones base-theme -> sites/, rewrites tbt -> slug (RENAME.md + recipe), then npm install && npm run build. +scripts/package-site.sh Builds blocks (wp-scripts) + lint gate -> dist/.zip. +scripts/visual-check/ The QA harness (the crown jewel — re-point, never rebuild). sites// The per-client theme that ships (git-ignored here). ``` -1. `scripts/new-site.sh ` → `sites//` from `base-theme/`. -2. Convert (§Conversion): `theme.json` + `tailwind.config.js` tokens, port the design CSS - into `src/css/app.css`, a full-page pattern per page + reusable section patterns, native - header/footer parts. -3. `cd sites/ && npm install && npm run build` (or `npm run dev` to watch). -4. QA by RENDERING — boot wp-now and run the DONE ledger (§The DONE gate). Iterate. -5. `scripts/package-site.sh ` → `dist/.zip` (re-runs lint as a blocking - gate; keeps dev tooling out). Upload via wp-admin > Appearance > Themes > Add New. +1. `scripts/new-site.sh "Display Name"` → `sites//` from `base-theme/`, + with every identifier rewritten to the slug (text domain, `tbt_`/`Tbt_`/`TBT_` prefixes, + block namespace `tbt/`→`/`, CSS `--tbt-`→`---`) and blocks built. +2. Convert (§Conversion): fold the design's computed styles into `theme.json` tokens + scoped + CSS; port each section to a Keel block or pattern; compose a full-page pattern per page. +3. `cd sites/ && npm run build` (wp-scripts) after block/source edits. +4. QA by RENDERING — boot WordPress and run the DONE ledger (§The DONE gate). Iterate. +5. `scripts/package-site.sh ` → `dist/.zip` (runtime tree only: PHP hierarchy, + `inc/`, `template-parts/`, `patterns/`, `assets/`, `build/`; excludes block source, deps, + tooling). Upload via wp-admin > Appearance > Themes > Add New. ## Use the design's real source -A Claude Design link returns a gzipped tar of a React/JSX project -([[claude-design-export-format]]). Extract it to a **readable** dir (repo or `/tmp`, NOT -`~/Documents` — the gates can't read TCC-protected dirs). Then: -- `src/styles.css` → the exact tokens and CSS. Port it faithfully into `src/css/app.css`; - fidelity comes from this CSS, not from utilities. -- `app.jsx` `TWEAK_DEFAULTS` → defaults that change the whole look. e.g. `headers:"sans"` - ⇒ headings are Inter, NOT a serif. Getting this wrong was the single biggest miss. +A Claude Design link returns a gzipped tar of a React/JSX project. Extract it to a **readable** +dir (repo or `/tmp`, NOT `~/Documents` — the gates can't read TCC-protected dirs). Then read +the actual rendered CSS — fidelity comes from what the design **computes**, not from utilities. +Annotated designs (per `base-theme/RENAME.md` §4 / the design contract) take a fast path +(`:root` tokens + `data-wp-role` routing); legacy Tailwind/HTML designs fall back to full +computed-style extraction below. ## Conversion (how each piece is built) -**Tokens → BOTH `theme.json` and `tailwind.config.js`.** Palette, fonts, spacing, -content/wide widths. They must agree (native blocks read theme.json, utilities read the -Tailwind config) — parallel sources synced by hand, not Global-Styles-drives-Tailwind. - -**Each section → one pattern in `patterns/`** (follow `patterns/hero.php`): -- Structure with native blocks (`group`, `columns`, `cover`, `image`, `heading`, - `paragraph`, `buttons`, `list`). Special bits are ALSO native: brand = Site Title + Site - Tagline; menus = Navigation block; search = core Search; socials = Social Icons - (`core/social-links`). -- Tailwind utilities ride on `className` — keep the rendered `class` attribute in sync with - the block's `className` (WP needs the class in saved HTML). -- Custom CSS for the last 5% goes in `src/css/app.css`, scoped to a section className, - never global. -- **Match every element's exact treatment** per section: font family/weight/style, colour, - size, position. Real misses to avoid: prices/labels serif-italic + muted (not sans + - wine); hero CTA bottom-RIGHT with lede bottom-LEFT (a `hero-meta` flex row, - `justify-content:space-between`); a single `→` on arrow links; footer socials in a white - horizontal row. - -**Video hero** → `core/cover` with `"backgroundType":"video"` and a `