Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
58c22b7
feat: remove old/deprecated files
May 7, 2025
80c2645
feat: init commit of rebuilt theme that is inline with other base themes
May 7, 2025
84b340e
feat: re-organize default templates, auto-register blocks, and twig n…
Jun 5, 2025
6ee5d00
chore: align release metadata for 2.0
Jun 27, 2026
644f78f
ci: replace release workflow for wordpress
Jun 27, 2026
2f9c8ff
test: add wordpress release readiness checks
Jun 27, 2026
6ac9313
feat: upgrade whisk starter to emulsify core 4
Jun 27, 2026
d924e9d
feat: align whisk starter structure with emulsify drupal
Jun 27, 2026
2c1af61
feat: rebuild timber theme bootstrap
Jun 27, 2026
308cb95
fix: implement timber attribute helpers
Jun 27, 2026
7decd36
feat: refine timber template defaults
Jun 27, 2026
0d639fe
feat: load core 4 theme assets
Jun 27, 2026
6e0967f
feat: separate timber and gutenberg block registration
Jun 27, 2026
495c583
test: add wordpress theme smoke coverage
Jun 27, 2026
ac7af7f
docs: document wordpress 2.0 workflow
Jun 27, 2026
c6bbe40
feat(theme): harden parent runtime services
Jun 27, 2026
dddcfa7
feat(starter): simplify Whisk child theme
Jun 27, 2026
8a9846b
docs: document WordPress 2.0 release model
Jun 27, 2026
7dfec74
ci(release): add WordPress release validation
Jun 27, 2026
61f6925
chore(deps): resolve release audit blockers
Jun 27, 2026
5481570
docs: add WordPress sister-project parity contract
Jun 27, 2026
9e5c764
ci(wordpress): add theme readiness validation
Jun 27, 2026
471c69b
chore(wordpress): use wordpress platform adapter
Jun 27, 2026
cbb2d51
test(wordpress): expand generated child fixture smoke
Jun 27, 2026
196f6a7
feat(twig): support project component references
Jun 28, 2026
5b545e9
feat(theme): add editor services and agnostic starter
Jun 28, 2026
d6171c1
refactor(whisk): keep starter source agnostic
Jun 28, 2026
a34c7dc
refactor(theme): improve parent template maintainability
Jun 28, 2026
b57e20c
feat(starter): support standalone wordpress starter
Jun 28, 2026
0ac719e
chore: adjust wordpress spelling and repo url references
Jun 29, 2026
afd7d43
fix: tighten composer stability settings
Jun 29, 2026
4daaf96
docs: clarify wordpress install workflows
Jun 29, 2026
cd9249e
fix: guard child theme force replacement
Jun 29, 2026
46bf29a
docs: document wordpress fixture release gate
Jun 29, 2026
fa897b6
feat: add generated child theme metadata
Jun 29, 2026
9fc90aa
docs: add wordpress component recipes
Jun 29, 2026
6d25eb7
docs: add post 2x optimization roadmap
Jul 6, 2026
099c594
refactor: add runtime autoloading
Jul 6, 2026
cb47609
refactor: group runtime services by domain
Jul 6, 2026
9d3a0e8
refactor: consolidate theme file discovery
Jul 6, 2026
ae9e15f
feat: support optional asset manifest loading
Jul 6, 2026
c57ef89
feat: support block scoped assets
Jul 6, 2026
f4b646a
feat: add optional component discovery cache
Jul 6, 2026
62cf982
refactor: split editor policy services
Jul 7, 2026
dcb451b
feat: support pattern category metadata
Jul 7, 2026
855199b
fix(blocks): use block-scoped acf field values in twig context
Jul 8, 2026
56a258a
refactor(support): consolidate shared asset and diagnostics helpers
Jul 8, 2026
8e3f716
perf(runtime): memoize manifest reads and asset discovery per request
Jul 8, 2026
5c5f378
perf(blocks): enable discovery caching by default outside development
Jul 8, 2026
1ac5c8a
refactor(twig): extract project component loader and config reader
Jul 8, 2026
9cc26ea
chore: remove dead compatibility shims and unused release tooling
Jul 8, 2026
44aa226
docs: refresh architecture docs and add index
Jul 8, 2026
9bd0c51
chore(lint): adopt phpcs wpcs and phpstan for runtime php
Jul 8, 2026
fe44d10
ci(release): force wordpress 2.0 stable release
Jul 8, 2026
d136804
feat(twig): add switch case tags
Jul 10, 2026
b8de146
fix(security): enable Twig autoescaping and escape ACF/block context
Jul 23, 2026
6abebc5
fix(ci): unblock release by scoping npm audit gate and patching fast-…
Jul 23, 2026
299d3cb
fix(cli): sanitize theme name, require generatedFrom for --force, mak…
Jul 23, 2026
9c6534e
feat(release): build and attach installable theme ZIP with bundled de…
Jul 23, 2026
951140b
ci: run WordPress fixture and Whisk a11y on PRs and add required PHP …
Jul 23, 2026
c782727
fix(runtime): log silent asset failures, fall through corrupt manifes…
Jul 23, 2026
f194d14
Merge pull request #30 from emulsify-ds/fix/npm-audit-release-gate
callinmullaney Jul 23, 2026
a01a4c6
Merge pull request #31 from emulsify-ds/fix/twig-autoescape
callinmullaney Jul 23, 2026
84b1ad2
Merge pull request #32 from emulsify-ds/fix/cli-generator-hardening
callinmullaney Jul 23, 2026
edd3060
Merge branch 'release-2.x' into feat/release-dist-artifact
callinmullaney Jul 23, 2026
9ad5791
Merge pull request #33 from emulsify-ds/feat/release-dist-artifact
callinmullaney Jul 23, 2026
a462365
Merge branch 'release-2.x' into ci/complete-readiness-gates
callinmullaney Jul 23, 2026
d9ff1e4
Merge pull request #35 from emulsify-ds/ci/complete-readiness-gates
callinmullaney Jul 23, 2026
39c596c
Merge branch 'release-2.x' into chore/observability-and-docs
callinmullaney Jul 23, 2026
1552742
Merge pull request #36 from emulsify-ds/chore/observability-and-docs
callinmullaney Jul 23, 2026
f1eba46
fix(ci): define audit step indices in release-check theme-readiness a…
Jul 25, 2026
d66fa69
fix(lint): allow missing node_modules in PHPStan exclusions
Jul 25, 2026
7864cff
fix(ci): stabilize WordPress fixture archive and teardown
Jul 25, 2026
b18d2a1
ci: scope extended theme readiness checks
Jul 25, 2026
cb133e2
fix(release): compute initial stable version as 2.0.0
Jul 25, 2026
91ee663
fix(ci): launch Chrome without sandbox in Linux CI
Jul 25, 2026
374e132
chore: use latest version of emulsify-core
Jul 25, 2026
d3f0312
chore: bump core version test
Jul 25, 2026
0385747
feat(whisk): add component inspector support
Jul 25, 2026
7444274
feat(generator): add project-specific theme documentation
Aug 2, 2026
45938e1
test(generator): enforce generated theme parity
Aug 2, 2026
e2446fb
ci(readiness): expand compatibility coverage
Aug 2, 2026
fb1661f
fix(release): stabilize semantic release analysis
Aug 2, 2026
3bf554d
fix(test): resolve Whisk tests from theme root
Aug 2, 2026
2c99bd3
build(deps): update release and core tooling
Aug 2, 2026
ad8fd6d
docs: document 2.0 generation and release workflows
Aug 2, 2026
e134175
docs(review): record 2.0 release readiness analysis
Aug 2, 2026
426834f
fix(ci): resolve Whisk a11y Storybook path
Aug 2, 2026
e07da7b
chore(docs): remove internal working notes
Aug 2, 2026
1406eeb
fix(release): ship complete installable theme
Aug 2, 2026
5a9c7f8
fix(cli): read version from theme metadata
Aug 2, 2026
4617b6b
test(cli): model packaged parent in parity smoke
Aug 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 4 additions & 3 deletions .browserslistrc
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Browsers that we support

