From 877b8ce42705e9fbc36c0073cf787bb28f3643f1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 01:30:10 +0000 Subject: [PATCH 1/6] Initial plan From 6058af07292192ba394443dfce9256e272175796 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 01:36:00 +0000 Subject: [PATCH 2/6] Add --actual flag to wp core version command for multisite db version reporting Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- composer.json | 3 +- features/core-version.feature | 70 +++++++++++++++++++++++++++++++ src/Core_Command.php | 79 ++++++++++++++++++++++++++++++++++- 3 files changed, 150 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 6a3fe712b..1734e6077 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,8 @@ "core multisite-install", "core update", "core update-db", - "core version" + "core version", + "core version-actual-db" ] }, "autoload": { diff --git a/features/core-version.feature b/features/core-version.feature index b46b47c30..c69b71b23 100644 --- a/features/core-version.feature +++ b/features/core-version.feature @@ -37,3 +37,73 @@ Feature: Find version for WordPress install TinyMCE version: 4.208 (4208-20151113) Package language: de_DE """ + + # This test downgrades to an older WordPress version, but the SQLite plugin requires 6.0+ + @require-mysql + Scenario: Verify actual database version shows correct values + Given a WP install + And I run `wp core download --version=5.4 --force` + And I run `wp option update db_version 45805` + + # Without --actual, should show expected version from version.php + When I run `wp core version --extra` + Then STDOUT should contain: + """ + Database revision: 47018 + """ + + # With --actual, should show actual database version + When I run `wp core version --extra --actual` + Then STDOUT should contain: + """ + Database revision: 45805 + """ + + # This test downgrades to an older WordPress version, but the SQLite plugin requires 6.0+ + @require-mysql + Scenario: Verify actual database version in multisite subsite + Given a WP multisite install + And I run `wp core download --version=5.4 --force` + And I run `wp option update db_version 47018` + And I run `wp site create --slug=subsite --porcelain` + And save STDOUT as {SUBSITE_ID} + And I run `wp option update db_version 45805 --url=example.com/subsite` + + # Main site shows expected version from version.php without --actual + When I run `wp core version --extra` + Then STDOUT should contain: + """ + Database revision: 47018 + """ + + # Main site shows actual database version with --actual + When I run `wp core version --extra --actual` + Then STDOUT should contain: + """ + Database revision: 47018 + """ + + # Subsite shows expected version from version.php without --actual + When I run `wp core version --extra --url=example.com/subsite` + Then STDOUT should contain: + """ + Database revision: 47018 + """ + + # Subsite shows its own actual database version with --actual + When I run `wp core version --extra --actual --url=example.com/subsite` + Then STDOUT should contain: + """ + Database revision: 45805 + """ + + Scenario: Error when using --actual without --extra + Given a WP install + + When I try `wp core version --actual` + Then STDERR should contain: + """ + Error: The --actual flag can only be used with --extra. + """ + And the return code should be 1 + diff --git a/src/Core_Command.php b/src/Core_Command.php index 18d340f9a..1f7120b01 100644 --- a/src/Core_Command.php +++ b/src/Core_Command.php @@ -903,6 +903,9 @@ private static function get_clean_basedomain() { * [--extra] * : Show extended version information. * + * [--actual] + * : Show the actual database version from the database. This requires WordPress to be loaded and only works with --extra flag. Useful for checking the database version of a specific site in a multisite installation using --url. + * * ## EXAMPLES * * # Display the WordPress version @@ -916,12 +919,50 @@ private static function get_clean_basedomain() { * TinyMCE version: 4.310 (4310-20160418) * Package language: en_US * + * # Display actual database version for a multisite subsite + * $ wp core version --extra --actual --url=example.com/subsite + * WordPress version: 4.5.2 + * Database revision: 35700 + * TinyMCE version: 4.310 (4310-20160418) + * Package language: en_US + * * @when before_wp_load * * @param string[] $args Positional arguments. Unused. - * @param array{extra?: bool} $assoc_args Associative arguments. + * @param array{extra?: bool, actual?: bool} $assoc_args Associative arguments. */ public function version( $args = [], $assoc_args = [] ) { + $use_actual_db_version = Utils\get_flag_value( $assoc_args, 'actual' ); + + // If --actual flag is used, delegate to a command that runs after WP load + if ( $use_actual_db_version ) { + if ( ! Utils\get_flag_value( $assoc_args, 'extra' ) ) { + WP_CLI::error( 'The --actual flag can only be used with --extra.' ); + } + + // Build the command to run after WP load + $cmd_args = []; + foreach ( $assoc_args as $key => $value ) { + if ( 'actual' !== $key ) { + if ( true === $value ) { + $cmd_args[] = "--{$key}"; + } elseif ( is_string( $value ) ) { + $cmd_args[] = "--{$key}=" . escapeshellarg( $value ); + } + } + } + $cmd = 'core version-actual-db ' . implode( ' ', $cmd_args ); + + WP_CLI::runcommand( + $cmd, + [ + 'launch' => true, + 'exit_error' => true, + ] + ); + return; + } + $details = self::get_wp_details(); if ( ! Utils\get_flag_value( $assoc_args, 'extra' ) ) { @@ -948,6 +989,42 @@ public function version( $args = [], $assoc_args = [] ) { ); } + /** + * Helper command to display actual database version (runs after WP load). + * + * This is an internal command called by 'core version --actual'. + * + * @subcommand version-actual-db + * @when after_wp_load + * + * @param string[] $args Positional arguments. Unused. + * @param array{extra?: bool} $assoc_args Associative arguments. + */ + public function version_actual_db( $args = [], $assoc_args = [] ) { + $details = self::get_wp_details(); + + // Get the actual database version from the options table + $actual_db_version = get_option( 'db_version' ); + + $match = []; + $found_version = preg_match( '/(\d)(\d+)-/', $details['tinymce_version'], $match ); + $human_readable_tiny_mce = $found_version ? "{$match[1]}.{$match[2]}" : ''; + + echo Utils\mustache_render( + self::get_template_path( 'versions.mustache' ), + [ + 'wp-version' => $details['wp_version'], + 'db-version' => $actual_db_version, + 'local-package' => empty( $details['wp_local_package'] ) + ? 'en_US' + : $details['wp_local_package'], + 'mce-version' => $human_readable_tiny_mce + ? "{$human_readable_tiny_mce} ({$details['tinymce_version']})" + : $details['tinymce_version'], + ] + ); + } + /** * Gets version information from `wp-includes/version.php`. * From 0d519df51d8fb8bf4d333cd05ef0c0f487dac3e8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 01:38:28 +0000 Subject: [PATCH 3/6] Address code review feedback: fix command args escaping and rename subcommand Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- composer.json | 2 +- src/Core_Command.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 1734e6077..926bb85bc 100644 --- a/composer.json +++ b/composer.json @@ -48,7 +48,7 @@ "core update", "core update-db", "core version", - "core version-actual-db" + "core version-db-actual" ] }, "autoload": { diff --git a/src/Core_Command.php b/src/Core_Command.php index 1f7120b01..a40987964 100644 --- a/src/Core_Command.php +++ b/src/Core_Command.php @@ -947,11 +947,11 @@ public function version( $args = [], $assoc_args = [] ) { if ( true === $value ) { $cmd_args[] = "--{$key}"; } elseif ( is_string( $value ) ) { - $cmd_args[] = "--{$key}=" . escapeshellarg( $value ); + $cmd_args[] = "--{$key}={$value}"; } } } - $cmd = 'core version-actual-db ' . implode( ' ', $cmd_args ); + $cmd = 'core version-db-actual ' . implode( ' ', $cmd_args ); WP_CLI::runcommand( $cmd, @@ -994,13 +994,13 @@ public function version( $args = [], $assoc_args = [] ) { * * This is an internal command called by 'core version --actual'. * - * @subcommand version-actual-db + * @subcommand version-db-actual * @when after_wp_load * * @param string[] $args Positional arguments. Unused. * @param array{extra?: bool} $assoc_args Associative arguments. */ - public function version_actual_db( $args = [], $assoc_args = [] ) { + public function version_db_actual( $args = [], $assoc_args = [] ) { $details = self::get_wp_details(); // Get the actual database version from the options table From 2e0553190b1f43f32c5d48cbda94723829f3d8ca Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 01:40:05 +0000 Subject: [PATCH 4/6] Refactor: extract TinyMCE version formatting and improve PHPDoc Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- src/Core_Command.php | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/Core_Command.php b/src/Core_Command.php index a40987964..caf9d27b2 100644 --- a/src/Core_Command.php +++ b/src/Core_Command.php @@ -970,10 +970,6 @@ public function version( $args = [], $assoc_args = [] ) { return; } - $match = []; - $found_version = preg_match( '/(\d)(\d+)-/', $details['tinymce_version'], $match ); - $human_readable_tiny_mce = $found_version ? "{$match[1]}.{$match[2]}" : ''; - echo Utils\mustache_render( self::get_template_path( 'versions.mustache' ), [ @@ -982,9 +978,7 @@ public function version( $args = [], $assoc_args = [] ) { 'local-package' => empty( $details['wp_local_package'] ) ? 'en_US' : $details['wp_local_package'], - 'mce-version' => $human_readable_tiny_mce - ? "{$human_readable_tiny_mce} ({$details['tinymce_version']})" - : $details['tinymce_version'], + 'mce-version' => self::format_tinymce_version( $details['tinymce_version'] ), ] ); } @@ -998,7 +992,7 @@ public function version( $args = [], $assoc_args = [] ) { * @when after_wp_load * * @param string[] $args Positional arguments. Unused. - * @param array{extra?: bool} $assoc_args Associative arguments. + * @param array $assoc_args Associative arguments passed through from version command. */ public function version_db_actual( $args = [], $assoc_args = [] ) { $details = self::get_wp_details(); @@ -1006,10 +1000,6 @@ public function version_db_actual( $args = [], $assoc_args = [] ) { // Get the actual database version from the options table $actual_db_version = get_option( 'db_version' ); - $match = []; - $found_version = preg_match( '/(\d)(\d+)-/', $details['tinymce_version'], $match ); - $human_readable_tiny_mce = $found_version ? "{$match[1]}.{$match[2]}" : ''; - echo Utils\mustache_render( self::get_template_path( 'versions.mustache' ), [ @@ -1018,13 +1008,29 @@ public function version_db_actual( $args = [], $assoc_args = [] ) { 'local-package' => empty( $details['wp_local_package'] ) ? 'en_US' : $details['wp_local_package'], - 'mce-version' => $human_readable_tiny_mce - ? "{$human_readable_tiny_mce} ({$details['tinymce_version']})" - : $details['tinymce_version'], + 'mce-version' => self::format_tinymce_version( $details['tinymce_version'] ), ] ); } + /** + * Formats the TinyMCE version for display. + * + * @param string $tinymce_version The TinyMCE version string. + * @return string Formatted TinyMCE version. + */ + private static function format_tinymce_version( $tinymce_version ) { + $match = []; + $found_version = preg_match( '/(\d)(\d+)-/', $tinymce_version, $match ); + $human_readable_tiny_mce = $found_version ? "{$match[1]}.{$match[2]}" : ''; + + if ( $human_readable_tiny_mce ) { + return "{$human_readable_tiny_mce} ({$tinymce_version})"; + } + + return $tinymce_version; + } + /** * Gets version information from `wp-includes/version.php`. * From eb2b614e09589b8fe9851a1c675ae358cb99b60b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 01:42:20 +0000 Subject: [PATCH 5/6] Security: properly escape command arguments and improve PHPDoc type Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- src/Core_Command.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Core_Command.php b/src/Core_Command.php index caf9d27b2..89468996b 100644 --- a/src/Core_Command.php +++ b/src/Core_Command.php @@ -945,9 +945,10 @@ public function version( $args = [], $assoc_args = [] ) { foreach ( $assoc_args as $key => $value ) { if ( 'actual' !== $key ) { if ( true === $value ) { - $cmd_args[] = "--{$key}"; + $cmd_args[] = '--' . $key; } elseif ( is_string( $value ) ) { - $cmd_args[] = "--{$key}={$value}"; + // Escape the value to prevent command injection + $cmd_args[] = '--' . $key . '=' . escapeshellarg( $value ); } } } @@ -992,7 +993,7 @@ public function version( $args = [], $assoc_args = [] ) { * @when after_wp_load * * @param string[] $args Positional arguments. Unused. - * @param array $assoc_args Associative arguments passed through from version command. + * @param array{extra?: bool} $assoc_args Associative arguments passed through from version command. */ public function version_db_actual( $args = [], $assoc_args = [] ) { $details = self::get_wp_details(); From 3e67d565ec81dcd08a5262b30a1a14b976fcf69d Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Mon, 2 Feb 2026 20:45:46 -0500 Subject: [PATCH 6/6] Apply suggestions from code review --- features/core-version.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/core-version.feature b/features/core-version.feature index c69b71b23..ec9838926 100644 --- a/features/core-version.feature +++ b/features/core-version.feature @@ -42,7 +42,7 @@ Feature: Find version for WordPress install @require-mysql Scenario: Verify actual database version shows correct values Given a WP install - And I run `wp core download --version=5.4 --force` + And I run `wp core download --version=6.6 --force` And I run `wp option update db_version 45805` # Without --actual, should show expected version from version.php @@ -63,7 +63,7 @@ Feature: Find version for WordPress install @require-mysql Scenario: Verify actual database version in multisite subsite Given a WP multisite install - And I run `wp core download --version=5.4 --force` + And I run `wp core download --version=6.6 --force` And I run `wp option update db_version 47018` And I run `wp site create --slug=subsite --porcelain` And save STDOUT as {SUBSITE_ID}