Emulsify WordPress 2.0.0 is a Timber-first WordPress parent theme for teams building component-driven sites with Emulsify Core 4, Vite, Storybook, and Twig.
The parent theme provides the WordPress runtime: theme setup, Timber bootstrapping, Twig namespaces and helpers, template fallbacks, asset loading, and optional block registration. Generated child themes provide the project layer: components, templates, source Sass and JavaScript, compiled assets, and site-specific overrides.
Track the parent theme through the site project's Composer configuration and install it as emulsify:
composer require emulsify-ds/emulsify-wordpressComposer-based applications should also require timber/timber from the application-level Composer project so Timber loads before WordPress activates the theme. If the parent theme owns its dependencies instead, run composer install inside the installed emulsify directory.
Download emulsify.zip from the matching GitHub release, then upload it through Appearance > Themes > Add New > Upload Theme. The release ZIP already includes production Composer dependencies under vendor/, so a manual installation does not need to run Composer.
The archive installs into the required emulsify/ directory. A WordPress.org listing and SVN deployment are planned as a future release step; they are not part of the current release workflow.
- WordPress 6.7 or newer.
- PHP 8.3 or newer.
- Composer 2 for Composer-based installation and parent-theme maintenance.
- Node.js 24. Root release tooling expects
>=24.10; generated child themes expect>=24. - Timber 2, installed by the site project or bundled in the manual release ZIP.
- WP-CLI when generating child themes or running the full WordPress fixture smoke test.
Install the parent theme as emulsify and pair it with a child theme for project work. In Bedrock, that usually means:
web/app/themes/emulsify
web/app/themes/whiskIn a standard WordPress install, use:
wp-content/themes/emulsify
wp-content/themes/whiskTimber 2 must be loaded before the theme renders. Composer-based site projects can satisfy that requirement in either place:
- Require
timber/timberfrom the application-level Composer project. - Run Composer inside the parent theme when the parent theme owns its PHP dependencies:
cd web/app/themes/emulsify
composer installActivate the child theme, not the parent theme. The child theme header includes Template: emulsify, which tells WordPress to use Emulsify as the parent runtime.
Do not run root npm commands in the parent theme for normal site implementation. Project frontend work happens in the generated child theme.
Run component, Vite, Storybook, and project lint commands from the generated child theme:
cd web/app/themes/whisk
npm install| Command | Purpose |
|---|---|
npm run build |
Build Core 4 assets with Vite. |
npm run vite |
Watch and rebuild Vite assets. |
npm run storybook |
Start Storybook on port 6006. |
npm run develop |
Run the Vite watcher and Storybook together. |
npm run storybook-build |
Build assets and export a static Storybook. |
npm run lint |
Run JavaScript and Sass linting with the Core 4 config. |
npm run audit |
Run the Core migration/static audit. |
npm run audit:twig-stories |
Check Twig story compatibility. |
npm run inspect:components |
Discover components and report metadata, dependencies, configuration issues, and orphaned files. |
npm run a11y |
Build Storybook and run the Core accessibility check. |
npm run test |
Run Jest with --passWithNoTests for starter projects. |
The component inspector comes from the installed @emulsify/core package and
runs from the generated child theme root without requiring WordPress to be
installed or bootstrapped:
npm run inspect:components
npm run inspect:components -- --json
npm run inspect:components -- --helpThe emulsify parent theme owns reusable runtime behavior:
includes/contains the namespaced runtime classes.templates/provides minimal Timber fallback templates.theme.jsonprovides editor settings and presets.whisk/is the generated starter child theme source.
The generated whisk child theme owns project implementation:
whisk/src/componentsis an empty placeholder until a project installs the component system it wants to use.- Source Sass, JavaScript, stories, data fixtures, and component metadata are defined by the selected Emulsify component system, not by this parent theme starter.
whisk/assets/imagesandwhisk/assets/iconsare empty placeholders for project-owned theme media and icon files.whisk/templates/page.twigis a small example override.whisk/dist/globalandwhisk/dist/componentsare runtime build output conventions when a component system emits them.whisk/project.emulsify.jsonuses"platform": "wordpress"so Core and CLI tooling can load the WordPress platform adapter. It also recordsgeneratedFromandgeneratedFromVersionso future upgrades and support diagnostics can identify Emulsify-generated WordPress child themes. Projects can also use Core-supported metadata such asvariant.structureImplementationsthere when a selected component system needs legacy Twig namespaces.
Timber is required for frontend template rendering. This repository declares timber/timber in the parent theme composer.json, so a standalone theme install can run Composer inside the parent theme.
For Bedrock applications, it is also valid to require Timber from the application-level Composer project as long as WordPress loads that Composer autoloader before the theme renders. If Timber is missing, the parent theme shows an actionable admin notice and stops frontend rendering with a clear runtime error.
Parent-theme root commands are for maintainers and release checks, not normal project frontend development. Run them from the parent theme repository root:
composer install
npm ci --ignore-scriptsComposer install creates the runtime autoloader. After adding or renaming parent runtime classes, run composer dump-autoload so Composer's optimized classmap sees the current files. The supported manual release ZIP ships that autoloader and its production dependencies; a source checkout without vendor/ still uses the Bootstrap fallback loader.
Install the PHP development dependencies, then run the combined coding-standards and static-analysis command:
composer install
npm run lint:phplint:php runs PHPCS with phpcs.xml.dist, followed by PHPStan with phpstan.neon.dist. Both configurations cover includes/ and the parent theme's root PHP entry points, including functions.php. Use npm run lint:php:fix to apply safe PHPCBF coding-standard fixes, then rerun npm run lint:php to confirm PHPStan and the remaining PHPCS checks.
The .husky/pre-commit hook already runs npm run lint, which delegates to this PHP check.
| Command | Purpose |
|---|---|
npm run lint:php |
Run PHPCS and PHPStan across the parent runtime. |
npm run pr:check |
Run the practical, stubbed pull request validation suite. |
npm run release:check |
Run release-readiness checks. |
npm run build:dist |
Build the installable dist-artifact/emulsify.zip release archive. |
npm run publish-test -- --no-ci |
Run a local semantic-release dry run. |
Every pull request to the configured branches runs two visible fast readiness jobs: practical smoke checks and dedicated PHPCS/PHPStan analysis. Pull requests targeting main or release-2.x additionally run the MySQL-backed WordPress fixture and Whisk Storybook accessibility audit. The WordPress job sets WP_SMOKE_REQUIRED=1, so missing WP-CLI/MySQL prerequisites or route render failures fail the job instead of producing a skip. The Whisk job installs Chrome explicitly, copies an accessible CI-only story and Vite entry into the otherwise component-agnostic starter, and then builds Storybook and runs axe.
Weekly scheduled runs repeat the WordPress fixture and Whisk accessibility audit. Manual GitHub Actions > WordPress Theme Readiness runs can select either extended fixture with the wordpress_fixture and extended_checks inputs. Local release:check still skips the database fixture when prerequisites are unavailable unless WP_SMOKE_REQUIRED=1 is set. Release publishing also requires the full WordPress fixture path before semantic-release can publish.
Generate a project child theme from the bundled Whisk starter with WP-CLI:
wp emulsify "Acme Site" --dry-run
wp emulsify "Acme Site" --machine-name=acme-site
wp emulsify "Acme Site" --machine-name=acme-site --parent=emulsify
wp emulsify "Acme Site" --machine-name=acme-site --force
wp emulsify "Acme Site" --machine-name=acme-site --activateThe generator copies <parent>/whisk to a sibling child theme directory, updates WordPress theme headers, package metadata, Emulsify project metadata, and visible starter labels, then optionally activates the generated child theme. --parent=<slug> selects a different installed parent theme directory; it defaults to emulsify.
--force only replaces an existing destination when its WordPress platform, generatedFrom: "emulsify-wordpress" lineage, generated version, parent template, and machine name all match the requested generated child theme. The replacement is staged atomically so a copy failure leaves the existing theme intact; use --dry-run --force to inspect replacement intent without deleting files.
For Emulsify CLI integration, the standalone starter repository is https://github.com/emulsify-ds/emulsify-wordpress-starter. It represents the generated child theme layer from whisk/, not the parent runtime theme root, and generated projects still declare Template: emulsify so WordPress loads the installed parent theme.
- Documentation index
- Generated-theme upgrade guide
- Upgrading from 1.x to 2.x
- Sister-project parity contract
- Parent and child theme architecture
- Timber and Twig authoring
- Emulsify Core 4 and Vite workflow
- Component recipes
- ACF Local JSON
- ACF/Twig blocks
- Core block Twig rendering
- Native Gutenberg blocks
- Block patterns
- Editor enhancements
- Editor policy
- Asset loading
- WP-CLI child theme generation
- Release process
- Post-2.x optimization roadmap
Emulsify WordPress is licensed under GPL-2.0-only. See LICENSE.
Read the Code of Conduct before contributing. File bugs and feature requests at emulsify-ds/emulsify-wordpress.
Emulsify® is a product of Four Kitchens — We make BIG websites.
