# AGENTS.md

Public WordPress theme monorepo deployed to WordPress.org and WordPress.com. Each top-level directory is a standalone theme. Maintained by the Automattic Theme Team (`THEMES` in Linear). Pub themes are network-enabled across WordPress.com — they're available on all sites once launched.

## Claude Code skills

Two specialized skills live in `.claude/skills/`. Use them before writing custom logic:

- **`/theme-maintenance`** — Triage and fix Linear bug reports. Fetches issue context, classifies bugs (Theme vs Gutenberg vs Core), generates a report, posts to Linear, optionally creates a fix.
- **`/theme-review`** — Block theme quality audit. Runs a 12-category checklist covering templates, theme.json, patterns, style variations, and block markup.

AGENTS.md documents the repo broadly. Skills handle specific workflows. Don't duplicate skill content here.

## Per-theme agent files

Individual themes may have their own `AGENTS.md` with theme-specific build commands, architecture, and testing guidance. **Always check `<theme-slug>/AGENTS.md` before making changes.**

If no per-theme file exists, refer to this root document for general conventions and create a per-theme `AGENTS.md` when adding build tooling, changing architecture, or introducing new commands/tests.

When creating per-theme CLAUDE.md files, use the `@AGENTS.md` pointer text (one line, no other content). Do NOT use symlinks — they break on Windows and some deploy tools.

## Classic vs block themes

The canonical check is whether `templates/index.html` exists (see [wp-includes/class-wp-theme.php](https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-includes/class-wp-theme.php)). `theme.json` alone does NOT indicate a block theme — classic themes can also have `theme.json` for editor settings.

```bash
# Quick type check
ls <theme-slug>/templates/index.html 2>/dev/null && echo "Block theme" || echo "Classic theme"
```

**CRITICAL:** Do not mix approaches. Block themes use HTML templates with block markup. Classic themes use PHP templates with template tags. Converting between types is a major architectural change — never attempt it as part of a bug fix.

## Non-obvious prerequisites

Standard tools (Node via `.nvmrc`, Composer via `composer.json`, Docker for wp-env) are discoverable from config files. These are the gotchas:

- **Python setuptools** for `node-sass` via `node-gyp` — install via `pip install setuptools` if `npm install` fails with `node-gyp` errors.

## Sandbox workflow

Sandbox path: `~/public_html/wp-content/themes/pub/`

```bash
# Push themes to sandbox (sync only — this does NOT deploy to production)
npm run deploy:push:theme -- <slug>    # Single theme
npm run deploy:push:changes            # Changed themes only
npm run sandbox:clean                  # Clean sandbox git state
```

**Key gotchas:**
- The sandbox HTTP server only runs while SSH is connected. Disconnecting makes it inaccessible via browser.
- The sandbox shares the **production database** and is **write-limited by default**.
- Git operations on sandbox require the canonical home path (not the symlink alias) or pre-commit hooks fail.

## Testing

No unit test framework. Testing is validation-based and visual.

1. **WordPress Playground** — https://playground.wordpress.net/ — fastest, no setup. CI posts Playground preview links on PRs automatically.
2. **wp-env** — `npx wp-env start` (Docker required). All themes available locally via `.wp-env.json`.
3. **Sandbox + test site** — push with `deploy:push:theme`, point a WordPress.com test site at your sandbox.
4. **Validation:** `npm run validate:theme -- <slug>` — JSON schema validation (theme.json, style.css, fonts).

### Testing a theme change

1. Identify theme type (block or classic — check for `templates/index.html`)
2. Run `npm run validate:theme -- <slug>` locally
3. Start wp-env and activate the theme — verify rendering
4. Push to sandbox: `npm run deploy:push:theme -- <slug>`
5. Verify on sandbox
6. Open PR — CI runs theme-check and validate-theme automatically

## CI/CD

See `.github/workflows/` for full workflow definitions. Key workflows:

| Workflow | Blocking | What it does |
|----------|----------|-------------|
| theme-check | **Yes** | WordPress Theme Check plugin. Fails on REQUIRED issues. |
| validate-theme | **Yes** | JSON schema validation on theme.json, styles, fonts, style.css. |
| preview-theme | No | WordPress Playground preview link on PR. |

