spree_google_analytics 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 073d2aa4a4a2b50971122cb0abd0b9808fb7f78acc541145c2e195ce58e4778f
4
- data.tar.gz: aa0bedfcafb490342aa0db3e9f4d5a41408929ad092ae35324235f6c34f94df9
3
+ metadata.gz: 19ff839e89a8bdedb1da8ed93fa302c690211e56ab199beaae23278d51178af8
4
+ data.tar.gz: c55371fada9e8c6d34b82f7bf05ceed492180b492e8b141bee7748846a46c207
5
5
  SHA512:
6
- metadata.gz: 38e7822a559720b891aeb09957ff38e41cd8cf7a4e060d84a9b8fd366f12f8273068a2d5071d72d3bd63e46a3a0aa5a4ee648042487b5232ad0f44b4348293c9
7
- data.tar.gz: 9485726d7f81a77c0165f1bd1fde3994501e06b271179c661b54cb411ad06b4a5927b6805413d2bdf94395cd1c70d11dca2c5580c50d0f5caa40e1f4c17735a0
6
+ metadata.gz: '0210987ac97d38ad1e72814a4eb391d2a887fea4af5c15ba429999b0d67ffe08da54d7f04b79a9f67445f7fcf36efa5137331209125e11fa288c30de4e2d35d7'
7
+ data.tar.gz: d777ce1865934d4739ec7c1c1c537b9e5b6987ffa88ba4accd47c5f0372281b8b8e8eb5564639b02d49365526a64cc60c3367633327fd60d1551cf4275e44e17
@@ -1 +1,5 @@
1
1
  //= link_tree ../images
2
+ //= link spree_google_analytics/application.js
3
+ //= link_tree ../../javascript/spree_google_analytics/controllers .js
4
+ //= link_tree ../../../vendor/javascript .js
5
+ //= link_tree ../../../vendor/stylesheets .css
@@ -7,3 +7,14 @@ module SpreeGoogleAnalytics
7
7
  end
8
8
 
9
9
  Spree::StoreController.prepend(SpreeGoogleAnalytics::StoreControllerDecorator) if defined?(Spree::StoreController)
10
+
11
+ # include in Devise controllers
12
+ if defined?(Spree::UserSessionsController)
13
+ Spree::UserSessionsController.prepend(SpreeGoogleAnalytics::StoreControllerDecorator)
14
+ end
15
+ if defined?(Spree::UserRegistrationsController)
16
+ Spree::UserRegistrationsController.prepend(SpreeGoogleAnalytics::StoreControllerDecorator)
17
+ end
18
+ if defined?(Spree::UserPasswordsController)
19
+ Spree::UserPasswordsController.prepend(SpreeGoogleAnalytics::StoreControllerDecorator)
20
+ end
@@ -1,9 +1,11 @@
1
1
  module SpreeGoogleAnalytics
2
2
  module BaseHelper
3
- def google_analytics_checkout_json
4
- return unless @order.present?
3
+ def google_analytics_client_type
4
+ @google_analytics_client_type ||= store_integration('google_analytics')&.preferred_client
5
+ end
5
6
 
6
- @google_analytics_checkout_json ||= SpreeGoogleAnalytics::CheckoutPresenter.new(order: @order).call.to_json.html_safe
7
+ def use_gtm?
8
+ google_analytics_client_type == 'gtm'
7
9
  end
8
10
 
9
11
  def google_analytics_add_shipping_info_json(shipment)
@@ -21,60 +23,206 @@ module SpreeGoogleAnalytics
21
23
  }.to_json.html_safe
22
24
  end
23
25
 
24
- def google_analytics_payment_json
25
- return unless @order.present?
26
-
27
- @google_analytics_payment_json ||= SpreeGoogleAnalytics::PaymentPresenter.new(order: @order).call.to_json.html_safe
28
- end
29
-
30
- def google_analytics_purchase_json
31
- return unless @order.present?
32
26
 
33
- @google_analytics_purchase_json ||= SpreeGoogleAnalytics::OrderPresenter.new(order: @order).call.to_json.html_safe
34
- end
35
27
 
36
28
  def google_analytics_view_item_json(variant = nil)
37
29
  variant ||= @selected_variant || @variant_from_options || @product&.default_variant
