From 0b57f1ba38bdc48a6d6363e518bcddbd5d9d63e0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 14:02:25 +0000 Subject: [PATCH 1/6] Initial plan From ea344fbe6bf04f55abbbfe324183f8184a8c840f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 14:05:55 +0000 Subject: [PATCH 2/6] Add --hook parameter to shell command and tests Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- features/shell.feature | 26 ++++++++++++++++++++++++++ src/Shell_Command.php | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/features/shell.feature b/features/shell.feature index d5595506..170d0316 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -77,3 +77,29 @@ Feature: WordPress REPL """ history: -1: invalid option """ + + Scenario: Shell with hook parameter + Given a WP install + And a session file: + """ + did_action('init'); + """ + + When I run `wp shell --basic --hook=init < session` + Then STDOUT should contain: + """ + int(1) + """ + + Scenario: Shell with hook parameter on already-fired hook + Given a WP install + And a session file: + """ + did_action('plugins_loaded'); + """ + + When I run `wp shell --basic --hook=plugins_loaded < session` + Then STDOUT should contain: + """ + int(1) + """ diff --git a/src/Shell_Command.php b/src/Shell_Command.php index edd2c611..526770d7 100644 --- a/src/Shell_Command.php +++ b/src/Shell_Command.php @@ -19,14 +19,55 @@ class Shell_Command extends WP_CLI_Command { * : Force the use of WP-CLI's built-in PHP REPL, even if the Boris or * PsySH PHP REPLs are available. * + * [--hook=] + * : Attach the shell to a specific WordPress action or filter hook. + * --- + * default: '' + * --- + * * ## EXAMPLES * * # Call get_bloginfo() to get the name of the site. * $ wp shell * wp> get_bloginfo( 'name' ); * => string(6) "WP-CLI" + * + * # Start a shell after the 'init' action has fired. + * $ wp shell --hook=init */ public function __invoke( $_, $assoc_args ) { + $hook = Utils\get_flag_value( $assoc_args, 'hook', '' ); + + if ( $hook ) { + // Attach shell execution to the specified hook. + add_action( + $hook, + function () use ( $assoc_args ) { + $this->start_shell( $assoc_args ); + } + ); + + // Trigger WordPress lifecycle to reach the hook. + if ( ! did_action( $hook ) ) { + // Hook hasn't fired yet, so we need to let WordPress run. + // The hook will be called during the normal WordPress lifecycle. + return; + } else { + // Hook already fired, start the shell immediately. + $this->start_shell( $assoc_args ); + } + } else { + // No hook specified, start immediately. + $this->start_shell( $assoc_args ); + } + } + + /** + * Start the shell REPL. + * + * @param array $assoc_args Associative arguments. + */ + private function start_shell( $assoc_args ) { $class = WP_CLI\Shell\REPL::class; $implementations = array( From bb60d94084f5df913a76ae1f1d1de0ec654c4e6b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 14:13:03 +0000 Subject: [PATCH 3/6] Refine hook implementation logic for shell command Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- src/Shell_Command.php | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/Shell_Command.php b/src/Shell_Command.php index 526770d7..9b9edb5c 100644 --- a/src/Shell_Command.php +++ b/src/Shell_Command.php @@ -39,22 +39,29 @@ public function __invoke( $_, $assoc_args ) { $hook = Utils\get_flag_value( $assoc_args, 'hook', '' ); if ( $hook ) { - // Attach shell execution to the specified hook. - add_action( - $hook, - function () use ( $assoc_args ) { - $this->start_shell( $assoc_args ); - } - ); - - // Trigger WordPress lifecycle to reach the hook. - if ( ! did_action( $hook ) ) { - // Hook hasn't fired yet, so we need to let WordPress run. - // The hook will be called during the normal WordPress lifecycle. - return; - } else { + // Check if the hook has already fired. + if ( did_action( $hook ) ) { // Hook already fired, start the shell immediately. $this->start_shell( $assoc_args ); + } else { + // Hook hasn't fired yet. We need to attach a callback and let WordPress continue. + // Since shell is interactive and blocks execution, we'll attach the callback + // and let it start when the hook fires naturally. + $shell_started = false; + add_action( + $hook, + function () use ( $assoc_args, &$shell_started ) { + if ( ! $shell_started ) { + $shell_started = true; + $this->start_shell( $assoc_args ); + } + }, + 10 + ); + // Note: The shell will start when the hook fires during WordPress lifecycle. + // Since commands typically run after WordPress is loaded, most common hooks + // will have already fired. For hooks that haven't fired yet, the shell will + // start when they do fire. } } else { // No hook specified, start immediately. From 81e5e729541d35cbd76b9509f7e8c38487978167 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 14:14:57 +0000 Subject: [PATCH 4/6] Add validation and error handling for hook parameter Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- features/shell.feature | 12 +++++++++++- src/Shell_Command.php | 28 +++++++++++----------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/features/shell.feature b/features/shell.feature index 170d0316..6cf104ce 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -91,7 +91,7 @@ Feature: WordPress REPL int(1) """ - Scenario: Shell with hook parameter on already-fired hook + Scenario: Shell with hook parameter using plugins_loaded hook Given a WP install And a session file: """ @@ -103,3 +103,13 @@ Feature: WordPress REPL """ int(1) """ + + Scenario: Shell with hook parameter for hook that hasn't fired + Given a WP install + + When I try `wp shell --basic --hook=shutdown < /dev/null` + Then STDERR should contain: + """ + Error: The 'shutdown' hook has not fired yet + """ + And the return code should be 1 diff --git a/src/Shell_Command.php b/src/Shell_Command.php index 9b9edb5c..986e17d6 100644 --- a/src/Shell_Command.php +++ b/src/Shell_Command.php @@ -39,29 +39,23 @@ public function __invoke( $_, $assoc_args ) { $hook = Utils\get_flag_value( $assoc_args, 'hook', '' ); if ( $hook ) { + // Validate hook parameter. + if ( ! is_string( $hook ) || '' === trim( $hook ) ) { + WP_CLI::error( 'The --hook parameter must be a non-empty string.' ); + } + // Check if the hook has already fired. if ( did_action( $hook ) ) { // Hook already fired, start the shell immediately. $this->start_shell( $assoc_args ); } else { - // Hook hasn't fired yet. We need to attach a callback and let WordPress continue. - // Since shell is interactive and blocks execution, we'll attach the callback - // and let it start when the hook fires naturally. - $shell_started = false; - add_action( - $hook, - function () use ( $assoc_args, &$shell_started ) { - if ( ! $shell_started ) { - $shell_started = true; - $this->start_shell( $assoc_args ); - } - }, - 10 + // Hook hasn't fired yet. + WP_CLI::error( + sprintf( + "The '%s' hook has not fired yet. The shell command runs after WordPress is loaded, so only hooks that have already been triggered can be used. Common hooks that are available include: init, plugins_loaded, wp_loaded, admin_init.", + $hook + ) ); - // Note: The shell will start when the hook fires during WordPress lifecycle. - // Since commands typically run after WordPress is loaded, most common hooks - // will have already fired. For hooks that haven't fired yet, the shell will - // start when they do fire. } } else { // No hook specified, start immediately. From 844f0bd271402426adeda9902bdffa024857fa7f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 14:16:31 +0000 Subject: [PATCH 5/6] Refine documentation and remove redundant validation Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- src/Shell_Command.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Shell_Command.php b/src/Shell_Command.php index 986e17d6..74f93a7f 100644 --- a/src/Shell_Command.php +++ b/src/Shell_Command.php @@ -20,7 +20,9 @@ class Shell_Command extends WP_CLI_Command { * PsySH PHP REPLs are available. * * [--hook=] - * : Attach the shell to a specific WordPress action or filter hook. + * : Ensure that a specific WordPress action hook has fired before starting the shell. + * This validates that the preconditions associated with that hook are met. + * Only hooks that have already been triggered can be used (e.g., init, plugins_loaded, wp_loaded). * --- * default: '' * --- @@ -32,18 +34,13 @@ class Shell_Command extends WP_CLI_Command { * wp> get_bloginfo( 'name' ); * => string(6) "WP-CLI" * - * # Start a shell after the 'init' action has fired. + * # Start a shell, ensuring the 'init' hook has already fired. * $ wp shell --hook=init */ public function __invoke( $_, $assoc_args ) { $hook = Utils\get_flag_value( $assoc_args, 'hook', '' ); if ( $hook ) { - // Validate hook parameter. - if ( ! is_string( $hook ) || '' === trim( $hook ) ) { - WP_CLI::error( 'The --hook parameter must be a non-empty string.' ); - } - // Check if the hook has already fired. if ( did_action( $hook ) ) { // Hook already fired, start the shell immediately. @@ -52,7 +49,7 @@ public function __invoke( $_, $assoc_args ) { // Hook hasn't fired yet. WP_CLI::error( sprintf( - "The '%s' hook has not fired yet. The shell command runs after WordPress is loaded, so only hooks that have already been triggered can be used. Common hooks that are available include: init, plugins_loaded, wp_loaded, admin_init.", + "The '%s' hook has not fired yet. The shell command runs after WordPress is loaded, so only hooks that have already been triggered can be used. Common hooks that are available include: init, plugins_loaded, wp_loaded.", $hook ) ); From ee5a48c56ea601aef28e76fcf1fbebed422a89d6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 14:17:44 +0000 Subject: [PATCH 6/6] Improve code structure with early returns and better string formatting Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- src/Shell_Command.php | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/Shell_Command.php b/src/Shell_Command.php index 74f93a7f..7c89a7b2 100644 --- a/src/Shell_Command.php +++ b/src/Shell_Command.php @@ -40,24 +40,28 @@ class Shell_Command extends WP_CLI_Command { public function __invoke( $_, $assoc_args ) { $hook = Utils\get_flag_value( $assoc_args, 'hook', '' ); - if ( $hook ) { - // Check if the hook has already fired. - if ( did_action( $hook ) ) { - // Hook already fired, start the shell immediately. - $this->start_shell( $assoc_args ); - } else { - // Hook hasn't fired yet. - WP_CLI::error( - sprintf( - "The '%s' hook has not fired yet. The shell command runs after WordPress is loaded, so only hooks that have already been triggered can be used. Common hooks that are available include: init, plugins_loaded, wp_loaded.", - $hook - ) - ); - } - } else { - // No hook specified, start immediately. + // No hook specified, start immediately. + if ( ! $hook ) { $this->start_shell( $assoc_args ); + return; } + + // Check if the hook has already fired. + if ( did_action( $hook ) ) { + // Hook already fired, start the shell immediately. + $this->start_shell( $assoc_args ); + return; + } + + // Hook hasn't fired yet. + WP_CLI::error( + sprintf( + "The '%s' hook has not fired yet. " . + 'The shell command runs after WordPress is loaded, so only hooks that have already been triggered can be used. ' . + 'Common hooks that are available include: init, plugins_loaded, wp_loaded.', + $hook + ) + ); } /**