pondeplu / acorn-common-config
Common configuration package for Acorn-based projects
Package info
git.pondeplu.nl/wordpress/acorn-common-config.git
Type:package
pkg:composer/pondeplu/acorn-common-config
Requires
- php: >=8.4
- roots/acorn: ^6.0
Requires (Dev)
- carthage-software/mago: ^1.46
- pestphp/pest: ^5.0
- php-stubs/acf-pro-stubs: ^6.5
- pondeplu/mago-config: ^1.0
- spatie/laravel-csp: ^3.21
Suggests
- spatie/laravel-csp: ^3.21 to use the shipped CSP integration (Csp\Presets\Basic, Support\WpNonceGenerator). Nothing in this package loads those classes; spatie's own config/csp.php in the host site does, so the host owns the dependency.
Provides
None
Conflicts
None
Replaces
None
- dev-main
- v2.2.2
- v2.2.1
- v2.2.0
- v2.1.0
- v2.0.1
- v2.0.0
- v1.5.9
- v1.5.8
- v1.5.7
- v1.5.6
- v1.5.5
- v1.5.4
- v1.5.3
- v1.5.2
- v1.5.1
- v1.5.0
- v1.4.5
- v1.4.4
- v1.4.3
- v1.4.2
- v1.4.1
- v1.4.0
- v1.3.2
- v1.3.1
- v1.3.0
- v1.2.10
- v1.2.9
- v1.2.8
- v1.2.7
- v1.2.6
- v1.2.5
- v1.2.4
- v1.2.3
- v1.2.2
- v1.2.1
- v1.2.0
- v1.1.16
- v1.1.15
- v1.1.14
- v1.1.13
- v1.1.12
- v1.1.11
- 1.1.10
- v1.1.9
- v1.1.8
- v1.1.7
- v1.1.6
- v1.1.5
- v1.1.4
- v1.1.3
- v1.1.2
- v1.1.1
- v1.1.0
- v1.0.7
- v1.0.6
- v1.0.5
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- dev-chore/gitattributes
This package is auto-updated.
Last update: 2026-09-24 17:57:56 UTC
README
Shared Acorn package that bundles cross-cutting WordPress configuration used across Pondeplu sites: asset enqueueing, CSP, comment/admin clean-up, plugin license activation, and a login gate for staging.
Modules
Each module is config-driven and can be toggled independently in config/common.php.
| Module | Config key | What it does |
|---|---|---|
Assets | assets | Prints the #common-config JSON block, optional imgproxy rewrite for attachment URLs. |
CleanUp | clean-up | Disables comments site-wide, the customizer "Additional CSS" tab, the ACF admin UI, core's speculation rules, and various commercial headers. |
Environment | environment | Prefixes the document title on non-production envs and adds an admin-bar item with the active Deployer release info. |
Licensing | licensing | Activates ACF Pro and Gravity Forms licenses from env vars on init. |
RequireLogin | require-login | On WP_ENV=staging only: sends logged-out visitors to the login screen and answers their REST requests with a 401. See Staging login gate. |
Sentry moved out of this package in v2.0.0. Use
pondeplu/acorn-sentry.
CSP integration (optional)
Two classes are shipped for spatie/laravel-csp and referenced from a host project's config/csp.php:
| Class | config/csp.php key |
|---|---|
Csp\Presets\Basic | presets |
Support\WpNonceGenerator | nonce_generator (deprecated, never called) |
spatie/laravel-csp is a suggested, not required, dependency: nothing in this package loads either class — spatie's service provider does, from the host's own config. A site that doesn't publish a config/csp.php never touches them and doesn't need the library. A site that does must require spatie/laravel-csp itself, which also lets it control the version it runs.
Csp\Presets\Basic composes spatie's own GoogleFonts, GoogleMaps, GoogleRecaptcha and Sentry presets, and hand-rolls the rest (YouTube/Vimeo embeds, Clarity, Font Awesome, Google Analytics, Google Translate, Gravatar, Filebird).
No nonce, by design
script-src is a plain allowlist — no nonce, no hash, no 'strict-dynamic'.
A nonce describes the one response body it was generated for, and a full-page cache stores the body and the header independently. MilliCache makes the failure concrete: on a stale hit it replays the stored headers, keeps the PHP process alive to re-render, then pairs the fresh body with those frozen headers. The regenerated HTML and the header it is served under can no longer agree, so every script is blocked — permanently, and again after each regeneration. Hashes fail the same way. Anything that varies per response is unusable under a page cache.
That is affordable because the policy has nothing inline to allow. Packages in this stack must not emit executable inline scripts on the front end. Payloads go out as inert <script type="application/json"> blocks (see AbstractModule::printJsonConfig()), which script-src does not gate at all, and everything that does execute is same-origin and covered by 'self'.
wp-admin is the exception and keeps 'unsafe-inline': it is full of inline scripts we don't control, and Acorn's request handler skips /wp/wp-admin/ anyway, so no header is emitted there.
Basic deliberately does not compose spatie's Basic, GoogleAnalytics or GoogleTagManager presets: each calls addNonce(SCRIPT), which would put a per-response value back in the header and reintroduce the mismatch. A nonce also makes browsers ignore 'unsafe-inline' in the same directive, breaking wp-admin.
Note that Presets\Sentry allows only *.ingest.{de,us}.sentry.io; a self-hosted Sentry needs its host added to connect-src explicitly.
Staging login gate
RequireLogin never acts outside WP_ENV=staging, whatever a site's published config says; enabled => false switches it off there too.
A logged-out visitor gets a 302 to wp-login.php?redirect_to=<page> (with no-cache headers) and lands back on the page after logging in — by password, two-factor or SSO. The redirect runs first on parse_request, ahead of everything that can answer a front-end request: Acorn's routes, The SEO Framework's and Yoast's sitemaps, core's sitemaps, feeds, robots.txt, embeds and the canonical redirect that turns ?author=1 into a username. Logged-out REST requests get a 401 instead.
What stays reachable while logged out, and why:
- Acorn routes named in
except—sso.*by default, sopondeplu/acorn-sso's login flow works. Every other Acorn route is gated. wp-login.php, which has to be, and wp-admin, which core already guards.admin-ajax.php/admin-post.php— background jobs loop back through theirnoprivactions without a login cookie (Gravity Forms sends its notifications that way), so gating them breaks the site.- Static files (uploads, theme builds) — they never reach PHP; gate them in the web server if they matter. (
xmlrpc.phpis already denied in the nginx baseline.)
A machine client that needs the REST API on staging should authenticate with an application password — the gate counts that as logged in — rather than get a hole in the gate.
The block editor is unaffected — its requests are logged in and carry a nonce, and embed previews of the site's own URLs resolve locally rather than over a (logged-out) loopback request.
Installation
composer require pondeplu/acorn-common-config
wp acorn package:discover
wp acorn vendor:publish --provider="Pondeplu\CommonConfig\CommonConfigServiceProvider"
The vendor:publish step copies config/common.php into the host project so its module flags can be customised.
Configuration
config/common.php after publishing:
return [
'assets' => [
'enabled' => true,
'imgproxy' => false, // rewrite /content/uploads/*.{jpg,png} → /imgproxy/...
],
'clean-up' => [
'enabled' => true,
'disable-acf-admin' => env('WP_ENV') !== 'development',
'disable-comments' => true,
'disable-additional-css' => true,
'disable-commercial-headers'=> true,
'disable-speculation-rules' => true,
'yoast-metabox-bottom' => true,
],
'environment' => [
'enabled' => true,
'title-prefix' => true, // prefix <title> with (DEV)/(TEST)/(STAGING)
'admin-bar-deploy-info' => true, // show release info from Deployer .dep/
'deploy-path' => null, // null = auto-detect by walking up
],
'licensing' => [
'enabled' => true,
'acf' => env('ACF_LICENSE_KEY'),
'gravityforms' => env('GRAVITYFORMS_LICENSE_KEY'),
],
'require-login' => [
'enabled' => true, // only ever acts on WP_ENV=staging
'except' => ['sso.*'], // Acorn route names reachable while logged out
],
];
Environment variables
| Variable | Purpose |
|---|---|
WP_ENV | development relaxes CSP for the Vite dev server; staging turns on RequireLogin. |
CSP_ENABLED | Read by the host's config/csp.php, not by this package. |
ACF_LICENSE_KEY | ACF Pro license, activated on init. |
GRAVITYFORMS_LICENSE_KEY | Gravity Forms license, stored in rg_gforms_key. |
Requirements
- PHP
>=8.4 - Roots Acorn
^6.0 - Node
>=20.19.0(for lint/format tooling)
Development
composer lint # mago lint
composer lint:fix
composer format # mago format --check
composer format:fix
npm run lint # oxlint
npm run format # oxfmt --check
Git hooks are managed by lefthook (npm run prepare to install). Pre-commit runs oxfmt, oxlint, and mago format on staged files.