last 1 version
> 1%
maintained node versions
last 2 versions
Firefox ESR
Chrome 41 # Support for Googlebot
not dead
ie 11
not IE 9-11 # For IE 9-11 support, remove 'not'.
35 changes: 0 additions & 35 deletions .eslintrc.yml

This file was deleted.

22 changes: 22 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/.gitattributes export-ignore
/.github export-ignore
/.github/** export-ignore
/.gitignore export-ignore
/.husky export-ignore
/.husky/** export-ignore
/.browserslistrc export-ignore
/.editorconfig export-ignore
/.nvmrc export-ignore
/CODE_OF_CONDUCT.md export-ignore
/commitlint.config.js export-ignore
/composer.lock export-ignore
/husky.config.js export-ignore
/package-lock.json export-ignore
/package.json export-ignore
/phpcs.xml.dist export-ignore
/phpstan.neon.dist export-ignore
/release.config.js export-ignore
/scripts export-ignore
/scripts/** export-ignore
/whisk/.cli export-ignore
/whisk/.cli/** export-ignore
11 changes: 11 additions & 0 deletions .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Emulsify WordPress version (see [releases](https://github.com/emulsify-ds/emulsify-wordpress/releases)):

**What you did:**

**What happened:**

**Reproduction repository (if necessary):**

**Problem description:**

**Suggested solution:**
13 changes: 13 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
**This PR does the following:**
- Adds functionality bullet item
- Fixes this or that bullet item

### Related Issue(s)
- [Title of the issue](https://github.com/emulsify-ds/emulsify-wordpress/issues/1) (if applicable)

### Notes:
- (optional) Document any intentionally unfinished parts or known issues within this PR

### Functional Testing:
- [ ] Document steps that allow someone to fully test your code changes. Include screenshot and links when appropriate.
- [ ] Confirm `Practical theme readiness`, `PHP coding standards and static analysis`, `WordPress fixture smoke`, and `Extended Whisk Storybook and a11y` pass for changes targeting the protected release branches.
4 changes: 4 additions & 0 deletions .github/fixtures/whisk-a11y/ci-readiness/ci-readiness.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* Harmless Vite entry used only by the CI-seeded Whisk readiness fixture.
*/
export const ciReadinessFixture = true;
16 changes: 16 additions & 0 deletions .github/fixtures/whisk-a11y/ci-readiness/ci-readiness.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import template from './ci-readiness.twig';

