-
Notifications
You must be signed in to change notification settings - Fork 138
Add Site Health check module for persistent object cache #111
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
+298
−0
Merged
Changes from 38 commits
Commits
Show all changes
48 commits
Select commit
Hold shift + click to select a range
2f7c803
initial code import
tillkruss 348fff5
use existing page; still needs section
tillkruss b6a1cc3
add some basic criteria
tillkruss 60d3862
make it easy to add a thresholds filter later on
tillkruss 8894446
please the formatting gods
tillkruss 234c048
detect object cache services
tillkruss ae1d6f7
please the gods again
tillkruss 4f89ffe
be more verbal
tillkruss bc01b45
refine 2nd part of the description
tillkruss 07f12a3
Update load.php
tillkruss 24cb869
revert debug value
tillkruss c880585
drop the word persistent
tillkruss ce40e36
docblock fixes; since tags; coding standards
tillkruss a0201f6
docblocks
tillkruss 21af177
fix filter ref
tillkruss 8d2d709
add more since tags
tillkruss 02f1094
tweak copy
tillkruss 5f51a6f
fix function name
tillkruss e3bd858
turn conditions into single loop
tillkruss af3dd69
allow easy bypass of expensive calls
tillkruss 64e4806
made thresholds filterable
tillkruss 6f4d1ce
sort
tillkruss 52c59ce
code styling
tillkruss 0114f3d
remove debug
tillkruss 839aad4
make badge orange when recommended
tillkruss afd077c
dump ci tests
tillkruss 9135d33
inital tests
tillkruss eec2d40
gte
tillkruss 38c1767
add alloptions tests
tillkruss aca709a
only run check in production
tillkruss 80d8a8c
added missing since tags
tillkruss 25e040c
document return values
tillkruss 2e38169
update module name; rename slug
tillkruss 831c85c
use long slug
tillkruss c992a7c
prefix functions with `perflab_oc_*`
tillkruss 3502b28
prefix all filters
tillkruss 5440969
use prefixed names in tests
tillkruss db8994f
fix test
tillkruss a83ae10
Update modules/object-cache/persistent-object-cache-health-check/load…
tillkruss fb4e749
Update modules/object-cache/persistent-object-cache-health-check/load…
tillkruss fd07b49
Update modules/object-cache/persistent-object-cache-health-check/load…
tillkruss 873dc12
simplify filter logic
tillkruss 1ea68fd
update tests
tillkruss ea06461
spacing
tillkruss badede0
Update modules/object-cache/persistent-object-cache-health-check/load…
tillkruss 6291513
simplify tests
tillkruss 0390c3a
formatting
tillkruss bbf79d8
remove useless vars from tests
tillkruss 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
252 changes: 252 additions & 0 deletions
252
modules/object-cache/persistent-object-cache-health-check/load.php
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,252 @@ | ||
| <?php | ||
| /** | ||
| * Module Name: Persistent Object Cache Health Check | ||
| * Description: Recommend a persistent object cache for sites with non-trivial amounts of data. | ||
| * Experimental: No | ||
| * | ||
| * @package performance-lab | ||
| * @since 1.0.0 | ||
| */ | ||
|
|
||
| /** | ||
| * Adds a health check testing for and suggesting a persistent object cache backend. | ||
| * | ||
| * @since 1.0.0 | ||
| * | ||
| * @param array $tests An associative array of direct and asynchronous tests. | ||
| * @return array An associative array of direct and asynchronous tests. | ||
| */ | ||
| function perflab_oc_health_add_tests( $tests ) { | ||
| if ( wp_get_environment_type() === 'production' ) { | ||
| $tests['direct']['persistent_object_cache'] = array( | ||
| 'label' => 'persistent_object_cache', | ||
| 'test' => 'perflab_oc_health_persistent_object_cache', | ||
| ); | ||
| } | ||
|
|
||
| return $tests; | ||
| } | ||
| add_filter( 'site_status_tests', 'perflab_oc_health_add_tests' ); | ||
|
|
||
| /** | ||
| * Callback for `persistent_object_cache` health check. | ||
| * | ||
| * @since 1.0.0 | ||
| * | ||
| * @return array The health check result suggesting persistent object caching. | ||
| */ | ||
| function perflab_oc_health_persistent_object_cache() { | ||
| /** | ||
| * Filter the action URL for the persistent object cache health check. | ||
| * | ||
| * @since 1.0.0 | ||
| * | ||
| * @param string $action_url Learn more link for persistent object cache health check. | ||
| */ | ||
| $action_url = apply_filters( | ||
| 'perflab_oc_site_status_persistent_object_cache_url', | ||
| /* translators: Localized Support reference. */ | ||
| __( 'https://wordpress.org/support/article/optimization/#object-caching', 'performance-lab' ) | ||
| ); | ||
|
|
||
| $result = array( | ||
| 'test' => 'persistent_object_cache', | ||
| 'status' => 'good', | ||
| 'badge' => array( | ||
| 'label' => __( 'Performance', 'performance-lab' ), | ||
| 'color' => 'blue', | ||
| ), | ||
| 'description' => sprintf( | ||
| '<p>%s</p>', | ||
| __( "WordPress performs at its best when a persistent object cache is used. A persistent object cache helps to reduce load on your SQL server significantly and allows WordPress to retrieve your site's content and settings much faster.", 'performance-lab' ) | ||
| ), | ||
| 'actions' => sprintf( | ||
| '<p><a href="%s" target="_blank" rel="noopener">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>', | ||
| esc_url( $action_url ), | ||
| __( 'Learn more about persistent object caching.', 'performance-lab' ), | ||
| /* translators: Accessibility text. */ | ||
| __( '(opens in a new tab)', 'performance-lab' ) | ||
| ), | ||
| ); | ||
|
|
||
| if ( wp_using_ext_object_cache() ) { | ||
| $result['label'] = __( 'A persistent object cache is being used', 'performance-lab' ); | ||
|
|
||
| return $result; | ||
| } | ||
|
|
||
| /** | ||
| * Filter whether to suggest using a persistent object cache. | ||
| * | ||
| * Plugin and theme authors should NOT use this filter to discourage the use of an object cache. | ||
| * | ||
| * @since 1.0.0 | ||
| * | ||
| * @param bool $suggest Whether to suggest using a persistent object cache. | ||
| */ | ||
| if ( ! apply_filters( 'perflab_oc_site_status_suggest_persistent_object_cache', false ) ) { | ||
tillkruss marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| $result['label'] = __( 'A persistent object cache is not required', 'performance-lab' ); | ||
|
|
||
| return $result; | ||
| } | ||
|
|
||
| $available_services = perflab_oc_health_available_object_cache_services(); | ||
|
|
||
| $notes = __( 'Speak to your web host about what persistent object caches are available and how to enable them.', 'performance-lab' ); | ||
|
|
||
| if ( ! empty( $available_services ) ) { | ||
| $notes .= sprintf( | ||
| /* translators: Available object caching services. */ | ||
| __( ' Your host appears to support the following object caching services: %s.', 'performance-lab' ), | ||
| implode( ', ', $available_services ) | ||
| ); | ||
tillkruss marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| /** | ||
| * Filter the second paragraph of the health check's description | ||
| * when suggesting the use of a persistent object cache. | ||
| * | ||
| * Hosts may want to replace the notes to recommend their preferred object caching solution. | ||
| * | ||
| * Plugin authors may want to append notes (not replace) on why object caching is recommended for their plugin. | ||
| * | ||
| * @since 1.0.0 | ||
| * | ||
| * @param string $notes The notes appended to the health check description. | ||
| * @param array $available_services The list of available persistent object cache services. | ||
tillkruss marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| */ | ||
| $notes = apply_filters( 'perflab_oc_site_status_persistent_object_cache_notes', $notes, $available_services ); | ||
|
|
||
| $result['status'] = 'recommended'; | ||
| $result['label'] = __( 'You should use a persistent object cache', 'performance-lab' ); | ||
| $result['badge']['color'] = 'orange'; | ||
| $result['description'] .= sprintf( | ||
| '<p>%s</p>', | ||
| wp_kses( | ||
| $notes, | ||
| array( | ||
| 'a' => array( 'href' => true ), | ||
| 'code' => true, | ||
| 'em' => true, | ||
| 'strong' => true, | ||
| ) | ||
| ) | ||
| ); | ||
|
|
||
| return $result; | ||
| } | ||
|
|
||
| /** | ||
| * Callback for `site_status_persistent_object_cache` filter. | ||
| * | ||
| * Determines whether to suggest using a persistent object cache. | ||
tillkruss marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * | ||
| * @since 1.0.0 | ||
| * | ||
| * @param mixed $should_suggest Whether to suggest using a persistent object cache. | ||
| * @return bool Whether to suggest using a persistent object cache. | ||
| */ | ||
| function perflab_oc_health_should_persistent_object_cache( $should_suggest ) { | ||
| global $wpdb; | ||
|
|
||
| // Bypass expensive calls if `$should_suggest` was already set truthy. | ||
| if ( $should_suggest ) { | ||
| return true; | ||
| } | ||
tillkruss marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /** | ||
| * Filter the thresholds used to determine whether to suggest the use of a persistent object cache. | ||
| * | ||
| * @since 1.0.0 | ||
| * | ||
| * @param array $thresholds The list of threshold names and numbers. | ||
| */ | ||
| $thresholds = apply_filters( | ||
| 'perflab_oc_site_status_persistent_object_cache_thresholds', | ||
| array( | ||
| 'alloptions_count' => 500, | ||
| 'alloptions_bytes' => 100000, | ||
| 'comments_count' => 1000, | ||
| 'options_count' => 1000, | ||
| 'posts_count' => 1000, | ||
| 'terms_count' => 1000, | ||
| 'users_count' => 1000, | ||
| ) | ||
| ); | ||
|
|
||
| $alloptions = wp_load_alloptions(); | ||
|
|
||
| if ( $thresholds['alloptions_count'] < count( $alloptions ) ) { | ||
| return true; | ||
| } | ||
|
|
||
| if ( $thresholds['alloptions_bytes'] < strlen( serialize( $alloptions ) ) ) { | ||
| return true; | ||
| } | ||
|
|
||
| $table_names = implode( "','", array( $wpdb->comments, $wpdb->options, $wpdb->posts, $wpdb->terms, $wpdb->users ) ); | ||
|
|
||
| // With InnoDB the `TABLE_ROWS` are estimates, which are accurate enough and faster to retrieve than individual `COUNT()` queries. | ||
| $results = $wpdb->get_results( | ||
| $wpdb->prepare( | ||
| // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared | ||
| "SELECT TABLE_NAME AS 'table', TABLE_ROWS AS 'rows', SUM(data_length + index_length) as 'bytes' | ||
| FROM information_schema.TABLES | ||
| WHERE TABLE_SCHEMA = %s | ||
| AND TABLE_NAME IN ('$table_names') | ||
| GROUP BY TABLE_NAME;", | ||
| // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared | ||
| DB_NAME | ||
| ), | ||
| OBJECT_K | ||
| ); | ||
|
|
||
| $threshold_map = array( | ||
| 'comments_count' => $wpdb->comments, | ||
| 'options_count' => $wpdb->options, | ||
| 'posts_count' => $wpdb->posts, | ||
| 'terms_count' => $wpdb->terms, | ||
| 'users_count' => $wpdb->users, | ||
| ); | ||
|
|
||
| foreach ( $threshold_map as $threshold => $table ) { | ||
| if ( $thresholds[ $threshold ] <= $results[ $table ]->rows ) { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
| add_filter( 'perflab_oc_site_status_suggest_persistent_object_cache', 'perflab_oc_health_should_persistent_object_cache', 20 ); | ||
|
|
||
| /** | ||
| * Returns a list of available persistent object cache services. | ||
| * | ||
| * @since 1.0.0 | ||
| * | ||
| * @return array The list of available persistent object cache services. | ||
| */ | ||
| function perflab_oc_health_available_object_cache_services() { | ||
| $extensions = array_map( | ||
| 'extension_loaded', | ||
| array( | ||
| 'APCu' => 'apcu', | ||
| 'Redis' => 'redis', | ||
| 'Relay' => 'relay', | ||
| 'Memcached' => 'memcache', // The `memcached` extension seems unmaintained. | ||
| ) | ||
| ); | ||
|
|
||
| $services = array_keys( array_filter( $extensions ) ); | ||
|
|
||
| /** | ||
| * Filter the persistent object cache services available to the user. | ||
| * | ||
| * This can be useful to hide or add services not included in the defaults. | ||
| * | ||
| * @since 1.0.0 | ||
| * | ||
| * @param array $services The list of available persistent object cache services. | ||
| */ | ||
| return apply_filters( 'perflab_oc_site_status_available_object_cache_services', $services ); | ||
| } | ||
142 changes: 142 additions & 0 deletions
142
tests/modules/object-cache/persistent-object-cache-health-check/health-check-test.php
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,142 @@ | ||
| <?php | ||
| /** | ||
| * Tests for persistent-object-cache-health-check module. | ||
| * | ||
| * @package performance-lab | ||
| * @group persistent-object-cache-health-check | ||
| */ | ||
|
|
||
| class Object_Cache_Health_Check_Tests extends WP_UnitTestCase { | ||
|
|
||
| function test_object_cache_thresholds_check_is_bypassed() { | ||
| $bypassed = true; | ||
|
|
||
| add_filter( | ||
| 'perflab_oc_site_status_persistent_object_cache_thresholds', | ||
| function ( $thresholds ) use ( $bypassed ) { | ||
| $bypassed = false; | ||
|
|
||
| return $thresholds; | ||
| } | ||
| ); | ||
|
|
||
| $result = perflab_oc_health_should_persistent_object_cache( true ); | ||
|
|
||
| $this->assertTrue( $result ); | ||
| $this->assertTrue( $bypassed ); | ||
|
|
||
| remove_all_filters( 'perflab_oc_site_status_persistent_object_cache_thresholds' ); | ||
tillkruss marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| function test_object_cache_default_thresholds() { | ||
| $result = perflab_oc_health_should_persistent_object_cache( false ); | ||
|
|
||
| $this->assertFalse( $result ); | ||
| } | ||
|
|
||
| function test_object_cache_comments_threshold() { | ||
| add_filter( | ||
| 'perflab_oc_site_status_persistent_object_cache_thresholds', | ||
| function ( $thresholds ) { | ||
| return array_merge( $thresholds, array( 'comments_count' => 0 ) ); | ||
| } | ||
| ); | ||
|
|
||
| $result = perflab_oc_health_should_persistent_object_cache( false ); | ||
|
|
||
| $this->assertTrue( $result ); | ||
|
|
||
| remove_all_filters( 'perflab_oc_site_status_persistent_object_cache_thresholds' ); | ||
| } | ||
|
|
||
| function test_object_cache_posts_threshold() { | ||
| add_filter( | ||
| 'perflab_oc_site_status_persistent_object_cache_thresholds', | ||
| function ( $thresholds ) { | ||
| return array_merge( $thresholds, array( 'posts_count' => 0 ) ); | ||
| } | ||
| ); | ||
|
|
||
| $result = perflab_oc_health_should_persistent_object_cache( false ); | ||
|
|
||
| $this->assertTrue( $result ); | ||
|
|
||
| remove_all_filters( 'perflab_oc_site_status_persistent_object_cache_thresholds' ); | ||
| } | ||
|
|
||
| function test_object_cache_terms_threshold() { | ||
| add_filter( | ||
| 'perflab_oc_site_status_persistent_object_cache_thresholds', | ||
| function ( $thresholds ) { | ||
| return array_merge( $thresholds, array( 'terms_count' => 1 ) ); | ||
| } | ||
| ); | ||
|
|
||
| $result = perflab_oc_health_should_persistent_object_cache( false ); | ||
|
|
||
| $this->assertTrue( $result ); | ||
|
|
||
| remove_all_filters( 'perflab_oc_site_status_persistent_object_cache_thresholds' ); | ||
| } | ||
|
|
||
| function test_object_cache_options_threshold() { | ||
| add_filter( | ||
| 'perflab_oc_site_status_persistent_object_cache_thresholds', | ||
| function ( $thresholds ) { | ||
| return array_merge( $thresholds, array( 'options_count' => 100 ) ); | ||
| } | ||
| ); | ||
|
|
||
| $result = perflab_oc_health_should_persistent_object_cache( false ); | ||
|
|
||
| $this->assertTrue( $result ); | ||
|
|
||
| remove_all_filters( 'perflab_oc_site_status_persistent_object_cache_thresholds' ); | ||
| } | ||
|
|
||
| function test_object_cache_users_threshold() { | ||
| add_filter( | ||
| 'perflab_oc_site_status_persistent_object_cache_thresholds', | ||
| function ( $thresholds ) { | ||
| return array_merge( $thresholds, array( 'users_count' => 0 ) ); | ||
| } | ||
| ); | ||
|
|
||
| $result = perflab_oc_health_should_persistent_object_cache( false ); | ||
|
|
||
| $this->assertTrue( $result ); | ||
|
|
||
| remove_all_filters( 'perflab_oc_site_status_persistent_object_cache_thresholds' ); | ||
| } | ||
|
|
||
| function test_object_cache_alloptions_count_threshold() { | ||
| add_filter( | ||
| 'perflab_oc_site_status_persistent_object_cache_thresholds', | ||
| function ( $thresholds ) { | ||
| return array_merge( $thresholds, array( 'alloptions_count' => 100 ) ); | ||
| } | ||
| ); | ||
|
|
||
| $result = perflab_oc_health_should_persistent_object_cache( false ); | ||
|
|
||
| $this->assertTrue( $result ); | ||
|
|
||
| remove_all_filters( 'perflab_oc_site_status_persistent_object_cache_thresholds' ); | ||
| } | ||
|
|
||
| function test_object_cache_alloptions_bytes_threshold() { | ||
| add_filter( | ||
| 'perflab_oc_site_status_persistent_object_cache_thresholds', | ||
| function ( $thresholds ) { | ||
| return array_merge( $thresholds, array( 'alloptions_bytes' => 1000 ) ); | ||
| } | ||
| ); | ||
|
|
||
| $result = perflab_oc_health_should_persistent_object_cache( false ); | ||
|
|
||
| $this->assertTrue( $result ); | ||
|
|
||
| remove_all_filters( 'perflab_oc_site_status_persistent_object_cache_thresholds' ); | ||
| } | ||
|
|
||
| } | ||
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.
Uh oh!
There was an error while loading. Please reload this page.