diff --git a/includes/CLI/Plugin_Check_Command.php b/includes/CLI/Plugin_Check_Command.php index 05f93faad..255af27c3 100644 --- a/includes/CLI/Plugin_Check_Command.php +++ b/includes/CLI/Plugin_Check_Command.php @@ -13,8 +13,6 @@ use WordPress\Plugin_Check\Checker\Check_Repository; use WordPress\Plugin_Check\Checker\CLI_Runner; use WordPress\Plugin_Check\Checker\Default_Check_Repository; -use WordPress\Plugin_Check\Checker\Runtime_Check; -use WordPress\Plugin_Check\Checker\Runtime_Environment_Setup; use WordPress\Plugin_Check\Plugin_Context; use WordPress\Plugin_Check\Utilities\Plugin_Request_Utility; use WP_CLI; @@ -192,25 +190,16 @@ static function ( $dirs ) use ( $excluded_files ) { ); } - $checks_to_run = array(); try { $runner->set_experimental_flag( $options['include-experimental'] ); $runner->set_check_slugs( $checks ); $runner->set_plugin( $plugin ); $runner->set_categories( $categories ); $runner->set_slug( $options['slug'] ); - - $checks_to_run = $runner->get_checks_to_run(); } catch ( Exception $error ) { WP_CLI::error( $error->getMessage() ); } - if ( $this->has_runtime_check( $checks_to_run ) ) { - WP_CLI::line( __( 'Setting up runtime environment.', 'plugin-check' ) ); - $runtime_setup = new Runtime_Environment_Setup(); - $runtime_setup->set_up(); - } - $result = false; // Run checks against the plugin. try { @@ -218,21 +207,11 @@ static function ( $dirs ) use ( $excluded_files ) { } catch ( Exception $error ) { Plugin_Request_Utility::destroy_runner(); - if ( isset( $runtime_setup ) ) { - $runtime_setup->clean_up(); - WP_CLI::line( __( 'Cleaning up runtime environment.', 'plugin-check' ) ); - } - WP_CLI::error( $error->getMessage() ); } Plugin_Request_Utility::destroy_runner(); - if ( isset( $runtime_setup ) ) { - $runtime_setup->clean_up(); - WP_CLI::line( __( 'Cleaning up runtime environment.', 'plugin-check' ) ); - } - // Get errors and warnings from the results. $errors = array(); if ( $result && empty( $assoc_args['ignore-errors'] ) ) { @@ -642,24 +621,6 @@ private function display_results( $formatter, $file_name, $file_results ) { WP_CLI::line(); } - /** - * Checks for a Runtime_Check in a list of checks. - * - * @since 1.0.0 - * - * @param array $checks An array of Check instances. - * @return bool True if a Runtime_Check exists in the array, false if not. - */ - private function has_runtime_check( array $checks ) { - foreach ( $checks as $check ) { - if ( $check instanceof Runtime_Check ) { - return true; - } - } - - return false; - } - /** * Returns check results filtered by severity level. * diff --git a/includes/Checker/Abstract_Check_Runner.php b/includes/Checker/Abstract_Check_Runner.php index 368418da3..001f1b3f5 100644 --- a/includes/Checker/Abstract_Check_Runner.php +++ b/includes/Checker/Abstract_Check_Runner.php @@ -310,8 +310,6 @@ final public function set_categories( $categories ) { * @throws Exception Thrown exception when preparation fails. */ final public function prepare() { - $cleanup_functions = array(); - if ( $this->initialized_early ) { /* * When initialized early, plugins are not loaded yet when this method is called. @@ -334,9 +332,9 @@ final public function prepare() { $initialize_runtime = $this->has_runtime_check( $this->get_checks_to_run() ); } + $cleanup_functions = array(); if ( $initialize_runtime ) { - $preparation = new Universal_Runtime_Preparation( $this->get_check_context() ); - $cleanup_functions[] = $preparation->prepare(); + $cleanup_functions = $this->initialize_runtime(); } if ( $this->delete_plugin_folder ) { @@ -489,6 +487,18 @@ final public function get_checks_to_run() { return $collection->to_map(); } + /** + * Initializes the runtime environment so that runtime checks can be run against a separate set of database tables. + * + * @since 1.3.0 + * + * @return callable[] Array of cleanup functions to run after the process has completed. + */ + protected function initialize_runtime(): array { + $preparation = new Universal_Runtime_Preparation( $this->get_check_context() ); + return array( $preparation->prepare() ); + } + /** * Checks whether the current environment allows for runtime checks to be used. * diff --git a/includes/Checker/CLI_Runner.php b/includes/Checker/CLI_Runner.php index 53ba12224..7b92dcf9f 100644 --- a/includes/Checker/CLI_Runner.php +++ b/includes/Checker/CLI_Runner.php @@ -178,6 +178,31 @@ protected function get_slug_param() { return $slug; } + /** + * Initializes the runtime environment so that runtime checks can be run against a separate set of database tables. + * + * @since 1.3.0 + * + * @return callable[] Array of cleanup functions to run after the process has completed. + */ + protected function initialize_runtime(): array { + /* + * Since for WP-CLI all checks are run in a single process, we should set up the runtime environment (i.e. + * install the separate database tables) as part of this step. + * This way it runs before the regular runtime preparations, just like it does for the AJAX based flow, where + * they are invoked in a separate request prior to the requests performing actual checks. + */ + $runtime_setup = new Runtime_Environment_Setup(); + $runtime_setup->set_up(); + + $cleanup_functions = parent::initialize_runtime(); + $cleanup_functions[] = function () use ( $runtime_setup ) { + $runtime_setup->clean_up(); + }; + + return $cleanup_functions; + } + /** * Checks whether the current environment allows for runtime checks to be used. * diff --git a/includes/Checker/Runtime_Environment_Setup.php b/includes/Checker/Runtime_Environment_Setup.php index bd84b784c..40c14dd95 100644 --- a/includes/Checker/Runtime_Environment_Setup.php +++ b/includes/Checker/Runtime_Environment_Setup.php @@ -28,9 +28,15 @@ public function set_up() { require_once ABSPATH . '/wp-admin/includes/upgrade.php'; + // Get the existing site URL. + $site_url = get_option( 'siteurl' ); + // Get the existing active plugins. $active_plugins = get_option( 'active_plugins' ); + // Get the existing active theme. + $active_theme = get_option( 'stylesheet' ); + // Get the existing permalink structure. $permalink_structure = get_option( 'permalink_structure' ); @@ -48,29 +54,25 @@ public function set_up() { add_action( 'populate_options', static function () use ( $permalink_structure ) { + /* + * If pretty permalinks are not used, temporarily enable them by setting a permalink structure, to + * avoid flushing rewrite rules in wp_install_maybe_enable_pretty_permalinks(). + * Afterwards, on the 'wp_install' action, set the original (empty) permalink structure. + */ + if ( ! $permalink_structure ) { + add_action( + 'wp_install', + static function () use ( $permalink_structure ) { + update_option( 'permalink_structure', $permalink_structure ); + } + ); + $permalink_structure = '/%postname%/'; + } add_option( 'permalink_structure', $permalink_structure ); } ); - if ( ! isset( $_SERVER['HTTP_HOST'] ) ) { - $site_url = get_option( 'siteurl' ); - $_SERVER['HTTP_HOST'] = preg_replace( '#^https?://#', '', rtrim( $site_url, '/' ) ); - } - - // Do not send post-install notification email, see https://github.com/WordPress/plugin-check/issues/424. - add_filter( 'pre_wp_mail', '__return_false' ); - - wp_install( - 'Plugin Check', - 'plugincheck', - 'demo@plugincheck.test', - false - ); - - remove_filter( 'pre_wp_mail', '__return_false' ); - - // Activate the same plugins in the test environment. - update_option( 'active_plugins', $active_plugins ); + $this->install_wordpress( $site_url, $active_theme, $active_plugins ); } // Restore the old prefix. @@ -186,4 +188,57 @@ public function can_set_up() { return false; } + + /** + * Installs WordPress, while providing tweaks to allow for early execution of the install process. + * + * @since 1.3.0 + * + * @param string $active_siteurl The actual site's site URL. + * @param string $active_theme The actual site's theme slug. + * @param string[] $active_plugins The actual site's list of plugin basenames. + */ + private function install_wordpress( string $active_siteurl, string $active_theme, array $active_plugins ): void { + if ( ! isset( $_SERVER['HTTP_HOST'] ) ) { + $site_url = $active_siteurl; + $_SERVER['HTTP_HOST'] = preg_replace( '#^https?://#', '', rtrim( $site_url, '/' ) ); + } + + // Do not send post-install notification email, see https://github.com/WordPress/plugin-check/issues/424. + add_filter( 'pre_wp_mail', '__return_false' ); + + // The `wp_install()` function requires the WP_DEFAULT_THEME constant to be set. + if ( ! defined( 'WP_DEFAULT_THEME' ) ) { + define( 'WP_DEFAULT_THEME', $active_theme ); + } + + // The `wp_install()` function requires some pluggable functions like `get_user_by()` to be loaded. + if ( ! function_exists( 'get_user_by' ) ) { + require_once ABSPATH . '/wp-includes/pluggable.php'; + } + + /* + * Cookie constants need to be set before installation, which normally happens immediately after + * 'muplugins_loaded', which is when the logic here typically runs. It is therefore safe to call these + * functions here already. + */ + if ( doing_action( 'muplugins_loaded' ) || ! did_action( 'muplugins_loaded' ) ) { + if ( is_multisite() ) { + ms_cookie_constants(); + } + wp_cookie_constants(); + } + + wp_install( + 'Plugin Check', + 'plugincheck', + 'demo@plugincheck.test', + false + ); + + remove_filter( 'pre_wp_mail', '__return_false' ); + + // Activate the same plugins in the test environment. + update_option( 'active_plugins', $active_plugins ); + } } diff --git a/tests/behat/features/plugin-check.feature b/tests/behat/features/plugin-check.feature index f7bca75a5..287c14a51 100644 --- a/tests/behat/features/plugin-check.feature +++ b/tests/behat/features/plugin-check.feature @@ -548,14 +548,6 @@ Feature: Test that the WP-CLI command works. # Running runtime checks, including the one from pcp-addon When I run the WP-CLI command `plugin check foo-sample --fields=code,type --format=csv --require=./wp-content/plugins/plugin-check/cli.php` Then STDOUT should contain: - """ - Setting up runtime environment. - """ - And STDOUT should contain: - """ - Cleaning up runtime environment. - """ - And STDOUT should contain: """ WordPress.WP.EnqueuedResourceParameters.NotInFooter,WARNING """ @@ -568,14 +560,6 @@ Feature: Test that the WP-CLI command works. # Same again, to verify object-cache.php was properly cleared again When I run the WP-CLI command `plugin check foo-sample --fields=code,type --format=csv --require=./wp-content/plugins/plugin-check/cli.php` Then STDOUT should contain: - """ - Setting up runtime environment. - """ - And STDOUT should contain: - """ - Cleaning up runtime environment. - """ - And STDOUT should contain: """ WordPress.WP.EnqueuedResourceParameters.NotInFooter,WARNING """