display name. */ public static function known_plugins() { return array( 'breeze/' => 'Breeze / Cloudways cache', 'litespeed-cache/' => 'LiteSpeed Cache', 'wp-rocket/' => 'WP Rocket', 'w3-total-cache/' => 'W3 Total Cache', 'wp-super-cache/' => 'WP Super Cache', 'sg-cachepress/' => 'SiteGround Optimizer', 'cloudflare/' => 'Cloudflare plugin', 'wp-cloudflare-page-cache/' => 'Cloudflare page cache plugin', 'cache-enabler/' => 'Cache Enabler', 'wp-fastest-cache/' => 'WP Fastest Cache', 'hummingbird-performance/' => 'Hummingbird', 'nitropack/' => 'NitroPack', 'swift-performance-lite/' => 'Swift Performance', 'surge/' => 'Surge', ); } /** * Caching plugins active on this site. * * @return string[] */ public static function active_plugins() { $active = (array) get_option( 'active_plugins', array() ); if ( is_multisite() ) { $active = array_merge( $active, array_keys( (array) get_site_option( 'active_sitewide_plugins', array() ) ) ); } $found = array(); foreach ( $active as $plugin ) { foreach ( self::known_plugins() as $needle => $label ) { if ( false !== stripos( (string) $plugin, $needle ) ) { $found[] = $label; } } } return array_values( array_unique( $found ) ); } /** * Every caching layer that can be identified from inside WordPress. * * A managed host's cache and a CDN edge are not plugins, so neither appears * in the plugin list. They are identifiable by the constants the host defines * and, for Cloudflare, by the headers on the request being served right now. * * @return string[] */ public static function detect() { $layers = self::active_plugins(); $host_constants = array( 'KINSTA_CACHE_ZONE' => 'Kinsta edge cache', 'WPE_APIKEY' => 'WP Engine cache', 'IS_PRESSABLE' => 'Pressable cache', 'SPINUPWP_CACHE' => 'SpinupWP page cache', 'FLYWHEEL_CONFIG_DIR' => 'Flywheel cache', 'GD_SYSTEM_PLUGIN_DIR' => 'GoDaddy managed cache', ); foreach ( $host_constants as $constant => $label ) { if ( defined( $constant ) ) { $layers[] = $label; } } // Set by Cloudflare on every request it proxies. if ( isset( $_SERVER['HTTP_CF_RAY'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- reading the presence of a proxy header, not acting on user input. $layers[] = 'Cloudflare'; } /* * WP_CACHE is set by several caching plugins in wp-config.php and can * outlive the plugin that set it. It is reported only when nothing more * specific was found, since on its own it says a cache was configured * here at some point, not which one is running. */ if ( empty( $layers ) && defined( 'WP_CACHE' ) && WP_CACHE ) { $layers[] = __( 'a page cache (WP_CACHE is on)', 'ai-o-optimiser' ); } $layers = array_values( array_unique( $layers ) ); /** * Filter the caching layers named on the Visibility dashboard. * * Use this for a host or edge cache this plugin cannot see from inside * WordPress. * * @param string[] $layers Detected layer names. */ $filtered = apply_filters( 'ai_o_optimiser_cache_layers', $layers ); return is_array( $filtered ) ? array_values( array_filter( array_map( 'strval', $filtered ) ) ) : $layers; } /** * One sentence for the dashboard, naming what was found. * * The caveat is stated either way. A site with no detectable cache may still * sit behind one this plugin cannot see, and saying nothing would imply a * completeness that measuring at WordPress cannot offer. * * @return string */ public static function dashboard_note() { $layers = self::detect(); if ( empty( $layers ) ) { return __( 'Counts are measured at WordPress, so they include only requests that reached it. No page cache or CDN was detected here, but one in front of WordPress that this plugin cannot see would still serve some requests without them being counted.', 'ai-o-optimiser' ); } return sprintf( /* translators: %s: comma-separated list of detected caching layers. */ __( 'Counts are measured at WordPress, so they include only requests that reached it. %s can answer a request before WordPress runs, and those requests are not counted here. Treat these figures as a floor rather than a total.', 'ai-o-optimiser' ), implode( ', ', $layers ) ); } }