Site Editor work — custom templates, template parts, user-created patterns, Global Styles, Font Library activations — lives in the WordPress database, not in your repo. Without a round-trip, that work is invisible to git, unreviewable, and lost when the site dies. rig:bake (shipped in WP Rig 3.5) closes the loop: it bakes database state into version-controlled theme files, then verifies and scrubs the database records.
Availability & requirements
- Paradigm: active for
universalandblock-basedthemes — classic themes refuse with guidance (exit 1). - Requirements: Node 18+, WP-CLI 2.12+, writable active block theme.
- Origin: a Node port of bacoords/wp-theme-control by Brian Coords, pinned to an upstream SHA, with WP Rig-specific forks.
Commands
npm run rig:bake # all scopes: fonts → templates → styles → patterns
npm run rig:bake:plan # read-only inventory + collision report
npm run rig:bake:clean -- .wp-theme-control/runs/<run>/manifest.tsv
npm run rig:bake -- <scope> [flags] # one scope + upstream flags passthrough| Scope | Writes |
plan | Nothing — inventory, collisions, “nothing to bake” report. |
patterns | patterns/<slug>.php from published unsynced wp_block posts. |
templates | templates/*.html, parts/*.html — runtime-URL content patternizes to patterns/hidden-*.php with Inserter: no. |
fonts | assets/fonts/<slug>/ + the overlay’s fonts block. |
styles | The overlay’s settings/styles blocks (raw user Global Styles). |
clean | Deletes only DB records whose exported files still match the manifest sha256; also removes the overlay. |
Passthrough flags: --path=, --url=, --user=, --state-dir=, --dry-run, --clean, --force.
What ships where
| Artifact | Path | Git |
| Baked patterns | patterns/*.php, patterns/hidden-*.php | tracked |
| Baked templates/parts | templates/*.html, parts/*.html | tracked |
| Baked font files | assets/fonts/<slug>/** | tracked |
| Global Styles overlay | config/user-styles.json | tracked |
Generated theme.json | theme.json | gitignored — tokens.js is the sole writer |
| Run manifests/backups | .wp-theme-control/** | gitignored |
The safety model
Every write appends kind / record_id / slug / target / sha256 to a per-run manifest under .wp-theme-control/runs/ (gitignored), with backups per run. Cleanup is conservative by design: rig:bake:clean deletes only records whose exported files still match the manifest hash, only for the expected post type, and only while the pattern is still unsynced or the Global Styles post is unchanged. --force bypasses the hash check only. Each baked pattern file carries an idempotent Baked: yes header so lint tooling can recognize it.
Runtime URLs
Content that references local absolute URLs (your dev site’s uploads, theme assets) is rewritten in PHP — via wp eval, so WordPress’ own parse_blocks() semantics stay byte-identical — to the three sanctioned runtime expressions: get_stylesheet_directory_uri(), wp_get_upload_dir()['baseurl'], and home_url(). Anything else containing PHP syntax is refused.
The user-styles overlay (SPEC-016)
Baked Global Styles and font activations never write theme.json directly — rig:tokens is the sole theme.json writer and would clobber them. Instead they land in config/user-styles.json, a git-tracked overlay that the tokens generator merges last:
- Objects deep-merge; arrays replace wholesale.
- Fonts collapse — custom definitions win on duplicate slugs.
- SSOT keys (
version,$schema,settings.viewport,settings.blockVisibility,isGlobalStylesUserThemeJSON) never merge. - Regeneration is deterministic: two
rig:tokensruns after a bake are byte-identical. - The PHP runtime is overlay-blind — it is a build-time input only, guarded by a PHPUnit parity test.
The usage loop
git status # must be clean — a bake is reviewed as a diff
npm run rig:bake:plan # inventory + collisions (writes nothing)
npm run rig:bake # writes files; does NOT clean the DB
npm run lint:patterns && npm run lint:blocks && npm run lint:css
git add -p && git commit # review the diff
npm run rig:bake:clean -- .wp-theme-control/runs/<run>/manifest.tsvThe bake is a review-first workflow: nothing leaves the database until you have read the diff and committed it.
Lint integration for baked files
Patterns marked Baked: yes keep their Title/Slug/Categories and markup-validity checks but get a tolerance profile: scaffold-placeholder content downgrades to a warning, and hidden runtime patterns get a Categories warning. The three sanctioned runtime-URL PHP expressions are neutralized in block-comment attributes — any other PHP still fails lint:patterns.
Known boundaries
- Synced patterns are not migrated; distribution packaging, localization, Media Library moves, and remote SSH targets are upstream boundaries, inherited.
- The overlay never carries PHP expressions — local absolute URLs in captured styles are flagged (report-only), and media belongs in block markup instead.
- Baked font families replace the token-derived
fontFamilieslist in editor presets (the user layer wins) — see Font Management. - Font asset files survive
cleanfor recoverability; the overlay is removed with the styles/fonts clean.
Related reading
Pair this with Design Tokens v2 (the merge contract), Font Management (the fonts boundary), and Theme Paradigms (why this is gated to block-capable themes).