Açıklama Yok

wp-google-analytics-universal.php 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. <?php
  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. * Bail if accessed directly
  11. */
  12. if ( ! defined( 'ABSPATH' ) ) {
  13. exit;
  14. }
  15. class Jetpack_Google_Analytics_Universal {
  16. public function __construct() {
  17. add_filter( 'jetpack_wga_universal_commands', array( $this, 'maybe_anonymize_ip' ) );
  18. add_filter( 'jetpack_wga_universal_commands', array( $this, 'maybe_track_purchases' ) );
  19. add_action( 'wp_head', array( $this, 'wp_head' ), 999999 );
  20. add_action( 'woocommerce_after_add_to_cart_button', array( $this, 'add_to_cart' ) );
  21. add_action( 'wp_footer', array( $this, 'loop_add_to_cart' ) );
  22. add_action( 'woocommerce_after_cart', array( $this, 'remove_from_cart' ) );
  23. add_action( 'woocommerce_after_mini_cart', array( $this, 'remove_from_cart' ) );
  24. add_filter( 'woocommerce_cart_item_remove_link', array( $this, 'remove_from_cart_attributes' ), 10, 2 );
  25. add_action( 'woocommerce_after_shop_loop_item', array( $this, 'listing_impression' ) );
  26. add_action( 'woocommerce_after_shop_loop_item', array( $this, 'listing_click' ) );
  27. add_action( 'woocommerce_after_single_product', array( $this, 'product_detail' ) );
  28. add_action( 'woocommerce_after_checkout_form', array( $this, 'checkout_process' ) );
  29. // we need to send a pageview command last - so we use priority 24 to add
  30. // this command's JavaScript just before wc_print_js is called (pri 25)
  31. add_action( 'wp_footer', array( $this, 'send_pageview_in_footer' ), 24 );
  32. }
  33. public function wp_head() {
  34. $tracking_code = Jetpack_Google_Analytics_Options::get_tracking_code();
  35. if ( empty( $tracking_code ) ) {
  36. echo "<!-- No tracking ID configured for Jetpack Google Analytics -->\r\n";
  37. return;
  38. }
  39. // If we're in the admin_area, return without inserting code.
  40. if ( is_admin() ) {
  41. return;
  42. }
  43. if ( Jetpack_AMP_Support::is_amp_request() ) {
  44. // For Reader mode — legacy.
  45. add_filter( 'amp_post_template_analytics', 'Jetpack_Google_Analytics::amp_analytics_entries', 1000 );
  46. // For Standard and Transitional modes.
  47. add_filter( 'amp_analytics_entries', 'Jetpack_Google_Analytics::amp_analytics_entries', 1000 );
  48. return;
  49. }
  50. /**
  51. * Allow for additional elements to be added to the universal Google Analytics queue (ga) array
  52. *
  53. * @since 5.6.0
  54. *
  55. * @param array $custom_vars Array of universal Google Analytics queue elements
  56. */
  57. $universal_commands = apply_filters( 'jetpack_wga_universal_commands', array() );
  58. $async_code = "
  59. <!-- Jetpack Google Analytics -->
  60. <script>
  61. window.ga = window.ga || function(){ ( ga.q = ga.q || [] ).push( arguments ) }; ga.l=+new Date;
  62. ga( 'create', '%tracking_id%', 'auto' );
  63. ga( 'require', 'ec' );
  64. %universal_commands%
  65. </script>
  66. <script async src='https://www.google-analytics.com/analytics.js'></script>
  67. <!-- End Jetpack Google Analytics -->
  68. ";
  69. $async_code = str_replace( '%tracking_id%', $tracking_code, $async_code );
  70. $universal_commands_string = implode( "\r\n", $universal_commands );
  71. $async_code = str_replace( '%universal_commands%', $universal_commands_string, $async_code );
  72. echo "$async_code\r\n";
  73. }
  74. public function maybe_anonymize_ip( $command_array ) {
  75. if ( Jetpack_Google_Analytics_Options::anonymize_ip_is_enabled() ) {
  76. array_push( $command_array, "ga( 'set', 'anonymizeIp', true );" );
  77. }
  78. return $command_array;
  79. }
  80. public function maybe_track_purchases( $command_array ) {
  81. global $wp;
  82. if ( ! Jetpack_Google_Analytics_Options::track_purchases_is_enabled() ) {
  83. return $command_array;
  84. }
  85. if ( ! class_exists( 'WooCommerce' ) ) {
  86. return $command_array;
  87. }
  88. $minimum_woocommerce_active = class_exists( 'WooCommerce' ) && version_compare( WC_VERSION, '3.0', '>=' );
  89. if ( ! $minimum_woocommerce_active ) {
  90. return $command_array;
  91. }
  92. if ( ! is_order_received_page() ) {
  93. return $command_array;
  94. }
  95. $order_id = isset( $wp->query_vars['order-received'] ) ? $wp->query_vars['order-received'] : 0;
  96. if ( 0 == $order_id ) {
  97. return $command_array;
  98. }
  99. // A 1 indicates we've already tracked this order - don't do it again
  100. if ( 1 == get_post_meta( $order_id, '_ga_tracked', true ) ) {
  101. return $command_array;
  102. }
  103. $order = new WC_Order( $order_id );
  104. $order_currency = $order->get_currency();
  105. $command = "ga( 'set', '&cu', '" . esc_js( $order_currency ) . "' );";
  106. array_push( $command_array, $command );
  107. // Order items
  108. if ( $order->get_items() ) {
  109. foreach ( $order->get_items() as $item ) {
  110. $product = $order->get_product_from_item( $item );
  111. $product_sku_or_id = Jetpack_Google_Analytics_Utils::get_product_sku_or_id( $product );
  112. $item_details = array(
  113. 'id' => $product_sku_or_id,
  114. 'name' => $item['name'],
  115. 'category' => Jetpack_Google_Analytics_Utils::get_product_categories_concatenated( $product ),
  116. 'price' => $order->get_item_total( $item ),
  117. 'quantity' => $item['qty'],
  118. );
  119. $command = "ga( 'ec:addProduct', " . wp_json_encode( $item_details ) . " );";
  120. array_push( $command_array, $command );
  121. }
  122. }
  123. // Order summary
  124. $summary = array(
  125. 'id' => $order->get_order_number(),
  126. 'affiliation' => get_bloginfo( 'name' ),
  127. 'revenue' => $order->get_total(),
  128. 'tax' => $order->get_total_tax(),
  129. 'shipping' => $order->get_total_shipping()
  130. );
  131. $command = "ga( 'ec:setAction', 'purchase', " . wp_json_encode( $summary ) . " );";
  132. array_push( $command_array, $command );
  133. update_post_meta( $order_id, '_ga_tracked', 1 );
  134. return $command_array;
  135. }
  136. public function add_to_cart() {
  137. if ( ! Jetpack_Google_Analytics_Options::track_add_to_cart_is_enabled() ) {
  138. return;
  139. }
  140. if ( ! is_single() ) {
  141. return;
  142. }
  143. global $product;
  144. $product_sku_or_id = Jetpack_Google_Analytics_Utils::get_product_sku_or_id( $product );
  145. $selector = ".single_add_to_cart_button";
  146. wc_enqueue_js(
  147. "$( '" . esc_js( $selector ) . "' ).click( function() {
  148. var productDetails = {
  149. 'id': '" . esc_js( $product_sku_or_id ) . "',
  150. 'name' : '" . esc_js( $product->get_title() ) . "',
  151. 'quantity': $( 'input.qty' ).val() ? $( 'input.qty' ).val() : '1',
  152. };
  153. ga( 'ec:addProduct', productDetails );
  154. ga( 'ec:setAction', 'add' );
  155. ga( 'send', 'event', 'UX', 'click', 'add to cart' );
  156. } );"
  157. );
  158. }
  159. public function loop_add_to_cart() {
  160. if ( ! Jetpack_Google_Analytics_Options::track_add_to_cart_is_enabled() ) {
  161. return;
  162. }
  163. if ( ! class_exists( 'WooCommerce' ) ) {
  164. return;
  165. }
  166. $minimum_woocommerce_active = class_exists( 'WooCommerce' ) && version_compare( WC_VERSION, '3.0', '>=' );
  167. if ( ! $minimum_woocommerce_active ) {
  168. return;
  169. }
  170. $selector = ".add_to_cart_button:not(.product_type_variable, .product_type_grouped)";
  171. wc_enqueue_js(
  172. "$( '" . esc_js( $selector ) . "' ).click( function() {
  173. var productSku = $( this ).data( 'product_sku' );
  174. var productID = $( this ).data( 'product_id' );
  175. var productDetails = {
  176. 'id': productSku ? productSku : '#' + productID,
  177. 'quantity': $( this ).data( 'quantity' ),
  178. };
  179. ga( 'ec:addProduct', productDetails );
  180. ga( 'ec:setAction', 'add' );
  181. ga( 'send', 'event', 'UX', 'click', 'add to cart' );
  182. } );"
  183. );
  184. }
  185. public function remove_from_cart() {
  186. if ( ! Jetpack_Google_Analytics_Options::enhanced_ecommerce_tracking_is_enabled() ) {
  187. return;
  188. }
  189. if ( ! Jetpack_Google_Analytics_Options::track_remove_from_cart_is_enabled() ) {
  190. return;
  191. }
  192. // We listen at div.woocommerce because the cart 'form' contents get forcibly
  193. // updated and subsequent removals from cart would then not have this click
  194. // handler attached
  195. wc_enqueue_js(
  196. "$( 'div.woocommerce' ).on( 'click', 'a.remove', function() {
  197. var productSku = $( this ).data( 'product_sku' );
  198. var productID = $( this ).data( 'product_id' );
  199. var quantity = $( this ).parent().parent().find( '.qty' ).val()
  200. var productDetails = {
  201. 'id': productSku ? productSku : '#' + productID,
  202. 'quantity': quantity ? quantity : '1',
  203. };
  204. ga( 'ec:addProduct', productDetails );
  205. ga( 'ec:setAction', 'remove' );
  206. ga( 'send', 'event', 'UX', 'click', 'remove from cart' );
  207. } );"
  208. );
  209. }
  210. /**
  211. * Adds the product ID and SKU to the remove product link (for use by remove_from_cart above) if not present
  212. *
  213. * @param string $url Full HTML a tag of the link to remove an item from the cart.
  214. * @param string $key Unique Key ID for a cart item.
  215. */
  216. public function remove_from_cart_attributes( $url, $key ) {
  217. if ( false !== strpos( $url, 'data-product_id' ) ) {
  218. return $url;
  219. }
  220. $item = WC()->cart->get_cart_item( $key );
  221. $product = $item['data'];
  222. $new_attributes = sprintf(
  223. '" data-product_id="%1$s" data-product_sku="%2$s">',
  224. esc_attr( $product->get_id() ),
  225. esc_attr( $product->get_sku() )
  226. );
  227. $url = str_replace( '">', $new_attributes, $url );
  228. return $url;
  229. }
  230. public function listing_impression() {
  231. if ( ! Jetpack_Google_Analytics_Options::enhanced_ecommerce_tracking_is_enabled() ) {
  232. return;
  233. }
  234. if ( ! Jetpack_Google_Analytics_Options::track_product_impressions_is_enabled() ) {
  235. return;
  236. }
  237. if ( isset( $_GET['s'] ) ) {
  238. $list = "Search Results";
  239. } else {
  240. $list = "Product List";
  241. }
  242. global $product, $woocommerce_loop;
  243. $product_sku_or_id = Jetpack_Google_Analytics_Utils::get_product_sku_or_id( $product );
  244. $item_details = array(
  245. 'id' => $product_sku_or_id,
  246. 'name' => $product->get_title(),
  247. 'category' => Jetpack_Google_Analytics_Utils::get_product_categories_concatenated( $product ),
  248. 'list' => $list,
  249. 'position' => $woocommerce_loop['loop']
  250. );
  251. wc_enqueue_js( "ga( 'ec:addImpression', " . wp_json_encode( $item_details ) . " );" );
  252. }
  253. public function listing_click() {
  254. if ( ! Jetpack_Google_Analytics_Options::enhanced_ecommerce_tracking_is_enabled() ) {
  255. return;
  256. }
  257. if ( ! Jetpack_Google_Analytics_Options::track_product_clicks_is_enabled() ) {
  258. return;
  259. }
  260. if ( isset( $_GET['s'] ) ) {
  261. $list = "Search Results";
  262. } else {
  263. $list = "Product List";
  264. }
  265. global $product, $woocommerce_loop;
  266. $product_sku_or_id = Jetpack_Google_Analytics_Utils::get_product_sku_or_id( $product );
  267. $selector = ".products .post-" . esc_js( $product->get_id() ) . " a";
  268. $item_details = array(
  269. 'id' => $product_sku_or_id,
  270. 'name' => $product->get_title(),
  271. 'category' => Jetpack_Google_Analytics_Utils::get_product_categories_concatenated( $product ),
  272. 'position' => $woocommerce_loop['loop']
  273. );
  274. wc_enqueue_js(
  275. "$( '" . esc_js( $selector ) . "' ).click( function() {
  276. if ( true === $( this ).hasClass( 'add_to_cart_button' ) ) {
  277. return;
  278. }
  279. ga( 'ec:addProduct', " . wp_json_encode( $item_details ) . " );
  280. ga( 'ec:setAction', 'click', { list: '" . esc_js( $list ) . "' } );
  281. ga( 'send', 'event', 'UX', 'click', { list: '" . esc_js( $list ) . "' } );
  282. } );"
  283. );
  284. }
  285. public function product_detail() {
  286. if ( ! Jetpack_Google_Analytics_Options::enhanced_ecommerce_tracking_is_enabled() ) {
  287. return;
  288. }
  289. if ( ! Jetpack_Google_Analytics_Options::track_product_detail_view_is_enabled() ) {
  290. return;
  291. }
  292. global $product;
  293. $product_sku_or_id = Jetpack_Google_Analytics_Utils::get_product_sku_or_id( $product );
  294. $item_details = array(
  295. 'id' => $product_sku_or_id,
  296. 'name' => $product->get_title(),
  297. 'category' => Jetpack_Google_Analytics_Utils::get_product_categories_concatenated( $product ),
  298. 'price' => $product->get_price()
  299. );
  300. wc_enqueue_js(
  301. "ga( 'ec:addProduct', " . wp_json_encode( $item_details ) . " );" .
  302. "ga( 'ec:setAction', 'detail' );"
  303. );
  304. }
  305. public function checkout_process() {
  306. if ( ! Jetpack_Google_Analytics_Options::enhanced_ecommerce_tracking_is_enabled() ) {
  307. return;
  308. }
  309. if ( ! Jetpack_Google_Analytics_Options::track_checkout_started_is_enabled() ) {
  310. return;
  311. }
  312. $universal_commands = array();
  313. $cart = WC()->cart->get_cart();
  314. foreach ( $cart as $cart_item_key => $cart_item ) {
  315. /**
  316. * This filter is already documented in woocommerce/templates/cart/cart.php
  317. */
  318. $product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
  319. $product_sku_or_id = Jetpack_Google_Analytics_Utils::get_product_sku_or_id( $product );
  320. $item_details = array(
  321. 'id' => $product_sku_or_id,
  322. 'name' => $product->get_title(),
  323. 'category' => Jetpack_Google_Analytics_Utils::get_product_categories_concatenated( $product ),
  324. 'price' => $product->get_price(),
  325. 'quantity' => $cart_item[ 'quantity' ]
  326. );
  327. array_push( $universal_commands, "ga( 'ec:addProduct', " . wp_json_encode( $item_details ) . " );" );
  328. }
  329. array_push( $universal_commands, "ga( 'ec:setAction','checkout' );" );
  330. wc_enqueue_js( implode( "\r\n", $universal_commands ) );
  331. }
  332. public function send_pageview_in_footer() {
  333. if ( ! Jetpack_Google_Analytics_Options::has_tracking_code() ) {
  334. return;
  335. }
  336. if ( is_admin() ) {
  337. return;
  338. }
  339. if ( ! class_exists( 'WooCommerce' ) ) {
  340. return;
  341. }
  342. wc_enqueue_js( "ga( 'send', 'pageview' );" );
  343. }
  344. }