From 6d835969801f10d2564b715cb2078f4580027763 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 24 Feb 2026 21:48:31 -0800 Subject: [PATCH 01/24] Ignore errors in src/wp-includes/build which currently come the Gutenberg build --- tests/phpstan/base.neon | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/phpstan/base.neon b/tests/phpstan/base.neon index 347c2198ae953..8260f02b3aa88 100644 --- a/tests/phpstan/base.neon +++ b/tests/phpstan/base.neon @@ -105,6 +105,8 @@ parameters: - ../../src/wp-includes/deprecated.php - ../../src/wp-includes/ms-deprecated.php - ../../src/wp-includes/pluggable-deprecated.php + # These files are currently pulled in from Gutenberg, but maybe not long-term. See . + - ../../src/wp-includes/build # These files are sourced by wordpress/gutenberg in `tools/release/sync-stable-blocks.js`. - ../../src/wp-includes/blocks # Third-party libraries. From 5dec036584b5d7811c139d74fc542dfe845c8876 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 24 Feb 2026 22:37:27 -0800 Subject: [PATCH 02/24] Bump phpstan to 2.1.40 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 17f53c2116f71..649a3d429324c 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "squizlabs/php_codesniffer": "3.13.5", "wp-coding-standards/wpcs": "~3.3.0", "phpcompatibility/phpcompatibility-wp": "~2.1.3", - "phpstan/phpstan": "2.1.39", + "phpstan/phpstan": "2.1.40", "yoast/phpunit-polyfills": "^1.1.0" }, "config": { From 593a10ca6bf9b9fe148dc56eb6b5e72fe9fcbe18 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 3 Mar 2026 18:07:14 -0800 Subject: [PATCH 03/24] Bump PHPStan to level 1 --- phpstan.neon.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index e74e6ec1a441b..186eac7f59505 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -14,7 +14,7 @@ includes: parameters: # https://phpstan.org/user-guide/rule-levels - level: 0 + level: 1 reportUnmatchedIgnoredErrors: true ignoreErrors: From 22de4b6588239441a9d0852b67820cda399af2f8 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 3 Mar 2026 18:09:21 -0800 Subject: [PATCH 04/24] Ignore variable.undefined errors since too noisy Co-authored-by: Dovid Levine --- phpstan.neon.dist | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 186eac7f59505..38dd9c63098d0 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -34,3 +34,8 @@ parameters: identifier: function.inner path: src/wp-includes/canonical.php count: 1 + + # Level 1: + - # These are too noisy at the moment. + identifier: variable.undefined + message: '#Variable \$[a-zA-Z0-9_]+ might not be defined\.#' From cb8db153dddbb84bb7dc3920e5aa7c12b0154946 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 3 Mar 2026 18:10:20 -0800 Subject: [PATCH 05/24] Regenerate baseline for level 1 --- tests/phpstan/baseline.php | 190 ++++++++++++++++++++++++++++++++++++- 1 file changed, 189 insertions(+), 1 deletion(-) diff --git a/tests/phpstan/baseline.php b/tests/phpstan/baseline.php index 646cbdbef630c..d0443d8bbf7b1 100644 --- a/tests/phpstan/baseline.php +++ b/tests/phpstan/baseline.php @@ -1,3 +1,191 @@ '#^Call to function compact\\(\\) contains possibly undefined variable \\$comment_author\\.$#', + 'identifier' => 'variable.undefined', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-admin/includes/ajax-actions.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Call to function compact\\(\\) contains possibly undefined variable \\$comment_author_email\\.$#', + 'identifier' => 'variable.undefined', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-admin/includes/ajax-actions.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Call to function compact\\(\\) contains possibly undefined variable \\$comment_author_url\\.$#', + 'identifier' => 'variable.undefined', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-admin/includes/ajax-actions.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Call to function compact\\(\\) contains possibly undefined variable \\$user_id\\.$#', + 'identifier' => 'variable.undefined', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-admin/includes/ajax-actions.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Variable \\$_POST in isset\\(\\) always exists and is not nullable\\.$#', + 'identifier' => 'isset.variable', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-admin/includes/class-custom-image-header.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Constructor of class WP_Filesystem_Direct has an unused parameter \\$arg\\.$#', + 'identifier' => 'constructor.unusedParameter', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-admin/includes/class-wp-filesystem-direct.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Variable \\$class in empty\\(\\) always exists and is always falsy\\.$#', + 'identifier' => 'empty.variable', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-admin/includes/class-wp-posts-list-table.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Variable \\$_POST in isset\\(\\) always exists and is not nullable\\.$#', + 'identifier' => 'isset.variable', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-admin/includes/media.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Variable \\$parent_file in empty\\(\\) always exists and is not falsy\\.$#', + 'identifier' => 'empty.variable', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-admin/themes.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Constant HEADER_IMAGE_HEIGHT not found\\.$#', + 'identifier' => 'constant.notFound', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-content/themes/twentyeleven/functions.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Constant HEADER_IMAGE_WIDTH not found\\.$#', + 'identifier' => 'constant.notFound', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-content/themes/twentyeleven/functions.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Constant HEADER_TEXTCOLOR not found\\.$#', + 'identifier' => 'constant.notFound', + 'count' => 2, + 'path' => __DIR__ . '/../../src/wp-content/themes/twentyeleven/functions.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Constant HEADER_IMAGE_WIDTH not found\\.$#', + 'identifier' => 'constant.notFound', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-content/themes/twentyeleven/header.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Constant HEADER_IMAGE_WIDTH not found\\.$#', + 'identifier' => 'constant.notFound', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-content/themes/twentyeleven/showcase.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Function twentyseventeen_edit_link invoked with 1 parameter, 0 required\\.$#', + 'identifier' => 'arguments.count', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Function twentyseventeen_edit_link invoked with 1 parameter, 0 required\\.$#', + 'identifier' => 'arguments.count', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Function twentyseventeen_edit_link invoked with 1 parameter, 0 required\\.$#', + 'identifier' => 'arguments.count', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-content/themes/twentyseventeen/template-parts/page/content-page.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Constant HEADER_IMAGE_HEIGHT not found\\.$#', + 'identifier' => 'constant.notFound', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-content/themes/twentyten/functions.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Constant HEADER_IMAGE_WIDTH not found\\.$#', + 'identifier' => 'constant.notFound', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-content/themes/twentyten/functions.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Constant HEADER_IMAGE_WIDTH not found\\.$#', + 'identifier' => 'constant.notFound', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-content/themes/twentyten/header.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Function wp_cache_switch_to_blog_fallback invoked with 1 parameter, 0 required\\.$#', + 'identifier' => 'arguments.count', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-includes/cache-compat.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Variable \\$addl_path in empty\\(\\) always exists and is always falsy\\.$#', + 'identifier' => 'empty.variable', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-includes/canonical.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Variable \\$namespace in isset\\(\\) always exists and is not nullable\\.$#', + 'identifier' => 'isset.variable', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-includes/class-wp-block-parser.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Variable \\$block_type in empty\\(\\) always exists and is not falsy\\.$#', + 'identifier' => 'empty.variable', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-includes/class-wp-block-supports.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Variable \\$loader in isset\\(\\) always exists and is not nullable\\.$#', + 'identifier' => 'isset.variable', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-includes/class-wp-oembed.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Variable \\$search in empty\\(\\) always exists and is not falsy\\.$#', + 'identifier' => 'empty.variable', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-includes/class-wp-query.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Variable \\$status_type_clauses in empty\\(\\) always exists and is not falsy\\.$#', + 'identifier' => 'empty.variable', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-includes/class-wp-query.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Variable \\$deprecated in empty\\(\\) always exists and is always falsy\\.$#', + 'identifier' => 'empty.variable', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-includes/pluggable.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Variable \\$schema in empty\\(\\) is never defined\\.$#', + 'identifier' => 'empty.variable', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Variable \\$the_parent in empty\\(\\) always exists and is not falsy\\.$#', + 'identifier' => 'empty.variable', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-includes/taxonomy.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Variable \\$s in isset\\(\\) is never defined\\.$#', + 'identifier' => 'isset.variable', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-includes/template.php', +]; + +return ['parameters' => ['ignoreErrors' => $ignoreErrors]]; From d3dd8ecd6306dabce1c12cccb94044f0595fe22e Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 3 Mar 2026 19:08:39 -0800 Subject: [PATCH 06/24] Remove unused parameter for WP_Filesystem_Direct constructor --- src/wp-admin/includes/class-wp-filesystem-direct.php | 4 +--- tests/phpstan/baseline.php | 6 ------ 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/wp-admin/includes/class-wp-filesystem-direct.php b/src/wp-admin/includes/class-wp-filesystem-direct.php index a4b197c15229f..34862a661d321 100644 --- a/src/wp-admin/includes/class-wp-filesystem-direct.php +++ b/src/wp-admin/includes/class-wp-filesystem-direct.php @@ -19,10 +19,8 @@ class WP_Filesystem_Direct extends WP_Filesystem_Base { * Constructor. * * @since 2.5.0 - * - * @param mixed $arg Not used. */ - public function __construct( $arg ) { + public function __construct() { $this->method = 'direct'; $this->errors = new WP_Error(); } diff --git a/tests/phpstan/baseline.php b/tests/phpstan/baseline.php index d0443d8bbf7b1..d656589f4a069 100644 --- a/tests/phpstan/baseline.php +++ b/tests/phpstan/baseline.php @@ -31,12 +31,6 @@ 'count' => 1, 'path' => __DIR__ . '/../../src/wp-admin/includes/class-custom-image-header.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Constructor of class WP_Filesystem_Direct has an unused parameter \\$arg\\.$#', - 'identifier' => 'constructor.unusedParameter', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-admin/includes/class-wp-filesystem-direct.php', -]; $ignoreErrors[] = [ 'message' => '#^Variable \\$class in empty\\(\\) always exists and is always falsy\\.$#', 'identifier' => 'empty.variable', From bf92684d1a5041de6a67abd1ce7b3ce38dcf3b05 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 3 Mar 2026 19:17:57 -0800 Subject: [PATCH 07/24] Add theme constants to config to address constant.notFound errors Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- tests/phpstan/base.neon | 7 ++++++ tests/phpstan/baseline.php | 48 ------------------------------------- tests/phpstan/bootstrap.php | 9 +++++++ 3 files changed, 16 insertions(+), 48 deletions(-) diff --git a/tests/phpstan/base.neon b/tests/phpstan/base.neon index 8260f02b3aa88..7bfe9d6eff3df 100644 --- a/tests/phpstan/base.neon +++ b/tests/phpstan/base.neon @@ -25,6 +25,8 @@ parameters: - ALLOW_SUBDIRECTORY_INSTALL - AUTH_SALT - AUTOMATIC_UPDATER_DISABLED + - BACKGROUND_COLOR + - BACKGROUND_IMAGE - COOKIEPATH - CUSTOM_TAGS - DISALLOW_FILE_EDIT @@ -32,8 +34,13 @@ parameters: - EMPTY_TRASH_DAYS - ENFORCE_GZIP - FORCE_SSL_LOGIN + - HEADER_IMAGE + - HEADER_IMAGE_HEIGHT + - HEADER_IMAGE_WIDTH + - HEADER_TEXTCOLOR - MEDIA_TRASH - MULTISITE + - NO_HEADER_TEXT - NOBLOGREDIRECT - SAVEQUERIES - SCRIPT_DEBUG diff --git a/tests/phpstan/baseline.php b/tests/phpstan/baseline.php index d656589f4a069..2ad8bac653169 100644 --- a/tests/phpstan/baseline.php +++ b/tests/phpstan/baseline.php @@ -49,36 +49,6 @@ 'count' => 1, 'path' => __DIR__ . '/../../src/wp-admin/themes.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Constant HEADER_IMAGE_HEIGHT not found\\.$#', - 'identifier' => 'constant.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-content/themes/twentyeleven/functions.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Constant HEADER_IMAGE_WIDTH not found\\.$#', - 'identifier' => 'constant.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-content/themes/twentyeleven/functions.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Constant HEADER_TEXTCOLOR not found\\.$#', - 'identifier' => 'constant.notFound', - 'count' => 2, - 'path' => __DIR__ . '/../../src/wp-content/themes/twentyeleven/functions.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Constant HEADER_IMAGE_WIDTH not found\\.$#', - 'identifier' => 'constant.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-content/themes/twentyeleven/header.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Constant HEADER_IMAGE_WIDTH not found\\.$#', - 'identifier' => 'constant.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-content/themes/twentyeleven/showcase.php', -]; $ignoreErrors[] = [ 'message' => '#^Function twentyseventeen_edit_link invoked with 1 parameter, 0 required\\.$#', 'identifier' => 'arguments.count', @@ -97,24 +67,6 @@ 'count' => 1, 'path' => __DIR__ . '/../../src/wp-content/themes/twentyseventeen/template-parts/page/content-page.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Constant HEADER_IMAGE_HEIGHT not found\\.$#', - 'identifier' => 'constant.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-content/themes/twentyten/functions.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Constant HEADER_IMAGE_WIDTH not found\\.$#', - 'identifier' => 'constant.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-content/themes/twentyten/functions.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Constant HEADER_IMAGE_WIDTH not found\\.$#', - 'identifier' => 'constant.notFound', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-content/themes/twentyten/header.php', -]; $ignoreErrors[] = [ 'message' => '#^Function wp_cache_switch_to_blog_fallback invoked with 1 parameter, 0 required\\.$#', 'identifier' => 'arguments.count', diff --git a/tests/phpstan/bootstrap.php b/tests/phpstan/bootstrap.php index c87a26babf83d..77a597609270e 100644 --- a/tests/phpstan/bootstrap.php +++ b/tests/phpstan/bootstrap.php @@ -93,3 +93,12 @@ define( 'FS_TIMEOUT', 1 ); define( 'FS_CHMOD_DIR', 1 ); define( 'FS_CHMOD_FILE', 1 ); + +// Theme constants referenced in add_theme_support(). +define( 'NO_HEADER_TEXT', false ); +define( 'HEADER_IMAGE_WIDTH', 0 ); +define( 'HEADER_IMAGE_HEIGHT', 0 ); +define( 'HEADER_TEXTCOLOR', '' ); +define( 'HEADER_IMAGE', '' ); +define( 'BACKGROUND_COLOR', '' ); +define( 'BACKGROUND_IMAGE', '' ); From d39600aa5b0d650b6d49cb6ce23594e3dfd95772 Mon Sep 17 00:00:00 2001 From: Christoph Daum Date: Tue, 24 Feb 2026 09:18:58 +0100 Subject: [PATCH 08/24] Docs: Add `@return never` to `dead_db()`. --- src/wp-includes/functions.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index 4b6330a697780..e4b96c6418c63 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -5501,6 +5501,8 @@ function wp_ob_end_flush_all() { * @since 2.3.2 * * @global wpdb $wpdb WordPress database abstraction object. + * + * @return never */ function dead_db() { global $wpdb; From 75797b7afa805a425e77e2b4ac7e6fce3f200c4c Mon Sep 17 00:00:00 2001 From: Christoph Daum Date: Tue, 24 Feb 2026 10:42:28 +0100 Subject: [PATCH 09/24] fix(phpstan): Ignore return.never on dead_db() PHPStan cannot verify that wp_die() always terminates due to its conditional return type and treatPhpDocTypesAsCertain being disabled. --- src/wp-includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index e4b96c6418c63..101585166bd65 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -5521,7 +5521,7 @@ function dead_db() { } // Otherwise, be terse. - wp_die( '