38
30
  return unless variant.present?
39
31
 
32
+ if use_gtm?
33
+ google_analytics_gtm_view_item_json(variant)
34
+ else
35
+ {
36
+ currency: current_currency,
37
+ value: variant.amount_in(current_currency).to_f,
38
+ items: [
39
+ SpreeGoogleAnalytics::ProductPresenter.new(
40
+ store_name: current_store.name,
41
+ resource: variant,
42
+ quantity: 1
43
+ ).call
44
+ ]
45
+ }.to_json.html_safe
46
+ end
47
+ end
48
+
49
+ def google_analytics_gtm_view_item_json(variant)
40
50
  {
41
- currency: current_currency,
42
- value: variant.amount_in(current_currency).to_f,
43
- items: [
44
- SpreeGoogleAnalytics::ProductPresenter.new(
45
- store_name: current_store.name,
46
- resource: variant,
47
- quantity: 1
48
- ).call
49
- ]
51
+ event: 'view_item',
52
+ ecommerce: {
53
+ currency: current_currency,
54
+ value: variant.amount_in(current_currency).to_f,
55
+ items: [
56
+ SpreeGoogleAnalytics::ProductPresenter.new(
57
+ store_name: current_store.name,
58
+ resource: variant,
59
+ quantity: 1
60
+ ).call
61
+ ]
62
+ }
50
63
  }.to_json.html_safe
51
64
  end
52
65
 
53
66
  def google_analytics_cart_event_json(line_item, quantity, position)
67
+ if use_gtm?
68
+ google_analytics_gtm_cart_event_json(line_item, quantity, position)
69
+ else
70
+ {
71
+ currency: line_item.currency,
72
+ value: line_item.amount.to_f,
73
+ items: [
74
+ SpreeGoogleAnalytics::ProductPresenter.new(
75
+ resource: line_item,
76
+ quantity: quantity,
77
+ position: position
78
+ ).call
79
+ ]
80
+ }.to_json.html_safe
81
+ end
82
+ end
83
+
84
+ def google_analytics_gtm_cart_event_json(line_item, quantity, position)
85
+ {
86
+ event: 'add_to_cart',
87
+ ecommerce: {
88
+ currency: line_item.currency,
89
+ value: line_item.amount.to_f,
90
+ items: [
91
+ SpreeGoogleAnalytics::ProductPresenter.new(
92
+ resource: line_item,
93
+ quantity: quantity,
94
+ position: position
95
+ ).call
96
+ ]
97
+ }
98
+ }.to_json.html_safe
99
+ end
100
+
101
+ def google_analytics_remove_from_cart_event_json(line_item, quantity, position)
102
+ if use_gtm?
103
+ google_analytics_gtm_remove_from_cart_event_json(line_item, quantity, position)
104
+ else
105
+ google_analytics_cart_event_json(line_item, quantity, position)
106
+ end
107
+ end
108
+
109
+ def google_analytics_gtm_remove_from_cart_event_json(line_item, quantity, position)
54
110
  {
55
- currency: line_item.currency,
56
- value: line_item.amount.to_f,
57
- items: [
58
- SpreeGoogleAnalytics::ProductPresenter.new(
59
- resource: line_item,
60
- quantity: quantity,
61
- position: position
62
- ).call
63
- ]
111
+ event: 'remove_from_cart',
112
+ ecommerce: {
113
+ currency: line_item.currency,
114
+ value: line_item.amount.to_f,
115
+ items: [
116
+ SpreeGoogleAnalytics::ProductPresenter.new(
117
+ resource: line_item,
118
+ quantity: quantity,
119
+ position: position
120
+ ).call
121
+ ]
122
+ }
64
123
  }.to_json.html_safe
65
124
  end
66
125
 
67
126
  def google_analytics_add_to_wishlist_event_json(variant)