export default {
title: 'CI/Readiness fixture',
};

export const Default = {
render: (args) => template(args),
args: {
title: 'CI accessibility readiness',
summary:
'This component gives the component-agnostic starter one real story during continuous integration.',
url: 'https://www.emulsify.info',
link_text: 'Visit the Emulsify documentation',
},
};
7 changes: 7 additions & 0 deletions .github/fixtures/whisk-a11y/ci-readiness/ci-readiness.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<main>
<article aria-labelledby="ci-readiness-title">
<h2 id="ci-readiness-title">{{ title }}</h2>
<p>{{ summary }}</p>
<a href="{{ url }}">{{ link_text }}</a>
</article>
</main>
216 changes: 216 additions & 0 deletions .github/scripts/acf-local-json-smoke.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
<?php
/**
* Smoke checks for ACF Local JSON path integration.
*
* @package Emulsify
*/

if ( PHP_SAPI !== 'cli' ) {
fwrite( STDERR, "This script must be run from the command line.\n" );
exit( 1 );
}

$GLOBALS['emulsify_acf_json_smoke_filters'] = array();

if ( ! function_exists( 'add_filter' ) ) {
function add_filter( string $hook, callable $callback, int $priority = 10, int $accepted_args = 1 ): bool {
$GLOBALS['emulsify_acf_json_smoke_filters'][ $hook ][ $priority ][] = array(
'accepted_args' => $accepted_args,
'callback' => $callback,
);

ksort( $GLOBALS['emulsify_acf_json_smoke_filters'][ $hook ] );

return true;
}
}

if ( ! function_exists( 'apply_filters' ) ) {
function apply_filters( string $hook, $value, ...$arguments ) {
if ( empty( $GLOBALS['emulsify_acf_json_smoke_filters'][ $hook ] ) ) {
return $value;
}

foreach ( $GLOBALS['emulsify_acf_json_smoke_filters'][ $hook ] as $callbacks ) {
foreach ( $callbacks as $callback ) {
$value = call_user_func_array(
$callback['callback'],
array_slice(
array_merge( array( $value ), $arguments ),
0,
$callback['accepted_args']
)
);
}
}

return $value;
}
}

if ( ! function_exists( 'get_stylesheet_directory' ) ) {
function get_stylesheet_directory(): string {
return $GLOBALS['emulsify_acf_json_smoke_child'];
}
}

/**
* Fails the smoke script when an assertion is false.
*
* @param bool $condition Assertion condition.
* @param string $message Failure message.
* @return void
*/
function emulsify_acf_json_smoke_assert( bool $condition, string $message ): void {
if ( ! $condition ) {
throw new RuntimeException( $message );
}
}

/**
* Recursively removes a path.
*
* @param string $path Path to remove.
* @return void
*/
function emulsify_acf_json_smoke_remove( string $path ): void {
if ( ! file_exists( $path ) ) {
return;
}

if ( is_file( $path ) || is_link( $path ) ) {
unlink( $path );
return;
}

$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator( $path, RecursiveDirectoryIterator::SKIP_DOTS ),
RecursiveIteratorIterator::CHILD_FIRST
);