' . __( 'Error establishing a database connection' ) . '

', __( 'Database Error' ) ); + wp_die( '

' . __( 'Error establishing a database connection' ) . '

', __( 'Database Error' ) ); // @phpstan-ignore return.never (wp_die() always exits by default.) } /** From e55878c43fe22cdd2289b1480e9af195f002101d Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 24 Feb 2026 15:18:55 -0800 Subject: [PATCH 10/24] Fix phpstan-return syntax Co-authored-by: Christoph Daum --- src/wp-includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index 101585166bd65..afc421079772a 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -3766,7 +3766,7 @@ function wp_nonce_ays( $action ) { * } * @return never|void Returns void if `$args['exit']` is false, otherwise exits. * - * @phpstan-return ( $args['exit'] is false ? void : never ) + * @phpstan-return ( $args is array{exit: false} ? void : never ) */ function wp_die( $message = '', $title = '', $args = array() ) { global $wp_query; From 46b656acb44e755085cb5e7d450b7b882e6a0eda Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 24 Feb 2026 15:19:03 -0800 Subject: [PATCH 11/24] Remove now-unnecessary phpstan-ignore --- src/wp-includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index afc421079772a..8bf46ef0b871f 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -5521,7 +5521,7 @@ function dead_db() { } // Otherwise, be terse. - wp_die( '