127
+ if use_gtm?
128
+ google_analytics_gtm_add_to_wishlist_event_json(variant)
129
+ else
130
+ {
131
+ currency: current_currency,
132
+ value: variant.amount_in(current_currency),
133
+ items: [
134
+ SpreeGoogleAnalytics::ProductPresenter.new(
135
+ store_name: current_store.name,
136
+ resource: variant,
137
+ quantity: 1
138
+ ).call
139
+ ]
140
+ }.to_json.html_safe
141
+ end
142
+ end
143
+
144
+ def google_analytics_gtm_add_to_wishlist_event_json(variant)
68
145
  {
69
- currency: current_currency,
70
- value: variant.amount_in(current_currency),
71
- items: [
72
- SpreeGoogleAnalytics::ProductPresenter.new(
73
- store_name: current_store.name,
74
- resource: variant,
75
- quantity: 1
76
- ).call
77
- ]
146
+ event: 'add_to_wishlist',
147
+ ecommerce: {
148
+ currency: current_currency,
149
+ value: variant.amount_in(current_currency),
150
+ items: [
151
+ SpreeGoogleAnalytics::ProductPresenter.new(
152
+ store_name: current_store.name,
153
+ resource: variant,
154
+ quantity: 1
155
+ ).call
156
+ ]
157
+ }
158
+ }.to_json.html_safe
159
+ end
160
+
161
+ def google_analytics_checkout_json
162
+ return unless @order.present?
163
+
164
+ if use_gtm?
165
+ google_analytics_gtm_checkout_json
166
+ else
167
+ @google_analytics_checkout_json ||= SpreeGoogleAnalytics::CheckoutPresenter.new(order: @order).call.to_json.html_safe
168
+ end
169
+ end
170
+
171
+ def google_analytics_gtm_checkout_json
172
+ @google_analytics_gtm_checkout_json ||= {
173
+ event: 'begin_checkout',
174
+ ecommerce: SpreeGoogleAnalytics::CheckoutPresenter.new(order: @order).call
175
+ }.to_json.html_safe
176
+ end
177
+
178
+ def google_analytics_purchase_json
179
+ return unless @order.present?
180
+
181
+ if use_gtm?
182
+ google_analytics_gtm_purchase_json
183
+ else
184
+ @google_analytics_purchase_json ||= SpreeGoogleAnalytics::OrderPresenter.new(order: @order).call.to_json.html_safe
185
+ end
186
+ end
187
+
188
+ def google_analytics_gtm_purchase_json
189
+ @google_analytics_gtm_purchase_json ||= {
190
+ event: 'purchase',
191
+ ecommerce: SpreeGoogleAnalytics::OrderPresenter.new(order: @order).call
192
+ }.to_json.html_safe
193
+ end
194
+
195
+ def google_analytics_payment_json
196
+ return unless @order.present?
197
+
198
+ if use_gtm?
199
+ google_analytics_gtm_payment_json
200
+ else
201
+ @google_analytics_payment_json ||= SpreeGoogleAnalytics::PaymentPresenter.new(order: @order).call.to_json.html_safe
202
+ end
203
+ end
204
+
205
+ def google_analytics_gtm_payment_json
206
+ @google_analytics_gtm_payment_json ||= {
207
+ event: 'add_payment_info',
208
+ ecommerce: SpreeGoogleAnalytics::PaymentPresenter.new(order: @order).call
209
+ }.to_json.html_safe
210
+ end
211
+
212
+ def google_analytics_view_cart_json
213
+ return unless @order.present?
214
+
215
+ if use_gtm?
216
+ google_analytics_gtm_view_cart_json
217
+ else
218
+ @google_analytics_view_cart_json ||= SpreeGoogleAnalytics::CheckoutPresenter.new(order: @order).call.to_json.html_safe
219
+ end
220
+ end
221
+
222
+ def google_analytics_gtm_view_cart_json
223
+ @google_analytics_gtm_view_cart_json ||= {
224
+ event: 'view_cart',
225
+ ecommerce: SpreeGoogleAnalytics::CheckoutPresenter.new(order: @order).call
78
226
  }.to_json.html_safe
79
227
  end
80
228
  end
@@ -0,0 +1,16 @@
1
+ import '@hotwired/turbo-rails'
2
+ import { Application } from '@hotwired/stimulus'
3
+
4
+ let application
5
+
6
+ if (typeof window.Stimulus === "undefined") {
7
+ application = Application.start()
8
+ application.debug = false
9
+ window.Stimulus = application
10
+ } else {
11
+ application = window.Stimulus
12
+ }
13
+
14
+ import SpreeGoogleAnalyticsController from 'spree_google_analytics/controllers/spree_google_analytics_controller'
15
+
16
+ application.register('spree_google_analytics', SpreeGoogleAnalyticsController)
@@ -0,0 +1,4 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ }
@@ -2,8 +2,12 @@ module Spree
2
2
  module Integrations
