Changeset 54043 for trunk/src/wp-admin/includes/class-wp-site-health.php
- Timestamp:
- 08/31/2022 10:44:04 PM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-admin/includes/class-wp-site-health.php
r54042 r54043 1668 1668 1669 1669 /** 1670 * Tests if a full page cache is available. 1671 * 1672 * @since 6.1.0 1673 * 1674 * @return array The test result. 1675 */ 1676 public function get_test_page_cache() { 1677 $description = '<p>' . __( 'Page cache enhances the speed and performance of your site by saving and serving static pages instead of calling for a page every time a user visits.' ) . '</p>'; 1678 $description .= '<p>' . __( 'Page cache is detected by looking for an active page cache plugin as well as making three requests to the homepage and looking for one or more of the following HTTP client caching response headers:' ) . '</p>'; 1679 $description .= '<code>' . implode( '</code>, <code>', array_keys( $this->get_page_cache_headers() ) ) . '.</code>'; 1680 1681 $result = array( 1682 'badge' => array( 1683 'label' => __( 'Performance' ), 1684 'color' => 'blue', 1685 ), 1686 'description' => wp_kses_post( $description ), 1687 'test' => 'page_cache', 1688 'status' => 'good', 1689 'label' => '', 1690 'actions' => sprintf( 1691 '<p><a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s <span class="screen-reader-text">%3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>', 1692 __( 'https://wordpress.org/support/article/optimization/#Caching' ), 1693 __( 'Learn more about page cache' ), 1694 /* translators: Accessibility text. */ 1695 __( '(opens in a new tab)' ) 1696 ), 1697 ); 1698 1699 $page_cache_detail = $this->get_page_cache_detail(); 1700 1701 if ( is_wp_error( $page_cache_detail ) ) { 1702 $result['label'] = __( 'Unable to detect the presence of page cache' ); 1703 $result['status'] = 'recommended'; 1704 $error_info = sprintf( 1705 /* translators: 1 is error message, 2 is error code */ 1706 __( 'Unable to detect page cache due to possible loopback request problem. Please verify that the loopback request test is passing. Error: %1$s (Code: %2$s)' ), 1707 $page_cache_detail->get_error_message(), 1708 $page_cache_detail->get_error_code() 1709 ); 1710 $result['description'] = wp_kses_post( "<p>$error_info</p>" ) . $result['description']; 1711 return $result; 1712 } 1713 1714 $result['status'] = $page_cache_detail['status']; 1715 1716 switch ( $page_cache_detail['status'] ) { 1717 case 'recommended': 1718 $result['label'] = __( 'Page cache is not detected but the server response time is OK' ); 1719 break; 1720 case 'good': 1721 $result['label'] = __( 'Page cache is detected and the server response time is good' ); 1722 break; 1723 default: 1724 if ( empty( $page_cache_detail['headers'] ) && ! $page_cache_detail['advanced_cache_present'] ) { 1725 $result['label'] = __( 'Page cache is not detected and the server response time is slow' ); 1726 } else { 1727 $result['label'] = __( 'Page cache is detected but the server response time is still slow' ); 1728 } 1729 } 1730 1731 $page_cache_test_summary = array(); 1732 1733 if ( empty( $page_cache_detail['response_time'] ) ) { 1734 $page_cache_test_summary[] = '<span class="dashicons dashicons-dismiss"></span> ' . __( 'Server response time could not be determined. Verify that loopback requests are working.' ); 1735 } else { 1736 1737 $threshold = $this->get_good_response_time_threshold(); 1738 if ( $page_cache_detail['response_time'] < $threshold ) { 1739 $page_cache_test_summary[] = '<span class="dashicons dashicons-yes-alt"></span> ' . sprintf( 1740 /* translators: 1: The response time in milliseconds. 2: The recommended threshold milliseconds. */ 1741 __( 'Median server response time was %1$s milliseconds. This is less than the recommended %2$s milliseconds threshold.' ), 1742 number_format_i18n( $page_cache_detail['response_time'] ), 1743 number_format_i18n( $threshold ) 1744 ); 1745 } else { 1746 $page_cache_test_summary[] = '<span class="dashicons dashicons-warning"></span> ' . sprintf( 1747 /* translators: 1: The response time in milliseconds. 2: The recommended threshold milliseconds. */ 1748 __( 'Median server response time was %1$s milliseconds. It should be less than the recommended %2$s milliseconds threshold.' ), 1749 number_format_i18n( $page_cache_detail['response_time'] ), 1750 number_format_i18n( $threshold ) 1751 ); 1752 } 1753 1754 if ( empty( $page_cache_detail['headers'] ) ) { 1755 $page_cache_test_summary[] = '<span class="dashicons dashicons-warning"></span> ' . __( 'No client caching response headers were detected.' ); 1756 } else { 1757 $headers_summary = '<span class="dashicons dashicons-yes-alt"></span>'; 1758 $headers_summary .= sprintf( 1759 /* translators: Placeholder is number of caching headers */ 1760 _n( 1761 ' There was %d client caching response header detected: ', 1762 ' There were %d client caching response headers detected: ', 1763 count( $page_cache_detail['headers'] ) 1764 ), 1765 count( $page_cache_detail['headers'] ) 1766 ); 1767 $headers_summary .= '<code>' . implode( '</code>, <code>', $page_cache_detail['headers'] ) . '</code>.'; 1768 $page_cache_test_summary[] = $headers_summary; 1769 } 1770 } 1771 1772 if ( $page_cache_detail['advanced_cache_present'] ) { 1773 $page_cache_test_summary[] = '<span class="dashicons dashicons-yes-alt"></span> ' . __( 'A page cache plugin was detected.' ); 1774 } elseif ( ! ( is_array( $page_cache_detail ) && ! empty( $page_cache_detail['headers'] ) ) ) { 1775 // Note: This message is not shown if client caching response headers were present since an external caching layer may be employed. 1776 $page_cache_test_summary[] = '<span class="dashicons dashicons-warning"></span> ' . __( 'A page cache plugin was not detected.' ); 1777 } 1778 1779 $result['description'] .= '<ul><li>' . implode( '</li><li>', $page_cache_test_summary ) . '</li></ul>'; 1780 return $result; 1781 } 1782 1783 /** 1670 1784 * Check if the HTTP API can handle SSL/TLS requests. 1671 1785 * 1672 1786 * @since 5.2.0 1673 1787 * 1674 * @return array The test result s.1788 * @return array The test result. 1675 1789 */ 1676 1790 public function get_test_ssl_support() { … … 2483 2597 } 2484 2598 2485 // Only check for a persistent object cache in production environments to not unnecessarily promote complicated setups.2599 // Only check for caches in production environments. 2486 2600 if ( 'production' === wp_get_environment_type() ) { 2601 $tests['async']['page_cache'] = array( 2602 'label' => __( 'Page cache' ), 2603 'test' => rest_url( 'wp-site-health/v1/tests/page-cache' ), 2604 'has_rest' => true, 2605 'async_direct_test' => array( WP_Site_Health::get_instance(), 'get_test_page_cache' ), 2606 ); 2607 2487 2608 $tests['direct']['persistent_object_cache'] = array( 2488 2609 'label' => __( 'Persistent object cache' ), … … 2967 3088 2968 3089 /** 3090 * Returns a list of headers and its verification callback to verify if page cache is enabled or not. 3091 * 3092 * Note: key is header name and value could be callable function to verify header value. 3093 * Empty value mean existence of header detect page cache is enabled. 3094 * 3095 * @since 6.1.0 3096 * 3097 * @return array List of client caching headers and their (optional) verification callbacks. 3098 */ 3099 public function get_page_cache_headers() { 3100 3101 $cache_hit_callback = static function ( $header_value ) { 3102 return false !== strpos( strtolower( $header_value ), 'hit' ); 3103 }; 3104 3105 $cache_headers = array( 3106 'cache-control' => static function ( $header_value ) { 3107 return (bool) preg_match( '/max-age=[1-9]/', $header_value ); 3108 }, 3109 'expires' => static function ( $header_value ) { 3110 return strtotime( $header_value ) > time(); 3111 }, 3112 'age' => static function ( $header_value ) { 3113 return is_numeric( $header_value ) && $header_value > 0; 3114 }, 3115 'last-modified' => '', 3116 'etag' => '', 3117 'x-cache-enabled' => static function ( $header_value ) { 3118 return 'true' === strtolower( $header_value ); 3119 }, 3120 'x-cache-disabled' => static function ( $header_value ) { 3121 return ( 'on' !== strtolower( $header_value ) ); 3122 }, 3123 'x-srcache-store-status' => $cache_hit_callback, 3124 'x-srcache-fetch-status' => $cache_hit_callback, 3125 ); 3126 3127 /** 3128 * Filters the list of cache headers supported by core. 3129 * 3130 * @since 6.1.0 3131 * 3132 * @param int $cache_headers Array of supported cache headers. 3133 */ 3134 return apply_filters( 'site_status_page_cache_supported_cache_headers', $cache_headers ); 3135 } 3136 3137 /** 3138 * Checks if site has page cache enabled or not. 3139 * 3140 * @since 6.1.0 3141 * 3142 * @return WP_Error|array { 3143 * Page cache detection details or else error information. 3144 * 3145 * @type bool $advanced_cache_present Whether a page cache plugin is present. 3146 * @type array[] $page_caching_response_headers Sets of client caching headers for the responses. 3147 * @type float[] $response_timing Response timings. 3148 * } 3149 */ 3150 private function check_for_page_caching() { 3151 3152 /** This filter is documented in wp-includes/class-wp-http-streams.php */ 3153 $sslverify = apply_filters( 'https_local_ssl_verify', false ); 3154 3155 $headers = array(); 3156 3157 // Include basic auth in loopback requests. Note that this will only pass along basic auth when user is 3158 // initiating the test. If a site requires basic auth, the test will fail when it runs in WP Cron as part of 3159 // wp_site_health_scheduled_check. This logic is copied from WP_Site_Health::can_perform_loopback(). 3160 if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) { 3161 $headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) ); 3162 } 3163 3164 $caching_headers = $this->get_page_cache_headers(); 3165 $page_caching_response_headers = array(); 3166 $response_timing = array(); 3167 3168 for ( $i = 1; $i <= 3; $i++ ) { 3169 $start_time = microtime( true ); 3170 $http_response = wp_remote_get( home_url( '/' ), compact( 'sslverify', 'headers' ) ); 3171 $end_time = microtime( true ); 3172 3173 if ( is_wp_error( $http_response ) ) { 3174 return $http_response; 3175 } 3176 if ( wp_remote_retrieve_response_code( $http_response ) !== 200 ) { 3177 return new WP_Error( 3178 'http_' . wp_remote_retrieve_response_code( $http_response ), 3179 wp_remote_retrieve_response_message( $http_response ) 3180 ); 3181 } 3182 3183 $response_headers = array(); 3184 3185 foreach ( $caching_headers as $header => $callback ) { 3186 $header_values = wp_remote_retrieve_header( $http_response, $header ); 3187 if ( empty( $header_values ) ) { 3188 continue; 3189 } 3190 $header_values = (array) $header_values; 3191 if ( empty( $callback ) || ( is_callable( $callback ) && count( array_filter( $header_values, $callback ) ) > 0 ) ) { 3192 $response_headers[ $header ] = $header_values; 3193 } 3194 } 3195 3196 $page_caching_response_headers[] = $response_headers; 3197 $response_timing[] = ( $end_time - $start_time ) * 1000; 3198 } 3199 3200 return array( 3201 'advanced_cache_present' => ( 3202 file_exists( WP_CONTENT_DIR . '/advanced-cache.php' ) 3203 && 3204 ( defined( 'WP_CACHE' ) && WP_CACHE ) 3205 && 3206 /** This filter is documented in wp-settings.php */ 3207 apply_filters( 'enable_loading_advanced_cache_dropin', true ) 3208 ), 3209 'page_caching_response_headers' => $page_caching_response_headers, 3210 'response_timing' => $response_timing, 3211 ); 3212 } 3213 3214 /** 3215 * Get page cache details. 3216 * 3217 * @since 6.1.0 3218 * 3219 * @return WP_Error|array { 3220 * Page cache detail or else a WP_Error if unable to determine. 3221 * 3222 * @type string $status Page cache status. Good, Recommended or Critical. 3223 * @type bool $advanced_cache_present Whether page cache plugin is available or not. 3224 * @type string[] $headers Client caching response headers detected. 3225 * @type float $response_time Response time of site. 3226 * } 3227 */ 3228 private function get_page_cache_detail() { 3229 $page_cache_detail = $this->check_for_page_caching(); 3230 if ( is_wp_error( $page_cache_detail ) ) { 3231 return $page_cache_detail; 3232 } 3233 3234 // Use the median server response time. 3235 $response_timings = $page_cache_detail['response_timing']; 3236 rsort( $response_timings ); 3237 $page_speed = $response_timings[ floor( count( $response_timings ) / 2 ) ]; 3238 3239 // Obtain unique set of all client caching response headers. 3240 $headers = array(); 3241 foreach ( $page_cache_detail['page_caching_response_headers'] as $page_caching_response_headers ) { 3242 $headers = array_merge( $headers, array_keys( $page_caching_response_headers ) ); 3243 } 3244 $headers = array_unique( $headers ); 3245 3246 // Page cache is detected if there are response headers or a page cache plugin is present. 3247 $has_page_caching = ( count( $headers ) > 0 || $page_cache_detail['advanced_cache_present'] ); 3248 3249 if ( $page_speed && $page_speed < $this->get_good_response_time_threshold() ) { 3250 $result = $has_page_caching ? 'good' : 'recommended'; 3251 } else { 3252 $result = 'critical'; 3253 } 3254 3255 return array( 3256 'status' => $result, 3257 'advanced_cache_present' => $page_cache_detail['advanced_cache_present'], 3258 'headers' => $headers, 3259 'response_time' => $page_speed, 3260 ); 3261 } 3262 3263 /** 3264 * Get the threshold below which a response time is considered good. 3265 * 3266 * @since 6.1.0 3267 * 3268 * @return int Threshold in milliseconds. 3269 */ 3270 private function get_good_response_time_threshold() { 3271 /** 3272 * Filters the threshold below which a response time is considered good. 3273 * 3274 * The default is based on https://web.dev/time-to-first-byte/. 3275 * 3276 * @param int $threshold Threshold in milliseconds. Default 600. 3277 * 3278 * @since 6.1.0 3279 */ 3280 return (int) apply_filters( 'site_status_good_response_time_threshold', 600 ); 3281 } 3282 3283 /** 2969 3284 * Determines whether to suggest using a persistent object cache. 2970 3285 *
Note: See TracChangeset
for help on using the changeset viewer.