' . __( 'Error establishing a database connection' ) . '

', __( 'Database Error' ) ); // @phpstan-ignore return.never (wp_die() always exits by default.) + wp_die( '

' . __( 'Error establishing a database connection' ) . '

', __( 'Database Error' ) ); } /** From 3c46095d92b4321a091937681e4586f9e7f7f9eb Mon Sep 17 00:00:00 2001 From: Christoph Daum Date: Wed, 25 Feb 2026 08:14:38 +0100 Subject: [PATCH 12/24] docs: Refine phpdoc of dead_db() Co-authored-by: Weston Ruter --- src/wp-includes/class-wpdb.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/class-wpdb.php b/src/wp-includes/class-wpdb.php index 23c865b87d817..de4f86ce753b0 100644 --- a/src/wp-includes/class-wpdb.php +++ b/src/wp-includes/class-wpdb.php @@ -2117,7 +2117,9 @@ public function parse_db_host( $host ) { * @since 3.9.0 * * @param bool $allow_bail Optional. Allows the function to bail. Default true. - * @return bool|void True if the connection is up. + * @return bool|never Whether the connection is up. + * + * @phpstan-return ( $allow_bail is true ? bool|never : bool ) */ public function check_connection( $allow_bail = true ) { // Check if the connection is alive. From c52438ac35ca5627d07b63fea65c6e5f008fc873 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 3 Mar 2026 19:28:22 -0800 Subject: [PATCH 13/24] Remove never from check_connection return --- src/wp-includes/class-wpdb.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wpdb.php b/src/wp-includes/class-wpdb.php index de4f86ce753b0..60026dbdc5c16 100644 --- a/src/wp-includes/class-wpdb.php +++ b/src/wp-includes/class-wpdb.php @@ -2117,7 +2117,7 @@ public function parse_db_host( $host ) { * @since 3.9.0 * * @param bool $allow_bail Optional. Allows the function to bail. Default true. - * @return bool|never Whether the connection is up. + * @return bool Whether the connection is up. Exits when `$allow_bail` is true and the connection is down. * * @phpstan-return ( $allow_bail is true ? bool|never : bool ) */ From 87a2c049b80664d5cfbf3b777b72a13059c49fff Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 3 Mar 2026 19:29:22 -0800 Subject: [PATCH 14/24] Remove errors from baseline which were fixed by never returns --- tests/phpstan/baseline.php | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/tests/phpstan/baseline.php b/tests/phpstan/baseline.php index 2ad8bac653169..0ebe3bbad7266 100644 --- a/tests/phpstan/baseline.php +++ b/tests/phpstan/baseline.php @@ -1,30 +1,6 @@ '#^Call to function compact\\(\\) contains possibly undefined variable \\$comment_author\\.$#', - 'identifier' => 'variable.undefined', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-admin/includes/ajax-actions.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Call to function compact\\(\\) contains possibly undefined variable \\$comment_author_email\\.$#', - 'identifier' => 'variable.undefined', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-admin/includes/ajax-actions.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Call to function compact\\(\\) contains possibly undefined variable \\$comment_author_url\\.$#', - 'identifier' => 'variable.undefined', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-admin/includes/ajax-actions.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Call to function compact\\(\\) contains possibly undefined variable \\$user_id\\.$#', - 'identifier' => 'variable.undefined', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-admin/includes/ajax-actions.php', -]; $ignoreErrors[] = [ 'message' => '#^Variable \\$_POST in isset\\(\\) always exists and is not nullable\\.$#', 'identifier' => 'isset.variable', From 95ddce21f75478d4b34e7873315e0de7b4c39885 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 3 Mar 2026 19:37:31 -0800 Subject: [PATCH 15/24] Resolve isset.variable error since $_POST global is always set --- src/wp-admin/includes/class-custom-image-header.php | 2 +- tests/phpstan/baseline.php | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/wp-admin/includes/class-custom-image-header.php b/src/wp-admin/includes/class-custom-image-header.php index eb65605728062..2c0eb26c0fc9a 100644 --- a/src/wp-admin/includes/class-custom-image-header.php +++ b/src/wp-admin/includes/class-custom-image-header.php @@ -841,7 +841,7 @@ public function step_2() { $file = get_attached_file( $attachment_id, true ); $url = wp_get_attachment_image_src( $attachment_id, 'full' ); $url = $url[0]; - } elseif ( isset( $_POST ) ) { + } else { $data = $this->step_2_manage_upload(); $attachment_id = $data['attachment_id']; $file = $data['file']; diff --git a/tests/phpstan/baseline.php b/tests/phpstan/baseline.php index 0ebe3bbad7266..810d719f57b6a 100644 --- a/tests/phpstan/baseline.php +++ b/tests/phpstan/baseline.php @@ -1,12 +1,6 @@ '#^Variable \\$_POST in isset\\(\\) always exists and is not nullable\\.$#', - 'identifier' => 'isset.variable', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-admin/includes/class-custom-image-header.php', -]; $ignoreErrors[] = [ 'message' => '#^Variable \\$class in empty\\(\\) always exists and is always falsy\\.$#', 'identifier' => 'empty.variable', From 2d774486763c0297208fb104a3c363b749eb2e5d Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 6 Mar 2026 11:43:06 -0800 Subject: [PATCH 16/24] Use allow-list for unknown globals --- phpstan.neon.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 38dd9c63098d0..1a0e1f5dd2f01 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -38,4 +38,4 @@ parameters: # Level 1: - # These are too noisy at the moment. identifier: variable.undefined - message: '#Variable \$[a-zA-Z0-9_]+ might not be defined\.#' + message: '#Variable \$(_comments|_nav_menu_selected_id|_object|_wp_admin_css_colors|all_items|authors_dropdown|auto_update_notice|auto_updates|b|badge_class|badge_title|blog_id|cache_found|cache_key|cached|callback|cat_id|cats|class|closer_potentially_starts_at|comment|comment_closing_at|comment_id|comment_ids|comment_opening_at|comment_status|comments|compat|context|control|control_callback|current_blog|current_screen|current_site|current_user|description|docs_select|end|error|filter_id|gen|h1|has_closer|has_void_flag|height|html|icon|id|image|is_IE|is_caddy|is_nginx|item_name|json_at|json_length|k|key|link|linkcheck|manage_url|matches|message|messages|metakey|mime|my_year|name|name_at|name_length|namespace_at|network|network_current|next_id|node|num_posts|old_user_data|option|options_to_update|original_content|original_result|output|page|paged|parent|parts|plugin_name|plugins|post|post_author|post_meta|post_type_cap|posts|primary|processed_response|query|redirect|required_mysql_version|required_php_version|resized|response|restore_link|result|return_to_post|revision|rollback_result|rootcommentmatch|rootcommentquery|rp_key|rp_login|s|secret_keys|section_id|self|shape|show_network_active|stat|status|sub1|sub1comment|sub1embed|sub1feed|sub1feed2|sub1tb|sub2|sub2comment|sub2embed|sub2feed|sub2feed2|sub2tb|subcommentquery|subembedquery|subfeedquery|subject|submenu|subquery|subtbquery|tab|table_prefix|tag|tag_ID|tax|taxnow|taxonomy|text|title|token_length|trackbackmatch|trackbackquery|type|typenow|unique_id|update|update_data|upgrader|user_ID|user_email|user_id|user_login|usersearch|version_url|was_active|width|working_dir_local|wp_db_version|wp_filter|wp_query|wp_registered_sidebars|wp_registered_widget_controls|wp_registered_widget_updates|wp_rewrite|wp_roles|wp_version|wpdb)\b might not be defined\.#' From eeefc04b560ba4dc45c1434cc7cea29a8d59be33 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 6 Mar 2026 11:50:01 -0800 Subject: [PATCH 17/24] Convert single variable.undefined ignore rule into one per variable --- phpstan.neon.dist | 520 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 518 insertions(+), 2 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 1a0e1f5dd2f01..8364f71cca9f5 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -36,6 +36,522 @@ parameters: count: 1 # Level 1: - - # These are too noisy at the moment. + - + identifier: variable.undefined + message: '#Variable \$_comments might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$_nav_menu_selected_id might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$_object might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$_wp_admin_css_colors might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$all_items might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$authors_dropdown might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$auto_update_notice might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$auto_updates might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$b might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$badge_class might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$badge_title might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$blog_id might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$cache_found might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$cache_key might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$cached might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$callback might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$cat_id might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$cats might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$class might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$closer_potentially_starts_at might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$comment might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$comment_closing_at might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$comment_id might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$comment_ids might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$comment_opening_at might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$comment_status might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$comments might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$compat might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$context might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$control might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$control_callback might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$current_blog might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$current_screen might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$current_site might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$current_user might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$description might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$docs_select might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$end might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$error might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$filter_id might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$gen might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$h1 might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$has_closer might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$has_void_flag might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$height might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$html might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$icon might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$id might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$image might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$is_IE might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$is_caddy might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$is_nginx might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$item_name might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$json_at might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$json_length might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$k might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$key might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$link might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$linkcheck might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$manage_url might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$matches might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$message might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$messages might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$metakey might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$mime might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$my_year might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$name might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$name_at might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$name_length might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$namespace_at might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$network might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$network_current might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$next_id might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$node might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$num_posts might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$old_user_data might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$option might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$options_to_update might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$original_content might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$original_result might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$output might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$page might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$paged might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$parent might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$parts might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$plugin_name might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$plugins might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$post might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$post_author might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$post_meta might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$post_type_cap might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$posts might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$primary might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$processed_response might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$query might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$redirect might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$required_mysql_version might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$required_php_version might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$resized might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$response might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$restore_link might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$result might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$return_to_post might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$revision might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$rollback_result might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$rootcommentmatch might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$rootcommentquery might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$rp_key might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$rp_login might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$s might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$secret_keys might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$section_id might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$self might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$shape might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$show_network_active might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$stat might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$status might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$sub1 might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$sub1comment might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$sub1embed might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$sub1feed might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$sub1feed2 might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$sub1tb might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$sub2 might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$sub2comment might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$sub2embed might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$sub2feed might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$sub2feed2 might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$sub2tb might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$subcommentquery might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$subembedquery might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$subfeedquery might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$subject might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$submenu might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$subquery might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$subtbquery might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$tab might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$table_prefix might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$tag might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$tag_ID might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$tax might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$taxnow might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$taxonomy might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$text might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$title might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$token_length might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$trackbackmatch might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$trackbackquery might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$type might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$typenow might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$unique_id might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$update might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$update_data might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$upgrader might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$user_ID might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$user_email might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$user_id might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$user_login might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$usersearch might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$version_url might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$was_active might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$width might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$working_dir_local might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$wp_db_version might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$wp_filter might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$wp_query might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$wp_registered_sidebars might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$wp_registered_widget_controls might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$wp_registered_widget_updates might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$wp_rewrite might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$wp_roles might not be defined\.#' + - + identifier: variable.undefined + message: '#Variable \$wp_version might not be defined\.#' + - identifier: variable.undefined - message: '#Variable \$(_comments|_nav_menu_selected_id|_object|_wp_admin_css_colors|all_items|authors_dropdown|auto_update_notice|auto_updates|b|badge_class|badge_title|blog_id|cache_found|cache_key|cached|callback|cat_id|cats|class|closer_potentially_starts_at|comment|comment_closing_at|comment_id|comment_ids|comment_opening_at|comment_status|comments|compat|context|control|control_callback|current_blog|current_screen|current_site|current_user|description|docs_select|end|error|filter_id|gen|h1|has_closer|has_void_flag|height|html|icon|id|image|is_IE|is_caddy|is_nginx|item_name|json_at|json_length|k|key|link|linkcheck|manage_url|matches|message|messages|metakey|mime|my_year|name|name_at|name_length|namespace_at|network|network_current|next_id|node|num_posts|old_user_data|option|options_to_update|original_content|original_result|output|page|paged|parent|parts|plugin_name|plugins|post|post_author|post_meta|post_type_cap|posts|primary|processed_response|query|redirect|required_mysql_version|required_php_version|resized|response|restore_link|result|return_to_post|revision|rollback_result|rootcommentmatch|rootcommentquery|rp_key|rp_login|s|secret_keys|section_id|self|shape|show_network_active|stat|status|sub1|sub1comment|sub1embed|sub1feed|sub1feed2|sub1tb|sub2|sub2comment|sub2embed|sub2feed|sub2feed2|sub2tb|subcommentquery|subembedquery|subfeedquery|subject|submenu|subquery|subtbquery|tab|table_prefix|tag|tag_ID|tax|taxnow|taxonomy|text|title|token_length|trackbackmatch|trackbackquery|type|typenow|unique_id|update|update_data|upgrader|user_ID|user_email|user_id|user_login|usersearch|version_url|was_active|width|working_dir_local|wp_db_version|wp_filter|wp_query|wp_registered_sidebars|wp_registered_widget_controls|wp_registered_widget_updates|wp_rewrite|wp_roles|wp_version|wpdb)\b might not be defined\.#' + message: '#Variable \$wpdb might not be defined\.#' From cb7a8c3c0308e052848ffc97a5e641da12721b04 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 6 Mar 2026 12:46:00 -0800 Subject: [PATCH 18/24] Remove unused $class variable after r54215 (56bde67811f432764d2be6c5c830c634624e7081) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes PHPStan issue: ------ --------------------------------------------------------------- Line wp-admin/includes/class-wp-posts-list-table.php ------ --------------------------------------------------------------- 357 Variable $class in empty() always exists and is always falsy. 🪪 empty.variable at src/wp-admin/includes/class-wp-posts-list-table.php:357 ------ --------------------------------------------------------------- --- .../includes/class-wp-posts-list-table.php | 16 +--------------- tests/phpstan/baseline.php | 6 ------ 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/src/wp-admin/includes/class-wp-posts-list-table.php b/src/wp-admin/includes/class-wp-posts-list-table.php index f9c08ad5c73ee..ae444905ac79f 100644 --- a/src/wp-admin/includes/class-wp-posts-list-table.php +++ b/src/wp-admin/includes/class-wp-posts-list-table.php @@ -298,7 +298,6 @@ protected function get_views() { $status_links = array(); $num_posts = wp_count_posts( $post_type, 'readable' ); $total_posts = array_sum( (array) $num_posts ); - $class = ''; $current_user_id = get_current_user_id(); $all_args = array( 'post_type' => $post_type ); @@ -310,10 +309,6 @@ protected function get_views() { } if ( $this->user_posts_count && $this->user_posts_count !== $total_posts ) { - if ( isset( $_GET['author'] ) && ( $current_user_id === (int) $_GET['author'] ) ) { - $class = 'current'; - } - $mine_args = array( 'post_type' => $post_type, 'author' => $current_user_id, @@ -337,7 +332,6 @@ protected function get_views() { ); $all_args['all_posts'] = 1; - $class = ''; } $all_inner_html = sprintf( @@ -354,7 +348,7 @@ protected function get_views() { $status_links['all'] = array( 'url' => esc_url( add_query_arg( $all_args, 'edit.php' ) ), 'label' => $all_inner_html, - 'current' => empty( $class ) && ( $this->is_base_request() || isset( $_REQUEST['all_posts'] ) ), + 'current' => ( $this->is_base_request() || isset( $_REQUEST['all_posts'] ) ), ); if ( $mine ) { @@ -362,18 +356,12 @@ protected function get_views() { } foreach ( get_post_stati( array( 'show_in_admin_status_list' => true ), 'objects' ) as $status ) { - $class = ''; - $status_name = $status->name; if ( ! in_array( $status_name, $avail_post_stati, true ) || empty( $num_posts->$status_name ) ) { continue; } - if ( isset( $_REQUEST['post_status'] ) && $status_name === $_REQUEST['post_status'] ) { - $class = 'current'; - } - $status_args = array( 'post_status' => $status_name, 'post_type' => $post_type, @@ -392,8 +380,6 @@ protected function get_views() { } if ( ! empty( $this->sticky_posts_count ) ) { - $class = ! empty( $_REQUEST['show_sticky'] ) ? 'current' : ''; - $sticky_args = array( 'post_type' => $post_type, 'show_sticky' => 1, diff --git a/tests/phpstan/baseline.php b/tests/phpstan/baseline.php index 810d719f57b6a..89265768f863a 100644 --- a/tests/phpstan/baseline.php +++ b/tests/phpstan/baseline.php @@ -1,12 +1,6 @@ '#^Variable \\$class in empty\\(\\) always exists and is always falsy\\.$#', - 'identifier' => 'empty.variable', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-admin/includes/class-wp-posts-list-table.php', -]; $ignoreErrors[] = [ 'message' => '#^Variable \\$_POST in isset\\(\\) always exists and is not nullable\\.$#', 'identifier' => 'isset.variable', From a47a4344cfcc6428b8ecf33080bdbdc0058441c9 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 6 Mar 2026 12:51:21 -0800 Subject: [PATCH 19/24] Fix wp_cache_switch_to_blog() issues --- src/wp-includes/cache-compat.php | 6 +++--- tests/phpstan/baseline.php | 6 ------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/wp-includes/cache-compat.php b/src/wp-includes/cache-compat.php index fe0e29c107b64..6f8842ab04ae0 100644 --- a/src/wp-includes/cache-compat.php +++ b/src/wp-includes/cache-compat.php @@ -327,11 +327,11 @@ function wp_cache_set_multiple_salted( $data, $group, $salt, $expire = 0 ) { * * @param int $blog_id Site ID. */ - function wp_cache_switch_to_blog( $blog_id ) { + function wp_cache_switch_to_blog( $blog_id ): void { global $wp_object_cache; // Attempt to use the drop-in object cache method if it exists. - if ( method_exists( $wp_object_cache, 'switch_to_blog' ) ) { + if ( is_object( $wp_object_cache ) && method_exists( $wp_object_cache, 'switch_to_blog' ) ) { $wp_object_cache->switch_to_blog( $blog_id ); return; } @@ -340,6 +340,6 @@ function wp_cache_switch_to_blog( $blog_id ) { * Perform a fallback blog switch, which will reinitialize the caches * for the new blog ID. */ - wp_cache_switch_to_blog_fallback( $blog_id ); + wp_cache_switch_to_blog_fallback(); } endif; diff --git a/tests/phpstan/baseline.php b/tests/phpstan/baseline.php index 89265768f863a..24b1c4aac44a8 100644 --- a/tests/phpstan/baseline.php +++ b/tests/phpstan/baseline.php @@ -31,12 +31,6 @@ 'count' => 1, 'path' => __DIR__ . '/../../src/wp-content/themes/twentyseventeen/template-parts/page/content-page.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Function wp_cache_switch_to_blog_fallback invoked with 1 parameter, 0 required\\.$#', - 'identifier' => 'arguments.count', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-includes/cache-compat.php', -]; $ignoreErrors[] = [ 'message' => '#^Variable \\$addl_path in empty\\(\\) always exists and is always falsy\\.$#', 'identifier' => 'empty.variable', From 680d165e5fc662f16ea2530cdf302053119f4c40 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 6 Mar 2026 12:54:18 -0800 Subject: [PATCH 20/24] Fix arguments.count issues in Twenty Seventeen where twentyseventeen_edit_link() takes no args --- .../page/content-front-page-panels.php | 2 +- .../template-parts/page/content-front-page.php | 2 +- .../template-parts/page/content-page.php | 2 +- tests/phpstan/baseline.php | 18 ------------------ 4 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php b/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php index 923c11f6132a1..f6f009a63a1c6 100644 --- a/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php +++ b/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php @@ -33,7 +33,7 @@
', '' ); ?> - +
diff --git a/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page.php b/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page.php index b80749861e291..0cea464c4c6b9 100644 --- a/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page.php +++ b/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page.php @@ -30,7 +30,7 @@
', '' ); ?> - +
diff --git a/src/wp-content/themes/twentyseventeen/template-parts/page/content-page.php b/src/wp-content/themes/twentyseventeen/template-parts/page/content-page.php index 6e99666e8dbee..f34d5fc829892 100644 --- a/src/wp-content/themes/twentyseventeen/template-parts/page/content-page.php +++ b/src/wp-content/themes/twentyseventeen/template-parts/page/content-page.php @@ -15,7 +15,7 @@
>
', '' ); ?> - +
1, 'path' => __DIR__ . '/../../src/wp-admin/themes.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Function twentyseventeen_edit_link invoked with 1 parameter, 0 required\\.$#', - 'identifier' => 'arguments.count', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Function twentyseventeen_edit_link invoked with 1 parameter, 0 required\\.$#', - 'identifier' => 'arguments.count', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Function twentyseventeen_edit_link invoked with 1 parameter, 0 required\\.$#', - 'identifier' => 'arguments.count', - 'count' => 1, - 'path' => __DIR__ . '/../../src/wp-content/themes/twentyseventeen/template-parts/page/content-page.php', -]; $ignoreErrors[] = [ 'message' => '#^Variable \\$addl_path in empty\\(\\) always exists and is always falsy\\.$#', 'identifier' => 'empty.variable', From a08886787c5a9d7506b422085e462f80bb987e36 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 6 Mar 2026 18:05:42 -0800 Subject: [PATCH 21/24] Remove $comment_id variable.undefined error after r61859 (ce40cd36) --- phpstan.neon.dist | 3 --- 1 file changed, 3 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 8364f71cca9f5..c433a89457cc1 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -102,9 +102,6 @@ parameters: - identifier: variable.undefined message: '#Variable \$comment_closing_at might not be defined\.#' - - - identifier: variable.undefined - message: '#Variable \$comment_id might not be defined\.#' - identifier: variable.undefined message: '#Variable \$comment_ids might not be defined\.#' From 202c39cbb02847eb6264179f1336f5ed0bc2ff32 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 6 Mar 2026 18:13:29 -0800 Subject: [PATCH 22/24] Remove $shape from being a variable.undefined ignored error --- phpstan.neon.dist | 3 --- 1 file changed, 3 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index c433a89457cc1..10864210817df 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -372,9 +372,6 @@ parameters: - identifier: variable.undefined message: '#Variable \$self might not be defined\.#' - - - identifier: variable.undefined - message: '#Variable \$shape might not be defined\.#' - identifier: variable.undefined message: '#Variable \$show_network_active might not be defined\.#' From de684c6ae6c9856de061244c3a9cd5854db5708d Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 6 Mar 2026 19:50:28 -0800 Subject: [PATCH 23/24] Revert "Fix arguments.count issues in Twenty Seventeen where twentyseventeen_edit_link() takes no args" This reverts commit 680d165e5fc662f16ea2530cdf302053119f4c40. --- .../page/content-front-page-panels.php | 2 +- .../template-parts/page/content-front-page.php | 2 +- .../template-parts/page/content-page.php | 2 +- tests/phpstan/baseline.php | 18 ++++++++++++++++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php b/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php index f6f009a63a1c6..923c11f6132a1 100644 --- a/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php +++ b/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php @@ -33,7 +33,7 @@
', '' ); ?> - +
diff --git a/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page.php b/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page.php index 0cea464c4c6b9..b80749861e291 100644 --- a/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page.php +++ b/src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page.php @@ -30,7 +30,7 @@
', '' ); ?> - +
diff --git a/src/wp-content/themes/twentyseventeen/template-parts/page/content-page.php b/src/wp-content/themes/twentyseventeen/template-parts/page/content-page.php index f34d5fc829892..6e99666e8dbee 100644 --- a/src/wp-content/themes/twentyseventeen/template-parts/page/content-page.php +++ b/src/wp-content/themes/twentyseventeen/template-parts/page/content-page.php @@ -15,7 +15,7 @@
>
', '' ); ?> - +
1, 'path' => __DIR__ . '/../../src/wp-admin/themes.php', ]; +$ignoreErrors[] = [ + 'message' => '#^Function twentyseventeen_edit_link invoked with 1 parameter, 0 required\\.$#', + 'identifier' => 'arguments.count', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Function twentyseventeen_edit_link invoked with 1 parameter, 0 required\\.$#', + 'identifier' => 'arguments.count', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Function twentyseventeen_edit_link invoked with 1 parameter, 0 required\\.$#', + 'identifier' => 'arguments.count', + 'count' => 1, + 'path' => __DIR__ . '/../../src/wp-content/themes/twentyseventeen/template-parts/page/content-page.php', +]; $ignoreErrors[] = [ 'message' => '#^Variable \\$addl_path in empty\\(\\) always exists and is always falsy\\.$#', 'identifier' => 'empty.variable', From db38dbfe953c70d5608dd1a037273a86399cb496 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 6 Mar 2026 20:23:19 -0800 Subject: [PATCH 24/24] Initialize $shape variable to suppress variable.undefined error --- src/wp-includes/theme-compat/embed-content.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-includes/theme-compat/embed-content.php b/src/wp-includes/theme-compat/embed-content.php index 42884fec0c5bc..8bf961ba2dace 100644 --- a/src/wp-includes/theme-compat/embed-content.php +++ b/src/wp-includes/theme-compat/embed-content.php @@ -13,6 +13,7 @@
>