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 | modules/woocommerce-analytics/classes/class-jetpack-woocommerce-analytics-universal.php +554 -0 16.2-beta → 16.3 View file →
@@ -1,0 +1,554 @@
1 +<?php
2 +/**
3 + * Jetpack_WooCommerce_Analytics_Universal
4 + *
5 + * @deprecated 13.3
6 + *
7 + * @package automattic/jetpack
8 + * @author Automattic
9 + */
10 +
11 +/**
12 + * Bail if accessed directly
13 + */
14 +if ( ! defined( 'ABSPATH' ) ) {
15 + exit( 0 );
16 +}
17 +
18 +/**
19 + * Class Jetpack_WooCommerce_Analytics_Universal
20 + * Filters and Actions added to Store pages to perform analytics
21 + *
22 + * @deprecated 13.3
23 + */
24 +class Jetpack_WooCommerce_Analytics_Universal {
25 +
26 + /**
27 + * Trait to handle common analytics functions.
28 + */
29 + use Jetpack_WooCommerce_Analytics_Trait;
30 +
31 + /**
32 + * Jetpack_WooCommerce_Analytics_Universal constructor.
33 + *
34 + * @deprecated 13.3
35 + */
36 + public function __construct() {
37 + $this->find_cart_checkout_content_sources();
38 + $this->additional_blocks_on_cart_page = $this->get_additional_blocks_on_page( 'cart' );
39 + $this->additional_blocks_on_checkout_page = $this->get_additional_blocks_on_page( 'checkout' );
40 +
41 + // add to carts from non-product pages or lists -- search, store etc.
42 + add_action( 'wp_head', array( $this, 'loop_session_events' ), 2 );
43 +
44 + // Capture cart events.
45 + add_action( 'woocommerce_add_to_cart', array( $this, 'capture_add_to_cart' ), 10, 6 );
46 +
47 + add_action( 'woocommerce_after_cart', array( $this, 'remove_from_cart' ) );
48 + add_action( 'woocommerce_after_mini_cart', array( $this, 'remove_from_cart' ) );
49 + add_action( 'wcct_before_cart_widget', array( $this, 'remove_from_cart' ) );
50 + add_filter( 'woocommerce_cart_item_remove_link', array( $this, 'remove_from_cart_attributes' ), 10, 2 );
51 +
52 + // Checkout.
53 + // Send events after checkout template (shortcode).
54 + add_action( 'woocommerce_after_checkout_form', array( $this, 'checkout_process' ) );
55 + // Send events after checkout block.
56 + add_action( 'woocommerce_blocks_enqueue_checkout_block_scripts_after', array( $this, 'checkout_process' ) );
57 +
58 + // order confirmed.
59 + add_action( 'woocommerce_thankyou', array( $this, 'order_process' ), 10, 1 );
60 + add_action( 'woocommerce_after_cart', array( $this, 'remove_from_cart_via_quantity' ), 10, 1 );
61 +
62 + add_filter( 'woocommerce_checkout_posted_data', array( $this, 'save_checkout_post_data' ), 10, 1 );
63 +
64 + add_action( 'woocommerce_created_customer', array( $this, 'capture_created_customer' ), 10, 2 );
65 + }
66 +
67 + /**
68 + * On product lists or other non-product pages, add an event listener to "Add to Cart" button click
69 + *
70 + * @deprecated 13.3
71 + */
72 + public function loop_session_events() {
73 + // Check for previous events queued in session data.
74 + if ( is_object( WC()->session ) ) {
75 + $data = WC()->session->get( 'wca_session_data' );
76 + if ( ! empty( $data ) ) {
77 + foreach ( $data as $data_instance ) {
78 + $this->record_event(
79 + $data_instance['event'],
80 + array(
81 + 'pq' => $data_instance['quantity'],
82 + ),
83 + $data_instance['product_id']
84 + );
85 + }
86 + // Clear data, now that these events have been recorded.
87 + WC()->session->set( 'wca_session_data', '' );
88 + }
89 + }
90 + }
91 +
92 + /**
93 + * On the cart page, add an event listener for removal of product click
94 + *
95 + * @deprecated 13.3
96 + */
97 + public function remove_from_cart() {
98 + $common_props = wp_json_encode(
99 + array_merge(
100 + array(
101 + '_en' => 'woocommerceanalytics_remove_from_cart',
102 + ),
103 + $this->get_common_properties()
104 + ),
105 + JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP
106 + );
107 +
108 + // We listen at div.woocommerce because the cart 'form' contents get forcibly
109 + // updated and subsequent removals from cart would then not have this click
110 + // handler attached.
111 + wc_enqueue_js(
112 + "jQuery( 'div.woocommerce' ).on( 'click', 'a.remove', function() {
113 + var productID = jQuery( this ).data( 'product_id' );
114 + var quantity = jQuery( this ).parent().parent().find( '.qty' ).val()
115 + var common_props = $common_props;
116 + common_props.pi = productID;
117 + common_props.pq = quantity ? quantity : '1';
118 + _wca.push( common_props );
119 + } );"
120 + );
121 + }
122 +
123 + /**
124 + * Adds the product ID to the remove product link (for use by remove_from_cart above) if not present
125 + *
126 + * @deprecated 13.3
127 + *
128 + * @param string $url Full HTML a tag of the link to remove an item from the cart.
129 + * @param string $key Unique Key ID for a cart item.
130 + *
131 + * @return string
132 + */
133 + public function remove_from_cart_attributes( $url, $key ) {
134 + if ( str_contains( $url, 'data-product_id' ) ) {
135 + return $url;
136 + }
137 +
138 + $item = WC()->cart->get_cart_item( $key );
139 + $product = $item['data'];
140 +
141 + $new_attributes = sprintf(
142 + '" data-product_id="%s">',
143 + esc_attr( $product->get_id() )
144 + );
145 +
146 + $url = str_replace( '">', $new_attributes, $url );
147 + return $url;
148 + }
149 +
150 + /**
151 + * Get the selected shipping option for a cart item. If the name cannot be found in the options table, the method's
152 + * ID will be used.
153 + *
154 + * @deprecated 13.3
155 + *
156 + * @param string $cart_item_key the cart item key.
157 + *
158 + * @return mixed|bool
159 + */
160 + public function get_shipping_option_for_item( $cart_item_key ) {
161 + $packages = wc()->shipping()->get_packages();
162 + $selected_options = wc()->session->get( 'chosen_shipping_methods' );
163 +
164 + if ( ! is_array( $packages ) || ! is_array( $selected_options ) ) {
165 + return false;
166 + }
167 +
168 + foreach ( $packages as $package_id => $package ) {
169 +
170 + if ( ! isset( $package['contents'] ) || ! is_array( $package['contents'] ) ) {
171 + return false;
172 + }
173 +
174 + foreach ( $package['contents'] as $package_item ) {
175 + if ( ! isset( $package_item['key'] ) || $package_item['key'] !== $cart_item_key || ! isset( $selected_options[ $package_id ] ) ) {
176 + continue;
177 + }
178 + $selected_rate_id = $selected_options[ $package_id ];
179 + $method_key_id = sanitize_text_field( str_replace( ':', '_', $selected_rate_id ) );
180 + $option_name = 'woocommerce_' . $method_key_id . '_settings';
181 + $option_value = get_option( $option_name );
182 + $title = '';
183 + if ( is_array( $option_value ) && isset( $option_value['title'] ) ) {
184 + $title = $option_value['title'];
185 + }
186 + if ( ! $title ) {
187 + return $selected_rate_id;
188 + }
189 + return $title;
190 + }
191 + }
192 +
193 + return false;
194 + }
195 +
196 + /**
197 + * On the Checkout page, trigger an event for each product in the cart
198 + *
199 + * @deprecated 13.3
200 + */
201 + public function checkout_process() {
202 + global $post;
203 + $checkout_page_id = wc_get_page_id( 'checkout' );
204 + $cart = WC()->cart->get_cart();
205 +
206 + $enabled_payment_options = array_filter(
207 + WC()->payment_gateways->get_available_payment_gateways(),
208 + function ( $payment_gateway ) {
209 + if ( ! $payment_gateway instanceof WC_Payment_Gateway ) {
210 + return false;
211 + }
212 +
213 + return $payment_gateway->is_available();
214 + }
215 + );
216 +
217 + $enabled_payment_options = array_keys( $enabled_payment_options );
218 +
219 + $is_in_checkout_page = $checkout_page_id === $post->ID ? 'Yes' : 'No';
220 + $session = WC()->session;
221 + if ( is_object( $session ) ) {
222 + $session->set( 'checkout_page_used', true );
223 + $session->save_data();
224 + }
225 +
226 + foreach ( $cart as $cart_item_key => $cart_item ) {
227 + /**
228 + * This filter is already documented in woocommerce/templates/cart/cart.php
229 + */
230 + $product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
231 +
232 + if ( ! $product || ! $product instanceof WC_Product ) {
233 + continue;
234 + }
235 +
236 + $data = $this->get_cart_checkout_shared_data();
237 +
238 + $data['from_checkout'] = $is_in_checkout_page;
239 +
240 + if ( ! empty( $data['products'] ) ) {
241 + unset( $data['products'] );
242 + }
243 +
244 + if ( ! empty( $data['shipping_options_count'] ) ) {
245 + unset( $data['shipping_options_count'] );
246 + }
247 +
248 + $data['pq'] = $cart_item['quantity'];
249 +
250 + $properties = $this->process_event_properties(
251 + 'woocommerceanalytics_product_checkout',
252 + $data,
253 + $product->get_id()
254 + );
255 +
256 + wc_enqueue_js(
257 + "
258 + var cartItem_{$cart_item_key}_logged = false;
259 + var properties = {$properties};
260 + // Check if jQuery is available
261 + if ( typeof jQuery !== 'undefined' ) {
262 + // This is only triggered on the checkout shortcode.
263 + jQuery( document.body ).on( 'init_checkout', function () {
264 + if ( true === cartItem_{$cart_item_key}_logged ) {
265 + return;
266 + }
267 + wp.hooks.addAction( 'wcpay.payment-request.availability', 'wcpay', function ( args ) {
268 + properties.express_checkout = args.paymentRequestType;
269 + } );
270 + properties.checkout_page_contains_checkout_block = '0';
271 + properties.checkout_page_contains_checkout_shortcode = '1';
272 +
273 + _wca.push( properties );
274 + cartItem_{$cart_item_key}_logged = true;
275 +
276 + } );
277 + }
278 +
279 + if (
280 + typeof wp !== 'undefined' &&
281 + typeof wp.data !== 'undefined' &&
282 + typeof wp.data.subscribe !== 'undefined'
283 + ) {
284 + wp.data.subscribe( function () {
285 + if ( true === cartItem_{$cart_item_key}_logged ) {
286 + return;
287 + }
288 +
289 + const checkoutDataStore = wp.data.select( 'wc/store/checkout' );
290 + // Ensures we're not in Cart, but in Checkout page.
291 + if (
292 + typeof checkoutDataStore !== 'undefined' &&
293 + checkoutDataStore.getOrderId() !== 0
294 + ) {
295 + properties.express_checkout = Object.keys( wc.wcBlocksRegistry.getExpressPaymentMethods() );
296 + properties.checkout_page_contains_checkout_block = '1';
297 + properties.checkout_page_contains_checkout_shortcode = '0';
298 +
299 + _wca.push( properties );
300 + cartItem_{$cart_item_key}_logged = true;
301 + }
302 + } );
303 + }
304 + "
305 + );
306 +
307 + }
308 + }
309 +
310 + /**
311 + * After the checkout process, fire an event for each item in the order
312 + *
313 + * @deprecated 13.3
314 + *
315 + * @param string $order_id Order Id.
316 + */
317 + public function order_process( $order_id ) {
318 + $order = wc_get_order( $order_id );
319 +
320 + if (
321 + ! $order
322 + || ! $order instanceof WC_Order
323 + ) {
324 + return;
325 + }
326 +
327 + $payment_option = $order->get_payment_method();
328 +
329 + if ( is_object( WC()->session ) ) {
330 + $create_account = true === WC()->session->get( 'wc_checkout_createaccount_used' ) ? 'Yes' : 'No';
331 + $checkout_page_used = true === WC()->session->get( 'checkout_page_used' ) ? 'Yes' : 'No';
332 +
333 + } else {
334 + $create_account = 'No';
335 + $checkout_page_used = 'No';
336 + }
337 +
338 + $guest_checkout = $order->get_user() ? 'No' : 'Yes';
339 +
340 + $express_checkout = 'null';
341 + // When the payment option is woocommerce_payment
342 + // See if Google Pay or Apple Pay was used.
343 + if ( 'woocommerce_payments' === $payment_option ) {
344 + $payment_option_title = $order->get_payment_method_title();
345 + if ( 'Google Pay (WooCommerce Payments)' === $payment_option_title ) {
346 + $express_checkout = array( 'google_pay' );
347 + } elseif ( 'Apple Pay (WooCommerce Payments)' === $payment_option_title ) {
348 + $express_checkout = array( 'apple_pay' );
349 + }
350 + }
351 +
352 + $checkout_page_contains_checkout_block = '0';
353 + $checkout_page_contains_checkout_shortcode = '0';
354 +
355 + $order_source = $order->get_created_via();
356 + if ( 'store-api' === $order_source ) {
357 + $checkout_page_contains_checkout_block = '1';
358 + } elseif ( 'checkout' === $order_source ) {
359 + $checkout_page_contains_checkout_shortcode = '1';
360 + }
361 +
362 + // loop through products in the order and queue a purchase event.
363 + foreach ( $order->get_items() as $order_item ) {
364 + // @phan-suppress-next-line PhanUndeclaredMethod -- Checked before being called. See also https://github.com/phan/phan/issues/1204.
365 + $product_id = is_callable( array( $order_item, 'get_product_id' ) ) ? $order_item->get_product_id() : -1;
366 +
367 + $order_items = $order->get_items();
368 + $order_items_count = 0;
369 + if ( is_array( $order_items ) ) {
370 + $order_items_count = count( $order_items );
371 + }
372 + $order_coupons = $order->get_coupons();
373 + $order_coupons_count = 0;
374 + if ( is_array( $order_coupons ) ) {
375 + $order_coupons_count = count( $order_coupons );
376 + }
377 + $this->record_event(
378 + 'woocommerceanalytics_product_purchase',
379 + array(
380 + 'oi' => $order->get_order_number(),
381 + 'pq' => $order_item->get_quantity(),
382 + 'payment_option' => $payment_option,
383 + 'create_account' => $create_account,
384 + 'guest_checkout' => $guest_checkout,
385 + 'express_checkout' => $express_checkout,
386 + 'products_count' => $order_items_count,
387 + 'coupon_used' => $order_coupons_count,
388 + 'order_value' => $order->get_total(),
389 + 'from_checkout' => $checkout_page_used,
390 + 'checkout_page_contains_checkout_block' => $checkout_page_contains_checkout_block,
391 + 'checkout_page_contains_checkout_shortcode' => $checkout_page_contains_checkout_shortcode,
392 + ),
393 + $product_id
394 + );
395 + }
396 + }
397 +
398 + /**
399 + * Listen for clicks on the "Update Cart" button to know if an item has been removed by
400 + * updating its quantity to zero
401 + *
402 + * @deprecated 13.3
403 + */
404 + public function remove_from_cart_via_quantity() {
405 + $common_props = wp_json_encode(
406 + array_merge(
407 + array(
408 + '_en' => 'woocommerceanalytics_remove_from_cart',
409 + ),
410 + $this->get_common_properties()
411 + ),
412 + JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP
413 + );
414 +
415 + wc_enqueue_js(
416 + "
417 + jQuery( 'button[name=update_cart]' ).on( 'click', function() {
418 + var cartItems = jQuery( '.cart_item' );
419 + cartItems.each( function( item ) {
420 + var qty = jQuery( this ).find( 'input.qty' );
421 + if ( qty && qty.val() === '0' ) {
422 + var productID = jQuery( this ).find( '.product-remove a' ).data( 'product_id' );
423 + var common_props = $common_props;
424 + common_props.pi = productID;
425 + _wca.push( common_props );
426 + }
427 + } );
428 + } );"
429 + );
430 + }
431 +
432 + /**
433 + * Gets the inner blocks of a block.
434 + *
435 + * @deprecated 13.3
436 + *
437 + * @param array $inner_blocks The inner blocks.
438 + *
439 + * @return array
440 + */
441 + private function get_inner_blocks( $inner_blocks ) {
442 + $block_names = array();
443 + if ( ! empty( $inner_blocks['blockName'] ) ) {
444 + $block_names[] = $inner_blocks['blockName'];
445 + }
446 + if ( isset( $inner_blocks['innerBlocks'] ) && is_array( $inner_blocks['innerBlocks'] ) ) {
447 + $block_names = array_merge( $block_names, $this->get_inner_blocks( $inner_blocks['innerBlocks'] ) );
448 + }
449 + return $block_names;
450 + }
451 +
452 + /**
453 + * Track adding items to the cart.
454 + *
455 + * @deprecated 13.3
456 + *
457 + * @param string $cart_item_key Cart item key.
458 + * @param int $product_id Product added to cart.
459 + * @param int $quantity Quantity added to cart.
460 + * @param int $variation_id Product variation.
461 + * @param array $variation Variation attributes..
462 + * @param array $cart_item_data Other cart data.
463 + */
464 + public function capture_add_to_cart( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
465 + $referer_postid = isset( $_SERVER['HTTP_REFERER'] ) ? url_to_postid( esc_url_raw( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) ) : 0;
466 + // if the referring post is not a product OR the product being added is not the same as post.
467 + // (eg. related product list on single product page) then include a product view event.
468 + $product_by_referer_postid = wc_get_product( $referer_postid );
469 + if ( ! $product_by_referer_postid instanceof WC_Product || (int) $product_id !== $referer_postid ) {
470 + $this->capture_event_in_session_data( $product_id, $quantity, 'woocommerceanalytics_product_view' );
471 + }
472 + // add cart event to the session data.
473 + $this->capture_event_in_session_data( $product_id, $quantity, 'woocommerceanalytics_add_to_cart' );
474 + }
475 +
476 + /**
477 + * Track in-session data.
478 + *
479 + * @deprecated 13.3
480 + *
481 + * @param int $product_id Product ID.
482 + * @param int $quantity Quantity.
483 + * @param string $event Fired event.
484 + */
485 + public function capture_event_in_session_data( $product_id, $quantity, $event ) {
486 +
487 + $product = wc_get_product( $product_id );
488 + if ( ! $product instanceof WC_Product ) {
489 + return;
490 + }
491 +
492 + $quantity = ( 0 === $quantity ) ? 1 : $quantity;
493 +
494 + // check for existing data.
495 + if ( is_object( WC()->session ) ) {
496 + $data = WC()->session->get( 'wca_session_data' );
497 + if ( empty( $data ) || ! is_array( $data ) ) {
498 + $data = array();
499 + }
500 + } else {
501 + $data = array();
502 + }
503 +
504 + // extract new event data.
505 + $new_data = array(
506 + 'event' => $event,
507 + 'product_id' => (string) $product_id,
508 + 'quantity' => (string) $quantity,
509 + );
510 +
511 + // append new data.
512 + $data[] = $new_data;
513 +
514 + WC()->session->set( 'wca_session_data', $data );
515 + }
516 +
517 + /**
518 + * Save createaccount post data to be used in $this->order_process.
519 + *
520 + * @deprecated 13.3
521 + *
522 + * @param array $data post data from the checkout page.
523 + *
524 + * @return array
525 + */
526 + public function save_checkout_post_data( array $data ) {
527 + $session = WC()->session;
528 + if ( is_object( $session ) ) {
529 + if ( isset( $data['createaccount'] ) && ! empty( $data['createaccount'] ) ) {
530 + $session->set( 'wc_checkout_createaccount_used', true );
531 + $session->save_data();
532 + }
533 + }
534 + return $data;
535 + }
536 +
537 + /**
538 + * Capture the create account event. Similar to save_checkout_post_data but works with Store API.
539 + *
540 + * @deprecated 13.3
541 + *
542 + * @param int $customer_id Customer ID.
543 + * @param array $new_customer_data New customer data.
544 + */
545 + public function capture_created_customer( $customer_id, $new_customer_data ) {
546 + $session = WC()->session;
547 + if ( is_object( $session ) ) {
548 + if ( str_contains( $new_customer_data['source'], 'store-api' ) ) {
549 + $session->set( 'wc_checkout_createaccount_used', true );
550 + $session->save_data();
551 + }
552 + }
553 + }
554 +}