Skip to content

Commit a59ced6

Browse files
committed
Simplify scaffold theme defaults
1 parent 76f9e33 commit a59ced6

3 files changed

Lines changed: 15 additions & 129 deletions

File tree

‎apps/cli/ai/system-prompt.ts‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,10 @@ Then continue with:
150150
151151
1. **Get site details**: Use site_info to get the site path, URL, and credentials.
152152
2. **Plan the design**: Before writing any code, review the site spec (from the site-spec skill) and the Design Guidelines below to plan the visual direction — layout, colors, typography, spacing.
153-
3. **Write theme/plugin files**: For a brand new theme, call \`scaffold_theme\` first — it drops a minimal block-theme baseline (style.css, theme.json with appearanceTools and a sane palette/spacing scale, functions.php with frontend + editor style enqueue, default templates and parts, empty assets/fonts and patterns dirs) and activates it by default. Then use Write and Edit to fill the scaffold (one part/template/file per turn). For the homepage, Edit \`templates/front-page.html\` directly — replace \`<!-- wp:post-content /-->\` with \`<!-- section:<concern> -->\` anchors (hero, features, cta, etc.) and fill one anchor per Edit using only core blocks. WP renders this template at \`/\` automatically, so no DB page and no \`show_on_front\`/\`page_on_front\` change is needed. Reserve \`templates/page.html\` for interior pages. For plugins or for editing an existing theme, use Write and Edit directly under the site's wp-content/themes/ or wp-content/plugins/ directory.
154-
4. **Configure WordPress**: Use wp_cli to install plugins, manage options, create posts and pages, edit and import content. The site must be running. Note: post content passed via \`wp post create\` or \`wp post update --post_content=...\` need to be pre-validated for editability and also validated using validate_blocks tool and adhere to the block content guidelines above as well. The \`wp_cli\` tool takes literal arguments, not shell commands: never use shell substitution or shell syntax such as \`$(cat file)\`, backticks, pipes, redirection, environment variables, or host temp-file paths to provide post content. Pass the literal content directly in \`--post_content=...\`, make \`--post_content\` the final argument in the command, and Studio will rewrite large content to a virtual temp file automatically.
155-
5. **Check the result**: Use take_screenshot to capture the site's landing page on desktop and mobile and verify the design visually on both viewports, check for wrong spacing, alignment, colors, contrast, borders, hover styles and other visual issues. Fix any issues found. Pay particular attention to the navigation menu and the CTA buttons. The design needs to match your original expectations. **Width check**: any section that was meant to be full-width (heroes, banners, edge-to-edge galleries, full-bleed footers) must visibly span the entire viewport in the desktop screenshot. If a "full-width" section only spans the content column (~700px at 1280px viewport), the block markup is missing \`align: "full"\` on the outer group or has a mismatched inner \`layout\` type — see the block-theme layout cascade rules above. Fix in markup, not custom CSS.
153+
3. **Write theme/plugin files**: For a brand new theme, call \`scaffold_theme\` first — it drops an unopinionated block-theme baseline (style.css with only the theme header, theme.json with appearanceTools only, functions.php with frontend + editor style enqueue, default templates and parts, empty assets/fonts and patterns dirs) and activates it by default. Then use Write and Edit to fill the scaffold (one part/template/file per turn). For plugins or for editing an existing theme, use Write and Edit directly under the site's wp-content/themes/ or wp-content/plugins/ directory.
154+
4. **Configure WordPress**: Use wp_cli to activate themes, install plugins, manage options, create posts and pages, edit and import content. The site must be running. Note: post content passed via \`wp post create\` or \`wp post update --post_content=...\` need to be pre-validated for editability and also validated using validate_blocks tool and adhere to the block content guidelines above as well. The \`wp_cli\` tool takes literal arguments, not shell commands: never use shell substitution or shell syntax such as \`$(cat file)\`, backticks, pipes, redirection, environment variables, or host temp-file paths to provide post content. Pass the literal content directly in \`--post_content=...\`, make \`--post_content\` the final argument in the command, and Studio will rewrite large content to a virtual temp file automatically.
155+
5. **Check the misuse of HTML blocks**: Verify if HTML blocks were used as sections or not. If they were, convert them to regular core blocks and run block validation again.
156+
6. **Check the result**: Use take_screenshot to capture the site's landing page on desktop and mobile and verify the design visually on both viewports, check for wrong spacing, alignment, colors, contrast, borders, hover styles and other visual issues. Fix any issues found. Pay particular attention to the navigation menu and the CTA buttons. The design needs to match your original expectations. **Width check**: any section that was meant to be full-width (heroes, banners, edge-to-edge galleries, full-bleed footers) must visibly span the entire viewport in the desktop screenshot. If a "full-width" section only spans the content column (~700px at 1280px viewport), the block markup is missing \`align: "full"\` on the outer group or has a mismatched inner \`layout\` type — see the block-theme layout cascade rules above. Fix in markup, not custom CSS.
156157
157158
## Working cadence
158159
@@ -162,8 +163,8 @@ One \`Write\` or \`Edit\` per turn (read-only \`site_info\`, \`site_list\`, \`wp
162163
163164
**Long files (>~200 lines): skeleton first, then fill across Edits.**
164165
165-
- \`style.css\`: skeleton = \`:root { ... }\` custom properties + 6–10 anchor comments \`/* === <concern> === */\` (e.g. \`reset\`, \`typography\`, \`hero\`, \`features\`, \`cta\`, \`footer\`, \`responsive\`), <2KB total. Fill one anchor per Edit (300–2000B each) — \`old_string\` is the anchor line, \`new_string\` is \`<anchor>\\n\\n<styles>\`. **When \`scaffold_theme\` was used, do NOT \`Write\` over the scaffolded \`style.css\`** — it already contains the theme header and UX-fix rules. Instead, \`Edit\` the file to append the \`:root { ... }\` block and anchor comments below the existing content, then fill anchors as above.
166-
- Interior page content (About, Contact, etc.): create the page empty (\`wp_cli post create --post_content=""\`), write \`<site>/tmp/page-<slug>.html\` (not inside the theme) with \`<!-- section:<concern> -->\` anchors (<1KB), fill one anchor per Edit using only core blocks (never wrap in \`core/html\`), then apply once with \`wp_cli eval '$content = file_get_contents(ABSPATH . "tmp/page-<slug>.html"); wp_update_post(["ID" => <id>, "post_content" => $content]); echo "ok";'\`. Do NOT use \`--post_content-file=<host path>\` — \`wp_cli\` runs inside the PHP-WASM filesystem (the host site directory is mounted at \`/wordpress/\`, so \`ABSPATH === "/wordpress/"\`) and cannot read host paths; \`--post_content-file=<host path>\` silently updates the post to empty content.
166+
- \`style.css\`: skeleton = \`:root { ... }\` custom properties + 6–10 anchor comments \`/* === <concern> === */\` (e.g. \`reset\`, \`typography\`, \`hero\`, \`features\`, \`cta\`, \`footer\`, \`responsive\`), <2KB total. Fill one anchor per Edit (300–2000B each) — \`old_string\` is the anchor line, \`new_string\` is \`<anchor>\\n\\n<styles>\`. **When \`scaffold_theme\` was used, do NOT \`Write\` over the scaffolded \`style.css\`** — it already contains the required theme header. Instead, \`Edit\` the file to append the \`:root { ... }\` block and anchor comments below the existing content, then fill anchors as above.
167+
- Page content: create the page empty (\`wp_cli post create --post_content=""\`), write \`<site>/tmp/page-<slug>.html\` (not inside the theme) with \`<!-- section:<concern> -->\` anchors (<1KB), fill one anchor per Edit using only core blocks (never wrap in \`core/html\`), then apply once with \`wp_cli eval '$content = file_get_contents(ABSPATH . "tmp/page-<slug>.html"); wp_update_post(["ID" => <id>, "post_content" => $content]); echo "ok";'\`. Do NOT use \`--post_content-file=<host path>\` — \`wp_cli\` runs inside the PHP-WASM filesystem (the host site directory is mounted at \`/wordpress/\`, so \`ABSPATH === "/wordpress/"\`) and cannot read host paths; \`--post_content-file=<host path>\` silently updates the post to empty content.
167168
168169
## Available Studio Tools (prefixed with mcp__studio__)
169170

‎apps/cli/ai/tests/tools.test.ts‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,6 @@ describe( 'Studio AI MCP tools', () => {
505505
'theme.json',
506506
'functions.php',
507507
'templates/index.html',
508-
'templates/front-page.html',
509508
'templates/single.html',
510509
'templates/page.html',
511510
'templates/archive.html',
@@ -537,7 +536,7 @@ describe( 'Studio AI MCP tools', () => {
537536
expect( functionsPhp ).toContain( "add_editor_style( 'style.css' )" );
538537

539538
expect( getTextContent( result ) ).toContain(
540-
`Block theme 'Acme Studio' scaffolded at ${ path.join( tempSiteRoot, 'wp-content', 'themes', 'acme-studio' ) }/.`
539+
"Block theme 'Acme Studio' scaffolded at wp-content/themes/acme-studio/."
541540
);
542541
expect( getTextContent( result ) ).toContain( 'wp theme activate acme-studio' );
543542
} );

‎apps/cli/ai/tools/scaffold-theme.ts‎

Lines changed: 8 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -70,28 +70,6 @@ License URI: http://www.gnu.org/licenses/gpl-2.0.html
7070
Text Domain: ${ slug }
7171
Tags: full-site-editing, block-patterns, block-styles, wide-blocks, accessibility-ready, style-variations
7272
*/
73-
74-
/* Link styles */
75-
a {
76-
text-decoration-thickness: 1px !important;
77-
text-underline-offset: .1em;
78-
}
79-
80-
/* Focus styles */
81-
:where(.wp-site-blocks *:focus) {
82-
outline-width: 2px;
83-
outline-style: solid;
84-
}
85-
86-
/* Reduce widows and orphans on prose */
87-
h1, h2, h3, h4, h5, h6, blockquote, caption, figcaption, p {
88-
text-wrap: pretty;
89-
}
90-
91-
/* Prevent unnecessary scrollbars on long preformatted text */
92-
:where(pre) {
93-
overflow-x: auto;
94-
}
9573
`;
9674
}
9775