foreach ( $iterator as $item ) {
$item->isDir() && ! $item->isLink() ? rmdir( $item->getPathname() ) : unlink( $item->getPathname() );
}

rmdir( $path );
}

$repo_root = dirname( __DIR__, 2 );
$work_root = sys_get_temp_dir() . '/emulsify-acf-local-json-' . uniqid( '', true );
$child = $work_root . '/child-theme';
$default = $child . '/config/acf-json';
$custom = $work_root . '/custom-acf-json';
$extra = $work_root . '/extra-acf-json';

$GLOBALS['emulsify_acf_json_smoke_child'] = $child;

try {
require_once $repo_root . '/includes/Acf/LocalJson.php';

$inactive = new Emulsify\Theme\Acf\LocalJson();
$inactive->register();

emulsify_acf_json_smoke_assert(
empty( $GLOBALS['emulsify_acf_json_smoke_filters']['acf/settings/save_json'] )
&& empty( $GLOBALS['emulsify_acf_json_smoke_filters']['acf/settings/load_json'] ),
'ACF Local JSON service should not register ACF filters when ACF is unavailable.'
);

if ( ! function_exists( 'acf' ) ) {
function acf(): bool {
return true;
}
}

$service = new Emulsify\Theme\Acf\LocalJson();
$service->register();

emulsify_acf_json_smoke_assert(
isset( $GLOBALS['emulsify_acf_json_smoke_filters']['acf/settings/save_json'] )
&& isset( $GLOBALS['emulsify_acf_json_smoke_filters']['acf/settings/load_json'] ),
'ACF Local JSON service should register ACF filters when ACF is available.'
);

$incoming_save = '/acf/default-save';
$incoming_load = array( '/acf/default-load' );

emulsify_acf_json_smoke_assert(
$incoming_save === apply_filters( 'acf/settings/save_json', $incoming_save ),
'ACF Local JSON save path should no-op when config/acf-json is missing.'
);
emulsify_acf_json_smoke_assert(
$incoming_load === apply_filters( 'acf/settings/load_json', $incoming_load ),
'ACF Local JSON load paths should no-op when config/acf-json is missing.'
);

if ( ! mkdir( $default, 0777, true ) || ! mkdir( $custom, 0777, true ) || ! mkdir( $extra, 0777, true ) ) {
throw new RuntimeException( 'Could not create ACF JSON smoke fixture directories.' );
}

emulsify_acf_json_smoke_assert(
$default === apply_filters( 'acf/settings/save_json', $incoming_save ),
'ACF Local JSON save path should use child config/acf-json by default.'
);
emulsify_acf_json_smoke_assert(
array( '/acf/default-load', $default ) === apply_filters( 'acf/settings/load_json', $incoming_load ),
'ACF Local JSON load paths should keep the default path and add child config/acf-json.'
);

add_filter(
'emulsify_theme_acf_json_remove_default_load_path',
static function (): bool {
return true;
}
);

emulsify_acf_json_smoke_assert(
array( $default ) === apply_filters( 'acf/settings/load_json', $incoming_load ),
'ACF Local JSON should remove the default load path only when explicitly configured.'
);

add_filter(
'emulsify_theme_acf_json_save_path',
static function () use ( $custom ): string {
return $custom;
}
);

add_filter(
'emulsify_theme_acf_json_load_paths',
static function ( array $paths ) use ( $extra ): array {
$paths[] = $extra;

return $paths;
}
);

emulsify_acf_json_smoke_assert(
$custom === apply_filters( 'acf/settings/save_json', $incoming_save ),
'ACF Local JSON save path filter should override the default save path.'
);
emulsify_acf_json_smoke_assert(
array( $custom, $extra ) === apply_filters( 'acf/settings/load_json', $incoming_load ),
'ACF Local JSON load paths filter should alter final load paths.'
);

add_filter(
'emulsify_theme_acf_json_enabled',
static function (): bool {
return false;
},
1
);

emulsify_acf_json_smoke_assert(
$incoming_save === apply_filters( 'acf/settings/save_json', $incoming_save )
&& $incoming_load === apply_filters( 'acf/settings/load_json', $incoming_load ),
'ACF Local JSON enabled filter should disable all path changes.'
);

echo "ACF Local JSON smoke checks passed.\n";
} catch ( Throwable $throwable ) {
fwrite( STDERR, $throwable->getMessage() . "\n" );
exit( 1 );
} finally {
emulsify_acf_json_smoke_remove( $work_root );
}
Loading
Loading