From 102abe7927b6b49f56e36a2833e644424a2c5458 Mon Sep 17 00:00:00 2001 From: Jan-Niclas Loosen Date: Mon, 29 Jun 2026 19:54:12 +0200 Subject: [PATCH] Improve wp acorn compability --- .gitignore | 3 +- CLAUDE.md | 94 + app/Acorn/BootCoordinator.php | 29 + app/Acorn/LivewireAssets.php | 28 + app/Providers/PluginServiceProvider.php | 49 + app/empty.txt | 1 - bootstrap.php | 47 +- composer.json | 60 +- composer.lock | 4501 +++++++++++++---- config/app.php | 126 - config/assets.php | 41 - config/auth.php | 115 - config/database.php | 193 - config/filesystems.php | 79 - config/logging.php | 132 - config/services.php | 38 - config/session.php | 217 - config/view.php | 83 - index.php | 14 +- phpcs.xml.dist | 94 + phpunit.xml.dist | 12 + .../views/components/say-hello.blade.php | 7 +- resources/views/hello-world.blade.php | 4 +- resources/views/injections/footer.blade.php | 2 - resources/views/injections/head.blade.php | 8 - tests/Acorn/BootCoordinatorTest.php | 50 + tests/TestCase.php | 28 + tests/bootstrap.php | 15 + 28 files changed, 4090 insertions(+), 1980 deletions(-) create mode 100644 CLAUDE.md create mode 100644 app/Acorn/BootCoordinator.php create mode 100644 app/Acorn/LivewireAssets.php create mode 100644 app/Providers/PluginServiceProvider.php delete mode 100644 app/empty.txt delete mode 100644 config/app.php delete mode 100644 config/assets.php delete mode 100644 config/auth.php delete mode 100644 config/database.php delete mode 100644 config/filesystems.php delete mode 100644 config/logging.php delete mode 100644 config/services.php delete mode 100644 config/session.php delete mode 100644 config/view.php create mode 100644 phpcs.xml.dist create mode 100644 phpunit.xml.dist delete mode 100644 resources/views/injections/footer.blade.php delete mode 100644 resources/views/injections/head.blade.php create mode 100644 tests/Acorn/BootCoordinatorTest.php create mode 100644 tests/TestCase.php create mode 100644 tests/bootstrap.php diff --git a/.gitignore b/.gitignore index 24e8192..943ee58 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .env -/vendor \ No newline at end of file +/vendor +.phpunit.result.cache diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..7e00744 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,94 @@ +# CLAUDE.md + +Guidance for working in this repository. + +## What this is + +A **starter WordPress plugin** built on the [Roots Acorn](https://roots.io/acorn/) +framework (Laravel components inside WordPress) with **Livewire 4** for reactive +front-end components. It is a scaffold/template designed to **coexist with other +Acorn-based plugins** in the same WordPress install without booting the framework +more than once. + +- `roots/acorn: ^6.0`, `livewire/livewire: ^4.1` +- Requires PHP 8.4, WordPress 5.2+ +- PSR-4: `AcornPlugin\` → `app/`, `AcornPlugin\Tests\` → `tests/` +- Acorn is bundled (in `vendor/`); the plugin `wp_die`s if `Roots\Acorn\Application` + is somehow absent. + +## The single-Acorn contract (read this before touching `bootstrap.php`) + +PHP classes and the Acorn container are **global to a request**. If two Acorn +plugins each call `Application::configure()->boot()`, the second clobbers the +first. This plugin avoids that with a cooperative **boot election** that every +Acorn plugin in the install must follow: + +1. **One booter per request, elected via a shared action.** On `after_setup_theme` + priority 0, a plugin boots Acorn only if `did_action('acorn/booted')` is false, + then fires `do_action('acorn/booted')`; otherwise it stands down. This lives in + `app/Acorn/BootCoordinator.php` (`BootCoordinator::BOOTED_ACTION = 'acorn/booted'`). + `did_action()` is used deliberately — it is a **read-only** probe, unlike + `Application::getInstance()`, which force-creates and installs an empty container. +2. **Providers are auto-discovered, never hand-registered.** Each plugin declares + its provider in `composer.json` under `extra.acorn.providers`. Whichever plugin + wins the election scans **all** active plugins' manifests and registers every + provider — so a plugin's provider boots even when a *sibling* booted Acorn. +3. **Livewire assets are emitted once, by the boot owner.** Only the elected booter + calls `LivewireAssets::registerOnce()` (`@livewireStyles` on `wp_head`, + `@livewireScripts` on `wp_footer`). Livewire 4 self-initialises — never add + `Livewire.start()` or a hand-rolled ESM ` - -@livewireStyles diff --git a/tests/Acorn/BootCoordinatorTest.php b/tests/Acorn/BootCoordinatorTest.php new file mode 100644 index 0000000..a261243 --- /dev/null +++ b/tests/Acorn/BootCoordinatorTest.php @@ -0,0 +1,50 @@ +justReturn(0); + + $result = (new BootCoordinator())->shouldBoot(); + + $this->assertTrue($result); + } + + public function test_should_boot_returns_false_when_action_already_fired(): void + { + Functions\expect('did_action') + ->once() + ->with(BootCoordinator::BOOTED_ACTION) + ->andReturn(1); + + $result = (new BootCoordinator())->shouldBoot(); + + $this->assertFalse($result); + } + + // ----------------------------------------------------------------------- + // markBooted() + // ----------------------------------------------------------------------- + + public function test_mark_booted_fires_the_booted_action_once(): void + { + Functions\expect('do_action') + ->once() + ->with(BootCoordinator::BOOTED_ACTION); + + (new BootCoordinator())->markBooted(); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..b004a3f --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,28 @@ +