-
Notifications
You must be signed in to change notification settings - Fork 354
Add how-to guide: Figure out why WordPress is slow #616
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
9903dc1
Initial plan
Copilot e4de1d2
Add how-to guide: Figure out why WordPress is slow
Copilot c05b7b3
Address code review feedback: remove duplication and improve language
Copilot 8d2c899
Update how-to/figure-out-why-wordpress-is-slow.md
swissspidy f84b0e0
Update how-to/figure-out-why-wordpress-is-slow.md
swissspidy 49f36f5
Add installation instructions for wp profile package
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| # Figure out why WordPress is slow | ||
|
|
||
| `wp profile` is a WP-CLI command to help you quickly identify what's slow with WordPress. It's designed to work alongside Xdebug and New Relic because it's easy to deploy to any server that has WP-CLI. With `wp profile`, you gain quick visibility into key performance metrics (execution time, query count, cache hit/miss ratio, etc.) to guide further debugging. | ||
|
|
||
| ## Installation | ||
|
|
||
| First, install the `wp profile` package if you haven't already: | ||
|
|
||
| ``` | ||
| $ wp package install wp-cli/profile-command | ||
| ``` | ||
|
|
||
| ### Step 1 - Profile the WordPress load process | ||
|
|
||
| Dealing with a slow WordPress install you've never worked with before? Run `wp profile stage` to see metrics for each stage of the WordPress load process. Include the `--url=<url>` argument to mock the request as a specific URL. | ||
|
|
||
| ``` | ||
| $ wp profile stage --url=runcommand.io | ||
| +------------+---------+------------+-------------+-------------+------------+--------------+-----------+------------+--------------+---------------+ | ||
| | stage | time | query_time | query_count | cache_ratio | cache_hits | cache_misses | hook_time | hook_count | request_time | request_count | | ||
| +------------+---------+------------+-------------+-------------+------------+--------------+-----------+------------+--------------+---------------+ | ||
| | bootstrap | 0.7597s | 0.0052s | 14 | 93.21% | 357 | 26 | 0.3328s | 2717 | 0s | 0 | | ||
| | main_query | 0.0131s | 0.0004s | 3 | 94.29% | 33 | 2 | 0.0065s | 78 | 0s | 0 | | ||
| | template | 0.7041s | 0.0192s | 147 | 92.16% | 2350 | 200 | 0.6982s | 6130 | 0s | 0 | | ||
| +------------+---------+------------+-------------+-------------+------------+--------------+-----------+------------+--------------+---------------+ | ||
| | total (3) | 1.477s | 0.0248s | 164 | 93.22% | 2740 | 228 | 1.0375s | 8925 | 0s | 0 | | ||
| +------------+---------+------------+-------------+-------------+------------+--------------+-----------+------------+--------------+---------------+ | ||
| ``` | ||
|
|
||
| When WordPress handles a request from a browser, it's essentially executing as one long PHP script. `wp profile stage` breaks the script into three stages: | ||
|
|
||
| * **bootstrap** is where WordPress is setting itself up, loading plugins and the main theme, and firing the `init` hook. | ||
| * **main_query** is how WordPress transforms the request (e.g. /2016/10/21/moms-birthday/) into the primary WP_Query. | ||
| * **template** is where WordPress determines which theme template to render based on the main query, and renders it. | ||
|
|
||
| ### Step 2 - Dive into a specific stage | ||
|
|
||
| In the example from above, bootstrap seems a bit slow, so let's dive into it further. Run `wp profile stage bootstrap` to dive into higher fidelity mode of a given stage. Use the `--spotlight` flag to filter out the zero-ish results. | ||
|
|
||
| ``` | ||
| $ wp profile stage bootstrap --url=runcommand.io --spotlight | ||
| +--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+ | ||
| | hook | callback_count | time | query_time | query_count | cache_ratio | cache_hits | cache_misses | request_time | request_count | | ||
| +--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+ | ||
| | muplugins_loaded:before | | 0.1644s | 0.0017s | 1 | 40% | 2 | 3 | 0s | 0 | | ||
| | muplugins_loaded | 2 | 0.0005s | 0s | 0 | 50% | 1 | 1 | 0s | 0 | | ||
| | plugins_loaded:before | | 0.1771s | 0.0008s | 6 | 77.63% | 59 | 17 | 0s | 0 | | ||
| | plugins_loaded | 14 | 0.0887s | 0s | 0 | 100% | 104 | 0 | 0s | 0 | | ||
| | after_setup_theme:before | | 0.043s | 0s | 0 | 100% | 26 | 0 | 0s | 0 | | ||
| | init | 82 | 0.1569s | 0.0018s | 7 | 96.88% | 155 | 5 | 0s | 0 | | ||
| | wp_loaded:after | | 0.027s | 0s | 0 | | 0 | 0 | 0s | 0 | | ||
| +--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+ | ||
| | total (7) | 98 | 0.6575s | 0.0043s | 14 | 77.42% | 347 | 26 | 0s | 0 | | ||
| +--------------------------+----------------+---------+------------+-------------+-------------+------------+--------------+--------------+---------------+ | ||
| ``` | ||
|
|
||
| Each stage is further segmented by `wp profile` based on its primary actions. For the bootstrap stage, the primary actions 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. | ||
|
|
||
| ### Step 3 - Profile specific hooks | ||
|
|
||
| When you've found a specific hook you'd like to assess, run `wp profile hook <hook>`. Include the `--fields=<fields>` argument to limit output to certain fields. | ||
|
|
||
| ``` | ||
| $ wp profile hook plugins_loaded --url=runcommand.io --fields=callback,time,location | ||
| +------------------------------------------------------------+---------+-----------------------------------------------------------------+ | ||
| | callback | time | location | | ||
| +------------------------------------------------------------+---------+-----------------------------------------------------------------+ | ||
| | wp_maybe_load_widgets() | 0.0046s | wp-includes/functions.php:3501 | | ||
| | wp_maybe_load_embeds() | 0.0003s | wp-includes/embed.php:162 | | ||
| | VaultPress_Hotfixes->protect_jetpack_402_from_oembed_xss() | 0s | vaultpress/class.vaultpress-hotfixes.php:124 | | ||
| | _wp_customize_include() | 0s | wp-includes/theme.php:2052 | | ||
| | EasyRecipePlus->pluginsLoaded() | 0.0013s | easyrecipeplus/lib/EasyRecipePlus.php:125 | | ||
| | Gamajo\GenesisHeaderNav\genesis_header_nav_i18n() | 0.0007s | genesis-header-nav/genesis-header-nav.php:61 | | ||
| | DS_Public_Post_Preview::init() | 0.0001s | public-post-preview/public-post-preview.php:52 | | ||
| | wpseo_load_textdomain() | 0.0004s | wordpress-seo-premium/wp-seo-main.php:222 | | ||
| | load_yoast_notifications() | 0.0016s | wordpress-seo-premium/wp-seo-main.php:381 | | ||
| | wpseo_init() | 0.0329s | wordpress-seo-premium/wp-seo-main.php:240 | | ||
| | wpseo_premium_init() | 0.0019s | wordpress-seo-premium/wp-seo-premium.php:79 | | ||
| | wpseo_frontend_init() | 0.0007s | wordpress-seo-premium/wp-seo-main.php:274 | | ||
| | Black_Studio_TinyMCE_Plugin->load_compatibility() | 0.0016s | black-studio-tinymce-widget/black-studio-tinymce-widget.php:206 | | ||
| | Jetpack::load_modules() | 0.0564s | jetpack/class.jetpack.php:1672 | | ||
| +------------------------------------------------------------+---------+-----------------------------------------------------------------+ | ||
| | total (14) | 0.1026s | | | ||
| +------------------------------------------------------------+---------+-----------------------------------------------------------------+ | ||
| ``` | ||
|
|
||
| There you have it! We've discovered that `wpseo_init()` and `Jetpack::load_modules()` are collectively contributing ~100ms to every page load. | ||
|
|
||
| With `wp profile`, discovering why WordPress is slow becomes the easy part. | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The guide should mention whether wp profile is a built-in command or requires installation as a package. Consider adding an introductory note like "First, install the wp profile package if you haven't already" with installation instructions, or clarify that it's included with WP-CLI by default if that's the case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot apply changes based on this feedback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added installation instructions for the wp-cli/profile-command package at the beginning of the guide (commit 49f36f5).