3
3
  class GoogleAnalytics < Spree::Integration
4
4
  preference :measurement_id, :string
5
+ preference :google_tag_manager_id, :string
6
+ preference :client, :string, default: 'ga4'
5
7
 
6
- validates :preferred_measurement_id, presence: true
8
+ validates :preferred_measurement_id, presence: true, if: -> { preferred_client == 'ga4' }
9
+ validates :preferred_google_tag_manager_id, presence: true, if: -> { preferred_client == 'gtm' }
10
+ validates :preferred_client, inclusion: { in: %w[ga4 gtm] }
7
11
 
8
12
  def self.integration_group
9
13
  'analytics'
@@ -1,15 +1,22 @@
1
1
  <div class="card mb-4">
2
- <div class="card-body">
2
+ <div class="card-body" data-controller="reveal">
3
3
  <% if @integration.persisted? %>
4
4
  <div class="alert alert-warning">
5
5
  <%= Spree.t('admin.integrations.google_analytics.reports_warning') %>
6
6
  </div>
7
7
  <% end %>
8
8
 
9
- <%= preference_field(@integration, form, 'measurement_id', i18n_scope: 'admin.integrations.google_analytics') %>
10
- <p class="mb-0 mt-2">
9
+ <%= form.spree_collection_select "preferred_client", [['Google Analytics 4', 'ga4'], ['Google Tag Manager', 'gtm']], :last, :first, { selected: @integration.preferred_client, label: Spree.t('admin.integrations.google_analytics.client'), help: Spree.t('admin.integrations.google_analytics.client_help') }, { data: { action: 'change->reveal#toggle' } } %>
10
+
11
+ <div data-reveal-target="item">
12
+ <%= preference_field(@integration, form, 'measurement_id', i18n_scope: 'admin.integrations.google_analytics') %>
11
13
  <%= external_link_to 'Where to find my Measurement ID?', 'https://support.google.com/analytics/answer/12270356' %>
12
- </p>
14
+ </div>
15
+
16
+ <div class="hidden" data-reveal-target="item">
17
+ <%= preference_field(@integration, form, 'google_tag_manager_id', i18n_scope: 'admin.integrations.google_analytics') %>
18
+ <%= external_link_to 'Where to find my Google Tag Manager ID?', 'https://support.google.com/tagmanager/answer/6107028' %>
19
+ </div>
13
20
  </div>
14
21
  </div>
15
22
 
@@ -1,9 +1,15 @@
1
1
  <% if store_integration('google_analytics').present? %>
2
2
  <script>
3
- if (window.gtag) {
4
- <% safely do %>
5
- gtag('event', 'add_to_cart', <%= google_analytics_cart_event_json(@line_item, @line_item.quantity, @order.line_items.pluck(:id).index(@line_item.id) + 1) %>);
3
+ <% safely do %>
4
+ <% if use_gtm? %>
5
+ if (window.dataLayer) {
6
+ dataLayer.push(<%= google_analytics_cart_event_json(@line_item, @line_item.quantity, @order.line_items.pluck(:id).index(@line_item.id) + 1) %>);
7
+ }
8
+ <% else %>
9
+ if (window.gtag) {
10
+ gtag('event', 'add_to_cart', <%= google_analytics_cart_event_json(@line_item, @line_item.quantity, @order.line_items.pluck(:id).index(@line_item.id) + 1) %>);
11
+ }
6
12
  <% end %>
7
- }
13
+ <% end %>
8
14
  </script>
9
15
  <% end %>
@@ -1,9 +1,15 @@
1
1
  <% if store_integration('google_analytics').present? && @wished_item&.variant.present? %>
2
2
  <script>
3
- if (window.gtag) {
4
- <% safely do %>
5
- gtag('event', 'add_to_wishlist', <%= google_analytics_add_to_wishlist_event_json(@wished_item.variant) %>);
3
+ <% safely do %>
4
+ <% if use_gtm? %>
5
+ if (window.dataLayer) {
6
+ dataLayer.push(<%= google_analytics_add_to_wishlist_event_json(@wished_item.variant) %>);
7
+ }
8
+ <% else %>
9
+ if (window.gtag) {
10
+ gtag('event', 'add_to_wishlist', <%= google_analytics_add_to_wishlist_event_json(@wished_item.variant) %>);
11
+ }
6
12
  <% end %>
7
- }
13
+ <% end %>
8
14
  </script>
