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-universal.php +725 -0 16.2-beta → 16.3 View file →
@@ -1,0 +1,725 @@
1 +<?php
2 +/**
3 + * General store tracking actions.
4 + *
5 + * @package automattic/woocommerce-analytics
6 + */
7 +
8 +namespace Automattic\Woocommerce_Analytics;
9 +
10 +use Automattic\Jetpack\Constants;
11 +use WC_Order;
12 +use WC_Product;
13 +
14 +/**
15 + * Filters and Actions added to Store pages to perform analytics.
16 + */
17 +class Universal {
18 + /**
19 + * Trait to handle common analytics functions.
20 + */
21 + use Woo_Analytics_Trait;
22 +
23 + /**
24 + * Constructor.
25 + */
26 + public function init_hooks() {
27 + $this->find_cart_checkout_content_sources();
28 + $this->additional_blocks_on_cart_page = $this->get_additional_blocks_on_page( 'cart' );
29 + $this->additional_blocks_on_checkout_page = $this->get_additional_blocks_on_page( 'checkout' );
30 +
31 + // Capture search
32 + add_action( 'template_redirect', array( $this, 'capture_search_query' ), 11 );
33 +
34 + // Capture cart events.
35 + add_action( 'woocommerce_add_to_cart', array( $this, 'capture_add_to_cart' ), 10, 6 );
36 + add_action( 'woocommerce_after_cart_item_quantity_update', array( $this, 'capture_cart_quantity_update' ), 10, 4 );
37 + add_action( 'woocommerce_cart_item_removed', array( $this, 'capture_remove_from_cart' ), 10, 2 );
38 + add_filter( 'woocommerce_cart_item_remove_link', array( $this, 'remove_from_cart_attributes' ), 10, 2 );
39 +
40 + // Checkout.
41 + // Send events after checkout template (shortcode).
42 + add_action( 'woocommerce_after_checkout_form', array( $this, 'checkout_process' ) );
43 + // Send events after checkout block.
44 + add_action( 'woocommerce_blocks_enqueue_checkout_block_scripts_after', array( $this, 'checkout_process' ) );
45 +
46 + // order processed.
47 + add_action( 'woocommerce_checkout_order_processed', array( $this, 'order_process' ), 10, 1 );
48 + add_action( 'woocommerce_store_api_checkout_order_processed', array( $this, 'order_process' ), 10, 1 );
49 +
50 + add_filter( 'woocommerce_checkout_posted_data', array( $this, 'save_checkout_post_data' ), 10, 1 );
51 +
52 + add_action( 'woocommerce_created_customer', array( $this, 'capture_created_customer' ), 10, 2 );
53 +
54 + add_action( 'woocommerce_created_customer', array( $this, 'capture_post_checkout_created_customer' ), 10, 2 );
55 +
56 + // single product page view.
57 + add_action( 'woocommerce_after_single_product', array( $this, 'capture_product_view' ) );
58 +
59 + // order confirmed page view
60 + add_action( 'woocommerce_thankyou', array( $this, 'capture_order_confirmation_view' ), 10, 1 );
61 +
62 + // checkout page view
63 + add_action( 'wp_footer', array( $this, 'capture_checkout_view' ), 11 );
64 +
65 + // cart page view
66 + add_action( 'wp_footer', array( $this, 'capture_cart_view' ), 11 );
67 +
68 + // Enqueue events to track.
69 + add_action( 'wp_footer', array( $this, 'inject_analytics_data' ), 999 );
70 + }
71 +
72 + /**
73 + * Inject analytics data into the window object
74 + */
75 + public function inject_analytics_data() {
76 + $is_clickhouse_enabled = Features::is_clickhouse_enabled();
77 + $is_proxy_tracking_enabled = Features::is_proxy_tracking_enabled();
78 + // When proxy tracking is enabled, we don't need to send the common properties to the client.
79 + // Otherwise send only the page-safe properties: this markup is cacheable, so nothing
80 + // derived from the current request may go into it.
81 + $common_properties = $is_proxy_tracking_enabled ? array() : $this->get_page_common_properties();
82 + ?>
83 + <script type="text/javascript">
84 + (function() {
85 + // Always start from a fresh object: a `||` fallback would keep a same-named DOM element alive.
86 + window.wcAnalytics = {};
87 + const wcAnalytics = window.wcAnalytics;
88 +
89 + // Set the assets URL for webpack to find the split assets.
90 + wcAnalytics.assets_url = '<?php echo esc_url( plugins_url( '../build/', __DIR__ . '/class-woocommerce-analytics.php' ) ); ?>';
91 +
92 + // Set the REST API tracking endpoint URL.
93 + <?php
94 + $track_endpoint = rest_url( 'woocommerce-analytics/v1/track' );
95 + // Include the WP REST nonce for logged-in users so WordPress can identify
96 + // the current user via cookie auth. This is needed for the store_admin
97 + // property detection, not for endpoint authorization.
98 + if ( is_user_logged_in() ) {
99 + $track_endpoint = add_query_arg( '_wpnonce', wp_create_nonce( 'wp_rest' ), $track_endpoint );
100 + }
101 + ?>
102 + wcAnalytics.trackEndpoint = <?php echo wp_json_encode( esc_url_raw( $track_endpoint ), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?>;
103 +
104 + // Set common properties for all events.
105 + wcAnalytics.commonProps = <?php echo wp_json_encode( $common_properties, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?>;
106 +
107 + // Set the event queue.
108 + wcAnalytics.eventQueue = <?php echo wp_json_encode( WC_Analytics_Tracking::get_event_queue(), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?>;
109 +
110 + // Features.
111 + wcAnalytics.features = {
112 + ch: <?php echo $is_clickhouse_enabled ? 'true' : 'false'; ?>,
113 + sessionTracking: <?php echo $is_clickhouse_enabled ? 'true' : 'false'; ?>,
114 + proxy: <?php echo $is_proxy_tracking_enabled ? 'true' : 'false'; ?>,
115 + };
116 +
117 + wcAnalytics.breadcrumbs = <?php echo wp_json_encode( $this->get_breadcrumb_titles(), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?>;
118 +
119 + // Page context flags.
120 + wcAnalytics.pages = {
121 + isAccountPage: <?php echo is_account_page() ? 'true' : 'false'; ?>,
122 + isCart: <?php echo is_cart() ? 'true' : 'false'; ?>,
123 + };
124 + })();
125 + </script>
126 + <?php
127 + }
128 +
129 + /**
130 + * Capture remove from cart events in mini-cart and cart blocks
131 + *
132 + * @param string $cart_item_key The cart item removed.
133 + * @param \WC_Cart $cart The cart.
134 + *
135 + * @return void
136 + */
137 + public function capture_remove_from_cart( $cart_item_key, $cart ) {
138 + $item = $cart->removed_cart_contents[ $cart_item_key ] ?? null;
139 +
140 + if ( ! is_array( $item ) || ! isset( $item['product_id'], $item['quantity'] ) ) {
141 + return;
142 + }
143 +
144 + WC_Analytics_Tracking::record_event(
145 + 'remove_from_cart',
146 + $this->get_cart_checkout_event_properties(
147 + array(
148 + 'pi' => (int) $item['product_id'],
149 + 'pq' => (int) $item['quantity'],
150 + )
151 + )
152 + );
153 + }
154 +
155 + /**
156 + * Capture remove/add from cart events using the Cart Controller
157 + *
158 + * @param string $cart_item_key The cart item updated.
159 + * @param int $quantity Contains the new quantity of the item.
160 + * @param int $old_quantity Contains the old quantity of the item.
161 + * @param \WC_Cart $cart The cart.
162 + *
163 + * @return void
164 + */
165 + public function capture_cart_quantity_update( $cart_item_key, $quantity, $old_quantity, $cart ) {
166 + if ( ! isset( $cart->cart_contents[ $cart_item_key ]['product_id'] ) ) {
167 + return;
168 + }
169 +
170 + $product_id = $cart->cart_contents[ $cart_item_key ]['product_id'];
171 + if ( $quantity > $old_quantity ) {
172 + WC_Analytics_Tracking::record_event(
173 + 'add_to_cart',
174 + $this->get_cart_checkout_event_properties(
175 + array(
176 + 'pi' => $product_id,
177 + 'pq' => $quantity,
178 + )
179 + )
180 + );
181 + $this->lock_add_to_cart_events = true;
182 + return;
183 + }
184 +
185 + if ( $quantity < $old_quantity ) {
186 + WC_Analytics_Tracking::record_event(
187 + 'remove_from_cart',
188 + $this->get_cart_checkout_event_properties(
189 + array(
190 + 'pi' => $product_id,
191 + 'pq' => $quantity,
192 + )
193 + )
194 + );
195 + return;
196 + }
197 + }
198 +
199 + /**
200 + * Adds the product ID to the remove product link (for use by remove_from_cart above) if not present
201 + *
202 + * @param string $url Full HTML a tag of the link to remove an item from the cart.
203 + * @param string $key Unique Key ID for a cart item.
204 + *
205 + * @return string
206 + */
207 + public function remove_from_cart_attributes( $url, $key ) {
208 + if ( str_contains( $url, 'data-product_id' ) ) {
209 + return $url;
210 + }
211 +
212 + $item = WC()->cart->get_cart_item( $key );
213 + $product = $item['data'];
214 +
215 + $new_attributes = sprintf(
216 + '" data-product_id="%s">',
217 + esc_attr( $product->get_id() )
218 + );
219 +
220 + $url = str_replace( '">', $new_attributes, $url );
221 + return $url;
222 + }
223 +
224 + /**
225 + * Get the selected shipping option for a cart item. If the name cannot be found in the options table, the method's
226 + * ID will be used.
227 + *
228 + * @param string $cart_item_key the cart item key.
229 + *
230 + * @return mixed|bool
231 + */
232 + public function get_shipping_option_for_item( $cart_item_key ) {
233 + $packages = wc()->shipping()->get_packages();
234 + $selected_options = wc()->session->get( 'chosen_shipping_methods' );
235 +
236 + if ( ! is_array( $packages ) || ! is_array( $selected_options ) ) {
237 + return false;
238 + }
239 +
240 + foreach ( $packages as $package_id => $package ) {
241 +
242 + if ( ! isset( $package['contents'] ) || ! is_array( $package['contents'] ) ) {
243 + return false;
244 + }
245 +
246 + foreach ( $package['contents'] as $package_item ) {
247 + if ( ! isset( $package_item['key'] ) || $package_item['key'] !== $cart_item_key || ! isset( $selected_options[ $package_id ] ) ) {
248 + continue;
249 + }
250 + $selected_rate_id = $selected_options[ $package_id ];
251 + $method_key_id = sanitize_text_field( str_replace( ':', '_', $selected_rate_id ) );
252 + $option_name = 'woocommerce_' . $method_key_id . '_settings';
253 + $option_value = get_option( $option_name );
254 + $title = '';
255 + if ( is_array( $option_value ) && isset( $option_value['title'] ) ) {
256 + $title = $option_value['title'];
257 + }
258 + if ( ! $title ) {
259 + return $selected_rate_id;
260 + }
261 + return $title;
262 + }
263 + }
264 +
265 + return false;
266 + }
267 +
268 + /**
269 + * On the Checkout page, trigger an event for each product in the cart
270 + */
271 + public function checkout_process() {
272 + global $post;
273 + $checkout_page_id = wc_get_page_id( 'checkout' );
274 + $cart = WC()->cart->get_cart();
275 + $is_in_checkout_page = isset( $post->ID ) && $checkout_page_id === $post->ID ? 'Yes' : 'No';
276 + $session = WC()->session;
277 + if ( is_object( $session ) ) {
278 + $session->set( 'checkout_page_used', 'Yes' === $is_in_checkout_page );
279 + $session->save_data();
280 + }
281 +
282 + foreach ( $cart as $cart_item_key => $cart_item ) {
283 + /**
284 + * This filter is already documented in woocommerce/templates/cart/cart.php
285 + */
286 + $product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
287 +
288 + if ( ! $product || ! $product instanceof WC_Product ) {
289 + continue;
290 + }
291 +
292 + $data = $this->get_cart_checkout_shared_data();
293 +
294 + $data['from_checkout'] = $is_in_checkout_page;
295 +
296 + if ( ! empty( $data['products'] ) ) {
297 + unset( $data['products'] );
298 + }
299 +
300 + if ( ! empty( $data['shipping_options_count'] ) ) {
301 + unset( $data['shipping_options_count'] );
302 + }
303 +
304 + $data['pq'] = $cart_item['quantity'];
305 + $this->enqueue_event( 'product_checkout', $this->get_cart_checkout_event_properties( $data ), $product->get_id() );
306 + }
307 + }
308 +
309 + /**
310 + * After the order processed, fire an event for each item in the order
311 + *
312 + * @param int|string|WC_Order $order_id_or_order Order Id or Order object.
313 + */
314 + public function order_process( $order_id_or_order ) {
315 + $order = wc_get_order( $order_id_or_order );
316 +
317 + if ( ! $order ) {
318 + return;
319 + }
320 +
321 + $payment_option = $order->get_payment_method();
322 +
323 + if ( is_object( WC()->session ) ) {
324 + $create_account = true === WC()->session->get( 'wc_checkout_createaccount_used' ) ? 'Yes' : 'No';
325 + $checkout_page_used = true === WC()->session->get( 'checkout_page_used' ) ? 'Yes' : 'No';
326 +
327 + } else {
328 + $create_account = 'No';
329 + $checkout_page_used = 'No';
330 + }
331 +
332 + $delayed_account_creation = ucfirst( get_option( 'woocommerce_enable_delayed_account_creation', 'Yes' ) );
333 +
334 + $guest_checkout = $order->get_user() ? 'No' : 'Yes';
335 +
336 + $express_checkout = 'null';
337 + // When the payment option is woocommerce_payment
338 + // See if Google Pay or Apple Pay was used.
339 + if ( 'woocommerce_payments' === $payment_option ) {
340 + $payment_option_title = $order->get_payment_method_title();
341 + if ( 'Google Pay (WooCommerce Payments)' === $payment_option_title ) {
342 + $express_checkout = array( 'google_pay' );
343 + } elseif ( 'Apple Pay (WooCommerce Payments)' === $payment_option_title ) {
344 + $express_checkout = array( 'apple_pay' );
345 + }
346 + }
347 +
348 + $checkout_page_contains_checkout_block = '0';
349 + $checkout_page_contains_checkout_shortcode = '0';
350 +
351 + $order_source = $order->get_created_via();
352 + if ( 'store-api' === $order_source ) {
353 + $checkout_page_contains_checkout_block = '1';
354 + } elseif ( 'checkout' === $order_source ) {
355 + $checkout_page_contains_checkout_shortcode = '1';
356 + }
357 +
358 + // loop through products in the order and queue a purchase event.
359 + foreach ( $order->get_items() as $order_item ) {
360 + // @phan-suppress-next-line PhanUndeclaredMethod -- Checked before being called. See also https://github.com/phan/phan/issues/1204.
361 + $product_id = is_callable( array( $order_item, 'get_product_id' ) ) ? $order_item->get_product_id() : -1;
362 +
363 + $order_items = $order->get_items();
364 + $order_items_count = 0;
365 + if ( is_array( $order_items ) ) {
366 + $order_items_count = count( $order_items );
367 + }
368 + $order_coupons = $order->get_coupons();
369 + $order_coupons_count = 0;
370 + if ( is_array( $order_coupons ) ) {
371 + $order_coupons_count = count( $order_coupons );
372 + }
373 +
374 + WC_Analytics_Tracking::record_event(
375 + 'product_purchase',
376 + $this->get_cart_checkout_event_properties(
377 + array(
378 + 'oi' => $order->get_order_number(),
379 + 'pi' => $product_id,
380 + 'pq' => $order_item->get_quantity(),
381 + 'payment_option' => $payment_option,
382 + 'create_account' => $create_account,
383 + 'guest_checkout' => $guest_checkout,
384 + 'delayed_account_creation' => $delayed_account_creation,
385 + 'express_checkout' => $express_checkout,
386 + 'coupon_used' => $order_coupons_count,
387 + 'products_count' => $order_items_count,
388 + 'order_value' => $order->get_subtotal(),
389 + 'order_total' => $order->get_total(),
390 + 'total_discount' => $order->get_discount_total(),
391 + 'total_taxes' => $order->get_total_tax(),
392 + 'total_shipping' => $order->get_shipping_total(),
393 + 'from_checkout' => $checkout_page_used,
394 + 'checkout_page_contains_checkout_block' => $checkout_page_contains_checkout_block,
395 + 'checkout_page_contains_checkout_shortcode' => $checkout_page_contains_checkout_shortcode,
396 + )
397 + )
398 + );
399 + }
400 + }
401 + /**
402 + * Gets the inner blocks of a block.
403 + *
404 + * @param array $inner_blocks The inner blocks.
405 + *
406 + * @return array
407 + */
408 + private function get_inner_blocks( $inner_blocks ) {
409 + $block_names = array();
410 + if ( ! empty( $inner_blocks['blockName'] ) ) {
411 + $block_names[] = $inner_blocks['blockName'];
412 + }
413 + if ( isset( $inner_blocks['innerBlocks'] ) && is_array( $inner_blocks['innerBlocks'] ) ) {
414 + $block_names = array_merge( $block_names, $this->get_inner_blocks( $inner_blocks['innerBlocks'] ) );
415 + }
416 + return $block_names;
417 + }
418 +
419 + /**
420 + * Track adding items to the cart.
421 + *
422 + * @param string $cart_item_key Cart item key.
423 + * @param int $product_id Product added to cart.
424 + * @param int $quantity Quantity added to cart.
425 + * @param int $variation_id Product variation.
426 + * @param array $variation Variation attributes..
427 + * @param array $cart_item_data Other cart data.
428 + */
429 + public function capture_add_to_cart( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
430 + if ( $this->lock_add_to_cart_events ) {
431 + return;
432 + }
433 + WC_Analytics_Tracking::record_event(
434 + 'add_to_cart',
435 + $this->get_cart_checkout_event_properties(
436 + array(
437 + 'pi' => $product_id,
438 + 'pq' => $quantity,
439 + )
440 + )
441 + );
442 + }
443 +
444 + /**
445 + * Get the event properties for the cart and checkout events.
446 + *
447 + * @param array $event_properties Event properties.
448 + */
449 + public function get_cart_checkout_event_properties( $event_properties = array() ) {
450 + if ( isset( $event_properties['pq'] ) ) {
451 + $event_properties['pq'] = 0 === $event_properties['pq'] ? 1 : $event_properties['pq'];
452 + $event_properties['pq'] = (string) $event_properties['pq'];
453 + }
454 + $product = isset( $event_properties['pi'] ) ? wc_get_product( $event_properties['pi'] ) : null;
455 + $product_details = $product instanceof WC_Product ? $this->get_product_details( $product ) : array();
456 +
457 + $checkout_cart_details = array(
458 + 'template_used' => $this->cart_checkout_templates_in_use ? '1' : '0',
459 + 'additional_blocks_on_cart_page' => $this->additional_blocks_on_cart_page,
460 + 'additional_blocks_on_checkout_page' => $this->additional_blocks_on_checkout_page,
461 + 'order_value' => $this->get_cart_subtotal(),
462 + 'order_total' => $this->get_cart_total(),
463 + 'total_tax' => $this->get_cart_taxes(),
464 + 'total_discount' => $this->get_total_discounts(),
465 + 'total_shipping' => $this->get_cart_shipping_total(),
466 + 'products_count' => $this->get_cart_items_count(),
467 + );
468 + $cart_checkout_info = $this->get_cart_checkout_info();
469 +
470 + $event_properties = array_merge( $product_details, $checkout_cart_details, $cart_checkout_info, $event_properties ); // event properties should be last to allow for overrides
471 +
472 + return $event_properties;
473 + }
474 +
475 + /**
476 + * Save create account post data to be used in $this->order_process.
477 + *
478 + * @param array|null $data Post data from the checkout page.
479 + *
480 + * @return array|null
481 + */
482 + public function save_checkout_post_data( ?array $data ) {
483 + if ( is_object( WC()->session ) && ! empty( $data['createaccount'] ) ) {
484 + WC()->session->set( 'wc_checkout_createaccount_used', true );
485 + WC()->session->save_data();
486 + }
487 + return $data;
488 + }
489 +
490 + /**
491 + * Capture the create account event. Similar to save_checkout_post_data but works with Store API.
492 + *
493 + * @param int $customer_id Customer ID.
494 + * @param array $new_customer_data New customer data.
495 + */
496 + public function capture_created_customer( $customer_id, $new_customer_data ) {
497 + $session = WC()->session;
498 + if (
499 + is_object( $session )
500 + && is_array( $new_customer_data )
501 + && ! empty( $new_customer_data['source'] )
502 + ) {
503 + if ( str_contains( $new_customer_data['source'], 'store-api' ) ) {
504 + $session->set( 'wc_checkout_createaccount_used', true );
505 + $session->save_data();
506 + }
507 + }
508 + }
509 +
510 + /**
511 + * Capture the post checkout create account event.
512 + *
513 + * @param int $customer_id Customer ID.
514 + * @param array $new_customer_data New customer data.
515 + */
516 + public function capture_post_checkout_created_customer( $customer_id, $new_customer_data ) {
517 + if (
518 + is_array( $new_customer_data )
519 + && ! empty( $new_customer_data['source'] )
520 + && str_contains( $new_customer_data['source'], 'delayed-account-creation' )
521 + ) {
522 +
523 + $checkout_page_used = true === WC()->session->get( 'checkout_page_used' ) ? 'Yes' : 'No';
524 + $checkout_page_contains_checkout_block = '1';
525 + $checkout_page_contains_checkout_shortcode = '0';
526 +
527 + $this->enqueue_event(
528 + 'post_account_creation',
529 + $this->get_cart_checkout_event_properties(
530 + array(
531 + 'from_checkout' => $checkout_page_used,
532 + 'checkout_page_contains_checkout_block' => $checkout_page_contains_checkout_block,
533 + 'checkout_page_contains_checkout_shortcode' => $checkout_page_contains_checkout_shortcode,
534 + )
535 + )
536 + );
537 + }
538 + }
539 +
540 + /**
541 + * Capture a search event.
542 + *
543 + * The term is capped because this event is assembled here but fired by the
544 + * client, so it travels through the page markup and then reaches the pixel
545 + * URL. See `cap_page_string()`.
546 + */
547 + public function capture_search_query() {
548 + if ( is_search() ) {
549 + global $wp_query;
550 + $this->enqueue_event(
551 + 'search_performed',
552 + array(
553 + 'search_query' => $this->cap_page_string( $wp_query->get( 's' ) ),
554 + 'qty' => $wp_query->found_posts,
555 + )
556 + );
557 + }
558 + }
559 +
560 + /**
561 + * Track the cart page view
562 + */
563 + public function capture_cart_view() {
564 + global $post;
565 + $cart_page_id = wc_get_page_id( 'cart' );
566 +
567 + $is_cart = $cart_page_id && is_page( $cart_page_id )
568 + || wc_post_content_has_shortcode( 'woocommerce_cart' )
569 + || has_block( 'woocommerce/cart', $post )
570 + || apply_filters( 'woocommerce_is_cart', false )
571 + || Constants::is_defined( 'WOOCOMMERCE_CART' )
572 + || is_cart();
573 +
574 + if ( ! $is_cart ) {
575 + return;
576 + }
577 +
578 + $this->enqueue_event(
579 + 'cart_view',
580 + $this->get_cart_checkout_event_properties(
581 + $this->get_cart_checkout_shared_data()
582 + )
583 + );
584 + }
585 +
586 + /**
587 + * Track a product page view
588 + */
589 + public function capture_product_view() {
590 + global $product;
591 + if ( ! $product instanceof WC_Product ) {
592 + return;
593 + }
594 +
595 + $this->enqueue_event(
596 + 'product_view',
597 + array(),
598 + $product->get_id()
599 + );
600 + }
601 +
602 + /**
603 + * Track the order confirmation page view
604 + */
605 + public function capture_order_confirmation_view() {
606 + $order_id = absint( get_query_var( 'order-received' ) );
607 + if ( ! $order_id ) {
608 + return;
609 + }
610 +
611 + if ( ! is_order_received_page() ) {
612 + return;
613 + }
614 +
615 + $order = wc_get_order( $order_id );
616 +
617 + $order_source = $order->get_created_via();
618 + $checkout_page_contains_checkout_block = '0';
619 + $checkout_page_contains_checkout_shortcode = '0';
620 +
621 + if ( 'store-api' === $order_source ) {
622 + $checkout_page_contains_checkout_block = '1';
623 + } elseif ( 'checkout' === $order_source ) {
624 + $checkout_page_contains_checkout_shortcode = '1';
625 + }
626 +
627 + $coupons = $order->get_coupons();
628 + $coupon_used = 0;
629 + if ( is_countable( $coupons ) ) {
630 + $coupon_used = count( $coupons ) ? 1 : 0;
631 + }
632 +
633 + if ( is_object( WC()->session ) ) {
634 + $create_account = true === WC()->session->get( 'wc_checkout_createaccount_used' ) ? 'Yes' : 'No';
635 + $checkout_page_used = true === WC()->session->get( 'checkout_page_used' ) ? 'Yes' : 'No';
636 + } else {
637 + $create_account = 'No';
638 + $checkout_page_used = 'No';
639 + }
640 +
641 + $delayed_account_creation = ucfirst( get_option( 'woocommerce_enable_delayed_account_creation', 'Yes' ) );
642 + $this->enqueue_event(
643 + 'order_confirmation_view',
644 + $this->get_cart_checkout_event_properties(
645 + array(
646 + 'coupon_used' => $coupon_used,
647 + 'create_account' => $create_account,
648 + 'express_checkout' => 'null', // TODO: not solved yet.
649 + 'guest_checkout' => $order->get_customer_id() ? 'No' : 'Yes',
650 + 'delayed_account_creation' => $delayed_account_creation,
651 + 'oi' => $order->get_id(),
652 + 'order_value' => $order->get_subtotal(),
653 + 'order_total' => $order->get_total(),
654 + 'products_count' => $order->get_item_count(),
655 + 'total_discount' => $order->get_discount_total(),
656 + 'total_shipping' => $order->get_shipping_total(),
657 + 'total_tax' => $order->get_total_tax(),
658 + 'payment_option' => $order->get_payment_method(),
659 + 'products' => $this->format_items_to_json( $order->get_items() ),
660 + 'order_note' => $order->get_customer_note(),
661 + 'shipping_option' => $order->get_shipping_method(),
662 + 'from_checkout' => $checkout_page_used,
663 + 'checkout_page_contains_checkout_block' => $checkout_page_contains_checkout_block,
664 + 'checkout_page_contains_checkout_shortcode' => $checkout_page_contains_checkout_shortcode,
665 + )
666 + )
667 + );
668 + }
669 +
670 + /**
671 + * Track the checkout page view
672 + */
673 + public function capture_checkout_view() {
674 + global $post;
675 + if ( ! $post instanceof \WP_Post ) {
676 + return;
677 + }
678 +
679 + $checkout_page_id = wc_get_page_id( 'checkout' );
680 +
681 + $is_checkout = $checkout_page_id && is_page( $checkout_page_id )
682 + || wc_post_content_has_shortcode( 'woocommerce_checkout' )
683 + || has_block( 'woocommerce/checkout', $post )
684 + || apply_filters( 'woocommerce_is_checkout', false )
685 + || Constants::is_defined( 'WOOCOMMERCE_CHECKOUT' );
686 +
687 + if ( ! $is_checkout ) {
688 + return;
689 + }
690 +
691 + $is_in_checkout_page = isset( $post->ID ) && $checkout_page_id === $post->ID ? 'Yes' : 'No';
692 + $checkout_page_contains_checkout_block = '0';
693 + $checkout_page_contains_checkout_shortcode = '1';
694 +
695 + $session = WC()->session;
696 + if ( is_object( $session ) ) {
697 + $session->set( 'checkout_page_used', true );
698 + $session->save_data();
699 + $draft_order_id = $session->get( 'store_api_draft_order', 0 );
700 + if ( $draft_order_id ) {
701 + $checkout_page_contains_checkout_block = '1';
702 + $checkout_page_contains_checkout_shortcode = '0';
703 + }
704 + }
705 +
706 + // Order received page is also a checkout page, so we need to bail out if we are on that page.
707 + if ( is_order_received_page() ) {
708 + return;
709 + }
710 +
711 + $this->enqueue_event(
712 + 'checkout_view',
713 + $this->get_cart_checkout_event_properties(
714 + array_merge(
715 + $this->get_cart_checkout_shared_data(),
716 + array(
717 + 'from_checkout' => $is_in_checkout_page,
718 + 'checkout_page_contains_checkout_block' => $checkout_page_contains_checkout_block,
719 + 'checkout_page_contains_checkout_shortcode' => $checkout_page_contains_checkout_shortcode,
720 + )
721 + )
722 + )
723 + );
724 + }
725 +}