Skip to content

Commit 9be1b9a

Browse files
authored
Merge branch 'main' into copilot/fix-shell-binary-detection
2 parents 8eae8ef + de92dc6 commit 9be1b9a

5 files changed

Lines changed: 95 additions & 3 deletions

File tree

.github/workflows/code-quality.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ on:
66
branches:
77
- main
88
- master
9+
schedule:
10+
- cron: '17 2 * * *' # Run every day on a seemly random time.
911

1012
jobs:
1113
code-quality:

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Quick links: [Using](#using) | [Installing](#installing) | [Contributing](#contr
1010
## Using
1111

1212
~~~
13-
wp shell [--basic]
13+
wp shell [--basic] [--hook=<hook>]
1414
~~~
1515

1616
`wp shell` allows you to evaluate PHP statements and expressions
@@ -25,13 +25,24 @@ that you can use within a WordPress plugin, for example.
2525
Force the use of WP-CLI's built-in PHP REPL, even if the Boris or
2626
PsySH PHP REPLs are available.
2727

28+
[--hook=<hook>]
29+
Ensure that a specific WordPress action hook has fired before starting the shell.
30+
This validates that the preconditions associated with that hook are met.
31+
Only hooks that have already been triggered can be used (e.g., init, plugins_loaded, wp_loaded).
32+
---
33+
default: ''
34+
---
35+
2836
**EXAMPLES**
2937

3038
# Call get_bloginfo() to get the name of the site.
3139
$ wp shell
3240
wp> get_bloginfo( 'name' );
3341
=> string(6) "WP-CLI"
3442

43+
# Start a shell, ensuring the 'init' hook has already fired.
44+
$ wp shell --hook=init
45+
3546
## Installing
3647

3748
This package is included with WP-CLI itself, no additional installation necessary.

features/shell.feature

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,39 @@ Feature: WordPress REPL
109109
"""
110110
history: -1: invalid option
111111
"""
112+
113+
Scenario: Shell with hook parameter
114+
Given a WP install
115+
And a session file:
116+
"""
117+
did_action('init');
118+
"""
119+
120+
When I run `wp shell --basic --hook=init < session`
121+
Then STDOUT should contain:
122+
"""
123+
int(1)
124+
"""
125+
126+
Scenario: Shell with hook parameter using plugins_loaded hook
127+
Given a WP install
128+
And a session file:
129+
"""
130+
did_action('plugins_loaded');
131+
"""
132+
133+
When I run `wp shell --basic --hook=plugins_loaded < session`
134+
Then STDOUT should contain:
135+
"""
136+
int(1)
137+
"""
138+
139+
Scenario: Shell with hook parameter for hook that hasn't fired
140+
Given a WP install
141+
142+
When I try `wp shell --basic --hook=shutdown < /dev/null`
143+
Then STDERR should contain:
144+
"""
145+
Error: The 'shutdown' hook has not fired yet
146+
"""
147+
And the return code should be 1

src/Shell_Command.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,57 @@ class Shell_Command extends WP_CLI_Command {
1919
* : Force the use of WP-CLI's built-in PHP REPL, even if the Boris or
2020
* PsySH PHP REPLs are available.
2121
*
22+
* [--hook=<hook>]
23+
* : Ensure that a specific WordPress action hook has fired before starting the shell.
24+
* This validates that the preconditions associated with that hook are met.
25+
* Only hooks that have already been triggered can be used (e.g., init, plugins_loaded, wp_loaded).
26+
* ---
27+
* default: ''
28+
* ---
29+
*
2230
* ## EXAMPLES
2331
*
2432
* # Call get_bloginfo() to get the name of the site.
2533
* $ wp shell
2634
* wp> get_bloginfo( 'name' );
2735
* => string(6) "WP-CLI"
36+
*
37+
* # Start a shell, ensuring the 'init' hook has already fired.
38+
* $ wp shell --hook=init
2839
*/
2940
public function __invoke( $_, $assoc_args ) {
41+
$hook = Utils\get_flag_value( $assoc_args, 'hook', '' );
42+
43+
// No hook specified, start immediately.
44+
if ( ! $hook ) {
45+
$this->start_shell( $assoc_args );
46+
return;
47+
}
48+
49+
// Check if the hook has already fired.
50+
if ( did_action( $hook ) ) {
51+
// Hook already fired, start the shell immediately.
52+
$this->start_shell( $assoc_args );
53+
return;
54+
}
55+
56+
// Hook hasn't fired yet.
57+
WP_CLI::error(
58+
sprintf(
59+
"The '%s' hook has not fired yet. " .
60+
'The shell command runs after WordPress is loaded, so only hooks that have already been triggered can be used. ' .
61+
'Common hooks that are available include: init, plugins_loaded, wp_loaded.',
62+
$hook
63+
)
64+
);
65+
}
66+
67+
/**
68+
* Start the shell REPL.
69+
*
70+
* @param array<string,bool|string> $assoc_args Associative arguments.
71+
*/
72+
private function start_shell( $assoc_args ) {
3073
$class = WP_CLI\Shell\REPL::class;
3174

3275
$implementations = array(

src/WP_CLI/Shell/REPL.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,13 @@ private static function create_prompt_cmd( $prompt, $history_path ) {
121121
$prompt = escapeshellarg( $prompt );
122122
$history_path = escapeshellarg( $history_path );
123123
if ( getenv( 'WP_CLI_CUSTOM_SHELL' ) ) {
124-
$shell_binary = getenv( 'WP_CLI_CUSTOM_SHELL' );
124+
$shell_binary = (string) getenv( 'WP_CLI_CUSTOM_SHELL' );
125125
} elseif ( is_file( '/bin/bash' ) && is_readable( '/bin/bash' ) ) {
126126
// Prefer /bin/bash when available since we use bash-specific commands.
127127
$shell_binary = '/bin/bash';
128128
} elseif ( getenv( 'SHELL' ) && self::is_bash_shell( getenv( 'SHELL' ) ) ) {
129129
// Only use SHELL as fallback if it's bash (we use bash-specific commands).
130-
$shell_binary = getenv( 'SHELL' );
130+
$shell_binary = (string) getenv( 'SHELL' );
131131
} else {
132132
// Final fallback for systems without /bin/bash.
133133
$shell_binary = 'bash';

0 commit comments

Comments
 (0)