PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 13.4.5
Jetpack – WP Security, Backup, Speed, & Growth v13.4.5
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 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 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 / modules / google-analytics / classes / wp-google-analytics-universal.php
jetpack / modules / google-analytics / classes Last commit date
class-jetpack-google-amp-analytics.php 2 years ago wp-google-analytics-legacy.php 2 years ago wp-google-analytics-options.php 2 years ago wp-google-analytics-universal.php 2 years ago wp-google-analytics-utils.php 2 years ago
wp-google-analytics-universal.php
548 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * Jetpack_Google_Analytics_Universal hooks and and enqueues support for analytics.js
4 * https://developers.google.com/analytics/devguides/collection/analyticsjs/
5 * https://developers.google.com/analytics/devguides/collection/analyticsjs/enhanced-ecommerce
6 *
7 * @author allendav
8 */
9
10 /**
11 * Bail if accessed directly
12 */
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 /**
18 * Jetpack_Google_Analytics_Universal main class.
19 */
20 class Jetpack_Google_Analytics_Universal {
21 /**
22 * Jetpack_Google_Analytics_Universal constructor.
23 */
24 public function __construct() {
25 add_filter( 'jetpack_wga_universal_commands', array( $this, 'maybe_anonymize_ip' ) );
26 add_filter( 'jetpack_wga_universal_commands', array( $this, 'maybe_track_purchases' ) );
27
28 add_action( 'wp_head', array( $this, 'wp_head' ), 999999 );
29
30 add_action( 'woocommerce_after_add_to_cart_button', array( $this, 'add_to_cart' ) );
31 add_action( 'wp_footer', array( $this, 'loop_add_to_cart' ) );
32 add_action( 'woocommerce_after_cart', array( $this, 'remove_from_cart' ) );
33 add_action( 'woocommerce_after_mini_cart', array( $this, 'remove_from_cart' ) );
34 add_filter( 'woocommerce_cart_item_remove_link', array( $this, 'remove_from_cart_attributes' ), 10, 2 );
35 add_action( 'woocommerce_after_shop_loop_item', array( $this, 'listing_impression' ) );
36 add_action( 'woocommerce_after_shop_loop_item', array( $this, 'listing_click' ) );
37 add_action( 'woocommerce_after_single_product', array( $this, 'product_detail' ) );
38 add_action( 'woocommerce_after_checkout_form', array( $this, 'checkout_process' ) );
39
40 // we need to send a pageview command last - so we use priority 24 to add
41 // this command's JavaScript just before wc_print_js is called (pri 25)
42 add_action( 'wp_footer', array( $this, 'send_pageview_in_footer' ), 24 );
43 }
44
45 /**
46 * Hook for the `wp_head` action to output the analytics code.
47 */
48 public function wp_head() {
49 $tracking_code = Jetpack_Google_Analytics_Options::get_tracking_code();
50 if ( empty( $tracking_code ) ) {
51 echo "<!-- No tracking ID configured for Jetpack Google Analytics -->\r\n";
52 return;
53 }
54
55 // If we're in the admin_area or DNT is honored and enabled, return without inserting code.
56 if (
57 is_admin()
58 || Jetpack_Google_Analytics_Utils::is_dnt_enabled()
59 ) {
60 return;
61 }
62
63 if ( class_exists( Jetpack_AMP_Support::class ) && Jetpack_AMP_Support::is_amp_request() ) {
64 // For Reader mode — legacy.
65 add_filter( 'amp_post_template_analytics', 'Jetpack_Google_Analytics::amp_analytics_entries', 1000 );
66 // For Standard and Transitional modes.
67 add_filter( 'amp_analytics_entries', 'Jetpack_Google_Analytics::amp_analytics_entries', 1000 );
68 return;
69 }
70
71 /**
72 * Allow for additional elements to be added to the universal Google Analytics queue (ga) array
73 *
74 * @since 5.6.0
75 *
76 * @param array $custom_vars Array of universal Google Analytics queue elements
77 */
78 $universal_commands = apply_filters( 'jetpack_wga_universal_commands', array() );
79
80 // phpcs:disable WordPress.WP.EnqueuedResources.NonEnqueuedScript -- Script is added to wp_head.
81 $async_code = "
82 <!-- Jetpack Google Analytics -->
83 <script>
84 window.ga = window.ga || function(){ ( ga.q = ga.q || [] ).push( arguments ) }; ga.l=+new Date;
85 ga( 'create', '%tracking_id%', 'auto' );
86 ga( 'require', 'ec' );
87 %universal_commands%
88 </script>
89 <script async src='https://www.google-analytics.com/analytics.js'></script>
90 <!-- End Jetpack Google Analytics -->
91 "; // phpcs:enable WordPress.WP.EnqueuedResources.NonEnqueuedScript
92 $async_code = str_replace( '%tracking_id%', $tracking_code, $async_code );
93
94 $universal_commands_string = implode( "\r\n", $universal_commands );
95 $async_code = str_replace( '%universal_commands%', $universal_commands_string, $async_code );
96
97 echo "$async_code\r\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
98 }
99
100 /**
101 * Check if the 'anonymize_ip' option should be added to the universal Google Analytics queue (ga) commands.
102 *
103 * @param array $command_array Array of commands.
104 * @return array `$command_array` with the additional command conditionally added.
105 */
106 public function maybe_anonymize_ip( $command_array ) {
107 if ( Jetpack_Google_Analytics_Options::anonymize_ip_is_enabled() ) {
108 array_push( $command_array, "ga( 'set', 'anonymizeIp', true );" );
109 }
110
111 return $command_array;
112 }
113
114 /**
115 * Process purchase tracking options for the universal Google Analytics queue (ga) commands.
116 *
117 * May also update post meta to indicate the order has been tracked.
118 *
119 * @param array $command_array Array of commands.
120 * @return array `$command_array` with additional commands conditionally added.
121 */
122 public function maybe_track_purchases( $command_array ) {
123 global $wp;
124
125 if ( ! Jetpack_Google_Analytics_Options::track_purchases_is_enabled() ) {
126 return $command_array;
127 }
128
129 if ( ! class_exists( 'WooCommerce' ) ) {
130 return $command_array;
131 }
132
133 $minimum_woocommerce_active = class_exists( 'WooCommerce' ) && version_compare( WC_VERSION, '3.0', '>=' );
134 if ( ! $minimum_woocommerce_active ) {
135 return $command_array;
136 }
137
138 if ( ! is_order_received_page() ) {
139 return $command_array;
140 }
141
142 $order_id = isset( $wp->query_vars['order-received'] ) ? $wp->query_vars['order-received'] : 0;
143 if ( 0 === (int) $order_id ) {
144 return $command_array;
145 }
146
147 $hpos_enabled =
148 class_exists( 'Automattic\WooCommerce\Utilities\OrderUtil' )
149 && \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled();
150 if ( $hpos_enabled ) {
151 return $this->maybe_track_hpos_purchases( $command_array );
152 }
153
154 // A 1 indicates we've already tracked this order - don't do it again
155 if ( 1 === (int) get_post_meta( $order_id, '_ga_tracked', true ) ) {
156 return $command_array;
157 }
158
159 $order = new WC_Order( $order_id );
160 $order_currency = $order->get_currency();
161 $command = "ga( 'set', '&cu', '" . esc_js( $order_currency ) . "' );";
162 array_push( $command_array, $command );
163
164 // Order items
165 if ( $order->get_items() ) {
166 foreach ( $order->get_items() as $item ) {
167 $product = $order->get_product_from_item( $item );
168 $product_sku_or_id = Jetpack_Google_Analytics_Utils::get_product_sku_or_id( $product );
169
170 $item_details = array(
171 'id' => $product_sku_or_id,
172 'name' => $item['name'],
173 'category' => Jetpack_Google_Analytics_Utils::get_product_categories_concatenated( $product ),
174 'price' => $order->get_item_total( $item ),
175 'quantity' => $item['qty'],
176 );
177 $command = "ga( 'ec:addProduct', " . wp_json_encode( $item_details ) . ' );';
178 array_push( $command_array, $command );
179 }
180 }
181
182 // Order summary
183 $summary = array(
184 'id' => $order->get_order_number(),
185 'affiliation' => get_bloginfo( 'name' ),
186 'revenue' => $order->get_total(),
187 'tax' => $order->get_total_tax(),
188 'shipping' => $order->get_total_shipping(),
189 );
190 $command = "ga( 'ec:setAction', 'purchase', " . wp_json_encode( $summary ) . ' );';
191 array_push( $command_array, $command );
192
193 update_post_meta( $order_id, '_ga_tracked', 1 );
194
195 return $command_array;
196 }
197
198 /**
199 * Process purchase tracking options for the universal Google Analytics queue (ga) commands.
200 *
201 * May also update post meta to indicate the order has been tracked.
202 *
203 * This method is different from maybe_track_purchases in HPOS support.
204 *
205 * @see https://github.com/woocommerce/woocommerce/wiki/High-Performance-Order-Storage-Upgrade-Recipe-Book
206 *
207 * @since 13.1
208 * @param array $command_array Array of commands.
209 * @return array `$command_array` with additional commands conditionally added.
210 */
211 public function maybe_track_hpos_purchases( $command_array ) {
212 global $wp;
213
214 $order_id = isset( $wp->query_vars['order-received'] ) ? $wp->query_vars['order-received'] : 0;
215 if ( 0 === (int) $order_id ) {
216 return $command_array;
217 }
218 $order = wc_get_order( $order_id );
219
220 if ( false === $order ) {
221 return $command_array;
222 }
223
224 // A 1 indicates we've already tracked this order - don't do it again
225 if ( 1 === (int) $order->get_meta( '_ga_tracked', true ) ) {
226 return $command_array;
227 }
228
229 $order_currency = $order->get_currency();
230 $command = "ga( 'set', '&cu', '" . esc_js( $order_currency ) . "' );";
231 array_push( $command_array, $command );
232
233 // Order items
234 if ( $order->get_items() ) {
235 foreach ( $order->get_items() as $item ) {
236 $product = $order->get_product_from_item( $item );
237 $product_sku_or_id = Jetpack_Google_Analytics_Utils::get_product_sku_or_id( $product );
238
239 $item_details = array(
240 'id' => $product_sku_or_id,
241 'name' => $item['name'],
242 'category' => Jetpack_Google_Analytics_Utils::get_product_categories_concatenated( $product ),
243 'price' => $order->get_item_total( $item ),
244 'quantity' => $item['qty'],
245 );
246 $command = "ga( 'ec:addProduct', " . wp_json_encode( $item_details ) . ' );';
247 array_push( $command_array, $command );
248 }
249 }
250
251 // Order summary
252 $summary = array(
253 'id' => $order->get_order_number(),
254 'affiliation' => get_bloginfo( 'name' ),
255 'revenue' => $order->get_total(),
256 'tax' => $order->get_total_tax(),
257 'shipping' => $order->get_shipping_total(),
258 );
259 $command = "ga( 'ec:setAction', 'purchase', " . wp_json_encode( $summary ) . ' );';
260 array_push( $command_array, $command );
261
262 $order->update_meta_data( '_ga_tracked', 1 );
263 $order->save();
264
265 return $command_array;
266 }
267
268 /**
269 * Enqueue add-to-cart click tracking script, if enabled.
270 */
271 public function add_to_cart() {
272 if ( ! Jetpack_Google_Analytics_Options::track_add_to_cart_is_enabled() ) {
273 return;
274 }
275
276 if ( ! is_single() ) {
277 return;
278 }
279
280 global $product;
281
282 $product_sku_or_id = Jetpack_Google_Analytics_Utils::get_product_sku_or_id( $product );
283 $selector = '.single_add_to_cart_button';
284
285 wc_enqueue_js(
286 "$( '" . esc_js( $selector ) . "' ).click( function() {
287 var productDetails = {
288 'id': '" . esc_js( $product_sku_or_id ) . "',
289 'name' : '" . esc_js( $product->get_title() ) . "',
290 'quantity': $( 'input.qty' ).val() ? $( 'input.qty' ).val() : '1',
291 };
292 ga( 'ec:addProduct', productDetails );
293 ga( 'ec:setAction', 'add' );
294 ga( 'send', 'event', 'UX', 'click', 'add to cart' );
295 } );"
296 );
297 }
298
299 /**
300 * Enqueue add-to-cart click tracking script for looped product views, if enabled.
301 */
302 public function loop_add_to_cart() {
303 if ( ! Jetpack_Google_Analytics_Options::track_add_to_cart_is_enabled() ) {
304 return;
305 }
306
307 if ( ! class_exists( 'WooCommerce' ) ) {
308 return;
309 }
310
311 $minimum_woocommerce_active = class_exists( 'WooCommerce' ) && version_compare( WC_VERSION, '3.0', '>=' );
312 if ( ! $minimum_woocommerce_active ) {
313 return;
314 }
315
316 $selector = '.add_to_cart_button:not(.product_type_variable, .product_type_grouped)';
317
318 wc_enqueue_js(
319 "$( '" . esc_js( $selector ) . "' ).click( function() {
320 var productSku = $( this ).data( 'product_sku' );
321 var productID = $( this ).data( 'product_id' );
322 var productDetails = {
323 'id': productSku ? productSku : '#' + productID,
324 'quantity': $( this ).data( 'quantity' ),
325 };
326 ga( 'ec:addProduct', productDetails );
327 ga( 'ec:setAction', 'add' );
328 ga( 'send', 'event', 'UX', 'click', 'add to cart' );
329 } );"
330 );
331 }
332
333 /**
334 * Enqueue remove-from-cart click tracking script, if enabled.
335 */
336 public function remove_from_cart() {
337 if ( ! Jetpack_Google_Analytics_Options::enhanced_ecommerce_tracking_is_enabled() ) {
338 return;
339 }
340
341 if ( ! Jetpack_Google_Analytics_Options::track_remove_from_cart_is_enabled() ) {
342 return;
343 }
344
345 // We listen at div.woocommerce because the cart 'form' contents get forcibly
346 // updated and subsequent removals from cart would then not have this click
347 // handler attached
348 wc_enqueue_js(
349 "$( 'div.woocommerce' ).on( 'click', 'a.remove', function() {
350 var productSku = $( this ).data( 'product_sku' );
351 var productID = $( this ).data( 'product_id' );
352 var quantity = $( this ).parent().parent().find( '.qty' ).val()
353 var productDetails = {
354 'id': productSku ? productSku : '#' + productID,
355 'quantity': quantity ? quantity : '1',
356 };
357 ga( 'ec:addProduct', productDetails );
358 ga( 'ec:setAction', 'remove' );
359 ga( 'send', 'event', 'UX', 'click', 'remove from cart' );
360 } );"
361 );
362 }
363
364 /**
365 * Adds the product ID and SKU to the remove product link (for use by remove_from_cart above) if not present
366 *
367 * @param string $url Full HTML a tag of the link to remove an item from the cart.
368 * @param string $key Unique Key ID for a cart item.
369 */
370 public function remove_from_cart_attributes( $url, $key ) {
371 if ( str_contains( $url, 'data-product_id' ) ) {
372 return $url;
373 }
374
375 $item = WC()->cart->get_cart_item( $key );
376 $product = $item['data'];
377
378 $new_attributes = sprintf(
379 '" data-product_id="%1$s" data-product_sku="%2$s">',
380 esc_attr( $product->get_id() ),
381 esc_attr( $product->get_sku() )
382 );
383
384 $url = str_replace( '">', $new_attributes, $url );
385 return $url;
386 }
387
388 /**
389 * Enqueue listing impression tracking script, if enabled.
390 */
391 public function listing_impression() {
392 if ( ! Jetpack_Google_Analytics_Options::enhanced_ecommerce_tracking_is_enabled() ) {
393 return;
394 }
395
396 if ( ! Jetpack_Google_Analytics_Options::track_product_impressions_is_enabled() ) {
397 return;
398 }
399
400 if ( isset( $_GET['s'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No site actions, just GA options being set.
401 $list = 'Search Results';
402 } else {
403 $list = 'Product List';
404 }
405
406 global $product, $woocommerce_loop;
407 $product_sku_or_id = Jetpack_Google_Analytics_Utils::get_product_sku_or_id( $product );
408
409 $item_details = array(
410 'id' => $product_sku_or_id,
411 'name' => $product->get_title(),
412 'category' => Jetpack_Google_Analytics_Utils::get_product_categories_concatenated( $product ),
413 'list' => $list,
414 'position' => $woocommerce_loop['loop'],
415 );
416 wc_enqueue_js( "ga( 'ec:addImpression', " . wp_json_encode( $item_details ) . ' );' );
417 }
418
419 /**
420 * Enqueue listing click tracking script, if enabled.
421 */
422 public function listing_click() {
423 if ( ! Jetpack_Google_Analytics_Options::enhanced_ecommerce_tracking_is_enabled() ) {
424 return;
425 }
426
427 if ( ! Jetpack_Google_Analytics_Options::track_product_clicks_is_enabled() ) {
428 return;
429 }
430
431 if ( isset( $_GET['s'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No site actions, just GA options being set.
432 $list = 'Search Results';
433 } else {
434 $list = 'Product List';
435 }
436
437 global $product, $woocommerce_loop;
438 $product_sku_or_id = Jetpack_Google_Analytics_Utils::get_product_sku_or_id( $product );
439
440 $selector = '.products .post-' . esc_js( $product->get_id() ) . ' a';
441
442 $item_details = array(
443 'id' => $product_sku_or_id,
444 'name' => $product->get_title(),
445 'category' => Jetpack_Google_Analytics_Utils::get_product_categories_concatenated( $product ),
446 'position' => $woocommerce_loop['loop'],
447 );
448
449 wc_enqueue_js(
450 "$( '" . esc_js( $selector ) . "' ).click( function() {
451 if ( true === $( this ).hasClass( 'add_to_cart_button' ) ) {
452 return;
453 }
454
455 ga( 'ec:addProduct', " . wp_json_encode( $item_details ) . " );
456 ga( 'ec:setAction', 'click', { list: '" . esc_js( $list ) . "' } );
457 ga( 'send', 'event', 'UX', 'click', { list: '" . esc_js( $list ) . "' } );
458 } );"
459 );
460 }
461
462 /**
463 * Enqueue product detail view tracking script, if enabled.
464 */
465 public function product_detail() {
466 if ( ! Jetpack_Google_Analytics_Options::enhanced_ecommerce_tracking_is_enabled() ) {
467 return;
468 }
469
470 if ( ! Jetpack_Google_Analytics_Options::track_product_detail_view_is_enabled() ) {
471 return;
472 }
473
474 global $product;
475 $product_sku_or_id = Jetpack_Google_Analytics_Utils::get_product_sku_or_id( $product );
476
477 $item_details = array(
478 'id' => $product_sku_or_id,
479 'name' => $product->get_title(),
480 'category' => Jetpack_Google_Analytics_Utils::get_product_categories_concatenated( $product ),
481 'price' => $product->get_price(),
482 );
483 wc_enqueue_js(
484 "ga( 'ec:addProduct', " . wp_json_encode( $item_details ) . ' );' .
485 "ga( 'ec:setAction', 'detail' );"
486 );
487 }
488
489 /**
490 * Enqueue post-checkout tracking script, if enabled.
491 */
492 public function checkout_process() {
493 if ( ! Jetpack_Google_Analytics_Options::enhanced_ecommerce_tracking_is_enabled() ) {
494 return;
495 }
496
497 if ( ! Jetpack_Google_Analytics_Options::track_checkout_started_is_enabled() ) {
498 return;
499 }
500
501 $universal_commands = array();
502 $cart = WC()->cart->get_cart();
503
504 foreach ( $cart as $cart_item_key => $cart_item ) {
505 /**
506 * This filter is already documented in woocommerce/templates/cart/cart.php
507 */
508 $product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
509 $product_sku_or_id = Jetpack_Google_Analytics_Utils::get_product_sku_or_id( $product );
510
511 $item_details = array(
512 'id' => $product_sku_or_id,
513 'name' => $product->get_title(),
514 'category' => Jetpack_Google_Analytics_Utils::get_product_categories_concatenated( $product ),
515 'price' => $product->get_price(),
516 'quantity' => $cart_item['quantity'],
517 );
518
519 array_push( $universal_commands, "ga( 'ec:addProduct', " . wp_json_encode( $item_details ) . ' );' );
520 }
521
522 array_push( $universal_commands, "ga( 'ec:setAction','checkout' );" );
523
524 wc_enqueue_js( implode( "\r\n", $universal_commands ) );
525 }
526
527 /**
528 * Enqueue pageview event in footer of all pages.
529 *
530 * Action hook added with later priority to come after all of the above tracking.
531 */
532 public function send_pageview_in_footer() {
533 if ( ! Jetpack_Google_Analytics_Options::has_tracking_code() ) {
534 return;
535 }
536
537 if ( is_admin() ) {
538 return;
539 }
540
541 if ( ! class_exists( 'WooCommerce' ) ) {
542 return;
543 }
544
545 wc_enqueue_js( "ga( 'send', 'pageview' );" );
546 }
547 }
548