Files
WP-Acorn-Starter/CLAUDE.md
T
2026-06-29 19:54:12 +02:00

5.2 KiB

CLAUDE.md

Guidance for working in this repository.

What this is

A starter WordPress plugin built on the Roots 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_dies 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 <script import> per plugin.

Rules for every Acorn plugin sharing this install (including siblings like siteminder-integration):

  • Use the exact action name acorn/booted — it is the cross-plugin contract.
  • Give the plugin its own PSR-4 namespace (do not reuse AcornPlugin\), or BootCoordinator/LivewireAssets/provider classes collide by FQCN (first autoloader wins).
  • Namespace your views (loadViewsFrom($path, 'your-plugin')) and Livewire components (Livewire::addNamespace('your-plugin', …)) so they don't collide in the shared container.
  • Keep all co-installed Acorn plugins on the same Acorn major version — they share one bundled copy at runtime (first loaded wins).

Caveat: the election only coordinates plugins that adopt this contract. A Sage theme (or anything else) that boots Acorn will not fire acorn/booted, so the plugins would boot a second container on top of it. If a Sage theme is ever added, make the theme the sole booter and let plugins rely on extra.acorn.providers auto-discovery alone — drop the configure()->boot() from the plugins.

Layout

  • index.php — plugin header; includes bootstrap.php.
  • bootstrap.php — runs the boot election (above); on win, boots Acorn with ->withRouting(wordpress: true) and emits Livewire assets once. No withProviders() — auto-discovery handles providers.
  • app/Acorn/BootCoordinator.php — the election seam (unit-tested).
  • app/Acorn/LivewireAssets.php — once-only Livewire asset emission.
  • app/Providers/PluginServiceProvider.php — registers namespaced views, the acorn-starter Livewire namespace, and the [acorn_hello] shortcode. Extends Illuminate\Support\ServiceProvider (Acorn's ServiceProvider is final in v6).
  • resources/views/hello-world.blade.php (mounts <livewire:acorn-starter::say-hello />), components/say-hello.blade.php (anonymous single-file Livewire component).
  • tests/ — PHPUnit + Brain\Monkey unit tests (tests/Acorn/BootCoordinatorTest.php).
  • storage/framework/ — compiled views / cache / sessions (gitignored runtime dirs).
  • .envAPP_KEY (generate with wp acorn key:generate).

There is no plugin-level config/: a plugin shouldn't own the framework's global config, so the elected booter uses Acorn's defaults. Add config only if this plugin is intentionally the sole booter.

Conventions

  • New classes go under app/ in the AcornPlugin\ namespace.
  • Reference views by their namespace: view('acorn-starter::…').
  • Naming: kebab (acorn-starter) for view/Livewire namespaces; the public shortcode stays acorn_hello (snake) as a published API.
  • Match the test style in tests/ (Brain\Monkey, AAA, test_ snake_case methods).

Commands

  • composer install — install deps (runs Acorn's post-autoload-dump, which rebuilds the package-discovery manifest; rerun after editing extra.acorn.providers).
  • composer test — PHPUnit unit suite.
  • composer lint — phpcs (PSR-12 + WordPress security/i18n sniffs).
  • wp acorn … — Acorn WP-CLI (e.g. wp acorn key:generate, wp acorn package:discover).