9
15
  <% end %>
@@ -1,27 +1,61 @@
1
1
  <% if store_integration('google_analytics').present? %>
2
- <script>
3
- if (window.gtag) {
4
- <% if controller_name == 'checkout' %>
5
- <% if @order && session[:checkout_started] %>
6
- <% safely do %>
7
- gtag('event', 'begin_checkout', <%= google_analytics_checkout_json %>);
2
+ <% if use_gtm? %>
3
+ <script>
4
+ if (window.dataLayer) {
5
+ <% if controller_name == 'checkout' %>
6
+ <% if @order && session[:checkout_started] %>
7
+ <% safely do %>
8
+ dataLayer.push(<%= google_analytics_checkout_json %>);
9
+ <% end %>
10
+ <% end %>
11
+
12
+ <% if @order && session[:checkout_step_completed] == 'delivery' %>
13
+ <% safely do %>
14
+ <% @order.shipments.each do |shipment| %>
15
+ dataLayer.push({
16
+ event: 'add_shipping_info',
17
+ ecommerce: <%= google_analytics_add_shipping_info_json(shipment) %>
18
+ });
19
+ <% end %>
20
+ <% end %>
8
21
  <% end %>
9
22
  <% end %>
10
23
 
11
- <% if @order && session[:checkout_step_completed] == 'delivery' %>
24
+ <% if controller_name == 'search' && action_name == 'show' && query.present? %>
12
25
  <% safely do %>
13
- <% @order.shipments.each do |shipment| %>
14
- gtag('event', 'add_shipping_info', <%= google_analytics_add_shipping_info_json(shipment) %>);
26
+ dataLayer.push({
27
+ event: 'search',
28
+ search_term: "<%= ERB::Util.html_escape(query) %>"
29
+ });
30
+ <% end %>
31
+ <% end %>
32
+ }
33
+ </script>
34
+ <% else %>
35
+ <script>
36
+ if (window.gtag) {
37
+ <% if controller_name == 'checkout' %>
38
+ <% if @order && session[:checkout_started] %>
39
+ <% safely do %>
40
+ gtag('event', 'begin_checkout', <%= google_analytics_checkout_json %>);
41
+ <% end %>
42
+ <% end %>
43
+
44
+ <% if @order && session[:checkout_step_completed] == 'delivery' %>
45
+ <% safely do %>
46
+ <% @order.shipments.each do |shipment| %>
47
+ gtag('event', 'add_shipping_info', <%= google_analytics_add_shipping_info_json(shipment) %>);
48
+ <% end %>
15
49
  <% end %>
16
50
  <% end %>
17
51
  <% end %>
18
- <% end %>
19
52
 
20
- <% if controller_name == 'search' && action_name == 'show' && query.present? %>
21
- <% safely do %>
22
- gtag('event', 'search', <%= raw({ search_term: ERB::Util.html_escape(query) }.to_json) %>);
53
+ <% if controller_name == 'search' && action_name == 'show' && query.present? %>
54
+ <% safely do %>
55
+ gtag('event', 'search', <%= raw({ search_term: ERB::Util.html_escape(query) }.to_json) %>);
56
+ <% end %>
23
57
  <% end %>
24
- <% end %>
25
- }
26
- </script>
58
+ }
59
+ </script>
60
+ <% end %>
27
61
  <% end %>
@@ -0,0 +1,6 @@
1
+ <% if store_integration('google_analytics').present? && use_gtm? %>
2
+ <!-- Google Tag Manager (noscript) -->
3
+ <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=<%= store_integration('google_analytics').preferred_google_tag_manager_id %>"
4
+ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
5
+ <!-- End Google Tag Manager (noscript) -->
6
+ <% end %>
@@ -1,11 +1,19 @@
1
1
  <% if store_integration('google_analytics').present? %>
2
2
  <script>
