diff --git a/features/plugin-list-wporg-status.feature b/features/plugin-list-wporg-status.feature index 13e71122..1da8360f 100644 --- a/features/plugin-list-wporg-status.feature +++ b/features/plugin-list-wporg-status.feature @@ -110,3 +110,50 @@ Feature: Check the status of plugins on WordPress.org | wordpress-importer | active | 2025-09-26 | | no-longer-in-directory | closed | 2017-11-13 | | never-wporg | | | + + @less-than-wp-5.3 + Scenario: The wp.org last updated date is still rendered on WordPress < 5.3 + Given a WP install + And I run `wp option update timezone_string Asia/Tokyo` + And a wp-content/plugins/wporg-dated/wporg-dated.php file: + """ + + + + + Fri, 26 Sep 2025 21:07:26 GMT + + + + """ + + # wp_date() only exists since WordPress 5.3, so this goes through the + # get_date_from_gmt() fallback. The pubDate above is 21:07 UTC, which is already + # the next day in Asia/Tokyo, so this also pins that the fallback renders in the + # site timezone rather than in UTC. + When I run `wp plugin list --fields=name,wporg_last_updated` + Then STDOUT should be a table containing rows: + | name | wporg_last_updated | + | wporg-dated | 2025-09-27 | diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 3b8aeab5..b383c386 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -14,3 +14,27 @@ parameters: - identifier: missingType.property - identifier: missingType.parameter - identifier: missingType.return + + # johnbillion/wp-compat checks every WordPress symbol against the WordPress 4.9 + # baseline that wp-cli-tests configures. It only recognizes function_exists() and + # method_exists() guards, so it cannot see the `wp_version_compare()` checks that + # gate the plugin dependency features, and reports those as errors. + # + # The entries below match on the message as well as the identifier, so that a call to + # something introduced later than the version each feature is gated on still gets + # reported rather than swallowed by a file-wide ignore. + + # `wp plugin install --with-dependencies` aborts on WordPress < 6.5 in + # `Plugin_Command::install()`, before reaching `get_plugin_dependencies()`, and + # `wp plugin install-dependencies` does the same check in the command method itself. + - + identifier: WPCompat.methodNotAvailable + message: '#^WP_Plugin_Dependencies::(get_dependencies|initialize)\(\) is only available since WordPress version 6\.5\.0\.$#' + path: src/Plugin_Command.php + + # WordPress 5.3 only formalized the already documented `...$arg` parameter of + # `do_action()` by adding it to the function signature. Additional arguments were + # collected through `func_get_args()` before that. + - + identifier: WPCompat.parameterNotAvailable.doaction.arg + path: src/Plugin_Command.php diff --git a/src/Plugin_Command.php b/src/Plugin_Command.php index e76b89b3..9624d340 100644 --- a/src/Plugin_Command.php +++ b/src/Plugin_Command.php @@ -1122,7 +1122,19 @@ protected function get_wporg_data( $plugin_name ) { if ( false !== $xml ) { $xml_pub_date = $xml->xpath( '//pubDate' ); if ( $xml_pub_date ) { - $data['last_updated'] = wp_date( 'Y-m-d', strtotime( $xml_pub_date[0] ) ?: null ); + $pub_date = strtotime( $xml_pub_date[0] ) ?: null; + + if ( function_exists( 'wp_date' ) ) { + $data['last_updated'] = wp_date( 'Y-m-d', $pub_date ); + } else { + // wp_date() is WordPress 5.3+. get_date_from_gmt() renders in the site + // timezone the same way, without date_i18n()'s pre-5.3 contract of + // expecting a timestamp that already has the offset added to it. + $data['last_updated'] = get_date_from_gmt( + gmdate( 'Y-m-d H:i:s', $pub_date ?? time() ), + 'Y-m-d' + ); + } } } }