@@ -101,79 +79,7 @@ function renderThemeJson(): string {
10179
version: 3,
10280
settings: {
10381
appearanceTools: true,
104-
useRootPaddingAwareAlignments: true,
105-
layout: {
106-
contentSize: '720px',
107-
wideSize: '1200px',
108-
},
109-
color: {
110-
palette: [
111-
{ color: '#FFFFFF', name: 'Base', slug: 'base' },
112-
{ color: '#111111', name: 'Contrast', slug: 'contrast' },
113-
{ color: '#3858E9', name: 'Accent', slug: 'accent' },
114-
],
115-
},
116-
spacing: {
117-
spacingSizes: [
118-
{ name: 'Tiny', size: '8px', slug: '20' },
119-
{ name: 'X-Small', size: '16px', slug: '30' },
120-
{ name: 'Small', size: '24px', slug: '40' },
121-
{ name: 'Regular', size: 'clamp(32px, 5vw, 48px)', slug: '50' },
122-
{ name: 'Large', size: 'clamp(48px, 8vw, 80px)', slug: '60' },
123-
{ name: 'X-Large', size: 'clamp(80px, 12vw, 128px)', slug: '70' },
124-
{ name: 'Huge', size: 'clamp(128px, 16vw, 192px)', slug: '80' },
125-
],
126-
},
127-
typography: {
128-
fluid: true,
129-
fontFamilies: [
130-
{
131-
name: 'System Sans',
132-
slug: 'system-sans',
133-
fontFamily:
134-
"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif",
135-
},
136-
],
137-
},
138-
},
139-
styles: {
140-
color: {
141-
background: 'var(--wp--preset--color--base)',
142-
text: 'var(--wp--preset--color--contrast)',
143-
},
144-
typography: {
145-
fontFamily: 'var(--wp--preset--font-family--system-sans)',
146-
lineHeight: '1.6',
147-
},
148-
elements: {
149-
link: {
150-
color: { text: 'var(--wp--preset--color--accent)' },
151-
},
152-
h1: {
153-
typography: {
154-
fontSize: 'clamp(2rem, 4vw, 3.5rem)',
155-
lineHeight: '1.1',
156-
},
157-
},
158-
h2: {
159-
typography: {
160-
fontSize: 'clamp(1.5rem, 3vw, 2.5rem)',
161-
lineHeight: '1.2',
162-
},
163-
},
164-
h3: {
165-
typography: {
166-
fontSize: 'clamp(1.25rem, 2vw, 1.75rem)',
167-
lineHeight: '1.3',
168-
},
169-
},
170-
},
17182
},
172-
templateParts: [
173-
{ name: 'header', title: 'Header', area: 'header' },
174-
{ name: 'footer', title: 'Footer', area: 'footer' },
175-
],
176-
customTemplates: [],
17783
};
17884
return JSON.stringify( data, null, '\t' ) + '\n';
17985
}
@@ -261,17 +167,6 @@ const TEMPLATE_SINGLE = `<!-- wp:template-part {"slug":"header"} /-->
261167
<!-- wp:template-part {"slug":"footer"} /-->
262168
`;
263169

