Introducing wp doctor v0.1.0

I’d like to formally introduce you to wp doctor, runcommand’s second premium WP-CLI command. The command is available exclusively to runcommand gold and silver subscribers. You can apply today for access, or read on for more details.

Inspired by Pantheon’s WP Launch Check (credit where credit is due), wp doctor saves your team hours of time by codifying diagnosis procedures into a series of checks run by WP-CLI. For example, cron-count is a check to ensure WP Cron hasn’t exploded with jobs:

138d9769-d7f0-4bdc-80a9-a822c1987670

Not only does it come with dozens of default checks, wp doctor is designed for extensibility. Easily create a custom doctor.yml file to define additional checks you deem necessary for your system:

b09af583-c44a-4ebf-b97c-37224d59a9cf

If you manage more than a few WordPress installations, wp doctor is your new favorite WP-CLI command.

wp profile v0.3.0: new commands; spotlight mode; intermediate actions

wp profile is a premium WP-CLI command to help you quickly identify what’s slow with WordPress. It reports key performance metrics (execution time, query count, cache hit/miss ratio, etc.) for segments of the WordPress execution process to give you easy visibility into what code is the least performant. v0.3.0 is the third significant release.

New commands: eval, eval-file

wp profile v0.3.0 introduces two new commands for profiling arbitrary code execution: wp profile eval and wp profile eval-file. Used creatively, this is an incredibly powerful tool for better understanding your codebase. Spend 15 minutes futzing around with xDebug, or 30 seconds using wp profile.

As an example, profile a WP REST API response by creating a get-posts.php file:

<?php
$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
$request->set_param( 'per_page', 100 );
$server = rest_get_server();
$server->dispatch( $request );

Then, profile get-posts.php by running wp profile eval-file get-posts.php:

$ wp profile eval-file get-posts.php
+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+
| time    | query_time | query_count | cache_ratio | cache_hits | cache_misses | request_time | request_count |
+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+
| 0.9429s | 0.002s     | 5           | 96.39%      | 7599       | 285          | 0s           | 0             |
+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+

Holy moly, that’s a lot of cache hits!

Identify the signal from the noise with --spotlight

In a long list of results, it can be difficult to tell the signal from the noise:

$ wp profile stage bootstrap
+--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+
| hook                     | callback_count | time    | query_time | query_count | cache_ratio | cache_hits | cache_misses | request_time | request_count |
+--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+
| muplugins_loaded:before  |                | 0.2536s | 0.0033s    | 1           | 40%         | 2          | 3            | 0s           | 0             |
| muplugins_loaded         | 2              | 0.0005s | 0s         | 0           | 50%         | 1          | 1            | 0s           | 0             |
| plugins_loaded:before    |                | 0.2955s | 0.0012s    | 6           | 77.63%      | 59         | 17           | 0s           | 0             |
| plugins_loaded           | 14             | 0.1572s | 0s         | 0           | 100%        | 104        | 0            | 0s           | 0             |
| setup_theme:before       |                | 0.0035s | 0s         | 0           | 100%        | 6          | 0            | 0s           | 0             |
| setup_theme              | 1              | 0.0001s | 0s         | 0           |             | 0          | 0            | 0s           | 0             |
| after_setup_theme:before |                | 0.0828s | 0s         | 0           | 100%        | 26         | 0            | 0s           | 0             |
| after_setup_theme        | 12             | 0.0038s | 0s         | 0           | 100%        | 4          | 0            | 0s           | 0             |
| init:before              |                | 0.0001s | 0s         | 0           |             | 0          | 0            | 0s           | 0             |
| init                     | 82             | 0.2954s | 0.0024s    | 7           | 96.88%      | 155        | 5            | 0s           | 0             |
| wp_loaded:before         |                | 0.0001s | 0s         | 0           |             | 0          | 0            | 0s           | 0             |
| wp_loaded                | 3              | 0.0049s | 0s         | 0           |             | 0          | 0            | 0s           | 0             |
| wp_loaded:after          |                | 0.0471s | 0s         | 0           |             | 0          | 0            | 0s           | 0             |
+--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+
| total (13)               | 114            | 1.1445s | 0.0069s    | 14          | 83.06%      | 357        | 26           | 0s           | 0             |
+--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+

The new --spotlight flag filters out the zero-ish results from the set, to help you focus on the greatest contributing factors:

$ wp profile stage bootstrap --spotlight
+--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+
| hook                     | callback_count | time    | query_time | query_count | cache_ratio | cache_hits | cache_misses | request_time | request_count |
+--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+
| muplugins_loaded:before  |                | 0.2253s | 0.0025s    | 1           | 40%         | 2          | 3            | 0s           | 0             |
| muplugins_loaded         | 2              | 0.0007s | 0s         | 0           | 50%         | 1          | 1            | 0s           | 0             |
| plugins_loaded:before    |                | 0.2018s | 0.0009s    | 6           | 77.63%      | 59         | 17           | 0s           | 0             |
| plugins_loaded           | 14             | 0.1239s | 0s         | 0           | 100%        | 104        | 0            | 0s           | 0             |
| after_setup_theme:before |                | 0.0598s | 0s         | 0           | 100%        | 26         | 0            | 0s           | 0             |
| init                     | 82             | 0.1751s | 0.0022s    | 7           | 96.88%      | 155        | 5            | 0s           | 0             |
| wp_loaded:after          |                | 0.0273s | 0s         | 0           |             | 0          | 0            | 0s           | 0             |
+--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+
| total (7)                | 98             | 0.8138s | 0.0056s    | 14          | 77.42%      | 347        | 26           | 0s           | 0             |
+--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+

Profile intermediate actions

In the example immediately above, the primary actions for the stage include ‘muplugins_loaded’, ‘plugins_loaded’, and ‘init’. You can also see some intermediate actions like ‘plugins_loaded:before’ and ‘wp_loaded:after’. These intermediate actions correspond to script execution before (or after) actual WordPress hooks. They’re pseudo hooks in a sense.

Try out wp profile hook plugins_loaded:before to see which plugins take the longest time to load.


wp profile is available to runcommand gold and silver subscribers, or you can purchase a single-seat updates and support subscription for $129 per year. Existing subscribers can download the latest from their account dashboard.

Have a developer seat? You can browse the full list of resolved issues in Github.

wp profile v0.2.0 released

The changelog for the latest version of wp profile includes:

  • Registers more basic hooks for the template stage.
  • Ensures the last step to a stage is logged appropriately
  • Fixes error notice when SAVEQUERIES is already defined. If SAVEQUERIES is defined as false, then wp profile bails.
  • Fixes bottom of the table when there aren’t any items displayed.
  • Fix profiling of early hooks. When we throw an Exception to bail out of the call, this means the rest of the bootstrap code hasn’t executed, and important things aren’t set up.
  • Updates installation instructions with detail on how to require private file.

runcommand customers can download wp profile v0.2.0 from their account.

Haven’t purchased a subscription yet? Don’t delay — early access ends on Friday. Sign up today.