PHPStan extension for Blockstudio. It adds type-safe template access, schema validation, hook checking, and stubs for the Blockstudio public PHP API.
composer require --dev blockstudio/phpstanIf you have
phpstan/extension-installer
installed, the extension is auto-discovered. Otherwise, include it manually in
your phpstan.neon:
includes:
- vendor/blockstudio/phpstan/extension.neonWhen a PHP file lives next to a block.json, the extension validates every
$a['key'] access against the block's declared attributes.
// blockstudio/hero/index.php
<?php
/** @var array<string, mixed> $a */
echo $a['title']; // OK
echo $a['subtitle']; // OK
echo $a['typo']; // Error: Field "typo" does not exist in block.jsonTwig and Blade templates are checked too:
<h1>{{ a.title }}</h1>
<p>{{ a.typo }}</p> {# Error #}<h1>{{ $a['title'] }}</h1>
<p>{{ $a['typo'] }}</p> {{-- Error --}}Both <block> and <bs:> tag syntaxes are validated across PHP, Twig, and
Blade templates.
<bs:mytheme-hero title="Hello" /> <!-- OK -->
<bs:mytheme-nonexistent /> <!-- Error: unknown block -->
<bs:mytheme-hero badattr="" /> <!-- Error: unknown attribute -->
<block name="core/separator" /> <!-- OK -->data-* and html-* attributes are treated as pass-through and are not
validated.
The extension reads your db.php schema and uses it to type record arrays
returned by Db::get().
// blockstudio/subscribers/db.php
return [
'storage' => 'table',
'fields' => [
'email' => ['type' => 'string', 'required' => true],
'name' => ['type' => 'string'],
],
];
$db = Db::get('mytheme/subscribers');
$record = $db->create(['email' => 'a@b.com']);
echo $record['email']; // string
echo $record['name']; // string|null
echo $record['typo']; // ErrorThis also works with the PHP-native builder syntax:
use Blockstudio\Db\Field;
use Blockstudio\Db\Schema;
use Blockstudio\Db\Storage;
return Schema::make(
storage: Storage::Table,
fields: [
'email' => Field::string(required: true),
'active' => Field::boolean(default: false),
],
);Settings::get() paths are checked against the known Blockstudio settings
schema.
Settings::get('tailwind/enabled'); // OK
Settings::get('tailwind/enabld'); // Error: Did you mean "tailwind/enabled"?
Blockstudio action and filter hook names are validated.
add_filter('blockstudio/render', $cb); // OK
add_filter('blockstudio/rendrr', $cb); // ErrorDynamic settings hooks such as blockstudio/settings/tailwind/enabled are
always allowed. Non-Blockstudio hooks are ignored.
The extension validates Blockstudio schema files across the project:
block.jsonfield.json- extension JSON files in
extensions/ page.jsondb.phprpc.phpcron.phpblockstudio.json
That covers missing required keys, invalid field types, malformed schema
shapes, bad RPC method values, invalid cron schedules, and deprecated settings
shorthand such as "tailwind": true.
db.php, rpc.php, and cron.php support both legacy arrays and the optional
PHP-native forms:
Blockstudio\Db\Schema/Blockstudio\Db\Field#[Blockstudio\Attributes\Rpc]#[Blockstudio\Attributes\Cron]
The package ships stubs for the Blockstudio public API, including:
Db,Settings,Build,Field_RegistryBlockstudio\Db\Schema,Blockstudio\Db\Field,Blockstudio\Db\StorageBlockstudio\Rpc\Method,Blockstudio\Rpc\AccessBlockstudio\Cron\ScheduleBlockstudio\Attributes\Rpc,Blockstudio\Attributes\Cron- global helpers like
bs_render_block()
Legacy compatibility aliases are stubbed too, so older codebases still analyze cleanly while migrating.
Add a @var annotation at the top of each PHP block template so PHPStan knows
$a exists:
<?php
/** @var array<string, mixed> $a */Twig and Blade templates do not need this annotation.
The extension requires no manual configuration. It auto-discovers
block.json, db.php, rpc.php, cron.php, page.json, field.json, and
blockstudio.json files in your project.
If you need to exclude specific paths, use PHPStan's standard excludePaths:
parameters:
excludePaths:
- some/path/to/exclude- PHP 8.2+
- PHPStan 2.0+
- phpstan/phpstan-wordpress
MIT