264-
const TEMPLATE_FRONT_PAGE = `<!-- wp:template-part {"slug":"header"} /-->
265-
266-
<!-- wp:group {"tagName":"main"} -->
267-
<main class="wp-block-group">
268-
<!-- wp:post-content /-->
269-
</main>
270-
<!-- /wp:group -->
271-
272-
<!-- wp:template-part {"slug":"footer"} /-->
273-
`;
274-
275170
const TEMPLATE_PAGE = `<!-- wp:template-part {"slug":"header"} /-->
276171
277172
<!-- wp:group {"tagName":"main"} -->
@@ -373,8 +268,8 @@ const PART_FOOTER = `<!-- wp:group {"layout":{"type":"constrained"},"style":{"sp
373268
export const scaffoldThemeTool = defineTool(
374269
'scaffold_theme',
375270
'Scaffolds a minimal block theme into the given site at wp-content/themes/<slug>/ and activates it by default. ' +
376-
'Drops in style.css, theme.json (with appearanceTools, semantic palette and a numeric spacing scale), ' +
377-
'functions.php (frontend + editor style enqueue), default templates (index, front-page, single, page, archive, 404), ' +
271+
'Drops in style.css (theme header only), theme.json (appearanceTools only), ' +
272+
'functions.php (frontend + editor style enqueue), default templates (index, single, page, archive, 404), ' +
378273
'header/footer parts, and empty assets/fonts and patterns directories. ' +
379274
'Use when the user wants to start a new custom theme — the agent fills in design-specific content afterwards. ' +
380275
'Block themes only; does not support classic (PHP template) themes. ' +
@@ -439,7 +334,6 @@ export const scaffoldThemeTool = defineTool(
439334
[ 'theme.json', renderThemeJson() ],
440335
[ 'functions.php', renderFunctionsPhp( trimmedName, slug ) ],
441336
[ path.join( 'templates', 'index.html' ), TEMPLATE_INDEX ],
442-
[ path.join( 'templates', 'front-page.html' ), TEMPLATE_FRONT_PAGE ],
443337
[ path.join( 'templates', 'single.html' ), TEMPLATE_SINGLE ],
444338
[ path.join( 'templates', 'page.html' ), TEMPLATE_PAGE ],
445339
[ path.join( 'templates', 'archive.html' ), TEMPLATE_ARCHIVE ],
@@ -456,22 +350,14 @@ export const scaffoldThemeTool = defineTool(
456350
const activation = shouldActivate ? await activateTheme( site.id, slug ) : null;
457351

458352
const summaryLines = [
459-
`Block theme '${ trimmedName }' scaffolded at ${ themeDir }/.`,
353+
`Block theme '${ trimmedName }' scaffolded at wp-content/themes/${ slug }/.`,
460354
'',
461-
'Files (paths relative to the theme directory above):',
462-
' style.css — WP header + UX-fix CSS. Append :root tokens and section anchors below the existing rules.',
463-
' theme.json — appearanceTools, useRootPaddingAwareAlignments, palette (base/contrast/accent), spacing scale 20–80, content/wide 720/1200, system-sans default.',
464-
' functions.php — versioned style.css frontend enqueue + add_editor_style.',
465-
' templates/front-page.html — Plain <main> + <wp:post-content/>. Replace post-content with section anchors for the homepage layout.',
466-
' templates/page.html — Constrained title group + constrained post-content. Interior pages.',
467-
' templates/single.html — Constrained title/date/featured-image + constrained post-content + constrained comments form.',
468-
' templates/index.html — Constrained query loop (blog index fallback).',
469-
' templates/archive.html — Constrained archive title + term description + query loop.',
470-
' templates/404.html — Constrained heading + message + search.',
471-
' parts/header.html — Constrained group: site-title + empty wp:navigation. Add menu items here.',
472-
' parts/footer.html — Constrained group: centered © + site-title.',
355+
'Created files:',
356+
...files.map( ( [ relPath ] ) => ` ${ relPath }` ),
473357
'',
474-
'Empty: assets/fonts/, patterns/',
358+
'Empty directories:',
359+
' assets/fonts/',
360+
' patterns/',
475361
'',
476362
];
477363

0 commit comments

Comments
 (0)