From d655100b805e5d0603c90f9ede4f66f2309d39bb Mon Sep 17 00:00:00 2001 From: Dimitrios Pantazis Date: Sun, 16 Aug 2026 10:04:30 -0700 Subject: [PATCH 1/6] feat: removes 4 phpstan baseline files and fixes their errors More specifically removes baselines deadCode.unreachable.neon, if.alwaysTrue.neon, while.alwaysFalse.neon and while.alwaysTrue.neon --- phpstan.neon.dist | 2 - .../themes/twentyfourteen/inc/widgets.php | 2 +- src/wp-includes/class-wp-query.php | 4 + src/wp-includes/query.php | 4 + .../baselines/deadCode.unreachable.neon | 230 -------------- tests/phpstan/baselines/if.alwaysTrue.neon | 5 - .../phpstan/baselines/while.alwaysFalse.neon | 25 -- tests/phpstan/baselines/while.alwaysTrue.neon | 300 ------------------ 8 files changed, 9 insertions(+), 563 deletions(-) delete mode 100644 tests/phpstan/baselines/while.alwaysFalse.neon delete mode 100644 tests/phpstan/baselines/while.alwaysTrue.neon diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 248623a5c01d6..f39d7c25a3455 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -87,8 +87,6 @@ includes: - tests/phpstan/baselines/ternary.alwaysTrue.neon - tests/phpstan/baselines/varTag.noVariable.neon - tests/phpstan/baselines/variable.undefined.neon - - tests/phpstan/baselines/while.alwaysFalse.neon - - tests/phpstan/baselines/while.alwaysTrue.neon # phpstan:baselines end parameters: diff --git a/src/wp-content/themes/twentyfourteen/inc/widgets.php b/src/wp-content/themes/twentyfourteen/inc/widgets.php index 36846daa84860..7ee2991d91b37 100644 --- a/src/wp-content/themes/twentyfourteen/inc/widgets.php +++ b/src/wp-content/themes/twentyfourteen/inc/widgets.php @@ -137,6 +137,7 @@ public function widget( $args, $instance ) { if ( $ephemera->have_posts() ) : $tmp_content_width = $GLOBALS['content_width']; $GLOBALS['content_width'] = 306; + $tmp_more = $GLOBALS['more']; echo $args['before_widget']; ?> @@ -148,7 +149,6 @@ public function widget( $args, $instance ) { have_posts() ) : $ephemera->the_post(); - $tmp_more = $GLOBALS['more']; $GLOBALS['more'] = 0; ?>
  • diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index 228691d26d12b..906cca0905e1a 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -3839,6 +3839,8 @@ function ( $carry, $post ) { * * @since 1.5.0 * + * @phpstan-impure + * * @return bool True if posts are available, false if end of the loop. */ public function have_posts() { @@ -3929,6 +3931,8 @@ public function the_comment() { * * @since 2.2.0 * + * @phpstan-impure + * * @return bool True if comments are available, false if no more comments. */ public function have_comments() { diff --git a/src/wp-includes/query.php b/src/wp-includes/query.php index 60571c01cb880..42592002c1cab 100644 --- a/src/wp-includes/query.php +++ b/src/wp-includes/query.php @@ -956,6 +956,8 @@ function is_main_query() { * * @global WP_Query $wp_query WordPress Query object. * + * @phpstan-impure + * * @return bool True if posts are available, false if end of the loop. */ function have_posts() { @@ -1036,6 +1038,8 @@ function the_post() { * * @global WP_Query $wp_query WordPress Query object. * + * @phpstan-impure + * * @return bool True if comments are available, false if no more comments. */ function have_comments() { diff --git a/tests/phpstan/baselines/deadCode.unreachable.neon b/tests/phpstan/baselines/deadCode.unreachable.neon index 0bd31fe524a9a..8a4288bc40c43 100644 --- a/tests/phpstan/baselines/deadCode.unreachable.neon +++ b/tests/phpstan/baselines/deadCode.unreachable.neon @@ -38,241 +38,11 @@ parameters: identifier: deadCode.unreachable count: 1 path: ../../../src/wp-admin/includes/class-wp-internal-pointers.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 2 - path: ../../../src/wp-admin/includes/dashboard.php - message: '#^Unreachable statement \- code above always terminates\.$#' identifier: deadCode.unreachable count: 2 path: ../../../src/wp-admin/post.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/archive.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/author.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/category.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/inc/widgets.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/index.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/search.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/showcase.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/tag.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyfifteen/archive.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyfifteen/index.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyfifteen/search.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/archive.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/author.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/category.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/inc/widgets.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/index.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/search.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/tag.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/taxonomy-post_format.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentynineteen/archive.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentynineteen/index.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentynineteen/search.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyseventeen/archive.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyseventeen/index.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyseventeen/search.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentysixteen/archive.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentysixteen/index.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentysixteen/search.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentythirteen/archive.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentythirteen/author.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentythirteen/category.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentythirteen/index.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentythirteen/search.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentythirteen/tag.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentythirteen/taxonomy-post_format.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentytwelve/archive.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentytwelve/author.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentytwelve/category.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentytwelve/index.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentytwelve/search.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentytwelve/tag.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentytwentyone/archive.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentytwentyone/index.php - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: ../../../src/wp-content/themes/twentytwentyone/search.php - message: '#^Unreachable statement \- code above always terminates\.$#' identifier: deadCode.unreachable diff --git a/tests/phpstan/baselines/if.alwaysTrue.neon b/tests/phpstan/baselines/if.alwaysTrue.neon index f049efde2d19d..6888b9780b5f9 100644 --- a/tests/phpstan/baselines/if.alwaysTrue.neon +++ b/tests/phpstan/baselines/if.alwaysTrue.neon @@ -28,11 +28,6 @@ parameters: identifier: if.alwaysTrue count: 2 path: ../../../src/wp-admin/upload.php - - - message: '#^If condition is always true\.$#' - identifier: if.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentynineteen/comments.php - message: '#^If condition is always true\.$#' identifier: if.alwaysTrue diff --git a/tests/phpstan/baselines/while.alwaysFalse.neon b/tests/phpstan/baselines/while.alwaysFalse.neon deleted file mode 100644 index 3c924003ea783..0000000000000 --- a/tests/phpstan/baselines/while.alwaysFalse.neon +++ /dev/null @@ -1,25 +0,0 @@ -# PHPStan baseline for the `while.alwaysFalse` errors in WordPress core. -# -# https://phpstan.org/error-identifiers/while.alwaysFalse -# -# Each entry is scoped to a single file and carries an exact occurrence count, -# so that a new instance is reported as a new error rather than being absorbed -# silently. Fixing an occurrence therefore means decrementing or removing its -# entry here as part of the same change. -# -# The goal is to empty this file and delete it, along with the `includes` entry -# for it in phpstan.neon.dist. -# -# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with -# -# composer phpstan:baselines -- --identifier=while.alwaysFalse -# -# which reruns the analysis with this file suppressed so the errors surface again. - -parameters: - ignoreErrors: - - - message: '#^While loop condition is always false\.$#' - identifier: while.alwaysFalse - count: 1 - path: ../../../src/wp-includes/feed-rdf.php diff --git a/tests/phpstan/baselines/while.alwaysTrue.neon b/tests/phpstan/baselines/while.alwaysTrue.neon deleted file mode 100644 index 5da6550e89cc0..0000000000000 --- a/tests/phpstan/baselines/while.alwaysTrue.neon +++ /dev/null @@ -1,300 +0,0 @@ -# PHPStan baseline for the `while.alwaysTrue` errors in WordPress core. -# -# https://phpstan.org/error-identifiers/while.alwaysTrue -# -# Each entry is scoped to a single file and carries an exact occurrence count, -# so that a new instance is reported as a new error rather than being absorbed -# silently. Fixing an occurrence therefore means decrementing or removing its -# entry here as part of the same change. -# -# The goal is to empty this file and delete it, along with the `includes` entry -# for it in phpstan.neon.dist. -# -# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with -# -# composer phpstan:baselines -- --identifier=while.alwaysTrue -# -# which reruns the analysis with this file suppressed so the errors surface again. - -parameters: - ignoreErrors: - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-admin/includes/dashboard.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-admin/includes/nav-menu.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/archive.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/author.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/category.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/inc/widgets.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/index.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/search.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/showcase.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/tag.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyfifteen/archive.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyfifteen/index.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyfifteen/search.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/archive.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/author.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/category.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/inc/widgets.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/index.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/search.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/tag.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/taxonomy-post_format.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentynineteen/archive.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentynineteen/index.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentynineteen/search.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyseventeen/archive.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyseventeen/front-page.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyseventeen/index.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyseventeen/search.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentysixteen/archive.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentysixteen/index.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentysixteen/search.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyten/loop-attachment.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyten/loop-page.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentyten/loop-single.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentythirteen/archive.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentythirteen/author.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentythirteen/category.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentythirteen/index.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentythirteen/search.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentythirteen/tag.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentythirteen/taxonomy-post_format.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentytwelve/archive.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentytwelve/author.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentytwelve/category.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentytwelve/index.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentytwelve/search.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentytwelve/tag.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentytwenty/index.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentytwenty/singular.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentytwenty/templates/template-cover.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentytwentyone/archive.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentytwentyone/index.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-content/themes/twentytwentyone/search.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-includes/block-template.php - - - message: '#^While loop condition is always true\.$#' - identifier: while.alwaysTrue - count: 1 - path: ../../../src/wp-includes/theme-compat/embed.php From 8d023724bdba769142f5d62ccf32f0d289edf5d5 Mon Sep 17 00:00:00 2001 From: Dimitrios Pantazis Date: Sun, 16 Aug 2026 11:04:35 -0700 Subject: [PATCH 2/6] tests: coverage for GLOBALS['more'] restoration after while loop --- .../theme/twentyFourteenEphemeraWidget.php | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php diff --git a/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php b/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php new file mode 100644 index 0000000000000..fc0622df3682c --- /dev/null +++ b/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php @@ -0,0 +1,50 @@ +markTestSkipped( 'The Twenty Fourteen theme is not installed.' ); + } + require_once $widgets; + } + + /** + * The widget must restore the original `$more` global, not the zeroed value + * it sets for each post it renders. + */ + public function test_widget_restores_more_global() { + // More than one post, so a stale `$more` from a previous iteration would be restored. + foreach ( self::factory()->post->create_many( 2 ) as $post_id ) { + set_post_format( $post_id, 'aside' ); + } + + $GLOBALS['more'] = 1; + $GLOBALS['content_width'] = 474; + + $widget = new Twenty_Fourteen_Ephemera_Widget(); + + ob_start(); + $widget->widget( + array( + 'before_widget' => '', + 'after_widget' => '', + ), + array( 'format' => 'aside' ) + ); + $output = ob_get_clean(); + + $this->assertNotEmpty( $output, 'The widget rendered nothing, so nothing was restored.' ); + $this->assertSame( 1, $GLOBALS['more'], 'The $more global was not restored to its original value.' ); + $this->assertSame( 474, $GLOBALS['content_width'], 'The $content_width global was not restored to its original value.' ); + } +} From c00715a89bd7ffc79f432437e60548b8a46032d8 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 26 Aug 2026 18:20:13 -0700 Subject: [PATCH 3/6] Address PHPStan errors in test --- tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php b/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php index fc0622df3682c..22d79b5a476af 100644 --- a/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php +++ b/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php @@ -25,6 +25,7 @@ public function set_up() { public function test_widget_restores_more_global() { // More than one post, so a stale `$more` from a previous iteration would be restored. foreach ( self::factory()->post->create_many( 2 ) as $post_id ) { + $this->assertIsInt( $post_id ); set_post_format( $post_id, 'aside' ); } @@ -44,7 +45,7 @@ public function test_widget_restores_more_global() { $output = ob_get_clean(); $this->assertNotEmpty( $output, 'The widget rendered nothing, so nothing was restored.' ); - $this->assertSame( 1, $GLOBALS['more'], 'The $more global was not restored to its original value.' ); + $this->assertSame( 1, $GLOBALS['more'], 'The $more global was not restored to its original value.' ); // @phpstan-ignore method.alreadyNarrowedType (The global variable is modified by Twenty_Fourteen_Ephemera_Widget::widget().) $this->assertSame( 474, $GLOBALS['content_width'], 'The $content_width global was not restored to its original value.' ); } } From cb1575a4ad54d2a9120181c13bd9556218486d04 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 26 Aug 2026 20:06:30 -0700 Subject: [PATCH 4/6] Assert the Twenty Fourteen ephemera widget renders teasers Give the test post content with a `` tag and count the resulting `more-link` anchors, so the test covers what the widget actually renders and not just the globals it leaves behind. Switch the manual output buffering to `get_echo()`, and correct the docblock: the `$more` global is zeroed by `WP_Query::setup_postdata()` on every `the_post()` call in the widget's secondary loop, not by the widget itself. A single post is enough. The widget saves `$more` before the loop rather than inside it, so a second post adds nothing to the restore assertion. Co-Authored-By: Claude Opus 5 (1M context) --- .../theme/twentyFourteenEphemeraWidget.php | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php b/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php index 22d79b5a476af..4d9ebf26ea9fb 100644 --- a/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php +++ b/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php @@ -19,32 +19,42 @@ public function set_up() { } /** - * The widget must restore the original `$more` global, not the zeroed value - * it sets for each post it renders. + * The widget must restore the original `$more` global, which `WP_Query::setup_postdata()` + * zeroes out for each post the widget's secondary loop renders. */ public function test_widget_restores_more_global() { - // More than one post, so a stale `$more` from a previous iteration would be restored. - foreach ( self::factory()->post->create_many( 2 ) as $post_id ) { - $this->assertIsInt( $post_id ); - set_post_format( $post_id, 'aside' ); - } + $post_id = self::factory()->post->create( + array( + 'post_content' => 'I want ice cream!', + ) + ); + $this->assertIsInt( $post_id ); + set_post_format( $post_id, 'aside' ); + // Sentinel value for the restore assertion below; it does not affect what the widget renders. $GLOBALS['more'] = 1; $GLOBALS['content_width'] = 474; $widget = new Twenty_Fourteen_Ephemera_Widget(); - ob_start(); - $widget->widget( + $output = get_echo( + array( $widget, 'widget' ), array( - 'before_widget' => '', - 'after_widget' => '', - ), - array( 'format' => 'aside' ) + array( + 'before_widget' => '', + 'after_widget' => '', + ), + array( 'format' => 'aside' ), + ) ); - $output = ob_get_clean(); - $this->assertNotEmpty( $output, 'The widget rendered nothing, so nothing was restored.' ); + $this->assertNotEmpty( $output, 'The widget content.' ); + $processor = new WP_HTML_Tag_Processor( $output ); + $more_link_count = 0; + while ( $processor->next_tag( array( 'class_name' => 'more-link' ) ) ) { + ++$more_link_count; + } + $this->assertSame( 1, $more_link_count, 'Expected there to be one more link.' ); $this->assertSame( 1, $GLOBALS['more'], 'The $more global was not restored to its original value.' ); // @phpstan-ignore method.alreadyNarrowedType (The global variable is modified by Twenty_Fourteen_Ephemera_Widget::widget().) $this->assertSame( 474, $GLOBALS['content_width'], 'The $content_width global was not restored to its original value.' ); } From e00370e508f17715f2ced08eff675d535d5dc29e Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 26 Aug 2026 20:18:07 -0700 Subject: [PATCH 5/6] Guard against an undefined $more global in the ephemera widget Reading `$GLOBALS['more']` before the widget's secondary loop is only safe once some loop has run, since `WP_Query::setup_postdata()` is the only thing that ever defines the global. The widget can render before that happens: on a 404, an empty search, or an empty archive the main loop never calls `the_post()`, and the sidebar then emits a warning even though the widget's own query has posts. The same applies to renders outside the template, such as the widget endpoints and the Customizer preview. Default to null so the save still happens and the later restore stays a plain assignment. Co-Authored-By: Claude Opus 5 (1M context) --- .../themes/twentyfourteen/inc/widgets.php | 3 +- .../theme/twentyFourteenEphemeraWidget.php | 34 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/wp-content/themes/twentyfourteen/inc/widgets.php b/src/wp-content/themes/twentyfourteen/inc/widgets.php index 7ee2991d91b37..b375113b308b5 100644 --- a/src/wp-content/themes/twentyfourteen/inc/widgets.php +++ b/src/wp-content/themes/twentyfourteen/inc/widgets.php @@ -137,7 +137,8 @@ public function widget( $args, $instance ) { if ( $ephemera->have_posts() ) : $tmp_content_width = $GLOBALS['content_width']; $GLOBALS['content_width'] = 306; - $tmp_more = $GLOBALS['more']; + // The global is unset until a loop has run, so this may be reached before it exists. + $tmp_more = $GLOBALS['more'] ?? null; echo $args['before_widget']; ?> diff --git a/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php b/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php index 4d9ebf26ea9fb..55a0e5596dca3 100644 --- a/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php +++ b/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php @@ -58,4 +58,38 @@ public function test_widget_restores_more_global() { $this->assertSame( 1, $GLOBALS['more'], 'The $more global was not restored to its original value.' ); // @phpstan-ignore method.alreadyNarrowedType (The global variable is modified by Twenty_Fourteen_Ephemera_Widget::widget().) $this->assertSame( 474, $GLOBALS['content_width'], 'The $content_width global was not restored to its original value.' ); } + + /** + * The `$more` global is only defined once a loop has run, so the widget must not + * assume it exists. It can render before any loop on a 404, an empty search, or an + * empty archive, as well as outside the template entirely. + */ + public function test_widget_when_more_global_is_undefined() { + $post_id = self::factory()->post->create( + array( + 'post_content' => 'I want ice cream!', + ) + ); + $this->assertIsInt( $post_id ); + set_post_format( $post_id, 'aside' ); + + unset( $GLOBALS['more'] ); + $GLOBALS['content_width'] = 474; + + $widget = new Twenty_Fourteen_Ephemera_Widget(); + + $output = get_echo( + array( $widget, 'widget' ), + array( + array( + 'before_widget' => '', + 'after_widget' => '', + ), + array( 'format' => 'aside' ), + ) + ); + + $this->assertNotEmpty( $output, 'The widget content.' ); + $this->assertNull( $GLOBALS['more'], 'The $more global was not restored to a falsey value.' ); // @phpstan-ignore offsetAccess.notFound (The global variable is set by Twenty_Fourteen_Ephemera_Widget::widget().) + } } From 29b9b3378ac30a57b2fb3abe447a4631c96986f4 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 26 Aug 2026 20:21:13 -0700 Subject: [PATCH 6/6] Restore the globals the ephemera widget tests overwrite The suite runs with `backupGlobals` disabled and nothing else restores `$more` or `$content_width`, so these tests left their values in place for every later test in the process. `tests/phpunit/tests/media.php` reads `$content_width` and only falls back to 640 when it is empty, so the leak can produce order-dependent failures well away from here. Capture both globals in `set_up()` and put them back in `tear_down()`, unsetting those that were not set to begin with. The capture happens before the skip for a missing theme, since that still runs `tear_down()`. Co-Authored-By: Claude Opus 5 (1M context) --- .../theme/twentyFourteenEphemeraWidget.php | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php b/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php index 55a0e5596dca3..c2442ef18ec7e 100644 --- a/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php +++ b/tests/phpunit/tests/theme/twentyFourteenEphemeraWidget.php @@ -8,9 +8,36 @@ */ class Tests_Theme_TwentyFourteenEphemeraWidget extends WP_UnitTestCase { + /** + * The names of the globals these tests overwrite. + * + * @var string[] + */ + private array $global_names = array( 'more', 'content_width' ); + + /** + * The values of those globals before the current test ran, keyed by name. + * + * A name is absent when the global was not set. + * + * @var array + */ + private array $original_globals = array(); + public function set_up() { parent::set_up(); + /* + * `backupGlobals` is disabled for the suite, so these have to be restored by hand + * to keep later tests in the process from inheriting them. Capture them before the + * skip below, which still runs `tear_down()`. + */ + foreach ( $this->global_names as $global_name ) { + if ( array_key_exists( $global_name, $GLOBALS ) ) { + $this->original_globals[ $global_name ] = $GLOBALS[ $global_name ]; + } + } + $widgets = WP_CONTENT_DIR . '/themes/twentyfourteen/inc/widgets.php'; if ( ! file_exists( $widgets ) ) { $this->markTestSkipped( 'The Twenty Fourteen theme is not installed.' ); @@ -18,6 +45,18 @@ public function set_up() { require_once $widgets; } + public function tear_down() { + foreach ( $this->global_names as $global_name ) { + if ( array_key_exists( $global_name, $this->original_globals ) ) { + $GLOBALS[ $global_name ] = $this->original_globals[ $global_name ]; + } else { + unset( $GLOBALS[ $global_name ] ); + } + } + + parent::tear_down(); + } + /** * The widget must restore the original `$more` global, which `WP_Query::setup_postdata()` * zeroes out for each post the widget's secondary loop renders.