3
- if (window.gtag) {
4
- <% if @order.present? && @line_items.any? %>
5
- window.addEventListener('slideover:open', () => {
6
- gtag('event', 'view_cart', <%= google_analytics_checkout_json %>);
7
- })
3
+ <% if @order.present? && @line_items.any? %>
4
+ <% if use_gtm? %>
5
+ if (window.dataLayer) {
6
+ window.addEventListener('slideover:open', () => {
7
+ dataLayer.push(<%= google_analytics_view_cart_json %>);
8
+ })
9
+ }
10
+ <% else %>
11
+ if (window.gtag) {
12
+ window.addEventListener('slideover:open', () => {
13
+ gtag('event', 'view_cart', <%= google_analytics_view_cart_json %>);
14
+ })
15
+ }
8
16
  <% end %>
9
- }
17
+ <% end %>
10
18
  </script>
11
19
  <% end %>
@@ -1,15 +1,29 @@
1
1
  <% if store_integration('google_analytics').present? %>
2
2
  <script>
3
- if (window.gtag) {
4
- <% safely do %>
5
- <% if @order.user.present? %>
6
- gtag('set', 'user_id', "<%= @order.reload.user_id %>");
7
- gtag('set', 'user_properties', <%= google_analytics_user_properties_json(@order.user) %>);
8
- <% end %>
3
+ <% safely do %>
4
+ <% if use_gtm? %>
5
+ if (window.dataLayer) {
6
+ <% if @order.user.present? %>
7
+ dataLayer.push({
8
+ user_id: "<%= @order.reload.user_id %>",
9
+ user_properties: <%= google_analytics_user_properties_json(@order.user) %>
10
+ });
11
+ <% end %>
9
12
 
10
- gtag('event', 'add_payment_info', <%= google_analytics_payment_json %>);
11
- gtag('event', 'purchase', <%= google_analytics_purchase_json %>);
13
+ dataLayer.push(<%= google_analytics_payment_json %>);
14
+ dataLayer.push(<%= google_analytics_purchase_json %>);
15
+ }
16
+ <% else %>
17
+ if (window.gtag) {
18
+ <% if @order.user.present? %>
19
+ gtag('set', 'user_id', "<%= @order.reload.user_id %>");
20
+ gtag('set', 'user_properties', <%= google_analytics_user_properties_json(@order.user) %>);
21
+ <% end %>
22
+
23
+ gtag('event', 'add_payment_info', <%= google_analytics_payment_json %>);
24
+ gtag('event', 'purchase', <%= google_analytics_purchase_json %>);
25
+ }
12
26
  <% end %>
13
- }
27
+ <% end %>
14
28
  </script>
15
29
  <% end %>
@@ -1,34 +1,55 @@
1
1
  <% if store_integration('google_analytics').present? %>
2
- <!-- Google tag (gtag.js) -->
3
- <script async src="https://www.googletagmanager.com/gtag/js?id=<%= store_integration('google_analytics').preferred_measurement_id %>"></script>
4
- <script>
5
- window.dataLayer = window.dataLayer || [];
6
- function gtag(){dataLayer.push(arguments);}
2
+ <% if use_gtm? %>
3
+ <!-- Google Tag Manager -->
4
+ <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
5
+ new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
6
+ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
7
+ 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
8
+ })(window,document,'script','dataLayer','<%= store_integration('google_analytics').preferred_google_tag_manager_id %>');</script>
9
+ <!-- End Google Tag Manager -->
10
+
11
+ <script>
12
+ window.dataLayer = window.dataLayer || [];
13
+
14
+ <% if try_spree_current_user %>
15
+ dataLayer.push({
16
+ user_id: "<%= try_spree_current_user.id %>",
17
+ user_properties: <%= google_analytics_user_properties_json(try_spree_current_user) %>
18
+ });
19
+ <% end %>
20
+ </script>
21
+ <% else %>
22
+ <!-- Google tag (gtag.js) -->
23
+ <script async src="https://www.googletagmanager.com/gtag/js?id=<%= store_integration('google_analytics').preferred_measurement_id %>"></script>
24
+ <script>
25
+ window.dataLayer = window.dataLayer || [];
26
+ function gtag(){dataLayer.push(arguments);}
7
27
 
