WP Rig supports three theme-development paradigms: classic (traditional PHP templates), universal (a hybrid theme with theme.json and block support), and block-based (Full Site Editing). The active paradigm is a single config value — theme.themeType — and every feature gate in the framework follows from it automatically. This document explains what each paradigm includes, how resolution works under the hood, and how to switch paradigms.
The three paradigms
Classic (Standard WP Rig)
The classic paradigm produces a traditional WordPress theme: PHP templates under the theme root (header.php, front-page.php, sidebar.php), a Customizer-first settings story, and no Full Site Editing surface. WP Rig enforces a true-classic guarantee: when you choose classic during rig-init, the framework strips any stale themeType override from config.local.json, moves leftover FSE artifacts (templates/, parts/) into a timestamped .rig-backup/ folder, and verifies that WordPress core does not detect a block theme. theme.json is intentionally kept — it is hybrid-legitimate, does not trigger the Site Editor, and the design token system owns it.
Universal (Hybrid)
The universal paradigm is the middle ground: a classic-style PHP theme that also carries theme.json, block editor support, block patterns, and the block-based CSS baseline. Universal themes can use the Navigation block, block visibility, and pattern-driven content while keeping full control over templates in PHP. Most modern client themes live here.
Block-based (Full Site Editing)
The block-based paradigm is a Full Site Editing theme: block templates under templates/ and parts/, the Site Editor as the primary surface, and the full rig:bake round-trip for moving Site Editor work back into git-tracked theme files. Block-based features are also available in universal themes — the two share every block-era capability; block-based simply makes FSE the primary workflow.
Paradigm tags
Every WP Rig feature is tagged with a paradigm scope that maps to the theme types where it is enabled. The tag → theme-type matrix lives once in config/paradigms.json:
| Tag | Enabled in | Example feature |
all | classic, universal, block-based | Design tokens, icon API, asset pipeline |
classic | classic, universal | Classic menu system, classic widgets |
universal | universal | Universal-only overrides |
block-based | universal, block-based | rig:bake, block patterns, _blocks-based.css |
The governing rule: block-based features are never wired into the classic core. They activate only when theme.themeType is universal or block-based.
How the active paradigm resolves
The active theme type resolves through the shared configuration chain, in increasing precedence:
config/config.default.json → config/config.json → config/config.local.jsonThe setting lives under theme.themeType and accepts exactly three values: classic, universal, or block-based. Both the JS build and the PHP runtime read the same merged chain and fail fast on invalid values — there is no silent fallback.
// config/config.json — change the paradigm in one line
{
"theme": {
"themeType": "universal"
}
}Changing this value is the single source of truth: every gate in the build and runtime follows automatically. There is no per-feature switch to hunt down.
How gating works in code
The paradigm system has a JS half (build-time) and a PHP half (runtime):
- JS:
scripts/lib/paradigm.jsexposesgetActiveThemeType()andisFeatureEnabled(tag)— the build uses these to include or exclude assets (for example,_blocks-based.cssnever ships in a classic build). - PHP:
inc/Paradigm.phpexposesParadigm::is_enabled(tag)— used at runtime for component and feature registration. - Components: a paradigm-gated component declares
const PARADIGM = 'block-based'(orclassic) and usesParadigm_Component_Trait;Themeskips inactive components automatically during discovery.
// A component gated to block-era themes
class Component implements Component_Interface {
use Paradigm_Component_Trait;
const PARADIGM = 'block-based';
public static function is_active(): bool {
return self::paradigm_active();
}
}Switching paradigms
Set your paradigm interactively during theme initialization:
npm run rig-initWhen you select classic, rig-init runs the true-classic teardown: it removes the theme.themeType and theme.enableBlocks keys from config.local.json (all other keys preserved) so your interactive choice is authoritative, and moves any leftover templates/ and parts/ folders to .rig-backup/<timestamp>/ — never deleted, always recoverable. To go the other way, edit theme.themeType in config/config.json and rebuild:
npm run buildThe build regenerates paradigm-dependent artifacts (the token pipeline, theme.json binding, included CSS/JS) to match the new type.
Child themes and bundling
Child theme conversion is paradigm-aware: npm run setup-child derives its component keep-list from the active theme type — the classic core for classic themes, plus the Editor, Blocks, Block_Patterns, Block_Styles, and Icons components for universal and block-based themes. A bundled theme never leaks its local config overrides, and framework version metadata is stripped so the shipped child carries only its own version.
Related reading
- WP Rig Node Scripts — the full
rig:*command reference, includingrig:bake - CSS in WP Rig — design tokens and the block-based CSS surface
- Building Custom Blocks — block authoring in universal and block-based themes