WooCommerce Google Analytics Integration - Version 1.4.0

Version Description

  • 20-11-2015
  • Feature - Support for enhanced eCommerce (tracking full store process from view to order)
  • Tweak - Setting up the plugin is now clearer with some helpful links and clearer language
  • Tweak - New filter on the ga global variable
  • Refactor - JavaScript generation functions have been moved to their own class
Download this release

Release Info

Developer mattyza
Plugin Icon 128x128 WooCommerce Google Analytics Integration
Version 1.4.0
Comparing to
See all releases

Code changes from version 1.3.0 to 1.4.0

Gruntfile.js ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* jshint node:true */
2
+ module.exports = function( grunt ) {
3
+ 'use strict';
4
+
5
+ grunt.initConfig({
6
+
7
+ // Gets the package vars
8
+ pkg: grunt.file.readJSON( 'package.json' ),
9
+
10
+ // Setting folder templates
11
+ dirs: {
12
+ js: 'assets/js'
13
+ },
14
+
15
+ // Minify .js files.
16
+ uglify: {
17
+ options: {
18
+ preserveComments: 'some'
19
+ },
20
+ jsfiles: {
21
+ files: [{
22
+ expand: true,
23
+ cwd: '<%= dirs.js %>/',
24
+ src: [
25
+ '*.js',
26
+ '!*.min.js',
27
+ '!Gruntfile.js',
28
+ ],
29
+ dest: '<%= dirs.js %>/',
30
+ ext: '.min.js'
31
+ }]
32
+ }
33
+ },
34
+
35
+ // Watch changes for assets
36
+ watch: {
37
+ js: {
38
+ files: [
39
+ '<%= dirs.js %>/*js',
40
+ '!<%= dirs.js %>/*.min.js'
41
+ ],
42
+ tasks: ['uglify']
43
+ }
44
+ },
45
+
46
+ // Generate POT files.
47
+ makepot: {
48
+ dist: {
49
+ options: {
50
+ type: 'wp-plugin',
51
+ potHeaders: {
52
+ 'report-msgid-bugs-to': 'https://wordpress.org/support/plugin/woocommerce-google-analytics-integration',
53
+ 'language-team': 'LANGUAGE <EMAIL@ADDRESS>'
54
+ }
55
+ }
56
+ }
57
+ },
58
+
59
+ // Check textdomain errors.
60
+ checktextdomain: {
61
+ options: {
62
+ text_domain: '<%= pkg.name %>',
63
+ keywords: [
64
+ '__:1,2d',
65
+ '_e:1,2d',
66
+ '_x:1,2c,3d',
67
+ 'esc_html__:1,2d',
68
+ 'esc_html_e:1,2d',
69
+ 'esc_html_x:1,2c,3d',
70
+ 'esc_attr__:1,2d',
71
+ 'esc_attr_e:1,2d',
72
+ 'esc_attr_x:1,2c,3d',
73
+ '_ex:1,2c,3d',
74
+ '_n:1,2,4d',
75
+ '_nx:1,2,4c,5d',
76
+ '_n_noop:1,2,3d',
77
+ '_nx_noop:1,2,3c,4d'
78
+ ]
79
+ },
80
+ files: {
81
+ src: [
82
+ '**/*.php', // Include all files
83
+ '!node_modules/**' // Exclude node_modules/
84
+ ],
85
+ expand: true
86
+ }
87
+ }
88
+ });
89
+
90
+ // Load NPM tasks to be used here
91
+ grunt.loadNpmTasks( 'grunt-wp-i18n' );
92
+ grunt.loadNpmTasks( 'grunt-checktextdomain' );
93
+ grunt.loadNpmTasks( 'grunt-contrib-uglify' );
94
+ grunt.loadNpmTasks( 'grunt-contrib-watch' );
95
+
96
+ // Register tasks
97
+ grunt.registerTask( 'default', [
98
+ 'uglify'
99
+ ] );
100
+
101
+ };
README.md ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ # WooCommerce Google Analytics Integration
2
+
3
+ WordPress plugin: Provides the integration between WooCommerce and Google Analytics.
4
+
5
+ Will be required for WooCommerce shops using the integration from WooCommerce 2.1 and up.
assets/js/admin-enhanced-settings.js ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready( function($) {
2
+
3
+ var enhancedSettingParentRow = $( '.enhanced-setting' ).parent().parent().parent().parent();
4
+ var enhancedToggle = $( '#woocommerce_google_analytics_ga_enhanced_ecommerce_tracking_enabled' ).parent().parent().parent().parent();
5
+
6
+ if ( false === $( '#woocommerce_google_analytics_ga_enhanced_ecommerce_tracking_enabled' ).is( ':checked' ) ) {
7
+ enhancedSettingParentRow.hide();
8
+ }
9
+
10
+ if ( false === $( '#woocommerce_google_analytics_ga_use_universal_analytics' ).is( ':checked' ) ) {
11
+ enhancedSettingParentRow.hide();
12
+ enhancedToggle.hide();
13
+ }
14
+
15
+ $( '#woocommerce_google_analytics_ga_enhanced_ecommerce_tracking_enabled' ).on( 'click', function() {
16
+ if ( false === $( '#woocommerce_google_analytics_ga_enhanced_ecommerce_tracking_enabled' ).is( ':checked' ) ) {
17
+ enhancedSettingParentRow.hide();
18
+ } else {
19
+ enhancedSettingParentRow.show();
20
+ }
21
+ } );
22
+
23
+ $( '#woocommerce_google_analytics_ga_use_universal_analytics' ).on( 'click', function() {
24
+ if ( false === $( '#woocommerce_google_analytics_ga_use_universal_analytics' ).is( ':checked' ) ) {
25
+ enhancedSettingParentRow.hide();
26
+ enhancedToggle.hide();
27
+ } else {
28
+ if ( true === $( '#woocommerce_google_analytics_ga_enhanced_ecommerce_tracking_enabled' ).is( ':checked' ) ) {
29
+ enhancedSettingParentRow.show();
30
+ }
31
+ enhancedToggle.show();
32
+ }
33
+ } );
34
+
35
+ } );
assets/js/admin-enhanced-settings.min.js ADDED
@@ -0,0 +1 @@
 
