From 80c3b5085e9b31f69f69221cf72214731dab1d2e Mon Sep 17 00:00:00 2001 From: Gary Jones Date: Thu, 11 Jun 2026 12:10:39 +0100 Subject: [PATCH 1/2] build: add PHPStan static analysis at level max The boilerplate showcases plugin tooling best practice but has had no static analysis since an earlier Psalm setup was removed, leaving only a stray export-ignore behind. Add PHPStan with the WordPress extension (auto-registered via phpstan/extension-installer) and a composer "phpstan" script. Analysis covers src/ and the main plugin file at the highest level, passing with no baseline and no ignores. The views/ and config/ templates are excluded because they depend on variables injected into their scope at runtime, which PHPStan cannot see. --- composer.json | 7 ++++++- phpstan.neon.dist | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 phpstan.neon.dist diff --git a/composer.json b/composer.json index a7bf0c0..8747790 100644 --- a/composer.json +++ b/composer.json @@ -27,10 +27,13 @@ "dealerdirect/phpcodesniffer-composer-installer": "^1.0", "infection/infection": "^0.33", "phpcompatibility/phpcompatibility-wp": "^2", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.2", "phpunit/phpunit": "^9", "rector/rector": "^2.4", "roave/security-advisories": "dev-master", "squizlabs/php_codesniffer": "^3", + "szepeviktor/phpstan-wordpress": "^2.0", "wp-coding-standards/wpcs": "^3", "yoast/phpunit-polyfills": "^4" }, @@ -39,7 +42,8 @@ "allow-plugins": { "composer/installers": true, "dealerdirect/phpcodesniffer-composer-installer": true, - "infection/extension-installer": true + "infection/extension-installer": true, + "phpstan/extension-installer": true } }, "autoload": { @@ -63,6 +67,7 @@ ], "cbf": "@php vendor/bin/phpcbf", "cs": "@php vendor/bin/phpcs", + "phpstan": "phpstan analyse", "test": [ "@lint", "@unit", diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..10d90f2 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,13 @@ +# PHPStan configuration. +# +# The WordPress stubs and rules are loaded automatically from +# szepeviktor/phpstan-wordpress via phpstan/extension-installer. +# +# views/ and config/ are deliberately not analysed: those files are pulled in +# via include/require and rely on variables injected into their scope at +# runtime (template data, plugin constants), which PHPStan cannot see. +parameters: + level: max + paths: + - plugin-slug.php + - src From e68965ef7ff4b01cadb6bdac2c0bd829a3ed77d8 Mon Sep 17 00:00:00 2001 From: Gary Jones Date: Thu, 11 Jun 2026 12:34:01 +0100 Subject: [PATCH 2/2] build: set PHPStan to level 8 Level 9's checkExplicitMixed rejects the untyped boundary of config-driven code: the BrightNucleus Config accessors return mixed by design, so the settings registration landing in the plugin-correctness branch would fail at max. Level 8 keeps every other strictness and the reasoning is recorded in the config for future revisiting. --- phpstan.neon.dist | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 10d90f2..c0ae816 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -6,8 +6,13 @@ # views/ and config/ are deliberately not analysed: those files are pulled in # via include/require and rely on variables injected into their scope at # runtime (template data, plugin constants), which PHPStan cannot see. +# +# Level 8 is the ceiling for this codebase: level 9 adds checkExplicitMixed, +# which fights the untyped boundary of config-driven WordPress code — the +# BrightNucleus Config accessors return mixed by design. Revisit if the +# config ever gains a typed accessor layer. parameters: - level: max + level: 8 paths: - plugin-slug.php - src