8
- <% if defined?(store_integration('cookie_first')) && store_integration('cookie_first').present? %>
9
- gtag('consent', 'default', {
10
- 'ad_storage': 'denied',
11
- 'ad_user_data': 'denied',
12
- 'ad_personalization': 'denied',
13
- 'analytics_storage': 'denied',
14
- 'functionality_storage': 'denied',
15
- 'security_storage': 'granted',
16
- 'wait_for_update': 2000
17
- });
18
- <% end %>
28
+ <% if defined?(store_integration('cookie_first')) && store_integration('cookie_first').present? %>
29
+ gtag('consent', 'default', {
30
+ 'ad_storage': 'denied',
31
+ 'ad_user_data': 'denied',
32
+ 'ad_personalization': 'denied',
33
+ 'analytics_storage': 'denied',
34
+ 'functionality_storage': 'denied',
35
+ 'security_storage': 'granted',
36
+ 'wait_for_update': 2000
37
+ });
38
+ <% end %>
19
39
 
20
- gtag('js', new Date());
21
- GA_MEASUREMENT_ID = "<%= store_integration('google_analytics').preferred_measurement_id %>";
40
+ gtag('js', new Date());
41
+ GA_MEASUREMENT_ID = "<%= store_integration('google_analytics').preferred_measurement_id %>";
22
42
 
23
- <% if ENV['GA_DEBUG_MODE'].present? %>
24
- gtag('config', GA_MEASUREMENT_ID, { "debug_mode": true });
25
- <% else %>
26
- gtag('config', GA_MEASUREMENT_ID);
27
- <% end %>
43
+ <% if ENV['GA_DEBUG_MODE'].present? %>
44
+ gtag('config', GA_MEASUREMENT_ID, { "debug_mode": true });
45
+ <% else %>
46
+ gtag('config', GA_MEASUREMENT_ID);
47
+ <% end %>
28
48
 
29
- <% if try_spree_current_user %>
30
- gtag('set', 'user_id', "<%= try_spree_current_user.id %>");
31
- gtag('set', 'user_properties', <%= google_analytics_user_properties_json(try_spree_current_user) %>);
32
- <% end %>
33
- </script>
49
+ <% if try_spree_current_user %>
50
+ gtag('set', 'user_id', "<%= try_spree_current_user.id %>");
51
+ gtag('set', 'user_properties', <%= google_analytics_user_properties_json(try_spree_current_user) %>);
52
+ <% end %>
53
+ </script>
54
+ <% end %>
34
55
  <% end %>
@@ -1,7 +1,13 @@
1
1
  <% if store_integration('google_analytics').present? %>
2
2
  <script>
3
- if (window.gtag) {
4
- gtag('event', 'view_item', <%= google_analytics_view_item_json %>);
5
- }
3
+ <% if use_gtm? %>
4
+ if (window.dataLayer) {
5
+ dataLayer.push(<%= google_analytics_view_item_json %>);
6
+ }
7
+ <% else %>
8
+ if (window.gtag) {
9
+ gtag('event', 'view_item', <%= google_analytics_view_item_json %>);
10
+ }
11
+ <% end %>
6
12
  </script>
7
13
  <% end %>
@@ -1,9 +1,15 @@
1
1
  <% if store_integration('google_analytics').present? %>
2
2
  <script>
3
- if (window.gtag) {
4
- <% safely do %>
5
- gtag('event', 'remove_from_cart', <%= google_analytics_cart_event_json(@line_item, @line_item.quantity, nil) %>);
3
+ <% safely do %>
4
+ <% if use_gtm? %>
5
+ if (window.dataLayer) {
6
+ dataLayer.push(<%= google_analytics_remove_from_cart_event_json(@line_item, @line_item.quantity, nil) %>);
7
+ }
8
+ <% else %>
9
+ if (window.gtag) {
10
+ gtag('event', 'remove_from_cart', <%= google_analytics_remove_from_cart_event_json(@line_item, @line_item.quantity, nil) %>);
11
+ }
6
12
  <% end %>
7
- }
13
+ <% end %>
8
14
  </script>
9
15
  <% end %>
