PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 16.2-a.1
Jetpack – WP Security, Backup, Speed, & Growth v16.2-a.1
16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / jetpack_vendor / automattic / woocommerce-analytics / src / class-woocommerce-analytics.php
jetpack / jetpack_vendor / automattic / woocommerce-analytics / src Last commit date
API 8 months ago mu-plugin 5 months ago class-consent-manager.php 8 months ago class-features.php 5 months ago class-my-account.php 8 months ago class-pixel-builder.php 5 months ago class-universal.php 3 weeks ago class-wc-analytics-tracking.php 3 weeks ago class-woo-analytics-trait.php 3 weeks ago class-woocommerce-analytics.php 3 weeks ago
class-woocommerce-analytics.php
389 lines
1 <?php
2 /**
3 * Main class for the WooCommerce Analytics package.
4 * Originally ported from the Jetpack_Google_Analytics code.
5 *
6 * @package automattic/woocommerce-analytics
7 */
8
9 namespace Automattic;
10
11 use Automattic\Jetpack\Assets;
12 use Automattic\Jetpack\Connection\Manager as Jetpack_Connection;
13 use Automattic\Woocommerce_Analytics\My_Account;
14 use Automattic\Woocommerce_Analytics\Universal;
15 use Automattic\Woocommerce_Analytics\WC_Analytics_Tracking_Proxy;
16 use Composer\InstalledVersions;
17
18 /**
19 * Instantiate WooCommerce Analytics
20 */
21 class Woocommerce_Analytics {
22 /**
23 * Package version.
24 */
25 const PACKAGE_VERSION = '0.16.3';
26
27 /**
28 * Proxy speed module version option.
29 *
30 * @var string
31 */
32 const PROXY_SPEED_MODULE_VERSION_OPTION = 'woocommerce_analytics_proxy_speed_module_version';
33
34 /**
35 * Proxy speed module version check transient.
36 *
37 * @var string
38 */
39 const PROXY_SPEED_MODULE_VERSION_CHECK_TRANSIENT = 'woocommerce_analytics_proxy_speed_module_version_check';
40
41 /**
42 * Initializer.
43 * Used to configure the WooCommerce Analytics package.
44 *
45 * @return void
46 */
47 public static function init() {
48 if ( ! self::should_track_store() || did_action( 'woocommerce_analytics_init' ) ) {
49 return;
50 }
51
52 // loading _wca.
53 add_action( 'wp_head', array( __CLASS__, 'wp_head_top' ), 1 );
54
55 // loading s.js.
56 add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_tracking_script' ) );
57
58 // loading client-side analytics script.
59 add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_client_script' ) );
60
61 // Initialize general store tracking actions.
62 add_action( 'init', array( new Universal(), 'init_hooks' ) );
63 add_action( 'init', array( new My_Account(), 'init_hooks' ) );
64
65 // Initialize REST API endpoints.
66 add_action( 'rest_api_init', array( __CLASS__, 'register_rest_routes' ) );
67
68 /**
69 * Fires after the WooCommerce Analytics package is initialized
70 *
71 * @since 0.1.5
72 */
73 do_action( 'woocommerce_analytics_init' );
74 }
75
76 /**
77 * WooCommerce Analytics is only available to Jetpack connected WooCommerce stores
78 * with WooCommerce version 3.0 or higher
79 *
80 * @return bool
81 */
82 public static function should_track_store() {
83 // Ensure this is available, even with mu-plugins.
84 if ( ! function_exists( 'is_plugin_active' ) ) {
85 require_once ABSPATH . 'wp-admin/includes/plugin.php';
86 }
87
88 /**
89 * Make sure WooCommerce is installed and active
90 *
91 * This action is documented in https://docs.woocommerce.com/document/create-a-plugin
92 */
93 if ( ! defined( 'WC_PLUGIN_FILE' ) || ! is_plugin_active( plugin_basename( WC_PLUGIN_FILE ) ) ) {
94 return false;
95 }
96 // Ensure the WooCommerce class exists and is a valid version.
97 $minimum_woocommerce_active = class_exists( 'WooCommerce' ) && version_compare( \WC_VERSION, '3.0', '>=' );
98 if ( ! $minimum_woocommerce_active ) {
99 return false;
100 }
101
102 // Ensure the WC Tracks classes exist.
103 if ( ! class_exists( 'WC_Tracks' ) ) {
104 if ( ! defined( 'WC_ABSPATH' ) || ! file_exists( WC_ABSPATH . 'includes/tracks/class-wc-tracks.php' ) ) {
105 return false;
106 }
107
108 include_once WC_ABSPATH . 'includes/tracks/class-wc-tracks.php';
109 include_once WC_ABSPATH . 'includes/tracks/class-wc-tracks-event.php';
110 include_once WC_ABSPATH . 'includes/tracks/class-wc-tracks-client.php';
111 }
112
113 add_action( 'admin_init', array( __CLASS__, 'maybe_update_proxy_speed_module' ) );
114
115 // Tracking only Site pages.
116 if ( is_admin() || wp_doing_ajax() || wp_is_xml_request() || is_login() || is_feed() || ( defined( 'WP_CLI' ) && WP_CLI ) ) {
117 return false;
118 }
119
120 // Make sure the site is connected to WordPress.com.
121 if ( ! ( new Jetpack_Connection() )->is_connected() ) {
122 return false;
123 }
124
125 return true;
126 }
127
128 /**
129 * Make _wca available to queue events
130 */
131 public static function wp_head_top() {
132 if ( is_cart() || is_checkout() || is_checkout_pay_page() || is_order_received_page() || is_add_payment_method_page() ) {
133 echo '<script>window._wca_prevent_referrer = true;</script>' . "\r\n";
134 }
135 echo '<script>window._wca = window._wca || [];</script>' . "\r\n";
136 }
137
138 /**
139 * Place script to call s.js, Store Analytics.
140 */
141 public static function enqueue_tracking_script() {
142 $url = sprintf(
143 'https://stats.wp.com/s-%d.js',
144 gmdate( 'YW' )
145 );
146
147 wp_enqueue_script(
148 'woocommerce-analytics',
149 $url,
150 array(),
151 null, // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion -- The version is set in the URL.
152 array(
153 'in_footer' => false,
154 'strategy' => 'defer',
155 )
156 );
157 }
158
159 /**
160 * Enqueue client-side analytics script.
161 */
162 public static function enqueue_client_script() {
163 Assets::register_script(
164 'woocommerce-analytics-client',
165 '../build/woocommerce-analytics-client.js',
166 __FILE__,
167 array(
168 'in_footer' => true,
169 'strategy' => 'defer',
170 'enqueue' => true,
171 )
172 );
173 }
174
175 /**
176 * Register REST API routes.
177 */
178 public static function register_rest_routes() {
179 $controller = new WC_Analytics_Tracking_Proxy();
180 $controller->register_routes();
181 }
182
183 /**
184 * Maybe update proxy speed module.
185 */
186 public static function maybe_update_proxy_speed_module() {
187 // Skip if we've already checked recently.
188 if ( get_transient( self::PROXY_SPEED_MODULE_VERSION_CHECK_TRANSIENT ) ) {
189 return;
190 }
191
192 $version = get_option( self::PROXY_SPEED_MODULE_VERSION_OPTION, false );
193
194 if ( \Automattic\Woocommerce_Analytics\Features::is_proxy_speed_module_enabled() ) {
195 if ( $version !== self::PACKAGE_VERSION ) {
196 self::maybe_add_proxy_speed_module();
197 }
198 } elseif ( $version !== false ) {
199 self::maybe_remove_proxy_speed_module();
200 }
201
202 // Set the transient after the update attempt to prevent checking on every admin_init.
203 // If the update failed, it will be retried after the transient expires (1 day).
204 set_transient( self::PROXY_SPEED_MODULE_VERSION_CHECK_TRANSIENT, 1, DAY_IN_SECONDS );
205 }
206
207 /**
208 * Maybe add proxy speed module.
209 */
210 public static function maybe_add_proxy_speed_module() {
211 if ( ! \Automattic\Woocommerce_Analytics\Features::is_proxy_speed_module_enabled() ) {
212 return;
213 }
214
215 if ( ! self::init_filesystem() ) {
216 return;
217 }
218
219 global $wp_filesystem;
220
221 // Create the mu-plugin directory if it doesn't exist.
222 if ( ! is_dir( WPMU_PLUGIN_DIR ) ) {
223 wp_mkdir_p( WPMU_PLUGIN_DIR );
224 }
225
226 // If the mu-plugin directory doesn't exist, we can't copy the files.
227 if ( ! is_dir( WPMU_PLUGIN_DIR ) ) {
228 return;
229 }
230
231 // Check if the mu-plugin directory is writable.
232 if ( ! $wp_filesystem->is_writable( WPMU_PLUGIN_DIR ) ) {
233 if ( function_exists( 'wc_get_logger' ) ) {
234 wc_get_logger()->debug( 'WooCommerce Analytics proxy speed module not installed: mu-plugins directory is not writable.', array( 'source' => 'woocommerce-analytics' ) );
235 }
236 return;
237 }
238
239 if ( get_option( self::PROXY_SPEED_MODULE_VERSION_OPTION ) === self::PACKAGE_VERSION ) {
240 // No need to copy the files again.
241 return;
242 }
243
244 $mu_plugin_src_file = __DIR__ . '/mu-plugin/woocommerce-analytics-proxy-speed-module-template.php';
245 $mu_plugin_dest_file = trailingslashit( WPMU_PLUGIN_DIR ) . 'woocommerce-analytics-proxy-speed-module.php';
246
247 // Verify source file exists before attempting to copy.
248 if ( ! file_exists( $mu_plugin_src_file ) ) {
249 if ( function_exists( 'wc_get_logger' ) ) {
250 wc_get_logger()->error( 'WooCommerce Analytics proxy speed module source file not found.', array( 'source' => 'woocommerce-analytics' ) );
251 }
252 return;
253 }
254
255 $content = $wp_filesystem->get_contents( $mu_plugin_src_file );
256 if ( false === $content ) {
257 if ( function_exists( 'wc_get_logger' ) ) {
258 wc_get_logger()->error( 'Failed to read the WooCommerce Analytics proxy speed module source file.', array( 'source' => 'woocommerce-analytics' ) );
259 }
260 return;
261 }
262
263 // Get the autoloader path from the current plugin location.
264 $autoloader_path = self::locate_autoloader_file();
265 if ( null === $autoloader_path ) {
266 if ( function_exists( 'wc_get_logger' ) ) {
267 wc_get_logger()->error( 'WooCommerce Analytics proxy speed module not installed: could not locate autoloader.', array( 'source' => 'woocommerce-analytics' ) );
268 }
269 return;
270 }
271
272 // Replace placeholders with actual values.
273 $content = str_replace(
274 array( '{{AUTOLOADER_PATH}}', '{{VERSION}}' ),
275 array( $autoloader_path, self::PACKAGE_VERSION ),
276 $content
277 );
278
279 if ( ! $wp_filesystem->put_contents( $mu_plugin_dest_file, $content ) ) {
280 if ( function_exists( 'wc_get_logger' ) ) {
281 wc_get_logger()->error( 'Failed to write the WooCommerce Analytics proxy speed module file.', array( 'source' => 'woocommerce-analytics' ) );
282 }
283 return;
284 }
285
286 update_option( self::PROXY_SPEED_MODULE_VERSION_OPTION, self::PACKAGE_VERSION );
287 }
288
289 /**
290 * Maybe removes the proxy speed module. This should be invoked when the plugin is deactivated.
291 */
292 public static function maybe_remove_proxy_speed_module() {
293 if ( ! self::init_filesystem() ) {
294 return;
295 }
296
297 global $wp_filesystem;
298
299 /**
300 * Clean up MU plugin.
301 */
302 $file_path = trailingslashit( WPMU_PLUGIN_DIR ) . 'woocommerce-analytics-proxy-speed-module.php';
303
304 if ( $wp_filesystem->exists( $file_path ) && $wp_filesystem->is_writable( $file_path ) ) {
305 $deleted = $wp_filesystem->delete( $file_path );
306 if ( ! $deleted && function_exists( 'wc_get_logger' ) ) {
307 wc_get_logger()->error( 'Failed to delete WooCommerce Analytics proxy speed module file. The MU-plugin may continue running.', array( 'source' => 'woocommerce-analytics' ) );
308 }
309 }
310
311 delete_option( self::PROXY_SPEED_MODULE_VERSION_OPTION );
312 delete_transient( self::PROXY_SPEED_MODULE_VERSION_CHECK_TRANSIENT );
313 }
314
315 /**
316 * Finds the path to the autoloader file.
317 *
318 * Uses multiple strategies to locate the autoloader, since this package
319 * can be included in different plugins (Jetpack, WooCommerce Analytics, etc.):
320 * 1. Jetpack autoloader global (if available)
321 * 2. Composer's InstalledVersions API
322 * 3. Directory-based guessing as a fallback
323 *
324 * @return string|null The path to the autoloader file, or null if not found.
325 */
326 private static function locate_autoloader_file() {
327 global $jetpack_autoloader_loader;
328
329 $autoload_file = null;
330
331 // Try the Jetpack autoloader.
332 if ( isset( $jetpack_autoloader_loader ) ) {
333 $class_file = $jetpack_autoloader_loader->find_class_file( self::class );
334 if ( $class_file ) {
335 // Walk up 5 levels: src/ → woocommerce-analytics/ → automattic/ → jetpack_vendor/ → plugin root.
336 $autoload_file = dirname( $class_file, 5 ) . '/vendor/autoload.php';
337 }
338 }
339
340 // Try Composer's InstalledVersions API.
341 if ( null === $autoload_file
342 && is_callable( array( InstalledVersions::class, 'getInstallPath' ) )
343 && InstalledVersions::isInstalled( 'automattic/woocommerce-analytics' )
344 ) {
345 $package_file = InstalledVersions::getInstallPath( 'automattic/woocommerce-analytics' );
346 $expected_suffix = '/automattic/woocommerce-analytics';
347 if ( substr( $package_file, -strlen( $expected_suffix ) ) === $expected_suffix ) {
348 // Walk up 3 levels: woocommerce-analytics/ → automattic/ → jetpack_vendor/ → plugin root.
349 $autoload_file = dirname( $package_file, 3 ) . '/vendor/autoload.php';
350 }
351 }
352
353 // Guess based on directory structure.
354 // First try standard vendor layout (vendor/automattic/woocommerce-analytics/src/),
355 // then try standalone package with its own vendor dir.
356 if ( null === $autoload_file ) {
357 // Walk up 4 levels from src/: woocommerce-analytics/ → automattic/ → vendor/ → project root.
358 $autoload_file = dirname( __DIR__, 4 ) . '/vendor/autoload.php';
359 if ( ! file_exists( $autoload_file ) ) {
360 $autoload_file = dirname( __DIR__ ) . '/vendor/autoload.php';
361 }
362 }
363
364 if ( ! file_exists( $autoload_file ) ) {
365 return null;
366 }
367
368 return $autoload_file;
369 }
370
371 /**
372 * Initialize the WP filesystem.
373 *
374 * @return bool True if filesystem is initialized, false otherwise.
375 */
376 private static function init_filesystem() {
377 if ( ! function_exists( 'WP_Filesystem' ) ) {
378 require_once ABSPATH . 'wp-admin/includes/file.php';
379 }
380
381 // Initialize the WP filesystem.
382 ob_start();
383 $initialized = WP_Filesystem();
384 ob_end_clean();
385
386 return $initialized;
387 }
388 }
389