wp shell
wp shell opens an interactive PHP REPL (Read-Eval-Print Loop) with the full WordPress environment loaded. Type PHP, press Enter, see the result — instantly. It is the fastest way to experiment with WordPress functions, explore object properties, and verify assumptions without writing a script file or a wp eval one-liner.
What It Does
When you run wp shell, WP-CLI bootstraps WordPress (config, core, plugins, themes) and then drops you into an interactive PHP session. Every expression you type is evaluated inside this live WordPress context. The session persists until you type exit or quit.
Syntax
wp shell [--basic-shell]
Options
| Flag | Description |
|---|---|
--basic-shell | Use a simple stdin/stdout loop instead of the psysh REPL (useful when psysh is not installed) |
wp shell uses psysh by default for a rich experience with syntax highlighting, tab completion, and inline docs. If psysh is not available, it falls back to a basic REPL.
Install psysh globally:
wp package install wp-cli/shell-command:@stable
Starting a Session
wp shell
Output:
Starting 6 second timer... hit any key to cancel.
Psy Shell v0.12.0 (PHP 8.2.0 — cli) by Justin Hileman
>>>
Basic Examples
Print a WordPress option
>>> echo get_option("siteurl");
https://example.com
Get the site name
>>> echo get_bloginfo("name");
My WordPress Site
Inspect the current WordPress version
>>> global $wp_version; echo $wp_version;
6.4.2
Dump an option to inspect its structure
>>> var_dump(get_option("active_plugins"));
array(4) {
[0] =>
string(27) "akismet/akismet.php"
[1] =>
string(31) "woocommerce/woocommerce.php"
[2] =>
string(29) "yoast-seo/wp-seo-main.php"
[3] =>
string(25) "my-plugin/my-plugin.php"
}
Count published posts
>>> echo wp_count_posts("post")->publish;
142
Flash inspect a user object
>>> $user = get_user_by("login", "admin");
>>> echo $user->user_email;
admin@example.com
>>> print_r($user->roles);
Array
(
[0] => administrator
)
Iterating and Debugging
Check if a plugin is active
>>> var_dump(is_plugin_active("woocommerce/woocommerce.php"));
bool(true)
Run a WP_Query and inspect results
>>> $q = new WP_Query(["post_type" => "product", "posts_per_page" => 3]);
>>> echo $q->found_posts;
87
>>> echo $q->posts[0]->post_title;
Red Running Shoes
Update an option interactively
>>> update_option("blogdescription", "Catch up on everything.");
=> true
>>> echo get_option("blogdescription");
Catch up on everything.
Explore a class interactively
>>> $q = new WP_Query(["post_type" => "post","posts_per_page" => 1]);
>>> print_r(array_keys((array)$q));
Array
(
[0] => query
[1] => query_vars
[2] => tax_query
[3] => meta_query
[4] => date_query
...
)
Test a custom action hook
>>> do_action("my_plugin_queue_worker");
(No output means it ran silently — hooks with echo output will print here.)
Multi-Line Expressions in the REPL
In psysh, multi-line expressions are supported natively:
>>> $results = get_posts([
... "post_type" => "post",
... "post_status" => "publish",
... "numberposts" => 5
... ]);
>>> foreach ($results as $p) {
... echo $p->post_title . "\n";
... }
First Blog Post
Second Blog Post
Third Blog Post
Fourth Blog Post
Fifth Blog Post
Database Queries in the Shell
>>> global $wpdb;
>>> $count = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->posts WHERE post_status = 'trash'");
>>> echo "Trashed posts: $count";
Trashed posts: 12
Inspecting Plugin/Theme Objects
>>> $theme = wp_get_theme();
>>> echo $theme->get("Name");
Twenty Twenty-Four
>>> echo $theme->get("Version");
1.0
>>> echo $theme->get("Template");
twentytwentyfour
psysh-Specific Features
Inline Documentation with doc
>>> doc get_posts
function get_posts(array|null $args = null): WP_Post[]|int[]
Retrieves an array of the latest posts, or posts matching the given criteria.
...
Listing variables with ls
>>> $a = 1; $b = "test";
>>> ls
Variables: $a, $b
Show last exception
>>> throw new Exception("Oops");
>>> show
Exiting the Shell
>>> exit
Or press Ctrl+D.
Running Without psysh (Basic Shell)
If psysh is unavailable:
wp shell --basic-shell
Session looks like:
wp> echo get_option("siteurl");
https://example.com
wp>
wp-shell vs. wp eval
| Feature | wp shell | wp eval |
|---|---|---|
| Interactive | ✅ Yes | ❌ No (single command) |
| Multi-statement session | ✅ Yes | Limited |
| Tab completion | ✅ psysh | ❌ No |
| Inline documentation | ✅ psysh doc | ❌ No |
| State persists between lines | ✅ Yes | ❌ Each wp eval is fresh |
| Scriptable | ❌ No | ✅ Yes |
Best Practices
- Use
wp shellfor exploration — when you're not sure what a function returns, the REPL lets you experiment safely before committing to a script. - Use
var_dumpheavily — it reveals types, making it easier to understand serialized data. - Don't modify production data interactively — easy to make typos; use
wp eval-filewith a proper script for writes that matter. - Use
doc FUNCTION(psysh) to get immediate WordPress function documentation without leaving the terminal. - Keep sessions short — for long operations, move code to
wp eval-file.
Quick Reference
wp shell # Start interactive REPL
wp shell --basic-shell # Start without psysh
wp shell --skip-plugins # Load WP without plugins
Inside the shell:
>>> echo get_option("siteurl"); # Basic output
>>> var_dump($GLOBALS["wpdb"]); # Inspect globals
>>> doc get_posts # Inline docs (psysh)
>>> ls # List variables (psysh)
>>> exit # Exit session
Next Steps
wp eval— for quick, non-interactive one-liners.wp eval-file— for executing a full PHP migration script.wp help— look up any WP-CLI command's syntax.