1
+ jQuery(document).ready(function(a){var b=a(".enhanced-setting").parent().parent().parent().parent(),c=a("#woocommerce_google_analytics_ga_enhanced_ecommerce_tracking_enabled").parent().parent().parent().parent();!1===a("#woocommerce_google_analytics_ga_enhanced_ecommerce_tracking_enabled").is(":checked")&&b.hide(),!1===a("#woocommerce_google_analytics_ga_use_universal_analytics").is(":checked")&&(b.hide(),c.hide()),a("#woocommerce_google_analytics_ga_enhanced_ecommerce_tracking_enabled").on("click",function(){!1===a("#woocommerce_google_analytics_ga_enhanced_ecommerce_tracking_enabled").is(":checked")?b.hide():b.show()}),a("#woocommerce_google_analytics_ga_use_universal_analytics").on("click",function(){!1===a("#woocommerce_google_analytics_ga_use_universal_analytics").is(":checked")?(b.hide(),c.hide()):(!0===a("#woocommerce_google_analytics_ga_enhanced_ecommerce_tracking_enabled").is(":checked")&&b.show(),c.show())})});
includes/class-wc-google-analytics-info-banner.php ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit;
4
+ }
5
+
6
+ /**
7
+ * WC_Google_Analytics_Info_Banner class
8
+ *
9
+ * Displays a message after install (if not dismissed and GA is not already configured) about how to configure the analytics plugin
10
+ */
11
+ class WC_Google_Analytics_Info_Banner {
12
+
13
+ /** @var object Class Instance */
14
+ private static $instance;
15
+
16
+ /** @var boolean If the banner has been dismissed */
17
+ private $is_dismissed = false;
18
+
19
+ /**
20
+ * Get the class instance
21
+ */
22
+ public static function get_instance( $dismissed = false, $ga_id = '' ) {
23
+ return null === self::$instance ? ( self::$instance = new self( $dismissed, $ga_id ) ) : self::$instance;
24
+ }
25
+
26
+ /**
27
+ * Constructor
28
+ */
29
+ public function __construct( $dismissed = false, $ga_id = '' ) {
30
+ $this->is_dismissed = (bool) $dismissed;
31
+ if ( ! empty( $ga_id ) ) {
32
+ $this->is_dismissed = true;
33
+ }
34
+
35
+ // Don't bother setting anything else up if we are not going to show the notice
36
+ if ( true === $this->is_dismissed ) {
37
+ return;
38
+ }
39
+
40
+ add_action( 'admin_notices', array( $this, 'banner' ) );
41
+ add_action( 'admin_init', array( $this, 'dismiss_banner' ) );
42
+ }
43
+
44
+ /**
45
+ * Displays a info banner on WooCommerce settings pages
46
+ */
47
+ public function banner() {
48
+ $screen = get_current_screen();
49
+
50
+ if ( ! in_array( $screen->base, array( 'woocommerce_page_wc-settings', 'plugins' ) ) || $screen->is_network || $screen->action ) {
51
+ return;
52
+ }
53
+
54
+ $integration_url = esc_url( admin_url('admin.php?page=wc-settings&tab=integration&section=google_analytics' ) );
55
+ $dismiss_url = $this->dismiss_url();
56
+
57
+ $heading = __( 'Google Analytics &amp; WooCommerce', 'woocommerce-google-analytics-integration' );
58
+ $configure = sprintf( __( '<a href="%s">Connect WooCommerce to Google Analytics</a> to finish setting up this integration.' ), $integration_url );
59
+
60
+ // Display the message..
61
+ echo '<div class="updated fade"><p><strong>' . $heading . '</strong> ';
62
+ echo '<a href="' . esc_url( $dismiss_url ). '" title="' . __( 'Dismiss this notice.', 'woocommerce-google-analytics-integration' ) . '"> ' . __( '(Dismiss)', 'woocommerce-google-analytics-integration' ) . '</a>';
63
+ echo '<p>' . $configure . "</p></div>\n";
64
+ }
65
+
66
+ /**
67
+ * Returns the url that the user clicks to remove the info banner
68
+ * @return (string)
69
+ */
70
+ function dismiss_url() {
71
+ $url = admin_url( 'admin.php' );
72
+
73
+ $url = add_query_arg( array(
74
+ 'page' => 'wc-settings',
75
+ 'tab' => 'integration',
76
+ 'wc-notice' => 'dismiss-info-banner',
77
+ ), $url );
78
+
79
+ return wp_nonce_url( $url, 'woocommerce_info_banner_dismiss' );
80
+ }
81
+
82
+ /**
83
+ * Handles the dismiss action so that the banner can be permanently hidden
84
+ */
85
+ function dismiss_banner() {
86
+ if ( ! isset( $_GET['wc-notice'] ) ) {
87
+ return;
88
+ }
89
+
90
+ if ( 'dismiss-info-banner' !== $_GET['wc-notice'] ) {
91
+ return;
92
+ }
93
+
94
+ if ( ! check_admin_referer( 'woocommerce_info_banner_dismiss' ) ) {
95
+ return;
96
+ }
97
+
98
+ update_option( 'woocommerce_dismissed_info_banner', true );
99
+
100
+ if ( wp_get_referer() ) {
101
+ wp_safe_redirect( wp_get_referer() );
102
+ } else {
103
+ wp_safe_redirect( admin_url( 'admin.php?page=wc-settings&tab=integration' ) );
104
+ }
105
+ }
106
+
107
+ }
includes/class-wc-google-analytics-js.php ADDED
@@ -0,0 +1,510 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit;
4
+ }
5
+
6
+ /**
7
+ * WC_Google_Analytics_JS class
8
+ *
9
+ * JS for recording Google Analytics info
10
+ */
11
+ class WC_Google_Analytics_JS {
12
+
13
+ /** @var object Class Instance */
14
+ private static $instance;
15
+
16
+ /** @var array Inherited Analytics options */
17
+ private static $options;
18
+
19
+ /**
20
+ * Get the class instance
21
+ */
22
+ public static function get_instance( $options = array() ) {
23
+ return null === self::$instance ? ( self::$instance = new self( $options ) ) : self::$instance;
24
+ }
25
+
26
+ /**
27
+ * Constructor
28
+ * Takes our options from the parent class so we can later use them in the JS snippets
29
+ */
30
+ public function __construct( $options = array() ) {
31
+ self::$options = $options;
32
+ }
33
+
34
+ /**
35
+ * Return one of our options
36
+ * @param string $option Key/name for the option
37
+ * @return string Value of the option
38
+ */
39
+ public static function get( $option ) {
40
+ return self::$options[$option];
41
+ }
42
+
43
+ /**
44
+ * Returns the tracker variable this integration should use
45
+ */
46
+ public static function tracker_var() {
47
+ return apply_filters( 'woocommerce_ga_tracker_variable', 'ga' );
48
+ }
49
+
50
+ /**
51
+ * Generic GA / header snippet for opt out
52
+ */
53
+ public static function header() {
54
+ return "<script type='text/javascript'>
55
+ var gaProperty = '" . esc_js( self::get( 'ga_id' ) ) . "';
56
+ var disableStr = 'ga-disable-' + gaProperty;
57
+ if ( document.cookie.indexOf( disableStr + '=true' ) > -1 ) {
58
+ window[disableStr] = true;
59
+ }
60
+ function gaOptout() {
61
+ document.cookie = disableStr + '=true; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/';
62
+ window[disableStr] = true;
63
+ }
64
+ </script>";
65
+ }
66
+
67
+ /**
68
+ * Loads the correct Google Analytics code (classic or universal)
69
+ * @param boolean $order Classic analytics needs order data to set the currency correctly
70
+ * @return string Analytics loading code
71
+ */
72
+ public static function load_analytics( $order = false ) {
73
+ $logged_in = is_user_logged_in() ? 'yes' : 'no';
74
+ if ( 'yes' === self::get( 'ga_use_universal_analytics' ) ) {
75
+ add_action( 'wp_footer', array( 'WC_Google_Analytics_JS', 'universal_analytics_footer' ) );
76
+ return self::load_analytics_universal( $logged_in );
77
+ } else {
78
+ add_action( 'wp_footer', array( 'WC_Google_Analytics_JS', 'classic_analytics_footer' ) );
79
+ return self::load_analytics_classic( $logged_in, $order );
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Loads ga.js analytics tracking code
85
+ * @param string $logged_in 'yes' if the user is logged in, no if not (this is a string so we can pass it to GA)
86
+ * @param boolean|object $order We don't always need to load order data for currency, so we omit that if false is set, otherwise this is an order object
87
+ * @return string Classic Analytics loading code
88
+ */
89
+ public static function load_analytics_classic( $logged_in, $order = false ) {
90
+ $anonymize_enabled = '';
91
+ if ( 'yes' === self::get( 'ga_anonymize_enabled' ) ) {
92
+ $anonymize_enabled = "['_gat._anonymizeIp'],";
93
+ }
94
+
95
+ $domainname = self::get( 'ga_set_domain_name' );
96
+
97
+ if ( ! empty( $domainname ) ) {
98
+ $set_domain_name = "['_setDomainName', '" . esc_js( self::get( 'ga_set_domain_name' ) ) . "'],";
99
+ } else {
100
+ $set_domain_name = '';
101
+ }
102
+
103
+ $code = "var _gaq = _gaq || [];
104
+ _gaq.push(
105
+ ['_setAccount', '" . esc_js( self::get( 'ga_id' ) ) . "'], " . $set_domain_name .
106
+ $anonymize_enabled . "
107
+ ['_setCustomVar', 1, 'logged-in', '" . esc_js( $logged_in ) . "', 1],
108
+ ['_trackPageview']";
109
+
110
+ if ( false !== $order ) {
111
+ $code .= ",['_set', 'currencyCode', '" . esc_js( $order->get_order_currency() ) . "']";
112
+ }
113
+
114
+ $code .= ");";
115
+
116
+ return $code;
117
+ }
118
+
119
+ /**
120
+ * Builds the addImpression object
121
+ */
122
+ public static function listing_impression( $product, $position ) {
123
+ if ( isset( $_GET['s'] ) ) {
124
+ $list = "Search Results";
125
+ } else {
126
+ $list = "Product List";
127
+ }
128
+
129
+ wc_enqueue_js( "
130
+ " . self::tracker_var() . "( 'ec:addImpression', {
131
+ 'id': '" . esc_js( $product->id ) . "',
132
+ 'name': '" . esc_js( $product->get_title() ) . "',
133
+ 'category': " . self::product_get_category_line( $product ) . "
134
+ 'list': '" . esc_js( $list ) . "',
135
+ 'position': " . esc_js( $position ) . "
136
+ } );
137
+ " );
138
+ }
139
+
140
+ /**
141
+ * Builds an addProduct and click object
142
+ */
143
+ public static function listing_click( $product, $position ) {
144
+ if ( isset( $_GET['s'] ) ) {
145
+ $list = "Search Results";
146
+ } else {
147
+ $list = "Product List";
148
+ }
149
+
150
+ echo( "
151
+ <script>
152
+ (function($) {
153
+ $( '.products .post-" . esc_js( $product->id ) . " a' ).click( function() {
154
+ if ( true === $(this).hasClass( 'add_to_cart_button' ) ) {
155
+ return;
156
+ }
157
+
158
+ " . self::tracker_var() . "( 'ec:addProduct', {
159
+ 'id': '" . esc_js( $product->id ) . "',
160
+ 'name': '" . esc_js( $product->get_title() ) . "',
161
+ 'category': " . self::product_get_category_line( $product ) . "
162
+ 'position': " . esc_js( $position ) . "
163
+ });
164
+
165
+ " . self::tracker_var() . "( 'ec:setAction', 'click', { list: '" . esc_js( $list ) . "' });
166
+ " . self::tracker_var() . "( 'send', 'event', 'UX', 'click', ' " . esc_js( $list ) . "' );
167
+ });
168
+ })(jQuery);
169
+ </script>
170
+ " );
171
+ }
172
+
173
+ /**
174
+ * Asyncronously loads the classic Google Analytics code, and does so after all of our properties are loaded
175
+ * Loads in the footer
176
+ * @see wp_footer
177
+ */
178
+ public static function classic_analytics_footer() {
179
+ if ( 'yes' === self::get( 'ga_support_display_advertising' ) ) {
180
+ $ga_url = "('https:' == document.location.protocol ? 'https://' : 'http://') + 'stats.g.doubleclick.net/dc.js'";
181
+ } else {
182
+ $ga_url = "('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'";
183
+ }
184
+
185
+ echo "<script type='text/javascript'>(function() {
186
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
187
+ ga.src = " . $ga_url . ";
188
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
189
+ })();</script>";
190
+ }
191
+
192
+ /**
193
+ * Sends the pageview last thing (needed for things like addImpression)
194
+ */
195
+ public static function universal_analytics_footer() {
196
+ wc_enqueue_js( "" . self::tracker_var() . "( 'send', 'pageview' ); ");
197
+ }
198
+
199
+ /**
200
+ * Loads the universal analytics code
201
+ * @param string $logged_in 'yes' if the user is logged in, no if not (this is a string so we can pass it to GA)
202
+ * @return string Universal Analytics Code
203
+ */
204
+ public static function load_analytics_universal( $logged_in ) {
205
+
206
+ $domainname = self::get( 'ga_set_domain_name' );
207
+
208
+ if ( ! empty( $domainname ) ) {
209
+ $set_domain_name = esc_js( self::get( 'ga_set_domain_name' ) );
210
+ } else {
211
+ $set_domain_name = 'auto';
212
+ }
213
+
214
+ $support_display_advertising = '';
215
+ if ( 'yes' === self::get( 'ga_support_display_advertising' ) ) {
216
+ $support_display_advertising = "" . self::tracker_var() . "( 'require', 'displayfeatures' );";
217
+ }
218
+
219
+ $anonymize_enabled = '';
220
+ if ( 'yes' === self::get( 'ga_anonymize_enabled' ) ) {
221
+ $anonymize_enabled = "" . self::tracker_var() . "( 'set', 'anonymizeIp', true );";
222
+ }
223
+
224
+ $code = "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
225
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
226
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
227
+ })(window,document,'script','//www.google-analytics.com/analytics.js','" . self::tracker_var() . "');
228
+
229
+ " . self::tracker_var() . "( 'create', '" . esc_js( self::get( 'ga_id' ) ) . "', '" . $set_domain_name . "' );" .
230
+ $support_display_advertising .
231
+ $anonymize_enabled . "
232
+ " . self::tracker_var() . "( 'set', 'dimension1', '" . $logged_in . "' );\n";
233
+
234
+ if ( 'yes' === self::get( 'ga_enhanced_ecommerce_tracking_enabled' ) ) {
235
+ $code .= "" . self::tracker_var() . "( 'require', 'ec' );";
236
+ } else {
237
+ $code .= "" . self::tracker_var() . "( 'require', 'ecommerce', 'ecommerce.js');";
238
+ }
239
+
240
+ return $code;
241
+ }
242
+
243
+ /**
244
+ * Used to pass transaction data to Google Analytics
245
+ * @param object $order WC_Order Object
246
+ * @return string Add Transaction code
247
+ */
248
+ function add_transaction( $order ) {
249
+ if ( 'yes' == self::get( 'ga_use_universal_analytics' ) ) {
250
+ if ( 'yes' === self::get( 'ga_enhanced_ecommerce_tracking_enabled' ) ) {
251
+ return self::add_transaction_enhanced( $order );
252
+ } else {
253
+ return self::add_transaction_universal( $order );
254
+ }
255
+ } else {
256
+ return self::add_transaction_classic( $order );
257
+ }
258
+ }
259
+
260
+ /**
261
+ * ga.js (classic) transaction tracking
262
+ * @param object $order WC_Order Object
263
+ * @return string Add Transaction Code
264
+ */
265
+ function add_transaction_classic( $order ) {
266
+ $code = "_gaq.push(['_addTrans',
267
+ '" . esc_js( $order->get_order_number() ) . "', // order ID - required
268
+ '" . esc_js( get_bloginfo( 'name' ) ) . "', // affiliation or store name
269
+ '" . esc_js( $order->get_total() ) . "', // total - required
270
+ '" . esc_js( $order->get_total_tax() ) . "', // tax
271
+ '" . esc_js( $order->get_total_shipping() ) . "', // shipping
272
+ '" . esc_js( $order->billing_city ) . "', // city
273
+ '" . esc_js( $order->billing_state ) . "', // state or province
274
+ '" . esc_js( $order->billing_country ) . "' // country
275
+ ]);";
276
+
277
+ // Order items
278
+ if ( $order->get_items() ) {
279
+ foreach ( $order->get_items() as $item ) {
280
+ $code .= self::add_item_classic( $order, $item );
281
+ }
282
+ }
283
+
284
+ $code .= "_gaq.push(['_trackTrans']);";
285
+ return $code;
286
+ }
287
+
288
+ /**
289
+ * Universal Analytics transaction tracking
290
+ * @param object $order WC_Order object
291
+ * @return string Add Transaction Code
292
+ */
293
+ function add_transaction_universal( $order ) {
294
+ $code = "" . self::tracker_var() . "('ecommerce:addTransaction', {
295
+ 'id': '" . esc_js( $order->get_order_number() ) . "', // Transaction ID. Required
296
+ 'affiliation': '" . esc_js( get_bloginfo( 'name' ) ) . "', // Affiliation or store name
297
+ 'revenue': '" . esc_js( $order->get_total() ) . "', // Grand Total
298
+ 'shipping': '" . esc_js( $order->get_total_shipping() ) . "', // Shipping
299
+ 'tax': '" . esc_js( $order->get_total_tax() ) . "', // Tax
300
+ 'currency': '" . esc_js( $order->get_order_currency() ) . "' // Currency
301
+ });";
302
+
303
+ // Order items
304
+ if ( $order->get_items() ) {
305
+ foreach ( $order->get_items() as $item ) {
306
+ $code .= self::add_item_universal( $order, $item );
307
+ }
308
+ }
309
+
310
+ $code .= "" . self::tracker_var() . "('ecommerce:send');";
311
+ return $code;
312
+ }
313
+
314
+ /**
315
+ * Enhanced Ecommerce Universal Analytics transaction tracking
316
+ */
317
+ function add_transaction_enhanced( $order ) {
318
+ $code = "" . self::tracker_var() . "( 'set', '&cu', '" . esc_js( $order->get_order_currency() ) . "' );";
319
+
320
+ // Order items
321
+ if ( $order->get_items() ) {
322
+ foreach ( $order->get_items() as $item ) {
323
+ $code .= self::add_item_enhanced( $order, $item );
324
+ }
325
+ }
326
+
327
+ $code .= "" . self::tracker_var() . "( 'ec:setAction', 'purchase', {
328
+ 'id': '" . esc_js( $order->get_order_number() ) . "',
329
+ 'affiliation': '" . esc_js( get_bloginfo( 'name' ) ) . "',
330
+ 'revenue': '" . esc_js( $order->get_total() ) . "',
331
+ 'tax': '" . esc_js( $order->get_total_tax() ) . "',
332
+ 'shipping': '" . esc_js( $order->get_total_shipping() ) . "'
333
+ } );";
334
+
335
+ return $code;
336
+ }
337
+
338
+ /**
339
+ * Add Item (Classic)
340
+ * @param object $order WC_Order Object
341
+ * @param array $item The item to add to a transaction/order
342
+ */
343
+ function add_item_classic( $order, $item ) {
344
+ $_product = $order->get_product_from_item( $item );
345
+
346
+ $code = "_gaq.push(['_addItem',";
347
+ $code .= "'" . esc_js( $order->get_order_number() ) . "',";
348
+ $code .= "'" . esc_js( $_product->get_sku() ? $_product->get_sku() : $_product->id ) . "',";
349
+ $code .= "'" . esc_js( $item['name'] ) . "',";
350
+ $code .= self::product_get_category_line( $_product );
351
+ $code .= "'" . esc_js( $order->get_item_total( $item ) ) . "',";
352
+ $code .= "'" . esc_js( $item['qty'] ) . "'";
353
+ $code .= "]);";
354
+
355
+ return $code;
356
+ }
357
+
358
+ /**
359
+ * Add Item (Universal)
360
+ * @param object $order WC_Order Object
361
+ * @param array $item The item to add to a transaction/order
362
+ */
363
+ function add_item_universal( $order, $item ) {
364
+ $_product = $order->get_product_from_item( $item );
365
+
366
+ $code = "" . self::tracker_var() . "('ecommerce:addItem', {";
367
+ $code .= "'id': '" . esc_js( $order->get_order_number() ) . "',";
368
+ $code .= "'name': '" . esc_js( $item['name'] ) . "',";
369
+ $code .= "'sku': '" . esc_js( $_product->get_sku() ? $_product->get_sku() : $_product->id ) . "',";
370
+ $code .= "'category': " . self::product_get_category_line( $_product );
371
+ $code .= "'price': '" . esc_js( $order->get_item_total( $item ) ) . "',";
372
+ $code .= "'quantity': '" . esc_js( $item['qty'] ) . "'";
373
+ $code .= "});";
374
+
375
+ return $code;
376
+ }
377
+
378
+ /**
379
+ * Add Item (Enhanced, Universal)
380
+ * @param object $order WC_Order Object
381
+ * @param array $item The item to add to a transaction/order
382
+ */
383
+ function add_item_enhanced( $order, $item ) {
384
+ $_product = $order->get_product_from_item( $item );
385
+
386
+ $code = "" . self::tracker_var() . "( 'ec:addProduct', {";
387
+ $code .= "'id': '" . esc_js( $_product->get_sku() ? $_product->get_sku() : $_product->id ) . "',";
388
+ $code .= "'name': '" . esc_js( $item['name'] ) . "',";
389
+ $code .= "'category': " . self::product_get_category_line( $_product );
390
+ $code .= "'price': '" . esc_js( $order->get_item_total( $item ) ) . "',";
391
+ $code .= "'quantity': '" . esc_js( $item['qty'] ) . "'";
392
+ $code .= "});";
393
+
394
+ return $code;
395
+ }
396
+
397
+ /**
398
+ * Returns a 'category' JSON line based on $product
399
+ * @param object $product Product to pull info for
400
+ * @return string Line of JSON
401
+ */
402
+ private static function product_get_category_line( $_product ) {
403
+ if ( is_array( $_product->variation_data ) && ! empty( $_product->variation_data ) ) {
404
+ $code = "'" . esc_js( woocommerce_get_formatted_variation( $_product->variation_data, true ) ) . "',";
405
+ } else {
406
+ $out = array();
407
+ $categories = get_the_terms( $_product->id, 'product_cat' );
408
+ if ( $categories ) {
409
+ foreach ( $categories as $category ) {
410
+ $out[] = $category->name;
411
+ }
412
+ }
413
+ $code = "'" . esc_js( join( "/", $out ) ) . "',";
414
+ }
415
+
416
+ return $code;
417
+ }
418
+
419
+ /**
420
+ * Tracks an enhanced ecommerce remove from cart action
421
+ */
422
+ function remove_from_cart() {
423
+ echo( "
424
+ <script>
425
+ (function($) {
426
+ $( '.remove' ).click( function() {
427
+ " . self::tracker_var() . "( 'ec:addProduct', {
428
+ 'id': ($(this).data('product_sku')) ? ('SKU: ' + $(this).data('product_sku')) : ('#' + $(this).data('product_id')),
429
+ 'quantity': $(this).parent().parent().find( '.qty' ).val() ? $(this).parent().parent().find( '.qty' ).val() : '1',
430
+ } );
431
+ " . self::tracker_var() . "( 'ec:setAction', 'remove' );
432
+ " . self::tracker_var() . "( 'send', 'event', 'UX', 'click', 'remove from cart' );
433
+ });
434
+ })(jQuery);
435
+ </script>
436
+ " );
437
+ }
438
+
439
+ /**
440
+ * Tracks a product detail view
441
+ */
442
+ function product_detail( $product ) {
443
+ wc_enqueue_js( "
444
+ " . self::tracker_var() . "( 'ec:addProduct', {
445
+ 'id': '" . esc_js( $product->get_sku() ? $product->get_sku() : $product->id ) . "',
446
+ 'name': '" . esc_js( $product->get_title() ) . "',
447
+ 'category': " . self::product_get_category_line( $product ) . "
448
+ 'price': '" . esc_js( $product->get_price() ) . "',
449
+ } );
450
+
451
+ " . self::tracker_var() . "( 'ec:setAction', 'detail' );" );
452
+ }
453
+
454
+ /**
455
+ * Tracks when the checkout process is started
456
+ */
457
+ function checkout_process( $cart ) {
458
+ $code = "";
459
+
460
+ foreach ( $cart as $cart_item_key => $cart_item ) {
461
+ $product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
462
+ $code .= "" . self::tracker_var() . "( 'ec:addProduct', {
463
+ 'id': '" . esc_js( $product->get_sku() ? $product->get_sku() : $product->id ) . "',
464
+ 'name': '" . esc_js( $product->get_title() ) . "',
465
+ 'category': " . self::product_get_category_line( $product ) . "
466
+ 'price': '" . esc_js( $product->get_price() ) . "',
467
+ 'quantity': '" . esc_js( $cart_item['quantity'] ) . "'
468
+ } );";
469
+ }
470
+
471
+ $code .= "" . self::tracker_var() . "( 'ec:setAction','checkout' );";
472
+ wc_enqueue_js( $code );
473
+ }
474
+
475
+ /**
476
+ * Add to cart
477
+ *
478
+ * @param array $parameters associative array of _trackEvent parameters
479
+ * @param string $selector jQuery selector for binding click event
480
+ *
481
+ * @return void
482
+ */
483
+ public function event_tracking_code( $parameters, $selector ) {
484
+ $parameters = apply_filters( 'woocommerce_ga_event_tracking_parameters', $parameters );
485
+
486
+ if ( 'yes' === self::get( 'ga_use_universal_analytics' ) ) {
487
+ if ( 'yes' === self::get( 'ga_enhanced_ecommerce_tracking_enabled' ) ) {
488
+ wc_enqueue_js( "
489
+ $( '" . $selector . "' ).click( function() {
490
+ " . $parameters['enhanced'] . "
491
+ " . self::tracker_var() . "( 'ec:setAction', 'add' );
492
+ " . self::tracker_var() . "( 'send', 'event', 'UX', 'click', 'add to cart' );
493
+ });
494
+ " );
495
+ return;
496
+ } else {
497
+ $track_event = "" . self::tracker_var() . "('send', 'event', %s, %s, %s);";
498
+ }
499
+ } else {
500
+ $track_event = "_gaq.push(['_trackEvent', %s, %s, %s]);";
501
+ }
502
+
503
+ wc_enqueue_js( "
504
+ $( '" . $selector . "' ).click( function() {
505
+ " . sprintf( $track_event, $parameters['category'], $parameters['action'], $parameters['label'] ) . "
506
+ });
507
+ " );
508
+ }
509
+
510
+ }
includes/class-wc-google-analytics.php CHANGED
@@ -19,26 +19,31 @@ class WC_Google_Analytics extends WC_Integration {
19
  * @return void
20
  */
21
  public function __construct() {
22
- $this->id = 'google_analytics';
23
- $this->method_title = __( 'Google Analytics', 'woocommerce-google-analytics-integration' );
24
- $this->method_description = __( 'Google Analytics is a free service offered by Google that generates detailed statistics about the visitors to a website.', 'woocommerce-google-analytics-integration' );
 
25
 
26
- // Load the settings.
27
  $this->init_form_fields();
28
  $this->init_settings();
 
29
 
30
- // Define user set variables
31
- $this->ga_id = $this->get_option( 'ga_id' );
32
- $this->ga_set_domain_name = $this->get_option( 'ga_set_domain_name' );
33
- $this->ga_standard_tracking_enabled = $this->get_option( 'ga_standard_tracking_enabled' );
34
- $this->ga_support_display_advertising = $this->get_option( 'ga_support_display_advertising' );
35
- $this->ga_use_universal_analytics = $this->get_option( 'ga_use_universal_analytics' );
36
- $this->ga_anonymize_enabled = $this->get_option( 'ga_anonymize_enabled' );
37
- $this->ga_ecommerce_tracking_enabled = $this->get_option( 'ga_ecommerce_tracking_enabled' );
38
- $this->ga_event_tracking_enabled = $this->get_option( 'ga_event_tracking_enabled' );
39
-
40
- // Actions
 
41
  add_action( 'woocommerce_update_options_integration_google_analytics', array( $this, 'process_admin_options') );
 
 
42
 
43
  // Tracking code
44
  add_action( 'wp_head', array( $this, 'tracking_code_display' ), 999999 );
@@ -46,24 +51,59 @@ class WC_Google_Analytics extends WC_Integration {
46
  // Event tracking code
47
  add_action( 'woocommerce_after_add_to_cart_button', array( $this, 'add_to_cart' ) );
48
  add_action( 'wp_footer', array( $this, 'loop_add_to_cart' ) );
 
 
 
 
 
 
 
49
 
50
  // utm_nooverride parameter for Google AdWords
51
  add_filter( 'woocommerce_get_return_url', array( $this, 'utm_nooverride' ) );
52
  }
53
 
54
  /**
55
- * Initialise Settings Form Fields
56
- *
57
- * @return void
58
  */
59
- public function init_form_fields() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  $this->form_fields = array(
62
  'ga_id' => array(
63
- 'title' => __( 'Google Analytics ID', 'woocommerce-google-analytics-integration' ),
64
- 'description' => __( 'Log into your google analytics account to find your ID. e.g. <code>UA-XXXXX-X</code>', 'woocommerce-google-analytics-integration' ),
65
- 'type' => 'text',
66
- 'default' => get_option( 'woocommerce_ga_id' ) // Backwards compat
 
67
  ),
68
  'ga_set_domain_name' => array(
69
  'title' => __( 'Set Domain Name', 'woocommerce-google-analytics-integration' ),
@@ -72,49 +112,152 @@ class WC_Google_Analytics extends WC_Integration {
72
  'default' => ''
73
  ),
74
  'ga_standard_tracking_enabled' => array(
75
- 'title' => __( 'Tracking code', 'woocommerce-google-analytics-integration' ),
76
- 'label' => __( 'Add tracking code to your site. You don\'t need to enable this if using a 3rd party analytics plugin.', 'woocommerce-google-analytics-integration' ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  'type' => 'checkbox',
78
  'checkboxgroup' => 'start',
79
- 'default' => get_option( 'woocommerce_ga_standard_tracking_enabled' ) ? get_option( 'woocommerce_ga_standard_tracking_enabled' ) : 'no' // Backwards compat
80
  ),
81
- 'ga_support_display_advertising' => array(
82
- 'label' => __( 'Set the Google Analytics code to support Display Advertising. <a href="https://support.google.com/analytics/answer/2700409" target="_blank">Read more about Display Advertising</a>.', 'woocommerce-google-analytics-integration' ),
83
  'type' => 'checkbox',
84
  'checkboxgroup' => '',
85
- 'default' => get_option( 'woocommerce_ga_support_display_advertising' ) ? get_option( 'woocommerce_ga_support_display_advertising' ) : 'no' // Backwards compat
86
  ),
87
- 'ga_use_universal_analytics' => array(
88
- 'label' => __( 'Use Universal Analytics instead of Classic Google Analytics', 'woocommerce-google-analytics-integration' ),
 
 
 
 
 
 
 
 
 
 
 
 
89
  'type' => 'checkbox',
90
  'checkboxgroup' => '',
91
- 'default' => get_option( 'woocommerce_ga_use_universal_analytics' ) ? get_option( 'woocommerce_ga_use_universal_analytics' ) : 'no' // Backwards compat
 
92
  ),
93
- 'ga_anonymize_enabled' => array(
94
- 'label' => __( 'Anonymize IP addresses. Setting this option is mandatory in certain countries due to national privacy laws. <a href="https://support.google.com/analytics/answer/2763052" target="_blank">Read more about IP Anonymization</a>.', 'woocommerce-google-analytics-integration' ),
 
95
  'type' => 'checkbox',
96
  'checkboxgroup' => '',
97
- 'default' => 'no'
 
98
  ),
99
- 'ga_ecommerce_tracking_enabled' => array(
100
- 'label' => __( 'Add eCommerce tracking code to the thankyou page', 'woocommerce-google-analytics-integration' ),
 
101
  'type' => 'checkbox',
102
  'checkboxgroup' => '',
103
- 'default' => get_option( 'woocommerce_ga_ecommerce_tracking_enabled' ) ? get_option( 'woocommerce_ga_ecommerce_tracking_enabled' ) : 'no' // Backwards compat
 
104
  ),
105
- 'ga_event_tracking_enabled' => array(
106
- 'label' => __( 'Add event tracking code for add to cart actions', 'woocommerce-google-analytics-integration' ),
 
107
  'type' => 'checkbox',
108
- 'checkboxgroup' => 'end',
109
- 'default' => 'no'
110
- )
 
 
 
 
 
 
 
 
 
111
  );
112
  }
113
 
114
  /**
115
- * Display the tracking codes
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  *
117
- * @return string
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  */
119
  public function tracking_code_display() {
120
  global $wp;
@@ -125,334 +268,66 @@ class WC_Google_Analytics extends WC_Integration {
125
  }
126
 
127
  // Check if is order received page and stop when the products and not tracked
128
- if ( is_order_received_page() && 'yes' == $this->ga_ecommerce_tracking_enabled ) {
129
  $order_id = isset( $wp->query_vars['order-received'] ) ? $wp->query_vars['order-received'] : 0;
130
-
131
  if ( 0 < $order_id && 1 != get_post_meta( $order_id, '_ga_tracked', true ) ) {
132
  $display_ecommerce_tracking = true;
133
-
134
  echo $this->get_ecommerce_tracking_code( $order_id );
135
  }
136
  }
137
 
138
- if ( ! $display_ecommerce_tracking && 'yes' == $this->ga_standard_tracking_enabled ) {
139
- echo $this->get_google_tracking_code();
 
140
  }
141
- }
142
 
143
- /**
144
- * Get the generic Google Analytics code snippet
145
- *
146
- * @return string
147
- */
148
- protected function get_generic_ga_code() {
149
- return "
150
- <script>
151
- var gaProperty = '" . esc_js( $this->ga_id ) . "';
152
- var disableStr = 'ga-disable-' + gaProperty;
153
- if (document.cookie.indexOf(disableStr + '=true') > -1) {
154
- window[disableStr] = true;
155
- }
156
- function gaOptout() {
157
- document.cookie = disableStr + '=true; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/';
158
- window[disableStr] = true;
159
- }
160
- </script>
161
- ";
162
  }
163
 
164
  /**
165
- * Google Analytics standard tracking
166
- *
167
- * @return string
168
  */
169
- protected function get_google_tracking_code() {
170
- $logged_in = ( is_user_logged_in() ) ? 'yes' : 'no';
171
-
172
- if ( 'yes' === $logged_in ) {
173
- $user_id = get_current_user_id();
174
- $current_user = get_user_by('id', $user_id);
175
- $username = $current_user->user_login;
176
- } else {
177
- $user_id = '';
178
- $username = __( 'Guest', 'woocommerce-google-analytics-integration' );
179
- }
180
-
181
- if ( 'yes' == $this->ga_use_universal_analytics ) {
182
- if ( ! empty( $this->ga_set_domain_name ) ) {
183
- $set_domain_name = esc_js( $this->ga_set_domain_name );
184
- } else {
185
- $set_domain_name = 'auto';
186
- }
187
-
188
- $support_display_advertising = '';
189
- if ( 'yes' == $this->ga_support_display_advertising ) {
190
- $support_display_advertising = "ga('require', 'displayfeatures');";
191
- }
192
-
193
- $anonymize_enabled = '';
194
- if ( 'yes' == $this->ga_anonymize_enabled ) {
195
- $anonymize_enabled = "ga('set', 'anonymizeIp', true);";
196
- }
197
-
198
- $code = "
199
- (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
200
- (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
201
- m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
202
- })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
203
-
204
- ga('create', '" . esc_js( $this->ga_id ) . "', '" . $set_domain_name . "');" .
205
- $support_display_advertising .
206
- $anonymize_enabled . "
207
- ga('set', 'dimension1', '" . $logged_in . "');
208
- ga('send', 'pageview');
209
- ";
210
-
211
- } else {
212
- if ( 'yes' == $this->ga_support_display_advertising ) {
213
- $ga_url = "('https:' == document.location.protocol ? 'https://' : 'http://') + 'stats.g.doubleclick.net/dc.js'";
214
- } else {
215
- $ga_url = "('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'";
216
- }
217
-
218
- $anonymize_enabled = '';
219
- if ( 'yes' == $this->ga_anonymize_enabled ) {
220
- $anonymize_enabled = "['_gat._anonymizeIp'],";
221
- }
222
-
223
- if ( ! empty( $this->ga_set_domain_name ) ) {
224
- $set_domain_name = "['_setDomainName', '" . esc_js( $this->ga_set_domain_name ) . "'],\n";
225
- } else {
226
- $set_domain_name = '';
227
- }
228
-
229
- $code = "
230
- var _gaq = _gaq || [];
231
- _gaq.push(
232
- ['_setAccount', '" . esc_js( $this->ga_id ) . "'], " . $set_domain_name .
233
- $anonymize_enabled . "
234
- ['_setCustomVar', 1, 'logged-in', '" . $logged_in . "', 1],
235
- ['_trackPageview']
236
- );
237
-
238
- (function() {
239
- var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
240
- ga.src = " . $ga_url . ";
241
- var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
242
- })();
243
- ";
244
- }
245
-
246
- return "
247
- <!-- WooCommerce Google Analytics Integration -->
248
- " . $this->get_generic_ga_code() . "
249
- <script type='text/javascript'>$code</script>
250
-
251
- <!-- /WooCommerce Google Analytics Integration -->
252
-
253
- ";
254
-
255
  }
256
 
257
  /**
258
- * Google Analytics eCommerce tracking
259
  *
260
  * @param int $order_id
261
- *
262
- * @return string
263
  */
264
  protected function get_ecommerce_tracking_code( $order_id ) {
265
  // Get the order and output tracking code
266
  $order = new WC_Order( $order_id );
267
 
268
- $logged_in = is_user_logged_in() ? 'yes' : 'no';
269
-
270
- if ( 'yes' === $logged_in ) {
271
- $user_id = get_current_user_id();
272
- $current_user = get_user_by( 'id', $user_id );
273
- $username = $current_user->user_login;
274
- } else {
275
- $user_id = '';
276
- $username = __( 'Guest', 'woocommerce-google-analytics-integration' );
277
- }
278
-
279
- if ( 'yes' == $this->ga_use_universal_analytics ) {
280
- if ( ! empty( $this->ga_set_domain_name ) ) {
281
- $set_domain_name = esc_js( $this->ga_set_domain_name );
282
- } else {
283
- $set_domain_name = 'auto';
284
- }
285
-
286
- $support_display_advertising = '';
287
- if ( 'yes' == $this->ga_support_display_advertising ) {
288
- $support_display_advertising = "ga('require', 'displayfeatures');";
289
- }
290
-
291
- $anonymize_enabled = '';
292
- if ( 'yes' == $this->ga_anonymize_enabled ) {
293
- $anonymize_enabled = "ga('set', 'anonymizeIp', true);";
294
- }
295
-
296
- $code = "
297
- (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
298
- (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
299
- m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
300
- })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
301
-
302
- ga('create', '" . esc_js( $this->ga_id ) . "', '" . $set_domain_name . "');" .
303
- $support_display_advertising .
304
- $anonymize_enabled . "
305
- ga('set', 'dimension1', '" . $logged_in . "');
306
- ga('send', 'pageview');
307
-
308
- ga('require', 'ecommerce', 'ecommerce.js');
309
-
310
- ga('ecommerce:addTransaction', {
311
- 'id': '" . esc_js( $order->get_order_number() ) . "', // Transaction ID. Required
312
- 'affiliation': '" . esc_js( get_bloginfo( 'name' ) ) . "', // Affiliation or store name
313
- 'revenue': '" . esc_js( $order->get_total() ) . "', // Grand Total
314
- 'shipping': '" . esc_js( $order->get_total_shipping() ) . "', // Shipping
315
- 'tax': '" . esc_js( $order->get_total_tax() ) . "', // Tax
316
- 'currency': '" . esc_js( $order->get_order_currency() ) . "' // Currency
317
- });
318
- ";
319
-
320
- // Order items
321
- if ( $order->get_items() ) {
322
- foreach ( $order->get_items() as $item ) {
323
- $_product = $order->get_product_from_item( $item );
324
-
325
- $code .= "ga('ecommerce:addItem', {";
326
- $code .= "'id': '" . esc_js( $order->get_order_number() ) . "',";
327
- $code .= "'name': '" . esc_js( $item['name'] ) . "',";
328
- $code .= "'sku': '" . esc_js( $_product->get_sku() ? $_product->get_sku() : $_product->id ) . "',";
329
-
330
- if ( isset( $_product->variation_data ) ) {
331
-
332
- $code .= "'category': '" . esc_js( woocommerce_get_formatted_variation( $_product->variation_data, true ) ) . "',";
333
-
334
- } else {
335
- $out = array();
336
- $categories = get_the_terms($_product->id, 'product_cat');
337
- if ( $categories ) {
338
- foreach ( $categories as $category ) {
339
- $out[] = $category->name;
340
- }
341
- }
342
- $code .= "'category': '" . esc_js( join( "/", $out) ) . "',";
343
- }
344
-
345
- $code .= "'price': '" . esc_js( $order->get_item_total( $item ) ) . "',";
346
- $code .= "'quantity': '" . esc_js( $item['qty'] ) . "'";
347
- $code .= "});";
348
- }
349
- }
350
-
351
- $code .= "ga('ecommerce:send'); // Send transaction and item data to Google Analytics.";
352
-
353
- } else {
354
- if ( $this->ga_support_display_advertising == 'yes' ) {
355
- $ga_url = "('https:' == document.location.protocol ? 'https://' : 'http://') + 'stats.g.doubleclick.net/dc.js'";
356
- } else {
357
- $ga_url = "('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'";
358
- }
359
-
360
- $anonymize_enabled = '';
361
- if ( 'yes' == $this->ga_anonymize_enabled ) {
362
- $anonymize_enabled = "['_gat._anonymizeIp'],";
363
- }
364
-
365
- if ( ! empty( $this->ga_set_domain_name ) ) {
366
- $set_domain_name = "['_setDomainName', '" . esc_js( $this->ga_set_domain_name ) . "'],";
367
- } else {
368
- $set_domain_name = '';
369
- }
370
-
371
- $code = "
372
- var _gaq = _gaq || [];
373
-
374
- _gaq.push(
375
- ['_setAccount', '" . esc_js( $this->ga_id ) . "'], " . $set_domain_name .
376
- $anonymize_enabled . "
377
- ['_setCustomVar', 1, 'logged-in', '" . esc_js( $logged_in ) . "', 1],
378
- ['_trackPageview'],
379
- ['_set', 'currencyCode', '" . esc_js( $order->get_order_currency() ) . "']
380
- );
381
-
382
- _gaq.push(['_addTrans',
383
- '" . esc_js( $order->get_order_number() ) . "', // order ID - required
384
- '" . esc_js( get_bloginfo( 'name' ) ) . "', // affiliation or store name
385
- '" . esc_js( $order->get_total() ) . "', // total - required
386
- '" . esc_js( $order->get_total_tax() ) . "', // tax
387
- '" . esc_js( $order->get_total_shipping() ) . "', // shipping
388
- '" . esc_js( $order->billing_city ) . "', // city
389
- '" . esc_js( $order->billing_state ) . "', // state or province
390
- '" . esc_js( $order->billing_country ) . "' // country
391
- ]);
392
- ";
393
-
394
- // Order items
395
- if ( $order->get_items() ) {
396
- foreach ( $order->get_items() as $item ) {
397
- $_product = $order->get_product_from_item( $item );
398
-
399
- $code .= "_gaq.push(['_addItem',";
400
- $code .= "'" . esc_js( $order->get_order_number() ) . "',";
401
- $code .= "'" . esc_js( $_product->get_sku() ? $_product->get_sku() : $_product->id ) . "',";
402
- $code .= "'" . esc_js( $item['name'] ) . "',";
403
-
404
- if ( isset( $_product->variation_data ) ) {
405
-
406
- $code .= "'" . esc_js( woocommerce_get_formatted_variation( $_product->variation_data, true ) ) . "',";
407
-
408
- } else {
409
- $out = array();
410
- $categories = get_the_terms($_product->id, 'product_cat');
411
- if ( $categories ) {
412
- foreach ( $categories as $category ){
413
- $out[] = $category->name;
414
- }
415
- }
416
- $code .= "'" . esc_js( join( "/", $out) ) . "',";
417
- }
418
-
419
- $code .= "'" . esc_js( $order->get_item_total( $item ) ) . "',";
420
- $code .= "'" . esc_js( $item['qty'] ) . "'";
421
- $code .= "]);";
422
- }
423
- }
424
-
425
- $code .= "
426
- _gaq.push(['_trackTrans']); // submits transaction to the Analytics servers
427
-
428
- (function() {
429
- var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
430
- ga.src = " . $ga_url . ";
431
- var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
432
- })();
433
- ";
434
- }
435
 
436
  // Mark the order as tracked
437
  update_post_meta( $order_id, '_ga_tracked', 1 );
438
 
439
  return "
440
- <!-- WooCommerce Google Analytics Integration -->
441
- " . $this->get_generic_ga_code() . "
442
- <script type='text/javascript'>$code</script>
443
- <!-- /WooCommerce Google Analytics Integration -->
444
- ";
445
  }
446
 
447
  /**
448
  * Check if tracking is disabled
449
  *
450
- * @param string $type
451
  *
452
- * @return bool
453
  */
454
  private function disable_tracking( $type ) {
455
- if ( is_admin() || current_user_can( 'manage_options' ) || ( ! $this->ga_id ) || 'no' == $type ) {
456
  return true;
457
  }
458
  }
@@ -463,7 +338,6 @@ class WC_Google_Analytics extends WC_Integration {
463
  * @return void
464
  */
465
  public function add_to_cart() {
466
-
467
  if ( $this->disable_tracking( $this->ga_event_tracking_enabled ) ) {
468
  return;
469
  }
@@ -473,15 +347,55 @@ class WC_Google_Analytics extends WC_Integration {
473
 
474
  global $product;
475
 
476
- $parameters = array();
477
  // Add single quotes to allow jQuery to be substituted into _trackEvent parameters
 
478
  $parameters['category'] = "'" . __( 'Products', 'woocommerce-google-analytics-integration' ) . "'";
479
  $parameters['action'] = "'" . __( 'Add to Cart', 'woocommerce-google-analytics-integration' ) . "'";
480
  $parameters['label'] = "'" . esc_js( $product->get_sku() ? __( 'SKU:', 'woocommerce-google-analytics-integration' ) . ' ' . $product->get_sku() : "#" . $product->id ) . "'";
481
 
482
- $this->event_tracking_code( $parameters, '.single_add_to_cart_button' );
 
 
 
 
 
 
 
 
483
  }
484
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
485
 
486
  /**
487
  * Google Analytics event tracking for loop add to cart
@@ -489,53 +403,114 @@ class WC_Google_Analytics extends WC_Integration {
489
  * @return void
490
  */
491
  public function loop_add_to_cart() {
492
-
493
  if ( $this->disable_tracking( $this->ga_event_tracking_enabled ) ) {
494
  return;
495
  }
496
 
497
- $parameters = array();
498
  // Add single quotes to allow jQuery to be substituted into _trackEvent parameters
 
499
  $parameters['category'] = "'" . __( 'Products', 'woocommerce-google-analytics-integration' ) . "'";
500
  $parameters['action'] = "'" . __( 'Add to Cart', 'woocommerce-google-analytics-integration' ) . "'";
501
  $parameters['label'] = "($(this).data('product_sku')) ? ('SKU: ' + $(this).data('product_sku')) : ('#' + $(this).data('product_id'))"; // Product SKU or ID
502
 
503
- $this->event_tracking_code( $parameters, '.add_to_cart_button:not(.product_type_variable, .product_type_grouped)' );
 
 
 
 
 
 
 
 
504
  }
505
 
506
  /**
507
- * Google Analytics event tracking for loop add to cart
508
- *
509
- * @param array $parameters associative array of _trackEvent parameters
510
- * @param string $selector jQuery selector for binding click event
511
- *
512
- * @return void
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
513
  */
514
- private function event_tracking_code( $parameters, $selector ) {
515
- $parameters = apply_filters( 'woocommerce_ga_event_tracking_parameters', $parameters );
 
 
516
 
517
- if ( 'yes' == $this->ga_use_universal_analytics ) {
518
- $track_event = "ga('send', 'event', %s, %s, %s);";
519
- } else {
520
- $track_event = "_gaq.push(['_trackEvent', %s, %s, %s]);";
521
  }
522
 
523
- wc_enqueue_js( "
524
- $( '" . $selector . "' ).click( function() {
525
- " . sprintf( $track_event, $parameters['category'], $parameters['action'], $parameters['label'] ) . "
526
- });
527
- " );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
528
  }
529
 
530
  /**
531
  * Add the utm_nooverride parameter to any return urls. This makes sure Google Adwords doesn't mistake the offsite gateway as the referrer.
532
  *
533
- * @param string $type
534
  *
535
- * @return string
536
  */
537
  public function utm_nooverride( $return_url ) {
538
-
539
  // We don't know if the URL already has the parameter so we should remove it just in case
540
  $return_url = remove_query_arg( 'utm_nooverride', $return_url );
541
 
19
  * @return void
20
  */
21
  public function __construct() {
22
+ $this->id = 'google_analytics';
23
+ $this->method_title = __( 'Google Analytics', 'woocommerce-google-analytics-integration' );
24
+ $this->method_description = __( 'Google Analytics is a free service offered by Google that generates detailed statistics about the visitors to a website.', 'woocommerce-google-analytics-integration' );
25
+ $this->dismissed_info_banner = get_option( 'woocommerce_dismissed_info_banner' );
26
 
27
+ // Load the settings
28
  $this->init_form_fields();
29
  $this->init_settings();
30
+ $constructor = $this->init_options();
31
 
32
+ // Contains snippets/JS tracking code
33
+ include_once( 'class-wc-google-analytics-js.php' );
34
+ WC_Google_Analytics_JS::get_instance( $constructor );
35
+
36
+ // Display an info banner on how to configure WooCommerce
37
+ if ( is_admin() ) {
38
+ include_once( 'class-wc-google-analytics-info-banner.php' );
39
+ WC_Google_Analytics_Info_Banner::get_instance( $this->dismissed_info_banner, $this->ga_id );
40
+ }
41
+
42
+ // Admin Options
43
+ add_filter( 'woocommerce_tracker_data', array( $this, 'track_options' ) );
44
  add_action( 'woocommerce_update_options_integration_google_analytics', array( $this, 'process_admin_options') );
45
+ add_action( 'woocommerce_update_options_integration_google_analytics', array( $this, 'show_options_info') );
46
+ add_action( 'admin_enqueue_scripts', array( $this, 'load_admin_assets') );
47
 
48
  // Tracking code
49
  add_action( 'wp_head', array( $this, 'tracking_code_display' ), 999999 );
51
  // Event tracking code
52
  add_action( 'woocommerce_after_add_to_cart_button', array( $this, 'add_to_cart' ) );
53
  add_action( 'wp_footer', array( $this, 'loop_add_to_cart' ) );
54
+ add_action( 'woocommerce_after_cart', array( $this, 'remove_from_cart' ) );
55
+ add_action( 'woocommerce_after_mini_cart', array( $this, 'remove_from_cart' ) );
56
+ add_filter( 'woocommerce_cart_item_remove_link', array( $this, 'remove_from_cart_attributes' ), 10, 2 );
57
+ add_action( 'woocommerce_after_shop_loop_item', array( $this, 'listing_impression' ) );
58
+ add_action( 'woocommerce_after_shop_loop_item', array( $this, 'listing_click' ) );
59
+ add_action( 'woocommerce_after_single_product', array( $this, 'product_detail' ) );
60
+ add_action( 'woocommerce_after_checkout_form', array( $this, 'checkout_process' ) );
61
 
62
  // utm_nooverride parameter for Google AdWords
63
  add_filter( 'woocommerce_get_return_url', array( $this, 'utm_nooverride' ) );
64
  }
65
 
66
  /**
67
+ * Loads all of our options for this plugin
68
+ * @return array An array of options that can be passed to other classes
 
69
  */
70
+ public function init_options() {
71
+ $options = array(
72
+ 'ga_id',
73
+ 'ga_set_domain_name',
74
+ 'ga_standard_tracking_enabled',
75
+ 'ga_support_display_advertising',
76
+ 'ga_use_universal_analytics',
77
+ 'ga_anonymize_enabled',
78
+ 'ga_ecommerce_tracking_enabled',
79
+ 'ga_enhanced_ecommerce_tracking_enabled',
80
+ 'ga_enhanced_remove_from_cart_enabled',
81
+ 'ga_enhanced_product_impression_enabled',
82
+ 'ga_enhanced_product_click_enabled',
83
+ 'ga_enhanced_checkout_process_enabled',
84
+ 'ga_enhanced_product_detail_view_enabled',
85
+ 'ga_event_tracking_enabled'
86
+ );
87
 
88
+ $constructor = array();
89
+ foreach ( $options as $option ) {
90
+ $constructor[ $option ] = $this->$option = $this->get_option( $option );
91
+ }
92
+
93
+ return $constructor;
94
+ }
95
+
96
+ /**
97
+ * Tells WooCommerce which settings to display under the "integration" tab
98
+ */
99
+ public function init_form_fields() {
100
  $this->form_fields = array(
101
  'ga_id' => array(
102
+ 'title' => __( 'Google Analytics ID', 'woocommerce-google-analytics-integration' ),
103
+ 'description' => __( 'Log into your Google Analytics account to find your ID. e.g. <code>UA-XXXXX-X</code>', 'woocommerce-google-analytics-integration' ),
104
+ 'type' => 'text',
105
+ 'placeholder' => 'UA-XXXXX-X',
106
+ 'default' => get_option( 'woocommerce_ga_id' ) // Backwards compat
107
  ),
108
  'ga_set_domain_name' => array(
109
  'title' => __( 'Set Domain Name', 'woocommerce-google-analytics-integration' ),
112
  'default' => ''
113
  ),
114
  'ga_standard_tracking_enabled' => array(
115
+ 'title' => __( 'Tracking Options', 'woocommerce-google-analytics-integration' ),
116
+ 'label' => __( 'Enable Standard Tracking', 'woocommerce-google-analytics-integration' ),
117
+ 'description' => __( 'This tracks session data such as demographics, system, etc. You don\'t need to enable this if you are using a 3rd party Google analytics plugin.', 'woocommerce-google-analytics-integration' ),
118
+ 'type' => 'checkbox',
119
+ 'checkboxgroup' => 'start',
120
+ 'default' => get_option( 'woocommerce_ga_standard_tracking_enabled' ) ? get_option( 'woocommerce_ga_standard_tracking_enabled' ) : 'no' // Backwards compat
121
+ ),
122
+ 'ga_support_display_advertising' => array(
123
+ 'label' => __( '"Display Advertising" Support', 'woocommerce-google-analytics-integration' ),
124
+ 'description' => sprintf( __( 'Set the Google Analytics code to support Display Advertising. %sRead more about Display Advertising%s.', 'woocommerce-google-analytics-integration' ), '<a href="https://support.google.com/analytics/answer/2700409" target="_blank">', '</a>' ),
125
+ 'type' => 'checkbox',
126
+ 'checkboxgroup' => '',
127
+ 'default' => get_option( 'woocommerce_ga_support_display_advertising' ) ? get_option( 'woocommerce_ga_support_display_advertising' ) : 'no' // Backwards compat
128
+ ),
129
+ 'ga_use_universal_analytics' => array(
130
+ 'label' => __( 'Enable Universal Analytics', 'woocommerce-google-analytics-integration' ),
131
+ 'description' => sprintf( __( 'Uses Universal Analytics instead of Classic Google Analytics. If you have <strong>not</strong> previously used Google Analytics on this site, check this box. Otherwise, %sfollow step 1 of the Universal Analytics upgrade guide.%s Enabling this setting will take care of step 2. %sRead more about Universal Analytics%s. Universal Analytics must be enabled to enable enhanced eCommerce.', 'woocommerce-google-analytics-integration' ), '<a href="https://developers.google.com/analytics/devguides/collection/upgrade/guide" target="_blank">', '</a>', '<a href="https://support.google.com/analytics/answer/2790010?hl=en" target="_blank">', '</a>' ),
132
+ 'type' => 'checkbox',
133
+ 'checkboxgroup' => '',
134
+ 'default' => get_option( 'woocommerce_ga_use_universal_analytics' ) ? get_option( 'woocommerce_ga_use_universal_analytics' ) : 'no' // Backwards compat
135
+ ),
136
+ 'ga_anonymize_enabled' => array(
137
+ 'label' => __( 'Anonymize IP addresses.', 'woocommerce-google-analytics-integration' ),
138
+ 'description' => sprintf( __( 'Enabling this option is mandatory in certain countries due to national privacy laws. %sRead more about IP Anonymization%s.', 'woocommerce-google-analytics-integration' ), '<a href="https://support.google.com/analytics/answer/2763052" target="_blank">', '</a>' ),
139
+ 'type' => 'checkbox',
140
+ 'checkboxgroup' => '',
141
+ 'default' => 'yes'
142
+ ),
143
+ 'ga_ecommerce_tracking_enabled' => array(
144
+ 'label' => __( 'Purchase Transactions', 'woocommerce-google-analytics-integration' ),
145
+ 'description' => __( 'This requires a payment gateway that redirects to the thank you/order received page after payment. Orders paid with gateways which do not do this will not be tracked.', 'woocommerce-google-analytics-integration' ),
146
  'type' => 'checkbox',
147
  'checkboxgroup' => 'start',
148
+ 'default' => get_option( 'woocommerce_ga_ecommerce_tracking_enabled' ) ? get_option( 'woocommerce_ga_ecommerce_tracking_enabled' ) : 'yes' // Backwards compat
149
  ),
150
+ 'ga_event_tracking_enabled' => array(
151
+ 'label' => __( 'Add to Cart Events', 'woocommerce-google-analytics-integration' ),
152
  'type' => 'checkbox',
153
  'checkboxgroup' => '',
154
+ 'default' => 'yes'
155
  ),
156
+
157
+ 'ga_enhanced_ecommerce_tracking_enabled' => array(
158
+ 'title' => __( 'Enhanced eCommerce', 'woocommerce-google-analytics-integration' ),
159
+ 'label' => __( 'Enable Enhanced eCommerce ', 'woocommerce-google-analytics-integration' ),
160
+ 'description' => sprintf( __( 'Enhanced eCommerce allows you to measure more user interactions with your store, including: product impressions, product detail views, starting the checkout process, adding cart items, and removing cart items. Universal Analytics must be enabled for Enhanced eCommerce to work. Before enabling this setting, turn on Enhanced eCommerce in your Google Analytics dashboard. <a href="%s">See here for more information</a>.', 'woocommerce-google-analytics-integration' ), 'https://support.google.com/analytics/answer/6032539?hl=en' ),
161
+ 'type' => 'checkbox',
162
+ 'checkboxgroup' => '',
163
+ 'default' => 'no'
164
+ ),
165
+
166
+ // Enhanced eCommerce Settings
167
+
168
+ 'ga_enhanced_remove_from_cart_enabled' => array(
169
+ 'label' => __( 'Remove from Cart Events', 'woocommerce-google-analytics-integration' ),
170
  'type' => 'checkbox',
171
  'checkboxgroup' => '',
172
+ 'default' => 'yes',
173
+ 'class' => 'enhanced-setting'
174
  ),
175
+
176
+ 'ga_enhanced_product_impression_enabled' => array(
177
+ 'label' => __( 'Product Impressions from Listing Pages', 'woocommerce-google-analytics-integration' ),
178
  'type' => 'checkbox',
179
  'checkboxgroup' => '',
180
+ 'default' => 'yes',
181
+ 'class' => 'enhanced-setting'
182
  ),
183
+
184
+ 'ga_enhanced_product_click_enabled' => array(
185
+ 'label' => __( 'Product Clicks from Listing Pages', 'woocommerce-google-analytics-integration' ),
186
  'type' => 'checkbox',
187
  'checkboxgroup' => '',
188
+ 'default' => 'yes',
189
+ 'class' => 'enhanced-setting'
190
  ),
191
+
192
+ 'ga_enhanced_product_detail_view_enabled' => array(
193
+ 'label' => __( 'Product Detail Views', 'woocommerce-google-analytics-integration' ),
194
  'type' => 'checkbox',
195
+ 'checkboxgroup' => '',
196
+ 'default' => 'yes',
197
+ 'class' => 'enhanced-setting'
198
+ ),
199
+
200
+ 'ga_enhanced_checkout_process_enabled' => array(
201
+ 'label' => __( 'Checkout Process Initiated', 'woocommerce-google-analytics-integration' ),
202
+ 'type' => 'checkbox',
203
+ 'checkboxgroup' => '',
204
+ 'default' => 'yes',
205
+ 'class' => 'enhanced-setting'
206
+ ),
207
  );
208
  }
209
 
210
  /**
211
+ * Shows some additional help text after saving the Google Analytics settings
212
+ */
213
+ function show_options_info() {
214
+ $this->method_description .= "<div class='notice notice-info'><p>" . __( 'Please allow Google Analytics 24 hours to start displaying results.', 'woocommerce-google-analytics-integration' ) . "</p></div>";
215
+
216
+ if ( isset( $_REQUEST['woocommerce_google_analytics_ga_ecommerce_tracking_enabled'] ) && true === (bool) $_REQUEST['woocommerce_google_analytics_ga_ecommerce_tracking_enabled'] ) {
217
+ $this->method_description .= "<div class='notice notice-info'><p>" . __( 'Please note, for transaction tracking to work properly, you will need to use a payment gateway that redirects the customer back to a WooCommerce order received/thank you page.', 'woocommerce-google-analytics-integration' ) . "</div>";
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Hooks into woocommerce_tracker_data and tracks some of the analytic settings (just enabled|disabled status)
223
+ * only if you have opted into WooCommerce tracking
224
+ * http://www.woothemes.com/woocommerce/usage-tracking/
225
+ */
226
+ function track_options( $data ) {
227
+ $data['wc-google-analytics'] = array(
228
+ 'standard_tracking_enabled' => $this->ga_standard_tracking_enabled,
229
+ 'support_display_advertising' => $this->ga_support_display_advertising,
230
+ 'use_universal_analytics' => $this->ga_use_universal_analytics,
231
+ 'anonymize_enabled' => $this->ga_anonymize_enabled,
232
+ 'ecommerce_tracking_enabled' => $this->ga_ecommerce_tracking_enabled,
233
+ 'event_tracking_enabled' => $this->ga_event_tracking_enabled
234
+ );
235
+ return $data;
236
+ }
237
+
238
+ /**
239
  *
240
+ */
241
+ function load_admin_assets() {
242
+ $screen = get_current_screen();
243
+ if ( 'woocommerce_page_wc-settings' !== $screen->id ) {
244
+ return;
245
+ }
246
+
247
+ if ( empty( $_GET['tab'] ) ) {
248
+ return;
249
+ }
250
+
251
+ if ( 'integration' !== $_GET['tab'] ) {
252
+ return;
253
+ }
254
+
255
+ wp_enqueue_script( 'wc-google-analytics-admin-enhanced-settings', plugins_url( '/assets/js/admin-enhanced-settings.js', dirname(__FILE__) ) );
256
+ }
257
+
258
+ /**
259
+ * Display the tracking codes
260
+ * Acts as a controller to figure out which code to display
261
  */
262
  public function tracking_code_display() {
263
  global $wp;
268
  }
269
 
270
  // Check if is order received page and stop when the products and not tracked
271
+ if ( is_order_received_page() && 'yes' === $this->ga_ecommerce_tracking_enabled ) {
272
  $order_id = isset( $wp->query_vars['order-received'] ) ? $wp->query_vars['order-received'] : 0;
 
273
  if ( 0 < $order_id && 1 != get_post_meta( $order_id, '_ga_tracked', true ) ) {
274
  $display_ecommerce_tracking = true;
 
275
  echo $this->get_ecommerce_tracking_code( $order_id );
276
  }
277
  }
278
 
279
+ if ( is_woocommerce() || is_cart() || ( is_checkout() && ! $display_ecommerce_tracking ) ) {
280
+ $display_ecommerce_tracking = true;
281
+ echo $this->get_standard_tracking_code();
282
  }
 
283
 
284
+ if ( ! $display_ecommerce_tracking && 'yes' === $this->ga_standard_tracking_enabled ) {
285
+ echo $this->get_standard_tracking_code();
286
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
  }
288
 
289
  /**
290
+ * Standard Google Analytics tracking
 
 
291
  */
292
+ protected function get_standard_tracking_code() {
293
+ return "<!-- WooCommerce Google Analytics Integration -->
294
+ " . WC_Google_Analytics_JS::get_instance()->header() . "
295
+ <script type='text/javascript'>" . WC_Google_Analytics_JS::get_instance()->load_analytics() . "</script>
296
+ <!-- /WooCommerce Google Analytics Integration -->";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  }
298
 
299
  /**
300
+ * eCommerce tracking
301
  *
302
  * @param int $order_id
 
 
303
  */
304
  protected function get_ecommerce_tracking_code( $order_id ) {
305
  // Get the order and output tracking code
306
  $order = new WC_Order( $order_id );
307
 
308
+ $code = WC_Google_Analytics_JS::get_instance()->load_analytics( $order );
309
+ $code .= WC_Google_Analytics_JS::get_instance()->add_transaction( $order );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
 
311
  // Mark the order as tracked
312
  update_post_meta( $order_id, '_ga_tracked', 1 );
313
 
314
  return "
315
+ <!-- WooCommerce Google Analytics Integration -->
316
+ " . WC_Google_Analytics_JS::get_instance()->header() . "
317
+ <script type='text/javascript'>$code</script>
318
+ <!-- /WooCommerce Google Analytics Integration -->
319
+ ";
320
  }
321
 
322
  /**
323
  * Check if tracking is disabled
324
  *
325
+ * @param string $type The setting to check
326
  *
327
+ * @return bool True if tracking for a certain setting is disabled
328
  */
329
  private function disable_tracking( $type ) {
330
+ if ( is_admin() || current_user_can( 'manage_options' ) || ( ! $this->ga_id ) || 'no' === $type ) {
331
  return true;
332
  }
333
  }
338
  * @return void
339
  */
340
  public function add_to_cart() {
 
341
  if ( $this->disable_tracking( $this->ga_event_tracking_enabled ) ) {
342
  return;
343
  }
347
 
348
  global $product;
349
 
 
350
  // Add single quotes to allow jQuery to be substituted into _trackEvent parameters
351
+ $parameters = array();
352
  $parameters['category'] = "'" . __( 'Products', 'woocommerce-google-analytics-integration' ) . "'";
353
  $parameters['action'] = "'" . __( 'Add to Cart', 'woocommerce-google-analytics-integration' ) . "'";
354
  $parameters['label'] = "'" . esc_js( $product->get_sku() ? __( 'SKU:', 'woocommerce-google-analytics-integration' ) . ' ' . $product->get_sku() : "#" . $product->id ) . "'";
355
 
356
+ if ( ! $this->disable_tracking( $this->ga_enhanced_ecommerce_tracking_enabled ) ) {
357
+ $code = "" . WC_Google_Analytics_JS::get_instance()->tracker_var() . "( 'ec:addProduct', {";
358
+ $code .= "'id': '" . esc_js( $product->get_sku() ? $product->get_sku() : $product->id ) . "',";
359
+ $code .= "'quantity': $( 'input.qty' ).val() ? $( 'input.qty' ).val() : '1'";
360
+ $code .= "} );";
361
+ $parameters['enhanced'] = $code;
362
+ }
363
+
364
+ WC_Google_Analytics_JS::get_instance()->event_tracking_code( $parameters, '.single_add_to_cart_button' );
365
  }
366
 
367
+ /**
368
+ * Enhanced Analytics event tracking for removing a product from the cart
369
+ */
370
+ public function remove_from_cart() {
371
+ if ( $this->disable_tracking( $this->ga_use_universal_analytics ) ) {
372
+ return;
373
+ }
374
+
375
+ if ( $this->disable_tracking( $this->ga_enhanced_ecommerce_tracking_enabled ) ) {
376
+ return;
377
+ }
378
+
379
+ if ( $this->disable_tracking( $this->ga_enhanced_remove_from_cart_enabled ) ) {
380
+ return;
381
+ }
382
+
383
+ WC_Google_Analytics_JS::get_instance()->remove_from_cart();
384
+ }
385
+
386
+ /**
387
+ * Adds the product ID and SKU to the remove product link if not present
388
+ */
389
+ public function remove_from_cart_attributes( $url, $key ) {
390
+ if ( strpos( $url,'data-product_id' ) !== false ) {
391
+ return $url;
392
+ }
393
+
394
+ $item = WC()->cart->get_cart_item( $key );
395
+ $product = $item['data'];
396
+ $url = str_replace( 'href=', 'data-product_id="' . esc_attr( $product->id ) . '" data-product_sku="' . esc_attr( $product->get_sku() ) . '" href=', $url );
397
+ return $url;
398
+ }
399
 
400
  /**
401
  * Google Analytics event tracking for loop add to cart
403
  * @return void
404
  */
405
  public function loop_add_to_cart() {
 
406
  if ( $this->disable_tracking( $this->ga_event_tracking_enabled ) ) {
407
  return;
408
  }
409
 
 
410
  // Add single quotes to allow jQuery to be substituted into _trackEvent parameters
411
+ $parameters = array();
412
  $parameters['category'] = "'" . __( 'Products', 'woocommerce-google-analytics-integration' ) . "'";
413
  $parameters['action'] = "'" . __( 'Add to Cart', 'woocommerce-google-analytics-integration' ) . "'";
414
  $parameters['label'] = "($(this).data('product_sku')) ? ('SKU: ' + $(this).data('product_sku')) : ('#' + $(this).data('product_id'))"; // Product SKU or ID
415
 
416
+ if ( ! $this->disable_tracking( $this->ga_enhanced_ecommerce_tracking_enabled ) ) {
417
+ $code = "" . WC_Google_Analytics_JS::get_instance()->tracker_var() . "( 'ec:addProduct', {";
418
+ $code .= "'id': ($(this).data('product_sku')) ? ('SKU: ' + $(this).data('product_sku')) : ('#' + $(this).data('product_id')),";
419
+ $code .= "'quantity': $(this).data('quantity')";
420
+ $code .= "} );";
421
+ $parameters['enhanced'] = $code;
422
+ }
423
+
424
+ WC_Google_Analytics_JS::get_instance()->event_tracking_code( $parameters, '.add_to_cart_button:not(.product_type_variable, .product_type_grouped)' );
425
  }
426
 
427
  /**
428
+ * Measures a listing impression (from search results)
429
+ */
430
+ public function listing_impression() {
431
+ if ( $this->disable_tracking( $this->ga_use_universal_analytics ) ) {
432
+ return;
433
+ }
434
+
435
+ if ( $this->disable_tracking( $this->ga_enhanced_ecommerce_tracking_enabled ) ) {
436
+ return;
437
+ }
438
+
439
+ if ( $this->disable_tracking( $this->ga_enhanced_product_impression_enabled ) ) {
440
+ return;
441
+ }
442
+
443
+ global $product, $woocommerce_loop;
444
+ WC_Google_Analytics_JS::get_instance()->listing_impression( $product, $woocommerce_loop['loop'] );
445
+ }
446
+
447
+ /**
448
+ * Measure a product click from a listing page
449
+ */
450
+ public function listing_click() {
451
+ if ( $this->disable_tracking( $this->ga_use_universal_analytics ) ) {
452
+ return;
453
+ }
454
+
455
+ if ( $this->disable_tracking( $this->ga_enhanced_ecommerce_tracking_enabled ) ) {
456
+ return;
457
+ }
458
+
459
+ if ( $this->disable_tracking( $this->ga_enhanced_product_click_enabled ) ) {
460
+ return;
461
+ }
462
+
463
+ global $product, $woocommerce_loop;
464
+ WC_Google_Analytics_JS::get_instance()->listing_click( $product, $woocommerce_loop['loop'] );
465
+ }
466
+
467
+ /**
468
+ * Measure a product detail view
469
  */
470
+ public function product_detail() {
471
+ if ( $this->disable_tracking( $this->ga_use_universal_analytics ) ) {
472
+ return;
473
+ }
474
 
475
+ if ( $this->disable_tracking( $this->ga_enhanced_ecommerce_tracking_enabled ) ) {
476
+ return;
 
 
477
  }
478
 
479
+ if ( $this->disable_tracking( $this->ga_enhanced_product_detail_view_enabled ) ) {
480
+ return;
481
+ }
482
+
483
+ global $product;
484
+ WC_Google_Analytics_JS::get_instance()->product_detail( $product );
485
+ }
486
+
487
+ /**
488
+ * Tracks when the checkout form is loaded
489
+ */
490
+ public function checkout_process( $checkout ) {
491
+ if ( $this->disable_tracking( $this->ga_use_universal_analytics ) ) {
492
+ return;
493
+ }
494
+
495
+ if ( $this->disable_tracking( $this->ga_enhanced_ecommerce_tracking_enabled ) ) {
496
+ return;
497
+ }
498
+
499
+ if ( $this->disable_tracking( $this->ga_enhanced_checkout_process_enabled ) ) {
500
+ return;
501
+ }
502
+
503
+ WC_Google_Analytics_JS::get_instance()->checkout_process( WC()->cart->get_cart() );
504
  }
505
 
506
  /**
507
  * Add the utm_nooverride parameter to any return urls. This makes sure Google Adwords doesn't mistake the offsite gateway as the referrer.
508
  *
509
+ * @param string $return_url WooCommerce Return URL
510
  *
511
+ * @return string URL
512
  */
513
  public function utm_nooverride( $return_url ) {
 
514
  // We don't know if the URL already has the parameter so we should remove it just in case
515
  $return_url = remove_query_arg( 'utm_nooverride', $return_url );
516
 
languages/woocommerce-google-analytics-integration.pot CHANGED
@@ -2,7 +2,7 @@
2
  # This file is distributed under the GPLv2 or later.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: WooCommerce Google Analytics Integration 1.3.0\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://wordpress.org/support/plugin/woocommerce-google-analytics-"
8
  "integration\n"
2
  # This file is distributed under the GPLv2 or later.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: WooCommerce Google Analytics Integration 1.4.0\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://wordpress.org/support/plugin/woocommerce-google-analytics-"
8
  "integration\n"
package.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "woocommerce-google-analytics-integration",
3
+ "title": "WooCommerce Google Analytics Integration",
4
+ "version": "1.4.0",
5
+ "homepage": "https://wordpress.org/plugins/woocommerce-google-analytics-integration/",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/woothemes/woocommerce-google-analytics-integration.git"
9
+ },
10
+ "main": "Gruntfile.js",
11
+ "devDependencies": {
12
+ "grunt": "^0.4.5",
13
+ "grunt-wp-i18n": "^0.4.9",
14
+ "grunt-checktextdomain": "^0.1.1",
15
+ "grunt-contrib-uglify": "~0.3.2",
16
+ "grunt-contrib-watch": "~0.5.3"
17
+ },
18
+ "engines": {
19
+ "node": ">=0.8.0",
20
+ "npm": ">=1.1.0"
21
+ }
22
+ }
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: woothemes, claudiosanches
3
  Tags: woocommerce, google analytics
4
  Requires at least: 3.8
5
- Tested up to: 4.0
6
- Stable tag: 1.3.0
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
@@ -11,7 +11,7 @@ Provides integration between Google Analytics and WooCommerce.
11
 
12
  == Description ==
13
 
14
- This plugin provides the integration between Google Analytics and the WooCommerce plugin. You can link a referral to a purchase and add transaction information to your Google Analytics data. It also supports the new Universal Analytics, eCommerce and event tracking.
15
 
16
  Starting WooCommerce 2.1, this integration will no longer be part of WooCommerce and will only be available by using this plugin.
17
 
@@ -64,6 +64,12 @@ Exact wording depends on the national data privacy laws and should be adjusted.
64
 
65
  == Changelog ==
66
 
 
 
 
 
 
 
67
  = 1.3.0 - 12/11/2014 =
68
 
69
  * Feature - Added the transaction currency in the tracking code
2
  Contributors: woothemes, claudiosanches
3
  Tags: woocommerce, google analytics
4
  Requires at least: 3.8
5
+ Tested up to: 4.5.2
6
+ Stable tag: 1.4.0
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
11
 
12
  == Description ==
13
 
14
+ This plugin provides the integration between Google Analytics and the WooCommerce plugin. You can link a referral to a purchase and add transaction information to your Google Analytics data. It also supports the new Universal Analytics, eCommerce, and enhanced eCommerce event tracking.
15
 
16
  Starting WooCommerce 2.1, this integration will no longer be part of WooCommerce and will only be available by using this plugin.
17
 
64
 
65
  == Changelog ==
66
 
67
+ = 1.4.0 - 20-11-2015
68
+ * Feature - Support for enhanced eCommerce (tracking full store process from view to order)
69
+ * Tweak - Setting up the plugin is now clearer with some helpful links and clearer language
70
+ * Tweak - New filter on the ga global variable
71
+ * Refactor - JavaScript generation functions have been moved to their own class
72
+
73
  = 1.3.0 - 12/11/2014 =
74
 
75
  * Feature - Added the transaction currency in the tracking code
woocommerce-google-analytics-integration.php CHANGED
@@ -5,7 +5,7 @@
5
  * Description: Allows Google Analytics tracking code to be inserted into WooCommerce store pages.
6
  * Author: WooThemes
7
  * Author URI: http://woothemes.com
8
- * Version: 1.3.0
9
  * License: GPLv2 or later
10
  * Text Domain: woocommerce-google-analytics-integration
11
  * Domain Path: languages/
@@ -27,7 +27,7 @@ class WC_Google_Analytics_Integration {
27
  *
28
  * @var string
29
  */
30
- const VERSION = '1.3.0';
31
 
32
  /**
33
  * Instance of this class.
5
  * Description: Allows Google Analytics tracking code to be inserted into WooCommerce store pages.
6
  * Author: WooThemes
7
  * Author URI: http://woothemes.com
8
+ * Version: 1.4.0
9
  * License: GPLv2 or later
10
  * Text Domain: woocommerce-google-analytics-integration
11
  * Domain Path: languages/
27
  *
28
  * @var string
29
  */
30
+ const VERSION = '1.4.0';
31
 
32
  /**
33
  * Instance of this class.