PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 All 508 releases
← 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