solidus_seo 1.0.7 → 1.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/decorators/controllers/spree/orders_controller_decorator.rb +55 -0
- data/app/decorators/models/spree/product_decorator.rb +3 -9
- data/app/views/solidus_seo/_analytics.html.erb +3 -152
- data/app/views/solidus_seo/_facebook.html.erb +37 -0
- data/app/views/solidus_seo/_google-analytics.html.erb +40 -0
- data/app/views/solidus_seo/_google-tag-manager.html.erb +50 -0
- data/app/views/solidus_seo/_pinterest.html.erb +84 -0
- data/lib/generators/solidus_seo/install/install_generator.rb +1 -0
- data/lib/generators/solidus_seo/install/templates/replace_taxon_breadcrumbs_helper.html.erb.deface +5 -0
- data/lib/solidus_seo/engine.rb +2 -0
- data/lib/solidus_seo/helpers/base_helper.rb +26 -0
- data/lib/solidus_seo/jsonld/breadcrumbs.rb +2 -2
- data/lib/solidus_seo/jsonld/list.rb +1 -1
- data/lib/solidus_seo/meta_data_builder.rb +0 -1
- data/lib/solidus_seo/version.rb +1 -1
- data/spec/examples.txt +30 -28
- data/spec/features/add_to_cart_spec.rb +29 -0
- data/spec/features/checkout_complete_spec.rb +14 -17
- data/spec/features/product_page_spec.rb +17 -1
- data/spec/support/testing_helpers.rb +10 -6
- data/spec/system_helper.rb +9 -7
- metadata +10 -3
- data/app/decorators/helpers/spree/base_helper_decorator.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3626084993746b4fd03d1ac122e5e5fd15e2c425e24c09ff66e48c85a8f58fd8
|
4
|
+
data.tar.gz: dc2e82b2dae8291d44ef540c3085b5ccc85682819acb3c405308e33e879f987b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5523b7a476f2e1f0fb42ea23ca16c926ecbff1f6c32f65438d431bfcb55c4ad84bdb3a4599356235f949b1c7dbafdfb1289d7edd98222851bd2d9d8aa6309471
|
7
|
+
data.tar.gz: 8b63780e4f7d9619c0c48dfda3f026a39e0b193fcda651df108d3ef5f60cbcc873d21155f1355ead1eeb8d60ec5249c536b469ec88ee69c51835e67a1183ad62
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module OrdersControllerDecorator
|
5
|
+
def self.prepended(base)
|
6
|
+
base.class_eval do
|
7
|
+
around_action :calculate_cart_diff, only: :populate
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def calculate_cart_diff
|
14
|
+
previous_cart_items = order_contents_hash
|
15
|
+
|
16
|
+
yield
|
17
|
+
|
18
|
+
current_cart_items = order_contents_hash
|
19
|
+
|
20
|
+
cart_diff = current_cart_items.map do |variant_sku, quantity|
|
21
|
+
added_quantity = quantity - (previous_cart_items[variant_sku] || 0)
|
22
|
+
|
23
|
+
[variant_sku, added_quantity.positive? ? added_quantity : nil]
|
24
|
+
end.to_h.compact
|
25
|
+
|
26
|
+
cart_diff = cart_diff.map do |variant_sku, quantity|
|
27
|
+
variant = Spree::Variant.find_by(sku: variant_sku)
|
28
|
+
|
29
|
+
[
|
30
|
+
variant_sku,
|
31
|
+
{
|
32
|
+
id: variant.product.master.sku,
|
33
|
+
name: variant.product.name,
|
34
|
+
variant: variant.options_text,
|
35
|
+
price: variant.price,
|
36
|
+
quantity: quantity
|
37
|
+
}
|
38
|
+
]
|
39
|
+
end.to_h
|
40
|
+
|
41
|
+
flash[:added_to_cart] = cart_diff if cart_diff.present?
|
42
|
+
end
|
43
|
+
|
44
|
+
def order_contents_hash
|
45
|
+
return {} if current_order.blank?
|
46
|
+
|
47
|
+
current_order.line_items.each_with_object({}) do |li, acc|
|
48
|
+
acc[li.variant.sku] ||= 0
|
49
|
+
acc[li.variant.sku] += li.quantity
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
::Spree::StoreController.prepend(self)
|
54
|
+
end
|
55
|
+
end
|
@@ -40,14 +40,8 @@ module Spree
|
|
40
40
|
master.default_price.amount
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
44
|
-
|
45
|
-
arel_conditions = [
|
46
|
-
variants_including_master.arel_table[:track_inventory].eq(false),
|
47
|
-
Spree::StockItem.arel_table[:count_on_hand].gt(0)
|
48
|
-
]
|
49
|
-
in_stock_variants = variants_including_master.joins(:stock_items).where(arel_conditions.inject(:or))
|
50
|
-
in_stock_variants.any?
|
43
|
+
def in_stock?
|
44
|
+
available? && variants_including_master.suppliable.any?
|
51
45
|
end
|
52
46
|
|
53
47
|
def seo_data
|
@@ -98,7 +92,7 @@ module Spree
|
|
98
92
|
"priceCurrency": seo_currency,
|
99
93
|
"price": seo_price,
|
100
94
|
"itemCondition": "http://schema.org/NewCondition",
|
101
|
-
"availability": "http://schema.org/#{
|
95
|
+
"availability": "http://schema.org/#{ in_stock? ? 'InStock' : 'OutOfStock'}",
|
102
96
|
}
|
103
97
|
}
|
104
98
|
end
|
@@ -1,159 +1,10 @@
|
|
1
|
-
<%
|
2
|
-
just_purchased = @order && order_just_completed?(@order)
|
3
|
-
if ENV.values_at('GOOGLE_TAG_MANAGER_ID', 'GOOGLE_ANALYTICS_ID', 'FACEBOOK_PIXEL_ID', 'PINTEREST_TAG_ID').any? \
|
4
|
-
&& just_purchased
|
5
|
-
|
6
|
-
shared_order_data = {
|
7
|
-
affiliation: current_store.name,
|
8
|
-
currency: @order.currency,
|
9
|
-
tax: @order.tax_total,
|
10
|
-
shipping: @order.ship_total
|
11
|
-
}
|
12
|
-
|
13
|
-
purchased_items = @order.line_items.map do |line_item|
|
14
|
-
variant = line_item.variant
|
15
|
-
|
16
|
-
next unless variant
|
17
|
-
|
18
|
-
{
|
19
|
-
id: variant.sku,
|
20
|
-
name: variant.name,
|
21
|
-
price: line_item.total,
|
22
|
-
variant: variant.options_text,
|
23
|
-
quantity: line_item.quantity
|
24
|
-
}
|
25
|
-
end.compact
|
26
|
-
|
27
|
-
end %>
|
28
|
-
|
29
1
|
<script>
|
30
|
-
window.
|
2
|
+
window.solidusSeoDataLayer = function (tagName, eventName) {
|
31
3
|
var tag = document.querySelector('script[data-tag=' + tagName + ']');
|
32
|
-
if(!tag) return;
|
33
4
|
tag.dataset.firedEvents = eventName;
|
34
5
|
}
|
35
6
|
</script>
|
36
7
|
|
37
|
-
<%
|
38
|
-
|
39
|
-
<script type="text/javascript" data-tag="google-tag-manager">
|
40
|
-
window.dataLayer = window.dataLayer || [];
|
41
|
-
|
42
|
-
<% if just_purchased %>
|
43
|
-
let orderData = Object.assign({}, <%= raw shared_order_data.to_json %>, {
|
44
|
-
'id': '<%= j @order.number %>', // Transaction ID. Required for purchases and refunds.
|
45
|
-
'revenue': '<%= @order.total %>', // Total transaction value (incl. tax and shipping)
|
46
|
-
'coupon': '' // TODO: Add coupon code if present
|
47
|
-
});
|
48
|
-
|
49
|
-
window.dataLayer.push({
|
50
|
-
'ecommerce': {
|
51
|
-
'purchase': {
|
52
|
-
'actionField': orderData,
|
53
|
-
'products': <%= raw purchased_items.to_json %>
|
54
|
-
}
|
55
|
-
}
|
56
|
-
});
|
57
|
-
window.solidusSeoListener('google-tag-manager', 'purchase');
|
58
|
-
<% end %>
|
59
|
-
|
60
|
-
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
61
|
-
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
62
|
-
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
63
|
-
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
64
|
-
})(window,document,'script','dataLayer','<%= ENV['GOOGLE_TAG_MANAGER_ID'] %>');
|
65
|
-
</script>
|
66
|
-
|
67
|
-
<% elsif ENV['GOOGLE_ANALYTICS_ID'].present? %>
|
68
|
-
|
69
|
-
<script async src="https://www.googletagmanager.com/gtag/js?id=<%= ENV['GOOGLE_ANALYTICS_ID'] %>"></script>
|
70
|
-
<script type="text/javascript" data-tag="google-analytics">
|
71
|
-
window.dataLayer = window.dataLayer || [];
|
72
|
-
function gtag(){ dataLayer.push(arguments); }
|
73
|
-
gtag('js', new Date());
|
74
|
-
gtag('config', '<%= ENV['GOOGLE_ANALYTICS_ID'] %>');
|
75
|
-
|
76
|
-
<% if just_purchased %>
|
77
|
-
let purchaseData = Object.assign({}, <%= raw shared_order_data.to_json %>, {
|
78
|
-
'transaction_id': '<%= @order.number %>',
|
79
|
-
'value': '<%= @order.total %>',
|
80
|
-
'items': <%= raw purchased_items.to_json %>
|
81
|
-
});
|
82
|
-
|
83
|
-
gtag('event', 'purchase', purchaseData);
|
84
|
-
window.solidusSeoListener('google-analytics', 'purchase');
|
85
|
-
<% end %>
|
86
|
-
</script>
|
87
|
-
<% end %>
|
88
|
-
|
89
|
-
<% if ENV['FACEBOOK_PIXEL_ID'].present? %>
|
90
|
-
<script type="text/javascript" data-tag="facebook">
|
91
|
-
!function(f,b,e,v,n,t,s) {
|
92
|
-
if (f.fbq) return;
|
93
|
-
n = f.fbq = function() { n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments) };
|
94
|
-
if (!f._fbq) f._fbq=n;
|
95
|
-
n.push = n; n.loaded = !0; n.version = '2.0'; n.queue=[]; t = b.createElement(e); t.async = !0; t.src = v;
|
96
|
-
s = b.getElementsByTagName(e)[0]; s.parentNode.insertBefore(t, s);
|
97
|
-
}(window, document,'script', 'https://connect.facebook.net/en_US/fbevents.js');
|
98
|
-
|
99
|
-
fbq('init', '<%= ENV['FACEBOOK_PIXEL_ID'] %>');
|
100
|
-
fbq('track', 'PageView');
|
101
|
-
|
102
|
-
<% if just_purchased %>
|
103
|
-
<% items = purchased_items.map { |li| li.slice(:id, :quantity) } %>
|
104
|
-
|
105
|
-
fbq('track', 'Purchase', {
|
106
|
-
value: <%= @order.total %>,
|
107
|
-
currency: 'USD',
|
108
|
-
contents: <%= raw items.to_json %>,
|
109
|
-
content_type: 'product',
|
110
|
-
|
111
|
-
// custom properties
|
112
|
-
order_number: '<%= @order.number %>',
|
113
|
-
item_total: <%= @order.item_total %>,
|
114
|
-
tax_total: <%= @order.tax_total %>,
|
115
|
-
ship_total: <%= @order.ship_total %>,
|
116
|
-
promo_total: <%= @order.promo_total %>,
|
117
|
-
});
|
118
|
-
window.solidusSeoListener('facebook', 'purchase');
|
119
|
-
<% end %>
|
120
|
-
</script>
|
121
|
-
<noscript>
|
122
|
-
<img height="1" width="1" src="https://www.facebook.com/tr?id=<%= ENV['FACEBOOK_PIXEL_ID'] %>&ev=PageView&noscript=1" />
|
123
|
-
</noscript>
|
124
|
-
<% end %>
|
125
|
-
|
126
|
-
<% if ENV['PINTEREST_TAG_ID'].present? %>
|
127
|
-
<script type="text/javascript" data-tag="pinterest">
|
128
|
-
!function(e){if(!window.pintrk){window.pintrk=function(){window.pintrk.queue.push(
|
129
|
-
Array.prototype.slice.call(arguments))};var
|
130
|
-
n=window.pintrk;n.queue=[],n.version="3.0";var
|
131
|
-
t=document.createElement("script");t.async=!0,t.src=e;var
|
132
|
-
r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(t,r)}}("https://s.pinimg.com/ct/core.js");
|
133
|
-
pintrk('load', '<%= ENV['PINTEREST_TAG_ID'] %>');
|
134
|
-
pintrk('page');
|
135
|
-
|
136
|
-
<% if just_purchased %>
|
137
|
-
<% items = purchased_items.map do |li|
|
138
|
-
{
|
139
|
-
product_id: li[:id],
|
140
|
-
product_name: li[:name],
|
141
|
-
product_quantity: li[:quantity],
|
142
|
-
product_price: li[:price],
|
143
|
-
}
|
144
|
-
end %>
|
145
|
-
|
146
|
-
pintrk('track', 'checkout', {
|
147
|
-
value: <%= @order.total %>,
|
148
|
-
order_quantity: <%= @order.line_items.sum(&:quantity) %>,
|
149
|
-
currency: 'USD',
|
150
|
-
line_items: <%= raw items.to_json %>
|
151
|
-
});
|
152
|
-
|
153
|
-
window.solidusSeoListener('pinterest', 'purchase');
|
154
|
-
<% end %>
|
155
|
-
</script>
|
156
|
-
<noscript>
|
157
|
-
<img height="1" width="1" style="display:none;" alt="" src="https://ct.pinterest.com/v3/?tid=<%= ENV['PINTEREST_TAG_ID'] %>&event=init&noscript=1" />
|
158
|
-
</noscript>
|
8
|
+
<% %w[google-tag-manager google-analytics facebook pinterest].each do |tag_name| %>
|
9
|
+
<%= render "solidus_seo/#{tag_name}", just_purchased: (@order && order_just_completed?(@order)), order: @order %>
|
159
10
|
<% end %>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<%
|
2
|
+
return if ENV['FACEBOOK_PIXEL_ID'].blank?
|
3
|
+
|
4
|
+
if just_purchased
|
5
|
+
order_data = {
|
6
|
+
value: order.total,
|
7
|
+
currency: order.currency,
|
8
|
+
content_type: 'product',
|
9
|
+
contents: order.line_items.map do |line_item|
|
10
|
+
next unless line_item.variant
|
11
|
+
|
12
|
+
{ id: line_item.variant.sku, quantity: line_item.quantity }
|
13
|
+
end.compact,
|
14
|
+
|
15
|
+
# custom properties
|
16
|
+
order_number: order.number,
|
17
|
+
item_total: order.item_total,
|
18
|
+
tax_total: order.tax_total,
|
19
|
+
ship_total: order.ship_total,
|
20
|
+
promo_total: order.promo_total
|
21
|
+
}
|
22
|
+
end
|
23
|
+
%>
|
24
|
+
<script type="text/javascript" data-tag="facebook">
|
25
|
+
!function(f,b,e,v,n,t,s) {if (f.fbq) return;n = f.fbq = function() { n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments) };if (!f._fbq) f._fbq=n;n.push = n; n.loaded = !0; n.version = '2.0'; n.queue=[]; t = b.createElement(e); t.async = !0; t.src = v;s = b.getElementsByTagName(e)[0]; s.parentNode.insertBefore(t, s);}(window, document,'script', 'https://connect.facebook.net/en_US/fbevents.js');
|
26
|
+
|
27
|
+
fbq('init', '<%= ENV['FACEBOOK_PIXEL_ID'] %>');
|
28
|
+
fbq('track', 'PageView');
|
29
|
+
|
30
|
+
<% if just_purchased %>
|
31
|
+
fbq('track', 'Purchase', <%== order_data.to_json %>);
|
32
|
+
window.solidusSeoDataLayer('facebook', 'purchase');
|
33
|
+
<% end %>
|
34
|
+
</script>
|
35
|
+
<noscript>
|
36
|
+
<img height="1" width="1" src="https://www.facebook.com/tr?id=<%= ENV['FACEBOOK_PIXEL_ID'] %>&ev=PageView&noscript=1" />
|
37
|
+
</noscript>
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<%
|
2
|
+
return if ENV['GOOGLE_TAG_MANAGER_ID'].present? || ENV['GOOGLE_ANALYTICS_ID'].blank?
|
3
|
+
|
4
|
+
if just_purchased
|
5
|
+
order_data = {
|
6
|
+
transaction_id: order.number,
|
7
|
+
value: order.total,
|
8
|
+
items: order.line_items.map do |line_item|
|
9
|
+
next unless line_item.variant
|
10
|
+
|
11
|
+
{
|
12
|
+
id: line_item.variant.sku,
|
13
|
+
name: line_item.variant.name,
|
14
|
+
price: line_item.price,
|
15
|
+
variant: line_item.variant.options_text,
|
16
|
+
quantity: line_item.quantity
|
17
|
+
}
|
18
|
+
end.compact,
|
19
|
+
|
20
|
+
affiliation: current_store.name,
|
21
|
+
currency: order.currency,
|
22
|
+
tax: order.tax_total,
|
23
|
+
shipping: order.ship_total
|
24
|
+
}
|
25
|
+
end
|
26
|
+
%>
|
27
|
+
<script async src="https://www.googletagmanager.com/gtag/js?id=<%= ENV['GOOGLE_ANALYTICS_ID'] %>"></script>
|
28
|
+
<script type="text/javascript" data-tag="google-analytics">
|
29
|
+
window.dataLayer = window.dataLayer || [];
|
30
|
+
|
31
|
+
function gtag(){ dataLayer.push(arguments); }
|
32
|
+
|
33
|
+
gtag('js', new Date());
|
34
|
+
gtag('config', '<%= ENV['GOOGLE_ANALYTICS_ID'] %>');
|
35
|
+
|
36
|
+
<% if just_purchased %>
|
37
|
+
gtag('event', 'purchase', <%== order_data.to_json %>);
|
38
|
+
window.solidusSeoDataLayer('google-analytics', 'purchase');
|
39
|
+
<% end %>
|
40
|
+
</script>
|
@@ -0,0 +1,50 @@
|
|
1
|
+
<%
|
2
|
+
return if ENV['GOOGLE_ANALYTICS_ID'].present? || ENV['GOOGLE_TAG_MANAGER_ID'].blank?
|
3
|
+
|
4
|
+
if just_purchased
|
5
|
+
order_data = {
|
6
|
+
id: order.number,
|
7
|
+
revenue: order.total,
|
8
|
+
coupon: '', # TODO: Add coupon code if present
|
9
|
+
|
10
|
+
affiliation: current_store.name,
|
11
|
+
currency: order.currency,
|
12
|
+
tax: order.tax_total,
|
13
|
+
shipping: order.ship_total
|
14
|
+
}
|
15
|
+
|
16
|
+
purchased_items = order.line_items.map do |line_item|
|
17
|
+
next unless line_item.variant
|
18
|
+
|
19
|
+
{
|
20
|
+
id: line_item.variant.sku,
|
21
|
+
name: line_item.variant.name,
|
22
|
+
price: line_item.total,
|
23
|
+
variant: line_item.variant.options_text,
|
24
|
+
quantity: line_item.quantity
|
25
|
+
}
|
26
|
+
end.compact
|
27
|
+
end
|
28
|
+
%>
|
29
|
+
<script type="text/javascript" data-tag="google-tag-manager">
|
30
|
+
window.dataLayer = window.dataLayer || [];
|
31
|
+
|
32
|
+
<% if just_purchased %>
|
33
|
+
window.dataLayer.push({
|
34
|
+
'ecommerce': {
|
35
|
+
'purchase': {
|
36
|
+
'actionField': <%== order_data.to_json %>,
|
37
|
+
'products': <%== purchased_items.to_json %>
|
38
|
+
}
|
39
|
+
}
|
40
|
+
});
|
41
|
+
|
42
|
+
window.solidusSeoDataLayer('google-tag-manager', 'purchase');
|
43
|
+
<% end %>
|
44
|
+
|
45
|
+
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
46
|
+
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
47
|
+
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
48
|
+
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
49
|
+
})(window,document,'script','dataLayer','<%= ENV['GOOGLE_TAG_MANAGER_ID'] %>');
|
50
|
+
</script>
|
@@ -0,0 +1,84 @@
|
|
1
|
+
<%
|
2
|
+
return if ENV['PINTEREST_TAG_ID'].blank?
|
3
|
+
|
4
|
+
product_data = {}
|
5
|
+
add_to_cart_data = {}
|
6
|
+
order_data = {}
|
7
|
+
em_data = {}
|
8
|
+
|
9
|
+
user_email = current_order&.email || try_spree_current_user&.email
|
10
|
+
if user_email.present?
|
11
|
+
em_data = { em: user_email }
|
12
|
+
end
|
13
|
+
|
14
|
+
if just_purchased
|
15
|
+
order_data = {
|
16
|
+
value: order.total,
|
17
|
+
currency: order.currency,
|
18
|
+
order_quantity: order.line_items.sum(&:quantity),
|
19
|
+
line_items: order.line_items.map do |line_item|
|
20
|
+
next unless line_item.variant
|
21
|
+
|
22
|
+
{
|
23
|
+
product_id: line_item.variant.product.master.sku,
|
24
|
+
product_name: line_item.variant.name,
|
25
|
+
product_variant_id: line_item.variant.sku,
|
26
|
+
product_variant: line_item.variant.options_text,
|
27
|
+
product_quantity: line_item.quantity,
|
28
|
+
product_price: line_item.price
|
29
|
+
}
|
30
|
+
end.compact
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
if @product
|
35
|
+
product_data = {
|
36
|
+
line_items: [
|
37
|
+
{
|
38
|
+
product_name: @product.name,
|
39
|
+
product_id: @product.master.sku
|
40
|
+
}
|
41
|
+
]
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
if flash[:added_to_cart].present?
|
46
|
+
add_to_cart_data = {
|
47
|
+
value: order.total,
|
48
|
+
currency: order.currency,
|
49
|
+
order_id: order.number,
|
50
|
+
line_items: flash[:added_to_cart].map do |variant_sku, variant|
|
51
|
+
{
|
52
|
+
product_id: variant['id'],
|
53
|
+
product_name: variant['name'],
|
54
|
+
product_variant_id: variant_sku,
|
55
|
+
product_variant: variant['variant'],
|
56
|
+
product_price: variant['price'],
|
57
|
+
product_quantity: variant['quantity']
|
58
|
+
}
|
59
|
+
end
|
60
|
+
}
|
61
|
+
end
|
62
|
+
%>
|
63
|
+
<script type="text/javascript" data-tag="pinterest">
|
64
|
+
!function(e){if(!window.pintrk){window.pintrk=function(){window.pintrk.queue.push(Array.prototype.slice.call(arguments))};var n=window.pintrk;n.queue=[],n.version="3.0";var t=document.createElement("script");t.async=!0,t.src=e;var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(t,r)}}("https://s.pinimg.com/ct/core.js");
|
65
|
+
|
66
|
+
pintrk('load', '<%= ENV['PINTEREST_TAG_ID'] %>' <%== em_data.present? ? ", #{em_data.to_json}" : '' %>);
|
67
|
+
pintrk('page');
|
68
|
+
|
69
|
+
pintrk('track', 'pagevisit'<%== product_data.present? ? ", #{product_data.to_json}" : '' %>);
|
70
|
+
window.solidusSeoDataLayer('pinterest', 'pagevisit');
|
71
|
+
|
72
|
+
<% if add_to_cart_data.present? %>
|
73
|
+
pintrk('track', 'addtocart', <%== add_to_cart_data.to_json %>);
|
74
|
+
window.solidusSeoDataLayer('pinterest', 'addtocart');
|
75
|
+
<% end %>
|
76
|
+
|
77
|
+
<% if order_data.present? %>
|
78
|
+
pintrk('track', 'checkout', <%== order_data.to_json %>);
|
79
|
+
window.solidusSeoDataLayer('pinterest', 'purchase');
|
80
|
+
<% end %>
|
81
|
+
</script>
|
82
|
+
<noscript>
|
83
|
+
<img height="1" width="1" style="display:none;" alt="" src="https://ct.pinterest.com/v3/?tid=<%= ENV['PINTEREST_TAG_ID'] %>&event=init&noscript=1" />
|
84
|
+
</noscript>
|
@@ -34,6 +34,7 @@ module SolidusSeo
|
|
34
34
|
copy_file 'remove_original_title_tag.deface', 'app/overrides/spree/shared/_head/remove_original_title_tag.deface'
|
35
35
|
copy_file 'insert_product_list_helper.html.erb.deface', 'app/overrides/spree/shared/_products/insert_product_list_helper.html.erb.deface'
|
36
36
|
copy_file 'insert_analytics_in_layout.html.erb.deface', 'app/overrides/spree/layouts/spree_application/insert_analytics_in_layout.html.erb.deface'
|
37
|
+
copy_file 'replace_taxon_breadcrumbs_helper.html.erb.deface', 'app/overrides/spree/layouts/spree_application/replace_taxon_breadcrumbs_helper.html.erb.deface'
|
37
38
|
end
|
38
39
|
end
|
39
40
|
end
|
data/lib/solidus_seo/engine.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require_dependency 'solidus_seo/jsonld/tag_helper'
|
3
|
+
require_dependency 'solidus_seo/helpers/base_helper'
|
3
4
|
|
4
5
|
module SolidusSeo
|
5
6
|
class Engine < Rails::Engine
|
@@ -21,6 +22,7 @@ module SolidusSeo
|
|
21
22
|
initializer "solidus_seo.view_helpers" do
|
22
23
|
ActiveSupport.on_load(:action_view) do
|
23
24
|
ActionView::Base.send :include, ::SolidusSeo::Jsonld::TagHelper
|
25
|
+
ActionView::Base.send :include, ::SolidusSeo::Helpers::BaseHelper
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
@@ -4,6 +4,32 @@ module SolidusSeo
|
|
4
4
|
def plain_text(text)
|
5
5
|
ActionController::Base.helpers.strip_tags(text.to_s).gsub(/\s+/, ' ')
|
6
6
|
end
|
7
|
+
|
8
|
+
def breadcrumb_pairs(taxon)
|
9
|
+
crumbs = []
|
10
|
+
|
11
|
+
if taxon
|
12
|
+
crumbs << [Spree.t(:products), products_url]
|
13
|
+
crumbs += taxon.ancestors.collect { |a| [a.name, spree.nested_taxons_url(a.permalink)] } unless taxon.ancestors.empty?
|
14
|
+
crumbs << [taxon.name, spree.nested_taxons_url(taxon.permalink)]
|
15
|
+
else
|
16
|
+
crumbs << [Spree.t(:products), products_url]
|
17
|
+
end
|
18
|
+
|
19
|
+
crumbs
|
20
|
+
end
|
21
|
+
|
22
|
+
def taxon_breadcrumbs_jsonld(taxon, separator = ' » ', list_class = 'list-inline', list_item_class = 'list-inline-item')
|
23
|
+
return '' if current_page?('/') || taxon.nil?
|
24
|
+
|
25
|
+
separator = tag.span(separator.html_safe, class: 'breadcrumb-separator')
|
26
|
+
original_output = Nokogiri::HTML::DocumentFragment.parse(taxon_breadcrumbs(taxon, separator, list_class).to_s)
|
27
|
+
original_output.xpath('@itemscope|@itemtype|@itemprop|.//@itemscope|.//@itemtype|.//@itemprop').remove
|
28
|
+
original_output.search('.columns').first['class'] = ''
|
29
|
+
original_output.search('li').attr('class', list_item_class)
|
30
|
+
|
31
|
+
jsonld_breadcrumbs(breadcrumb_pairs(taxon)) + original_output.to_s.html_safe
|
32
|
+
end
|
7
33
|
end
|
8
34
|
end
|
9
35
|
end
|
@@ -2,7 +2,7 @@ require_dependency 'solidus_seo/jsonld/list'
|
|
2
2
|
|
3
3
|
module SolidusSeo
|
4
4
|
module Jsonld
|
5
|
-
class Breadcrumbs < List
|
5
|
+
class Breadcrumbs < SolidusSeo::Jsonld::List
|
6
6
|
private
|
7
7
|
|
8
8
|
def list_type
|
@@ -15,7 +15,7 @@ module SolidusSeo
|
|
15
15
|
|
16
16
|
def as_list_item(item)
|
17
17
|
# `item` in the form of [text, url]
|
18
|
-
breadcrumb_text, breadcrumb_url =
|
18
|
+
breadcrumb_text, breadcrumb_url = item
|
19
19
|
|
20
20
|
{
|
21
21
|
'@type': 'ListItem',
|
data/lib/solidus_seo/version.rb
CHANGED
data/spec/examples.txt
CHANGED
@@ -1,30 +1,32 @@
|
|
1
1
|
example_id | status | run_time |
|
2
2
|
------------------------------------------------ | ------ | --------------- |
|
3
|
-
./spec/features/
|
4
|
-
./spec/features/checkout_complete_spec.rb[1:
|
5
|
-
./spec/features/checkout_complete_spec.rb[1:
|
6
|
-
./spec/features/checkout_complete_spec.rb[1:
|
7
|
-
./spec/features/
|
8
|
-
./spec/features/homepage_spec.rb[1:1:
|
9
|
-
./spec/features/homepage_spec.rb[1:2
|
10
|
-
./spec/features/homepage_spec.rb[1:2:
|
11
|
-
./spec/features/homepage_spec.rb[1:
|
12
|
-
./spec/features/homepage_spec.rb[1:3:
|
13
|
-
./spec/features/
|
14
|
-
./spec/features/product_page_spec.rb[1:1:
|
15
|
-
./spec/features/product_page_spec.rb[1:1:
|
16
|
-
./spec/features/product_page_spec.rb[1:
|
17
|
-
./spec/features/product_page_spec.rb[1:2:
|
18
|
-
./spec/features/product_page_spec.rb[1:2:
|
19
|
-
./spec/features/product_page_spec.rb[1:3:1]
|
20
|
-
./spec/features/product_page_spec.rb[1:3:
|
21
|
-
./spec/features/product_page_spec.rb[1:3:
|
22
|
-
./spec/features/
|
23
|
-
./spec/features/
|
24
|
-
./spec/features/taxon_page_spec.rb[1:1:
|
25
|
-
./spec/features/taxon_page_spec.rb[1:2
|
26
|
-
./spec/features/taxon_page_spec.rb[1:
|
27
|
-
./spec/features/taxon_page_spec.rb[1:2:
|
28
|
-
./spec/features/taxon_page_spec.rb[1:
|
29
|
-
./spec/features/taxon_page_spec.rb[1:3:
|
30
|
-
./spec/features/taxon_page_spec.rb[1:
|
3
|
+
./spec/features/add_to_cart_spec.rb[1:1:1] | passed | 1.6 seconds |
|
4
|
+
./spec/features/checkout_complete_spec.rb[1:1:1] | passed | 0.65012 seconds |
|
5
|
+
./spec/features/checkout_complete_spec.rb[1:2:1] | passed | 0.56665 seconds |
|
6
|
+
./spec/features/checkout_complete_spec.rb[1:3:1] | passed | 0.66929 seconds |
|
7
|
+
./spec/features/checkout_complete_spec.rb[1:4:1] | passed | 0.44838 seconds |
|
8
|
+
./spec/features/homepage_spec.rb[1:1:1] | passed | 2.3 seconds |
|
9
|
+
./spec/features/homepage_spec.rb[1:1:2] | passed | 0.22388 seconds |
|
10
|
+
./spec/features/homepage_spec.rb[1:2:1] | passed | 0.2209 seconds |
|
11
|
+
./spec/features/homepage_spec.rb[1:2:2] | passed | 0.18137 seconds |
|
12
|
+
./spec/features/homepage_spec.rb[1:3:1] | passed | 0.20727 seconds |
|
13
|
+
./spec/features/homepage_spec.rb[1:3:2] | passed | 0.20346 seconds |
|
14
|
+
./spec/features/product_page_spec.rb[1:1:1] | passed | 0.29118 seconds |
|
15
|
+
./spec/features/product_page_spec.rb[1:1:2] | passed | 0.30857 seconds |
|
16
|
+
./spec/features/product_page_spec.rb[1:1:3] | passed | 0.28452 seconds |
|
17
|
+
./spec/features/product_page_spec.rb[1:2:1] | passed | 0.47017 seconds |
|
18
|
+
./spec/features/product_page_spec.rb[1:2:2:1] | passed | 0.3369 seconds |
|
19
|
+
./spec/features/product_page_spec.rb[1:2:3:1] | passed | 0.37361 seconds |
|
20
|
+
./spec/features/product_page_spec.rb[1:3:1] | passed | 0.33857 seconds |
|
21
|
+
./spec/features/product_page_spec.rb[1:3:2] | passed | 0.29488 seconds |
|
22
|
+
./spec/features/product_page_spec.rb[1:3:3] | passed | 0.26324 seconds |
|
23
|
+
./spec/features/product_page_spec.rb[1:4:1:1] | passed | 0.4502 seconds |
|
24
|
+
./spec/features/taxon_page_spec.rb[1:1:1] | passed | 1.04 seconds |
|
25
|
+
./spec/features/taxon_page_spec.rb[1:1:2] | passed | 0.31403 seconds |
|
26
|
+
./spec/features/taxon_page_spec.rb[1:1:3] | passed | 0.30921 seconds |
|
27
|
+
./spec/features/taxon_page_spec.rb[1:2:1] | passed | 0.32058 seconds |
|
28
|
+
./spec/features/taxon_page_spec.rb[1:2:2:1] | passed | 0.30031 seconds |
|
29
|
+
./spec/features/taxon_page_spec.rb[1:2:3:1] | passed | 0.31003 seconds |
|
30
|
+
./spec/features/taxon_page_spec.rb[1:3:1] | passed | 0.30324 seconds |
|
31
|
+
./spec/features/taxon_page_spec.rb[1:3:2] | passed | 0.3043 seconds |
|
32
|
+
./spec/features/taxon_page_spec.rb[1:4:1] | passed | 0.5174 seconds |
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe 'Add to cart', type: :system do
|
4
|
+
let!(:store) { Spree::Store.default }
|
5
|
+
let!(:order) { create :completed_order_with_totals }
|
6
|
+
let!(:line_item) { order.line_items.first }
|
7
|
+
|
8
|
+
stub_authorization!
|
9
|
+
|
10
|
+
before do
|
11
|
+
current_order_stubs(order)
|
12
|
+
stub_const 'ENV', ENV.to_h.merge(env_variable => 'XXX-YYYYY')
|
13
|
+
|
14
|
+
visit spree.product_path(line_item.product)
|
15
|
+
find('#add-to-cart-button').click
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when PINTEREST_TAG_ID environment variable is present' do
|
19
|
+
let(:env_variable) { 'PINTEREST_TAG_ID' }
|
20
|
+
|
21
|
+
it 'tracks "add to cart" event' do
|
22
|
+
expect(page).to track_analytics_event :pinterest, 'addtocart', [
|
23
|
+
'track', 'addtocart', order.total, order.number, line_item.variant.product.master.sku,
|
24
|
+
line_item.name, line_item.variant.sku, line_item.variant.price
|
25
|
+
]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -1,14 +1,17 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe 'Checkout complete', type: :system do
|
2
4
|
let!(:store) { Spree::Store.default }
|
3
5
|
let!(:taxon) { create :taxon, name: 'MyTaxon' }
|
4
6
|
let!(:order) { create :completed_order_with_totals }
|
5
7
|
let!(:line_item) { order.line_items.first }
|
6
|
-
|
8
|
+
|
9
|
+
stub_authorization!
|
7
10
|
|
8
11
|
subject { visit spree.order_path(order) }
|
9
12
|
|
10
13
|
before do
|
11
|
-
|
14
|
+
current_order_stubs(order)
|
12
15
|
stub_const 'ENV', ENV.to_h.merge(env_variable => 'XXX-YYYYY')
|
13
16
|
allow_any_instance_of(Spree::OrdersHelper).to receive(:order_just_completed?).with(order) { true }
|
14
17
|
end
|
@@ -18,8 +21,7 @@ describe "Checkout complete", type: :system do
|
|
18
21
|
|
19
22
|
it 'includes and executes a purchase event script' do
|
20
23
|
subject
|
21
|
-
|
22
|
-
expect(page).to matcher_for 'google-tag-manager', [order.number, order.total, 'ecommerce', 'purchase', line_item.sku, line_item.total]
|
24
|
+
expect(page).to track_analytics_event 'google-tag-manager', 'purchase', ['ecommerce', 'purchase', order.number, order.total, line_item.sku]
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
@@ -28,7 +30,11 @@ describe "Checkout complete", type: :system do
|
|
28
30
|
|
29
31
|
it 'includes and executes a purchase event script' do
|
30
32
|
subject
|
31
|
-
expect(page).to
|
33
|
+
expect(page).to track_analytics_event 'google-analytics', 'purchase', [
|
34
|
+
'event', 'purchase', 'transaction_id', order.number,
|
35
|
+
order.total, line_item.sku, line_item.variant.name,
|
36
|
+
line_item.price, line_item.variant.options_text
|
37
|
+
]
|
32
38
|
end
|
33
39
|
end
|
34
40
|
|
@@ -37,7 +43,7 @@ describe "Checkout complete", type: :system do
|
|
37
43
|
|
38
44
|
it 'includes and executes a purchase event script' do
|
39
45
|
subject
|
40
|
-
expect(page).to
|
46
|
+
expect(page).to track_analytics_event :facebook, 'purchase', ['track', 'Purchase', order.total, line_item.sku, line_item.quantity, order.number]
|
41
47
|
end
|
42
48
|
end
|
43
49
|
|
@@ -46,16 +52,7 @@ describe "Checkout complete", type: :system do
|
|
46
52
|
|
47
53
|
it 'includes and executes a purchase event script' do
|
48
54
|
subject
|
49
|
-
expect(page).to
|
55
|
+
expect(page).to track_analytics_event :pinterest, 'purchase', ['track', 'checkout', order.total, line_item.sku, line_item.name, line_item.price]
|
50
56
|
end
|
51
57
|
end
|
52
58
|
end
|
53
|
-
|
54
|
-
# Builds a regex matcher for script tag contents
|
55
|
-
# @param tag_name [String] Value of script's data-tag attribute
|
56
|
-
# @param matches [Array] Keywords that must appear in script contents (order matters!)
|
57
|
-
# @return [Object] Returns a capybara matcher for a script tag with specific attributes and contents
|
58
|
-
def matcher_for(tag_name, matches)
|
59
|
-
matches = matches.flatten.map {|v| Regexp.escape(v.to_s) }.join('.+')
|
60
|
-
have_selector :css, "script[data-tag=#{tag_name}][data-fired-events=purchase]", visible: false, text: /#{matches}/i
|
61
|
-
end
|
@@ -26,7 +26,6 @@ describe "Product page", type: :system do
|
|
26
26
|
|
27
27
|
subject { visit spree.product_path(product) }
|
28
28
|
|
29
|
-
|
30
29
|
context 'jsonld markup output' do
|
31
30
|
it "contains 'Store' entity type" do
|
32
31
|
subject
|
@@ -92,4 +91,21 @@ describe "Product page", type: :system do
|
|
92
91
|
expect(page).to have_css "meta[property='product:price:amount'][content='#{seo_price}']", visible: false
|
93
92
|
end
|
94
93
|
end
|
94
|
+
|
95
|
+
context 'analytics event tracking' do
|
96
|
+
before do
|
97
|
+
stub_const 'ENV', ENV.to_h.merge(env_variable => 'XXX-YYYYY')
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'when PINTEREST_TAG_ID environment variable is present' do
|
101
|
+
let(:env_variable) { 'PINTEREST_TAG_ID' }
|
102
|
+
|
103
|
+
it 'tracks "pagevisit" event with product data' do
|
104
|
+
subject
|
105
|
+
expect(page).to track_analytics_event :pinterest, 'pagevisit', [
|
106
|
+
'track', 'pagevisit', product.name, product.master.sku
|
107
|
+
]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
95
111
|
end
|
@@ -10,13 +10,17 @@ module TestingHelpers
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
14
|
-
user ||= order.user
|
13
|
+
def current_order_stubs(order)
|
15
14
|
allow_any_instance_of(Spree::CheckoutController).to receive_messages(current_order: order)
|
15
|
+
allow_any_instance_of(Spree::OrdersController).to receive_messages(current_order: order)
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
# Builds a regex matcher for script tag contents
|
19
|
+
# @param tag_name [String] Value of script's data-tag attribute
|
20
|
+
# @param matches [Array] Keywords that must appear in script contents (order matters!)
|
21
|
+
# @return [Object] Returns a capybara matcher for a script tag with specific attributes and contents
|
22
|
+
def track_analytics_event(tag_name, event_name, matches)
|
23
|
+
matches = matches.flatten.map {|v| Regexp.escape(v.to_s) }.join('.+')
|
24
|
+
have_selector :css, "script[data-tag=#{tag_name}][data-fired-events=#{event_name}]", visible: false, text: /#{matches}/i
|
21
25
|
end
|
22
26
|
end
|
data/spec/system_helper.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
RSpec.configure do |
|
3
|
-
|
4
|
-
|
2
|
+
RSpec.configure do |c|
|
3
|
+
Capybara.disable_animation = true
|
4
|
+
|
5
|
+
c.before(:example, type: :system) do
|
6
|
+
driven_by ENV['DEBUG_CAPYBARA'] ? :selenium_chrome : :selenium_chrome_headless
|
7
|
+
end
|
8
|
+
|
9
|
+
c.when_first_matching_example_defined(type: :system) do
|
10
|
+
c.before :suite do
|
5
11
|
# Preload assets
|
6
12
|
if Rails.application.respond_to?(:precompiled_assets)
|
7
13
|
Rails.application.precompiled_assets
|
8
14
|
end
|
9
15
|
end
|
10
|
-
|
11
|
-
config.before(:example, type: :system) do
|
12
|
-
driven_by :apparition
|
13
|
-
end
|
14
16
|
end
|
15
17
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solidus_seo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karma Creative
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: solidus_core
|
@@ -337,12 +337,16 @@ files:
|
|
337
337
|
- app/assets/javascripts/spree/frontend/solidus_seo.js
|
338
338
|
- app/assets/stylesheets/spree/backend/solidus_seo.css
|
339
339
|
- app/assets/stylesheets/spree/frontend/solidus_seo.css
|
340
|
+
- app/decorators/controllers/spree/orders_controller_decorator.rb
|
340
341
|
- app/decorators/controllers/spree/store_controller_decorator.rb
|
341
|
-
- app/decorators/helpers/spree/base_helper_decorator.rb
|
342
342
|
- app/decorators/helpers/spree/core/controller_helpers/common_decorator.rb
|
343
343
|
- app/decorators/models/spree/product_decorator.rb
|
344
344
|
- app/decorators/models/spree/store_decorator.rb
|
345
345
|
- app/views/solidus_seo/_analytics.html.erb
|
346
|
+
- app/views/solidus_seo/_facebook.html.erb
|
347
|
+
- app/views/solidus_seo/_google-analytics.html.erb
|
348
|
+
- app/views/solidus_seo/_google-tag-manager.html.erb
|
349
|
+
- app/views/solidus_seo/_pinterest.html.erb
|
346
350
|
- config/locales/en.yml
|
347
351
|
- config/routes.rb
|
348
352
|
- lib/generators/solidus_seo/install/install_generator.rb
|
@@ -354,6 +358,7 @@ files:
|
|
354
358
|
- lib/generators/solidus_seo/install/templates/insert_product_list_helper.html.erb.deface
|
355
359
|
- lib/generators/solidus_seo/install/templates/paperclip_optimizer.rb
|
356
360
|
- lib/generators/solidus_seo/install/templates/remove_original_title_tag.deface
|
361
|
+
- lib/generators/solidus_seo/install/templates/replace_taxon_breadcrumbs_helper.html.erb.deface
|
357
362
|
- lib/solidus_seo.rb
|
358
363
|
- lib/solidus_seo/engine.rb
|
359
364
|
- lib/solidus_seo/factories.rb
|
@@ -373,6 +378,7 @@ files:
|
|
373
378
|
- lib/solidus_seo/model.rb
|
374
379
|
- lib/solidus_seo/version.rb
|
375
380
|
- spec/examples.txt
|
381
|
+
- spec/features/add_to_cart_spec.rb
|
376
382
|
- spec/features/checkout_complete_spec.rb
|
377
383
|
- spec/features/homepage_spec.rb
|
378
384
|
- spec/features/product_page_spec.rb
|
@@ -410,6 +416,7 @@ test_files:
|
|
410
416
|
- spec/features/checkout_complete_spec.rb
|
411
417
|
- spec/features/homepage_spec.rb
|
412
418
|
- spec/features/taxon_page_spec.rb
|
419
|
+
- spec/features/add_to_cart_spec.rb
|
413
420
|
- spec/features/product_page_spec.rb
|
414
421
|
- spec/support/testing_helpers.rb
|
415
422
|
- spec/system_helper.rb
|
@@ -1,39 +0,0 @@
|
|
1
|
-
module Spree
|
2
|
-
module BaseHelperDecorator
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
def self.prepended(base)
|
6
|
-
base.class_eval do
|
7
|
-
def breadcrumb_pairs(taxon)
|
8
|
-
crumbs = []
|
9
|
-
|
10
|
-
if taxon
|
11
|
-
crumbs << [Spree.t(:products), products_url]
|
12
|
-
crumbs += taxon.ancestors.collect { |a| [a.name, spree.nested_taxons_url(a.permalink)] } unless taxon.ancestors.empty?
|
13
|
-
crumbs << [taxon.name, spree.nested_taxons_url(taxon.permalink)]
|
14
|
-
else
|
15
|
-
crumbs << [Spree.t(:products), products_url]
|
16
|
-
end
|
17
|
-
|
18
|
-
crumbs
|
19
|
-
end
|
20
|
-
|
21
|
-
# TODO: Make this method replace original `taxon_breadcrumbs` so we can use super;
|
22
|
-
# prepending a module with anothe doesn't seem to be working as intended.
|
23
|
-
def taxon_breadcrumbs_jsonld(taxon, separator = ' » ', list_class = 'list-inline', list_item_class = 'list-inline-item')
|
24
|
-
return '' if current_page?('/') || taxon.nil?
|
25
|
-
|
26
|
-
separator = tag.span(separator.html_safe, class: 'breadcrumb-separator')
|
27
|
-
original_output = Nokogiri::HTML::DocumentFragment.parse(taxon_breadcrumbs(taxon, separator, list_class).to_s)
|
28
|
-
original_output.xpath('@itemscope|@itemtype|@itemprop|.//@itemscope|.//@itemtype|.//@itemprop').remove
|
29
|
-
original_output.search('.columns').first['class'] = ''
|
30
|
-
original_output.search('li').attr('class', list_item_class)
|
31
|
-
|
32
|
-
jsonld_breadcrumbs(breadcrumb_pairs(taxon)) + original_output.to_s.html_safe
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
::Spree::BaseHelper.prepend(self)
|
38
|
-
end
|
39
|
-
end
|