**TeamCity** auto-commits version bumps and changelog updates to **pub theme PRs only**. Premium and a8c themes need manual version bumps. Don't manually bump pub theme feature branches — TeamCity handles it.

## Deployment

**CRITICAL: Agents MUST NOT merge PRs or run deploy commands. Deployment is human-only.**

Merging to trunk does NOT auto-deploy anywhere. After merge, humans deploy via the Theme Dashboard (Mission Control) or `deploy pub <slug>` on sandbox. WordPress.org deployment is a separate manual process.

## Error monitoring

- **PHP errors:** PHP error log on sandbox (rotated daily)
- **JS console:** Browser developer tools when testing on sandbox or wp-env

## Conventions

- **Default branch:** `trunk`
- **Coding standards:** WordPress PHP standards enforced by PHPCS pre-commit hook (Husky). Don't skip with `--no-verify`.
- **GHE branch naming:** Use Linear-suggested branch names when available. Otherwise: `fix/<theme-slug>-<description>` or `add/<theme-slug>-<description>`.
- **Text domains:** Each theme declares its own in `style.css` `Text Domain:` header. Wrong domain = translations won't load.

## Architectural decisions

| Decision | Don't do this | Why |
|----------|---------------|-----|
| Block + classic themes coexist | Don't convert classic themes to block | Each theme has its own lifecycle; many classic themes are maintenance-mode only |
| `node-sass` in some themes | Don't replace globally with dart-sass | Theme-specific dependency; change per-theme only if maintainer agrees |
| `.theme-utils/` custom tooling | Don't replace with generic tools | Purpose-built for this monorepo's deploy, sandbox, and validation workflow |
| Husky pre-commit PHPCS | Don't disable or skip with `--no-verify` | Maintains coding standards across all contributors |
| `.wp-env.json` maps entire repo | Don't change to single-theme mapping | All themes available locally matches how the repo is used in practice |
| WordPress Playground PR previews | Don't replace with custom preview system | Standard .org tooling, zero infrastructure cost |
| Separate .org and .com deploy | Don't try to unify them | .org deploy is currently disabled/manual, .com is via Theme Dashboard. Different pipelines, different timing. |
| TeamCity auto-version-bump | Don't manually version-bump pub theme feature branches | TeamCity commits the bump automatically. Only adjust manually if the auto-commit is wrong. |
| Core sync scripts exist but are broken | Don't rely on `npm run core:sync` | These haven't been maintained since repo migration. Core themes are synced manually. |
| Per-theme build steps | Don't add root-level build-all requirement | Not all themes need builds. `batch:build` exists for themes that opt in via `package.json`. |

## Common pitfalls

1. **Thinking merge = deploy.** Merging to trunk does NOT auto-deploy anywhere. A merged PR is NOT live until explicitly deployed.

2. **Editing generated CSS.** Many themes compile CSS from SCSS/PostCSS. Check for `package.json` and `sass/` directory before editing `style.css` directly — changes will be overwritten on next build.

3. **Forgetting Python setuptools.** `npm install` fails with `node-gyp` errors because of `node-sass`. Fix: `pip install setuptools`.

4. **Hardcoded text in block template HTML files.** Block `.html` templates can't use PHP i18n functions. Translatable text must live in patterns (PHP files) or block attributes.

5. **Navigation blocks with `ref` attribute.** Site-specific menu IDs break on other sites. Remove all `"ref"` attributes from navigation blocks.

6. **Missing font/image credits in readme.txt.** Every bundled asset needs copyright holder, license, and source URL.

7. **Block markup JSON syntax errors.** Block templates use `<!-- wp:block-name {"attr":"value"} -->` with strict JSON. Missing quotes or trailing commas break rendering silently.

8. **Wrong text domain.** Each theme declares its domain in `style.css` `Text Domain:` header. Wrong domain means translations won't load.

9. **Running npm commands without per-theme package.json.** Many classic themes have no `package.json`. Running `npm install` creates an empty `node_modules/`. Check first.

10. **Sandbox not loading in browser.** The HTTP server only runs while SSH is connected.

11. **Sandbox path symlink breaks git hooks.** Use the canonical home path for git operations on sandbox, not the symlink alias.
