php-stubs/wordpress-globals
Stub declarations for WordPress globals like $wpdb, $post, and $wp_query, giving PHPStan, Psalm, and other static analyzers accurate types. Pairs with php-stubs/wordpress-stubs to silence undefined-variable warnings and improve autocompletion in plugin and theme code.
This package is not a runtime library — it is a static-analysis stub set. Its only job is to teach PHPStan/Psalm about WordPress's ambient globals ($wpdb, $post, $current_user, $wp_query, etc.) and the constants WordPress defines at bootstrap (ABSPATH, WP_CONTENT_DIR, WP_DEBUG, MINUTE_IN_SECONDS, …). Treat it as a dev dependency you wire into your analyzer, not something your plugin ships.
Minimal setup:
Install alongside the function/class stubs (the two are complementary):
composer require --dev php-stubs/wordpress-globals php-stubs/wordpress-stubs
Register the stub with PHPStan. scanFiles is the correct bucket — it makes the declared symbols visible without executing the file:
parameters:
scanFiles:
- vendor/php-stubs/wordpress-globals/wordpress-globals.php
- vendor/php-stubs/wordpress-stubs/wordpress-stubs.php
For Psalm, add it as a stub file:
<stubs>
<file name="vendor/php-stubs/wordpress-globals/wordpress-globals.php"/>
</stubs>
Where to look first: open vendor/php-stubs/wordpress-globals/ and grep the single stub file for the exact symbol you're chasing. That file is the entire package — there is no service provider, no runtime code, no config surface. If a constant or global is not in that file, it will not be fixed by the package.
First use case: activating PHPStan on a plugin bootstrapper that references ABSPATH, WP_PLUGIN_DIR, and $wpdb. Before the stubs you get "Constant ABSPATH not found" and "Variable $wpdb might not be defined"; after wiring, those disappear and the remaining errors are real code issues.
wordpress-stubs covers functions/classes; wordpress-globals covers constants/globals. Register both in the same scanFiles array. Using only one leaves half of WordPress invisible to the analyzer.phpstan.neon.dist / psalm.xml with the stub paths, and run analysis in CI (vendor/bin/phpstan analyse --no-progress). This is the day-to-day payoff: every PR gets WordPress-aware static analysis without each developer configuring their editor.$wpdb exists, but precise inference inside functions still depends on scope. In hot spots, write:
global $wpdb;
/** @var \wpdb $wpdb */
$rows = $wpdb->get_results( $sql );
This gives you IDE completion and return-type checks on query results.stubs/project-globals.php in your repo and append it to scanFiles rather than forking this package.--generate-baseline, commit the baseline, and fail CI on new errors only. This lets you adopt the package without a 3,000-error cleanup.phpstan.neon; once the stub paths are committed, in-editor "undefined constant" noise disappears for the whole team."scripts": { "analyse": "phpstan analyse" },
"require-dev": { "php-stubs/wordpress-globals": "^1.0", "php-stubs/wordpress-stubs": "^5.5" }
Keep both in require-dev and deploy with composer install --no-dev.WP_DEVELOPMENT_MODE, and similar — will be missing. Symptom: "Constant X not found" for a legitimate modern core constant. Fix by adding your own define()/const declarations in a project stub and appending it to scanFiles.bootstrapFiles or Composer autoload for this file. bootstrapFiles executes the stub, and if the stub unconditionally defines ABSPATH or other constants it can corrupt WordPress bootstrap order or trigger "already defined" notices. Analysis-only means scanFiles (PHPStan) or <stubs> (Psalm).composer.json autoload section before deploying. If it ever autoloads the stub file, exclude it in production — the file is meant to be parsed, not run.$GLOBALS is limited. The stub declares that $wpdb exists; it does not make $wpdb magically in-scope inside a function that forgot global $wpdb;. That warning is usually a real bug — fix the code, don't suppress it.if ( defined( 'WP_DEBUG' ) ), the analyzer now assumes it is always defined and may prune the else branch. That's acceptable for analysis but can mask runtime paths; use PHPStan's dynamicConstantNames when a constant is genuinely runtime-defined rather than core-defined.scanFiles vs stubFiles: scanFiles adds symbols to the symbol table; stubFiles overrides signatures of things the analyzer already knows. For constants and globals, scanFiles is what you want. Mixing them up produces "symbol already exists" or no effect at all.dev-master drift between local and CI. A tag or commit hash keeps analysis reproducible.define() inside a stub are picked up by both, but edge-case inference (conditional defines, $GLOBALS array access) differs. Run both if you use both; don't assume a clean PHPStan run means a clean Psalm run.scanFiles. Keep project-specific stubs in your repo so upgrades of this package never overwrite them.How can I help you explore Laravel packages today?