@@ -0,0 +1,6 @@
1
+ pin 'application-spree_google_analytics', to: 'spree_google_analytics/application.js', preload: false
2
+
3
+ pin_all_from SpreeGoogleAnalytics::Engine.root.join('app/javascript/spree_google_analytics/controllers'),
4
+ under: 'spree_google_analytics/controllers',
5
+ to: 'spree_google_analytics/controllers',
6
+ preload: 'application-spree_google_analytics'
@@ -3,6 +3,7 @@ Rails.application.config.after_initialize do
3
3
 
4
4
  if Rails.application.config.respond_to?(:spree_storefront)
5
5
  Rails.application.config.spree_storefront.head_partials << 'spree_google_analytics/head'
6
+ Rails.application.config.spree_storefront.body_start_partials << 'spree_google_analytics/body_start'
6
7
  Rails.application.config.spree_storefront.body_end_partials << 'spree_google_analytics/body_end'
7
8
 
8
9
  Rails.application.config.spree_storefront.cart_partials << 'spree_google_analytics/cart'
@@ -8,3 +8,6 @@ en:
8
8
  reports_warning: It can take up to 48 hours for the data to appear in standard reports
9
9
  measurement_id: Measurement ID
10
10
  api_secret: API Secret
11
+ google_tag_manager_id: Google Tag Manager ID
12
+ client: Client Type
13
+ client_help: Choose between Google Analytics 4 (direct gtag.js implementation) or Google Tag Manager (dataLayer events)
@@ -14,7 +14,18 @@ module SpreeGoogleAnalytics
14
14
  end
15
15
 
16
16
  initializer 'spree_google_analytics.assets' do |app|
17
- app.config.assets.precompile += %w[spree_google_analytics_manifest]
17
+ if app.config.respond_to?(:assets)
18
+ app.config.assets.paths << root.join('app/javascript')
19
+ app.config.assets.paths << root.join('vendor/javascript')
20
+ app.config.assets.paths << root.join('vendor/stylesheets')
21
+ app.config.assets.precompile += %w[spree_google_analytics_manifest]
22
+ end
23
+ end
24
+
25
+ initializer 'spree_google_analytics.importmap', before: 'importmap' do |app|
26
+ app.config.importmap.paths << root.join('config/importmap.rb')
27
+ # https://github.com/rails/importmap-rails?tab=readme-ov-file#sweeping-the-cache-in-development-and-test
28
+ app.config.importmap.cache_sweepers << root.join('app/javascript')
18
29
  end
19
30
 
20
31
  def self.activate
@@ -1,5 +1,5 @@
1
1
  module SpreeGoogleAnalytics
2
- VERSION = '1.0.1'.freeze
2
+ VERSION = '1.1.0'.freeze
3
3
 
4
4
  def gem_version
5
5
  Gem::Version.new(VERSION)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_google_analytics
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vendo Connect Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-07-08 00:00:00.000000000 Z
11
+ date: 2025-11-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: spree
@@ -79,6 +79,8 @@ files:
79
79
  - app/assets/images/integration_icons/google-analytics-logo.png
80
80
  - app/controllers/spree_google_analytics/store_controller_decorator.rb
81
81
  - app/helpers/spree_google_analytics/base_helper.rb
82
+ - app/javascript/spree_google_analytics/application.js
83
+ - app/javascript/spree_google_analytics/controllers/spree_google_analytics_controller.js
82
84
  - app/models/spree/integrations/google_analytics.rb
83
85
  - app/presenters/spree_google_analytics/checkout_presenter.rb
84
86
  - app/presenters/spree_google_analytics/order_presenter.rb
@@ -88,11 +90,13 @@ files:
88
90
  - app/views/spree_google_analytics/_add_to_cart.html.erb
89
91
  - app/views/spree_google_analytics/_add_to_wishlist.erb
90
92
  - app/views/spree_google_analytics/_body_end.html.erb
93
+ - app/views/spree_google_analytics/_body_start.html.erb
91
94
  - app/views/spree_google_analytics/_cart.html.erb
92
95
  - app/views/spree_google_analytics/_checkout_complete.html.erb
93
96
  - app/views/spree_google_analytics/_head.html.erb
94
97
  - app/views/spree_google_analytics/_product.html.erb
95
98
  - app/views/spree_google_analytics/_remove_from_cart.html.erb
99
+ - config/importmap.rb
96
100
  - config/initializers/spree.rb
97
101
  - config/locales/en.yml
98
102
  - config/routes.rb