티스토리 수익 글 보기
Navigation Menu
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
OPcache: Add information to the Site Health -> Server #9260
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
base: trunk
Are you sure you want to change the base?
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project’s expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
westonruter
left a comment
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.
I think this also needs a Site Health test. A site without Opcode Cache should be flagged to users as a performance problem.
| 'debug' => $opcache_loaded, | ||
| ); | ||
|
|
||
| if ( $opcache_loaded && function_exists( 'opcache_get_status' ) ) { |
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.
If these don’t exist, then there should be something indicating as such in the data to say that Opcache is not available, right?
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.
| 'debug' => $imagick_loaded, | ||
| ); | ||
|
|
||
| // OPCache. |
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.
It seems this should be referred to throughout as “Opcode Cache” per https://core.trac.wordpress.org/ticket/63697#comment:2
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.
Thanks! – I’ll update it together with the labels
|
If using The question is, should we do a more robust approach by using Hey @westonruter – if you can give advice/opinion, that would be great. Thanks in advance.. |
|
I haven’t done much with Opcode Cache internals, so I don’t have a lot to add. But it seems like using
|
westonruter
left a comment
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.
Based on https://core.trac.wordpress.org/ticket/63697#comment:2 any references to “OPcache” should be replaced with “Opcode cache”.
There are some merge conflicts with trunk that need to be resolved.
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
| $fields['opcode_cache_memory_usage'] = array( | ||
| 'label' => __( 'Opcode cache memory usage' ), | ||
| 'value' => sprintf( | ||
| /* translators: 1: Used memory, 2: Total memory */ | ||
| __( '%1$s of %2$s' ), | ||
| size_format( $opcache_status['memory_usage']['used_memory'] ), | ||
| size_format( $opcache_status['memory_usage']['free_memory'] + $opcache_status['memory_usage']['used_memory'] ) | ||
| ), | ||
| 'debug' => sprintf( | ||
| '%s of %s', | ||
| $opcache_status['memory_usage']['used_memory'], | ||
| $opcache_status['memory_usage']['free_memory'] + $opcache_status['memory_usage']['used_memory'] | ||
| ), | ||
| ); | ||
|
|
||
| $fields['opcode_cache_hit_rate'] = array( | ||
| 'label' => __( 'Opcode cache hit rate' ), | ||
| 'value' => sprintf( | ||
| /* translators: %s: Hit rate percentage */ | ||
| __( '%s%%' ), | ||
| round( $opcache_status['opcache_statistics']['opcache_hit_rate'], 2 ) | ||
| ), | ||
| 'debug' => $opcache_status['opcache_statistics']['opcache_hit_rate'], | ||
| ); |
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.
What if $opcache_status['opcache_enabled'] is false? Will the $opcache_status['memory_usage'] and $opcache_status['opcache_statistics'] keys be set. It seems these two conditions fields should be be set conditionally when $opcache_status['opcache_enabled'] is true, no?
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.
Based on https://www.php.net/manual/en/function.opcache-get-status.php, these keys should still be accessible even when the $opcache_status['opcache_enabled'] is false, though it wouldn’t hurt if we add conditional statement
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.
Alternatively, shouldn’t opcode_cache_memory_usage and opcode_cache_hit_rate be omitted if $opcache_status['opcache_enabled'] is false?
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.
In other words, wrap these two assignments with a if ( $opcache_status['opcache_enabled'] ) { ... } check?
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.
That’s correct – I’m wrapping this inside if statement
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 the conditional extra info only if the opcache_enabled is true: b8ee643
| public function get_test_opcode_cache() { | ||
| $opcode_cache_enabled = false; | ||
| if ( function_exists( 'opcache_get_status' ) ) { | ||
| $status = opcache_get_status( false ); |
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.
What if opcache_get_status( false ) returns false as seen in class-wp-debug-data.php above?
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.
Used the same logic as on the class-wp-debug-data.php. We only use the opcache_enabled value in order to display the recommended status or not.
|
@rollybueno Hello! Are you intending to follow up on this? |
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Hey @westonruter – gonna look at this today |
Co-authored-by: Weston Ruter <westonruter@gmail.com>
| 'debug' => $opcache_status['opcache_enabled'], | ||
| ); | ||
|
|
||
| if ( true === $opcache_status['opcache_enabled'] ) { |
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.
I see this is only being added to the debug data. Is this intentionally not included in the Site Health test?
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.
You mean displaying the data inside this condition in the site health status? Do we need to do it though?
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.
I suppose not.
Co-authored-by: Weston Ruter <westonruter@gmail.com>
|
|
||
| // Opcode Cache. | ||
| if ( function_exists( 'opcache_get_status' ) ) { | ||
| $opcache_status = @opcache_get_status( false ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discourage — Warning emitted in failure 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.
Sorry, my suggestion was missing the last character.
| $opcache_status = @opcache_get_status( false ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discourage — Warning emitted in failure case. | |
| $opcache_status = @opcache_get_status( false ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged — Warning emitted in failure case. |
| * | ||
| * @since 7.0.0 | ||
| * | ||
| * @return array The test result. |
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.
| * @return array The test result. | |
| * @return array<string, string|array<string, string>> The test result. |
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.
Pull request overview
This pull request adds OPcache monitoring capabilities to WordPress Site Health, providing administrators with visibility into their PHP opcode cache performance and configuration.
Changes:
- Added a new Site Health test (
get_test_opcode_cache()) that checks if opcode cache is enabled and displays appropriate recommendations - Added OPcache metrics to the Site Health Info debug data, including cache status, memory usage, and hit rate statistics
- Fixed code alignment in the
get_page_cache_headers()method for improved readability
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.
| File | Description |
|---|---|
| src/wp-admin/includes/class-wp-site-health.php | Adds opcode cache test method, registers it in the test suite, and includes minor code alignment improvements |
| src/wp-admin/includes/class-wp-debug-data.php | Adds opcode cache detection and displays status, memory usage, and hit rate in debug information |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if ( ! $opcode_cache_enabled ) { | ||
| $result['status'] = 'recommended'; | ||
| $result['label'] = __( 'Opcode cache is not enabled' ); | ||
| $result['description'] .= '<p>' . __( 'Opcode cache is not enabled. Enabling this cache can significantly improve the performance of your site.' ) . '</p>'; |
Copilot
AI
Jan 21, 2026
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 error message is redundant. Since the label already states “Opcode cache is not enabled”, the description should not repeat this information. Consider changing the message to something like “Enabling opcode cache can significantly improve the performance of your site.” to avoid repetition.
| $result[‘description‘] .= ‘<p>‘ . __( ‘Opcode cache is not enabled. Enabling this cache can significantly improve the performance of your site.‘ ) . ‘</p>‘; | |
| $result[‘description‘] .= ‘<p>‘ . __( ‘Enabling this cache can significantly improve the performance of your site.‘ ) . ‘</p>‘; |
| ), | ||
| 'actions' => sprintf( | ||
| '<p><a href="%s" target="_blank">%s<span class="screen-reader-text"> %s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>', | ||
| 'https://www.php.net/manual/en/book.opcache.php', |
Copilot
AI
Jan 21, 2026
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 URL should be escaped using esc_url() for consistency with WordPress best practices, even though it’s a hardcoded external URL. Similar patterns in the codebase (like line 2552 for persistent object cache) use esc_url() to sanitize URLs before output.
| ‘https://www.php.net/manual/en/book.opcache.php‘, | |
| esc_url( ‘https://www.php.net/manual/en/book.opcache.php‘ ), |
| 'value' => $opcache_status['opcache_enabled'] ? __( 'Enabled' ) : __( 'Disabled' ), | ||
| 'debug' => $opcache_status['opcache_enabled'], |
Copilot
AI
Jan 21, 2026
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.
For consistency with the check in class-wp-site-health.php (line 2769), consider using strict comparison with true here: $opcache_status[‘opcache_enabled’] === true. This ensures the value is explicitly boolean true rather than any truthy value.
| ‘value‘ => $opcache_status[‘opcache_enabled‘] ? __( ‘Enabled‘ ) : __( ‘Disabled‘ ), | |
| ‘debug‘ => $opcache_status[‘opcache_enabled‘], | |
| ‘value‘ => ( true === $opcache_status[‘opcache_enabled‘] ) ? __( ‘Enabled‘ ) : __( ‘Disabled‘ ), | |
| ‘debug‘ => ( true === $opcache_status[‘opcache_enabled‘] ), |
| public function get_test_opcode_cache() { | ||
| $opcode_cache_enabled = false; | ||
| if ( function_exists( 'opcache_get_status' ) ) { | ||
| $status = @opcache_get_status( false ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discourage — Warning emitted in failure case. | ||
| if ( $status && true === $status['opcache_enabled'] ) { | ||
| $opcode_cache_enabled = true; | ||
| } | ||
| } | ||
|
|
||
| $result = array( | ||
| 'label' => __( 'Opcode cache is enabled' ), | ||
| 'status' => 'good', | ||
| 'badge' => array( | ||
| 'label' => __( 'Performance' ), | ||
| 'color' => 'blue', | ||
| ), | ||
| 'description' => sprintf( | ||
| '<p>%s</p>', | ||
| __( 'Opcode cache improves PHP performance by storing precompiled script bytecode in memory, reducing the need for PHP to load and parse scripts on each request.' ) | ||
| ), | ||
| 'actions' => sprintf( | ||
| '<p><a href="%s" target="_blank">%s<span class="screen-reader-text"> %s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>', | ||
| 'https://www.php.net/manual/en/book.opcache.php', | ||
| __( 'Learn more about OPcache.' ), | ||
| /* translators: Hidden accessibility text. */ | ||
| __( '(opens in a new tab)' ) | ||
| ), | ||
| 'test' => 'opcache_cache', | ||
| ); | ||
|
|
||
| if ( ! $opcode_cache_enabled ) { | ||
| $result['status'] = 'recommended'; | ||
| $result['label'] = __( 'Opcode cache is not enabled' ); | ||
| $result['description'] .= '<p>' . __( 'Opcode cache is not enabled. Enabling this cache can significantly improve the performance of your site.' ) . '</p>'; | ||
| } | ||
|
|
||
| return $result; | ||
| } |
Copilot
AI
Jan 21, 2026
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 new get_test_opcode_cache() method lacks test coverage. Similar test methods in this class (like get_test_page_cache() and get_test_autoloaded_options()) have corresponding tests in tests/phpunit/tests/admin/wpSiteHealth.php. Consider adding tests to cover different scenarios: opcache enabled, disabled, not available, and when opcache_get_status() returns false.
| /* translators: Hidden accessibility text. */ | ||
| __( '(opens in a new tab)' ) | ||
| ), | ||
| 'test' => 'opcache_cache', |
Copilot
AI
Jan 21, 2026
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 test identifier should be ‘opcode_cache’ to match the test registration in the get_tests() method at line 2898. Currently it’s ‘opcache_cache’ which creates an inconsistency.
| ‘test‘ => ‘opcache_cache‘, | |
| ‘test‘ => ‘opcode_cache‘, |
| $opcode_cache_enabled = false; | ||
| if ( function_exists( 'opcache_get_status' ) ) { | ||
| $status = @opcache_get_status( false ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discourage — Warning emitted in failure case. | ||
| if ( $status && true === $status['opcache_enabled'] ) { |
Copilot
AI
Jan 21, 2026
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.
Array keys should be checked for existence before access. After opcache_get_status() returns a non-false value, the code assumes ‘opcache_enabled’ key exists. While this key is typically present, defensive programming would check isset($status[‘opcache_enabled’]) before accessing it to avoid potential undefined array key warnings.
| if ( $status && true === $status[‘opcache_enabled‘] ) { | |
| if ( $status && isset( $status[‘opcache_enabled‘] ) && true === $status[‘opcache_enabled‘] ) { |
| $fields['opcode_cache'] = array( | ||
| 'label' => __( 'Opcode cache' ), | ||
| 'value' => $opcache_status['opcache_enabled'] ? __( 'Enabled' ) : __( 'Disabled' ), | ||
| 'debug' => $opcache_status['opcache_enabled'], | ||
| ); | ||
|
|
||
| if ( true === $opcache_status['opcache_enabled'] ) { | ||
| $fields['opcode_cache_memory_usage'] = array( | ||
| 'label' => __( 'Opcode cache memory usage' ), | ||
| 'value' => sprintf( | ||
| /* translators: 1: Used memory, 2: Total memory */ | ||
| __( '%1$s of %2$s' ), | ||
| size_format( $opcache_status['memory_usage']['used_memory'] ), | ||
| size_format( $opcache_status['memory_usage']['free_memory'] + $opcache_status['memory_usage']['used_memory'] ) | ||
| ), | ||
| 'debug' => sprintf( | ||
| '%s of %s', | ||
| $opcache_status['memory_usage']['used_memory'], | ||
| $opcache_status['memory_usage']['free_memory'] + $opcache_status['memory_usage']['used_memory'] | ||
| ), | ||
| ); | ||
|
|
||
| $fields['opcode_cache_hit_rate'] = array( | ||
| 'label' => __( 'Opcode cache hit rate' ), | ||
| 'value' => sprintf( | ||
| /* translators: %s: Hit rate percentage */ | ||
| __( '%s%%' ), | ||
| round( $opcache_status['opcache_statistics']['opcache_hit_rate'], 2 ) | ||
| ), | ||
| 'debug' => $opcache_status['opcache_statistics']['opcache_hit_rate'], | ||
| ); |
Copilot
AI
Jan 21, 2026
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.
Array keys should be checked for existence before access. The code assumes ‘opcache_enabled’ key exists in the $opcache_status array. Add isset() checks to avoid potential undefined array key warnings when the opcache_get_status() return structure is unexpected.
| $fields[‘opcode_cache‘] = array( | |
| ‘label‘ => __( ‘Opcode cache‘ ), | |
| ‘value‘ => $opcache_status[‘opcache_enabled‘] ? __( ‘Enabled‘ ) : __( ‘Disabled‘ ), | |
| ‘debug‘ => $opcache_status[‘opcache_enabled‘], | |
| ); | |
| if ( true === $opcache_status[‘opcache_enabled‘] ) { | |
| $fields[‘opcode_cache_memory_usage‘] = array( | |
| ‘label‘ => __( ‘Opcode cache memory usage‘ ), | |
| ‘value‘ => sprintf( | |
| /* translators: 1: Used memory, 2: Total memory */ | |
| __( ‘%1$s of %2$s‘ ), | |
| size_format( $opcache_status[‘memory_usage‘][‘used_memory‘] ), | |
| size_format( $opcache_status[‘memory_usage‘][‘free_memory‘] + $opcache_status[‘memory_usage‘][‘used_memory‘] ) | |
| ), | |
| ‘debug‘ => sprintf( | |
| ‘%s of %s‘, | |
| $opcache_status[‘memory_usage‘][‘used_memory‘], | |
| $opcache_status[‘memory_usage‘][‘free_memory‘] + $opcache_status[‘memory_usage‘][‘used_memory‘] | |
| ), | |
| ); | |
| $fields[‘opcode_cache_hit_rate‘] = array( | |
| ‘label‘ => __( ‘Opcode cache hit rate‘ ), | |
| ‘value‘ => sprintf( | |
| /* translators: %s: Hit rate percentage */ | |
| __( ‘%s%%‘ ), | |
| round( $opcache_status[‘opcache_statistics‘][‘opcache_hit_rate‘], 2 ) | |
| ), | |
| ‘debug‘ => $opcache_status[‘opcache_statistics‘][‘opcache_hit_rate‘], | |
| ); | |
| $opcache_enabled = ( is_array( $opcache_status ) && isset( $opcache_status[‘opcache_enabled‘] ) ) | |
| ? (bool) $opcache_status[‘opcache_enabled‘] | |
| : null; | |
| $fields[‘opcode_cache‘] = array( | |
| ‘label‘ => __( ‘Opcode cache‘ ), | |
| ‘value‘ => ( null === $opcache_enabled ) | |
| ? __( ‘Unknown‘ ) | |
| : ( $opcache_enabled ? __( ‘Enabled‘ ) : __( ‘Disabled‘ ) ), | |
| ‘debug‘ => ( null === $opcache_enabled ) ? ‘not available‘ : $opcache_enabled, | |
| ); | |
| if ( true === $opcache_enabled ) { | |
| if ( isset( $opcache_status[‘memory_usage‘][‘used_memory‘], $opcache_status[‘memory_usage‘][‘free_memory‘] ) ) { | |
| $used_memory = $opcache_status[‘memory_usage‘][‘used_memory‘]; | |
| $free_memory = $opcache_status[‘memory_usage‘][‘free_memory‘]; | |
| $total_memory = $free_memory + $used_memory; | |
| $fields[‘opcode_cache_memory_usage‘] = array( | |
| ‘label‘ => __( ‘Opcode cache memory usage‘ ), | |
| ‘value‘ => sprintf( | |
| /* translators: 1: Used memory, 2: Total memory */ | |
| __( ‘%1$s of %2$s‘ ), | |
| size_format( $used_memory ), | |
| size_format( $total_memory ) | |
| ), | |
| ‘debug‘ => sprintf( | |
| ‘%s of %s‘, | |
| $used_memory, | |
| $total_memory | |
| ), | |
| ); | |
| } | |
| if ( isset( $opcache_status[‘opcache_statistics‘][‘opcache_hit_rate‘] ) ) { | |
| $hit_rate = $opcache_status[‘opcache_statistics‘][‘opcache_hit_rate‘]; | |
| $fields[‘opcode_cache_hit_rate‘] = array( | |
| ‘label‘ => __( ‘Opcode cache hit rate‘ ), | |
| ‘value‘ => sprintf( | |
| /* translators: %s: Hit rate percentage */ | |
| __( ‘%s%%‘ ), | |
| round( $hit_rate, 2 ) | |
| ), | |
| ‘debug‘ => $hit_rate, | |
| ); | |
| } |
| $fields['opcode_cache_memory_usage'] = array( | ||
| 'label' => __( 'Opcode cache memory usage' ), | ||
| 'value' => sprintf( | ||
| /* translators: 1: Used memory, 2: Total memory */ | ||
| __( '%1$s of %2$s' ), | ||
| size_format( $opcache_status['memory_usage']['used_memory'] ), | ||
| size_format( $opcache_status['memory_usage']['free_memory'] + $opcache_status['memory_usage']['used_memory'] ) | ||
| ), | ||
| 'debug' => sprintf( | ||
| '%s of %s', | ||
| $opcache_status['memory_usage']['used_memory'], | ||
| $opcache_status['memory_usage']['free_memory'] + $opcache_status['memory_usage']['used_memory'] | ||
| ), | ||
| ); | ||
|
|
||
| $fields['opcode_cache_hit_rate'] = array( | ||
| 'label' => __( 'Opcode cache hit rate' ), | ||
| 'value' => sprintf( | ||
| /* translators: %s: Hit rate percentage */ | ||
| __( '%s%%' ), | ||
| round( $opcache_status['opcache_statistics']['opcache_hit_rate'], 2 ) | ||
| ), | ||
| 'debug' => $opcache_status['opcache_statistics']['opcache_hit_rate'], | ||
| ); |
Copilot
AI
Jan 21, 2026
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.
Array keys should be checked for existence before access. The code directly accesses nested array keys like $opcache_status[‘memory_usage’][‘used_memory’], $opcache_status[‘memory_usage’][‘free_memory’], and $opcache_status[‘opcache_statistics’][‘opcache_hit_rate’] without verifying they exist. Add isset() checks for these nested keys to prevent undefined array key warnings if the opcache_get_status() structure is incomplete or unexpected.
| $fields[‘opcode_cache_memory_usage‘] = array( | |
| ‘label‘ => __( ‘Opcode cache memory usage‘ ), | |
| ‘value‘ => sprintf( | |
| /* translators: 1: Used memory, 2: Total memory */ | |
| __( ‘%1$s of %2$s‘ ), | |
| size_format( $opcache_status[‘memory_usage‘][‘used_memory‘] ), | |
| size_format( $opcache_status[‘memory_usage‘][‘free_memory‘] + $opcache_status[‘memory_usage‘][‘used_memory‘] ) | |
| ), | |
| ‘debug‘ => sprintf( | |
| ‘%s of %s‘, | |
| $opcache_status[‘memory_usage‘][‘used_memory‘], | |
| $opcache_status[‘memory_usage‘][‘free_memory‘] + $opcache_status[‘memory_usage‘][‘used_memory‘] | |
| ), | |
| ); | |
| $fields[‘opcode_cache_hit_rate‘] = array( | |
| ‘label‘ => __( ‘Opcode cache hit rate‘ ), | |
| ‘value‘ => sprintf( | |
| /* translators: %s: Hit rate percentage */ | |
| __( ‘%s%%‘ ), | |
| round( $opcache_status[‘opcache_statistics‘][‘opcache_hit_rate‘], 2 ) | |
| ), | |
| ‘debug‘ => $opcache_status[‘opcache_statistics‘][‘opcache_hit_rate‘], | |
| ); | |
| if ( isset( $opcache_status[‘memory_usage‘][‘used_memory‘], $opcache_status[‘memory_usage‘][‘free_memory‘] ) ) { | |
| $fields[‘opcode_cache_memory_usage‘] = array( | |
| ‘label‘ => __( ‘Opcode cache memory usage‘ ), | |
| ‘value‘ => sprintf( | |
| /* translators: 1: Used memory, 2: Total memory */ | |
| __( ‘%1$s of %2$s‘ ), | |
| size_format( $opcache_status[‘memory_usage‘][‘used_memory‘] ), | |
| size_format( $opcache_status[‘memory_usage‘][‘free_memory‘] + $opcache_status[‘memory_usage‘][‘used_memory‘] ) | |
| ), | |
| ‘debug‘ => sprintf( | |
| ‘%s of %s‘, | |
| $opcache_status[‘memory_usage‘][‘used_memory‘], | |
| $opcache_status[‘memory_usage‘][‘free_memory‘] + $opcache_status[‘memory_usage‘][‘used_memory‘] | |
| ), | |
| ); | |
| } | |
| if ( isset( $opcache_status[‘opcache_statistics‘][‘opcache_hit_rate‘] ) ) { | |
| $fields[‘opcode_cache_hit_rate‘] = array( | |
| ‘label‘ => __( ‘Opcode cache hit rate‘ ), | |
| ‘value‘ => sprintf( | |
| /* translators: %s: Hit rate percentage */ | |
| __( ‘%s%%‘ ), | |
| round( $opcache_status[‘opcache_statistics‘][‘opcache_hit_rate‘], 2 ) | |
| ), | |
| ‘debug‘ => $opcache_status[‘opcache_statistics‘][‘opcache_hit_rate‘], | |
| ); | |
| } |



This PR adds OPCache information to the Site Health Info page so administrators can see how their PHP OPcache is performing.
The code checks if OPcache is available using
extension_loaded('opcache'), then gets detailed status usingopcache_get_status(). It displays both user-friendly formatted values and debug information for copying to clipboard. All text is properly internationalized and follows WordPress coding standards.Trac ticket: https://core.trac.wordpress.org/ticket/63697
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.