← All changes
|
jetpack_vendor/automattic/woocommerce-analytics/src/class-woocommerce-analytics.php
+119
-6
16.2
→
16.3
View file →
| @@ -19,11 +19,13 @@ | ||
| 19 | 19 | * Instantiate WooCommerce Analytics |
| 20 | 20 | */ |
| 21 | 21 | class Woocommerce_Analytics { |
| 22 | 22 | /** |
| 23 | - * Package version. | |
| 23 | + * Package version, also the key that triggers the proxy speed module refresh. Rewritten from | |
| 24 | + * composer.json by tasks/build-package.sh when the package is published, so bumping it here | |
| 25 | + * does not refresh published copies. Bump the version in composer.json instead. | |
| 24 | 26 | */ |
| 25 | - const PACKAGE_VERSION = '0.16.3'; | |
| 27 | + const PACKAGE_VERSION = '0.18.0'; | |
| 26 | 28 | |
| 27 | 29 | /** |
| 28 | 30 | * Proxy speed module version option. |
| 29 | 31 | * |
| @@ -38,8 +40,32 @@ | ||
| 38 | 40 | */ |
| 39 | 41 | const PROXY_SPEED_MODULE_VERSION_CHECK_TRANSIENT = 'woocommerce_analytics_proxy_speed_module_version_check'; |
| 40 | 42 | |
| 41 | 43 | /** |
| 44 | + * Whether the MU-plugin speed module may serve requests. | |
| 45 | + * | |
| 46 | + * It reads this option because filters are unavailable before plugins load. | |
| 47 | + * It tracks installation eligibility, so removal cannot reauthorize the module. | |
| 48 | + * | |
| 49 | + * @since 0.18.0 | |
| 50 | + * | |
| 51 | + * @var string | |
| 52 | + */ | |
| 53 | + const PROXY_SPEED_MODULE_AUTHORIZED_OPTION = 'woocommerce_analytics_proxy_speed_module_authorized'; | |
| 54 | + | |
| 55 | + /** | |
| 56 | + * Whether proxy tracking has ever been enabled on this site. | |
| 57 | + * | |
| 58 | + * Keeps the REST route registered to return 403 to cached pages after the | |
| 59 | + * feature is disabled. Clear it only after those cached pages have expired. | |
| 60 | + * | |
| 61 | + * @since 0.18.0 | |
| 62 | + * | |
| 63 | + * @var string | |
| 64 | + */ | |
| 65 | + const PROXY_TRACKING_EVER_ENABLED_OPTION = 'woocommerce_analytics_proxy_tracking_ever_enabled'; | |
| 66 | + | |
| 67 | + /** | |
| 42 | 68 | * Initializer. |
| 43 | 69 | * Used to configure the WooCommerce Analytics package. |
| 44 | 70 | * |
| 45 | 71 | * @return void |
| @@ -79,8 +105,11 @@ | ||
| 79 | 105 | * |
| 80 | 106 | * @return bool |
| 81 | 107 | */ |
| 82 | 108 | public static function should_track_store() { |
| 109 | + // Register before early returns so the MU-plugin does not keep stale state. | |
| 110 | + add_action( 'init', array( __CLASS__, 'sync_proxy_tracking_state' ), 20 ); | |
| 111 | + | |
| 83 | 112 | // Ensure this is available, even with mu-plugins. |
| 84 | 113 | if ( ! function_exists( 'is_plugin_active' ) ) { |
| 85 | 114 | require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
| 86 | 115 | } |
| @@ -173,17 +202,70 @@ | ||
| 173 | 202 | } |
| 174 | 203 | |
| 175 | 204 | /** |
| 176 | 205 | * Register REST API routes. |
| 206 | + * | |
| 207 | + * A site that has never used proxy tracking does not get the endpoint. It stays | |
| 208 | + * registered after being disabled, so cached pages receive a visible 403. | |
| 177 | 209 | */ |
| 178 | 210 | public static function register_rest_routes() { |
| 211 | + if ( 'yes' !== get_option( self::PROXY_TRACKING_EVER_ENABLED_OPTION ) ) { | |
| 212 | + return; | |
| 213 | + } | |
| 214 | + | |
| 179 | 215 | $controller = new WC_Analytics_Tracking_Proxy(); |
| 180 | 216 | $controller->register_routes(); |
| 181 | 217 | } |
| 182 | 218 | |
| 183 | 219 | /** |
| 184 | - * Maybe update proxy speed module. | |
| 220 | + * Sync proxy tracking state for the REST route and MU-plugin speed module. | |
| 221 | + * | |
| 222 | + * @since 0.18.0 | |
| 223 | + * | |
| 224 | + * @return void | |
| 185 | 225 | */ |
| 226 | + public static function sync_proxy_tracking_state() { | |
| 227 | + if ( \Automattic\Woocommerce_Analytics\Features::is_proxy_tracking_enabled() | |
| 228 | + && 'yes' !== get_option( self::PROXY_TRACKING_EVER_ENABLED_OPTION ) ) { | |
| 229 | + update_option( self::PROXY_TRACKING_EVER_ENABLED_OPTION, 'yes' ); | |
| 230 | + } | |
| 231 | + | |
| 232 | + // Track module eligibility so a removed module cannot be reauthorized. | |
| 233 | + $authorized = self::should_install_proxy_speed_module() ? 'yes' : 'no'; | |
| 234 | + $current = get_option( self::PROXY_SPEED_MODULE_AUTHORIZED_OPTION ); | |
| 235 | + | |
| 236 | + if ( $current === $authorized ) { | |
| 237 | + return; | |
| 238 | + } | |
| 239 | + | |
| 240 | + // An absent option already means unauthorized, so most sites installing this | |
| 241 | + // package never need a row saying so. | |
| 242 | + if ( false === $current && 'no' === $authorized ) { | |
| 243 | + return; | |
| 244 | + } | |
| 245 | + | |
| 246 | + update_option( self::PROXY_SPEED_MODULE_AUTHORIZED_OPTION, $authorized ); | |
| 247 | + } | |
| 248 | + | |
| 249 | + /** | |
| 250 | + * Forget that proxy tracking was enabled, so the REST route is unregistered. | |
| 251 | + * | |
| 252 | + * This is separate from removing the speed module because cached pages may remain. | |
| 253 | + * | |
| 254 | + * @since 0.18.0 | |
| 255 | + * | |
| 256 | + * @return void | |
| 257 | + */ | |
| 258 | + public static function reset_proxy_tracking_state() { | |
| 259 | + delete_option( self::PROXY_TRACKING_EVER_ENABLED_OPTION ); | |
| 260 | + delete_option( self::PROXY_SPEED_MODULE_AUTHORIZED_OPTION ); | |
| 261 | + } | |
| 262 | + | |
| 263 | + /** | |
| 264 | + * Update the proxy speed module. | |
| 265 | + * | |
| 266 | + * The module must refuse itself because this periodic check can be delayed. | |
| 267 | + */ | |
| 186 | 268 | public static function maybe_update_proxy_speed_module() { |
| 187 | 269 | // Skip if we've already checked recently. |
| 188 | 270 | if ( get_transient( self::PROXY_SPEED_MODULE_VERSION_CHECK_TRANSIENT ) ) { |
| 189 | 271 | return; |
| @@ -190,9 +272,9 @@ | ||
| 190 | 272 | } |
| 191 | 273 | |
| 192 | 274 | $version = get_option( self::PROXY_SPEED_MODULE_VERSION_OPTION, false ); |
| 193 | 275 | |
| 194 | - if ( \Automattic\Woocommerce_Analytics\Features::is_proxy_speed_module_enabled() ) { | |
| 276 | + if ( self::should_install_proxy_speed_module() ) { | |
| 195 | 277 | if ( $version !== self::PACKAGE_VERSION ) { |
| 196 | 278 | self::maybe_add_proxy_speed_module(); |
| 197 | 279 | } |
| 198 | 280 | } elseif ( $version !== false ) { |
| @@ -204,16 +286,37 @@ | ||
| 204 | 286 | set_transient( self::PROXY_SPEED_MODULE_VERSION_CHECK_TRANSIENT, 1, DAY_IN_SECONDS ); |
| 205 | 287 | } |
| 206 | 288 | |
| 207 | 289 | /** |
| 290 | + * Whether the proxy speed module belongs on this site. | |
| 291 | + * | |
| 292 | + * It requires its own opt-in and proxy tracking, so it cannot serve when | |
| 293 | + * tracking is disabled. | |
| 294 | + * | |
| 295 | + * @since 0.18.0 | |
| 296 | + * | |
| 297 | + * @return bool | |
| 298 | + */ | |
| 299 | + private static function should_install_proxy_speed_module() { | |
| 300 | + return \Automattic\Woocommerce_Analytics\Features::is_proxy_speed_module_enabled() | |
| 301 | + && \Automattic\Woocommerce_Analytics\Features::is_proxy_tracking_enabled(); | |
| 302 | + } | |
| 303 | + | |
| 304 | + /** | |
| 208 | 305 | * Maybe add proxy speed module. |
| 209 | 306 | */ |
| 210 | 307 | public static function maybe_add_proxy_speed_module() { |
| 211 | - if ( ! \Automattic\Woocommerce_Analytics\Features::is_proxy_speed_module_enabled() ) { | |
| 308 | + if ( ! self::should_install_proxy_speed_module() ) { | |
| 212 | 309 | return; |
| 213 | 310 | } |
| 214 | 311 | |
| 312 | + // Write before the module file exists because it fails closed on this option. | |
| 313 | + self::sync_proxy_tracking_state(); | |
| 314 | + | |
| 215 | 315 | if ( ! self::init_filesystem() ) { |
| 316 | + if ( function_exists( 'wc_get_logger' ) ) { | |
| 317 | + wc_get_logger()->error( 'WooCommerce Analytics proxy speed module not installed: filesystem unavailable.', array( 'source' => 'woocommerce-analytics' ) ); | |
| 318 | + } | |
| 216 | 319 | return; |
| 217 | 320 | } |
| 218 | 321 | |
| 219 | 322 | global $wp_filesystem; |
| @@ -224,8 +327,11 @@ | ||
| 224 | 327 | } |
| 225 | 328 | |
| 226 | 329 | // If the mu-plugin directory doesn't exist, we can't copy the files. |
| 227 | 330 | if ( ! is_dir( WPMU_PLUGIN_DIR ) ) { |
| 331 | + if ( function_exists( 'wc_get_logger' ) ) { | |
| 332 | + wc_get_logger()->error( 'WooCommerce Analytics proxy speed module not installed: mu-plugins directory could not be created.', array( 'source' => 'woocommerce-analytics' ) ); | |
| 333 | + } | |
| 228 | 334 | return; |
| 229 | 335 | } |
| 230 | 336 | |
| 231 | 337 | // Check if the mu-plugin directory is writable. |
| @@ -286,11 +392,18 @@ | ||
| 286 | 392 | update_option( self::PROXY_SPEED_MODULE_VERSION_OPTION, self::PACKAGE_VERSION ); |
| 287 | 393 | } |
| 288 | 394 | |
| 289 | 395 | /** |
| 290 | - * Maybe removes the proxy speed module. This should be invoked when the plugin is deactivated. | |
| 396 | + * Remove the proxy speed module when the plugin is deactivated. | |
| 397 | + * | |
| 398 | + * Clear its authorization because an undeletable MU-plugin can still load. | |
| 291 | 399 | */ |
| 292 | 400 | public static function maybe_remove_proxy_speed_module() { |
| 401 | + // Revoked before anything can fail: WP_Filesystem() returns false outright on | |
| 402 | + // hosts that ask for credentials, and that is exactly the case where the file | |
| 403 | + // survives and keeps loading. | |
| 404 | + delete_option( self::PROXY_SPEED_MODULE_AUTHORIZED_OPTION ); | |
| 405 | + | |
| 293 | 406 | if ( ! self::init_filesystem() ) { |
| 294 | 407 | return; |
| 295 | 408 | } |
| 296 | 409 | |