spree_storefront 5.4.0 → 5.4.3
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 +4 -4
- data/app/helpers/spree/json_ld_helper.rb +12 -0
- data/app/helpers/spree/products_helper.rb +40 -0
- data/app/presenters/spree/colors_preview_styles_presenter.rb +17 -4
- data/app/views/themes/default/spree/page_sections/_newsletter.html.erb +1 -1
- data/app/views/themes/default/spree/posts/_json_ld.html.erb +15 -19
- data/app/views/themes/default/spree/products/_description.html.erb +1 -1
- data/app/views/themes/default/spree/products/_details.html.erb +1 -1
- data/app/views/themes/default/spree/products/_featured_image.html.erb +1 -1
- data/app/views/themes/default/spree/products/_json_ld.html.erb +2 -40
- data/app/views/themes/default/spree/products/_json_ld_list.html.erb +6 -8
- data/app/views/themes/default/spree/shared/_json_ld.html.erb +23 -26
- metadata +6 -6
- data/app/views/themes/default/spree/products/_json_ld_variant.html.erb +0 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 86f9eaec23e1403d7ca88d9ad9888265d90b70749aa0fbc38b5cfb80208111b7
|
|
4
|
+
data.tar.gz: 141654121255c1801335bcc1bc6854aeca3824bae3523f888599f1d94ea58659
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 47f847c1933bdfe5e7a41692146f76c913df33f7cec7fa5f8eb3c4e73eb5d9f07f99c4703fdd57b9d2e0ae563ddde3c91979ffc26a1ac25fedd853d14403cd9b
|
|
7
|
+
data.tar.gz: 1498db74ea682506648e9a22bf4324f3658a0eabb34614a64470f618ed895e342f7e65daa9773b89f6ae559b608a92332ee4823a69061729b9a76b9ec7364006
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module JsonLdHelper
|
|
3
|
+
# spree_api globally sets ActiveSupport::JSON::Encoding.escape_html_entities_in_json = false,
|
|
4
|
+
# so a literal `</script>` in any field would break out of the surrounding script tag.
|
|
5
|
+
# ERB::Util.json_escape post-processes the encoded JSON to escape `<`, `>`, `&` regardless
|
|
6
|
+
# of that global flag.
|
|
7
|
+
def json_ld_script(data, **html_attrs)
|
|
8
|
+
json = ERB::Util.json_escape(data.to_json)
|
|
9
|
+
content_tag(:script, json.html_safe, type: 'application/ld+json', **html_attrs)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -225,6 +225,46 @@ module Spree
|
|
|
225
225
|
json_ld
|
|
226
226
|
end
|
|
227
227
|
|
|
228
|
+
def product_json_ld_data(product, selected_variant: nil)
|
|
229
|
+
first_or_default_variant = product.first_or_default_variant(current_currency)
|
|
230
|
+
data = {
|
|
231
|
+
'@context' => 'https://schema.org/',
|
|
232
|
+
'@type' => 'Product',
|
|
233
|
+
'name' => product.name,
|
|
234
|
+
'url' => spree.product_url(product, host: current_store.url_or_custom_domain)
|
|
235
|
+
}
|
|
236
|
+
data['image'] = [spree_image_url(product.primary_media, variant: :large)] if product.has_images?
|
|
237
|
+
data['description'] = strip_tags(product.description) if product.description.present?
|
|
238
|
+
|
|
239
|
+
sku_variant = product.has_variants? ? selected_variant : first_or_default_variant
|
|
240
|
+
data['sku'] = sku_variant.sku if sku_variant&.sku.present?
|
|
241
|
+
|
|
242
|
+
if product.brand_taxon
|
|
243
|
+
data['brand'] = { '@type' => 'Brand', 'name' => product.brand_taxon.name }
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
data['offers'] = if product.has_variants?
|
|
247
|
+
product.variants.map { |variant| product_json_ld_variant_offer(product, variant) }
|
|
248
|
+
else
|
|
249
|
+
[product_json_ld_variant_offer(product, first_or_default_variant)]
|
|
250
|
+
end
|
|
251
|
+
data
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def product_json_ld_variant_offer(product, variant)
|
|
255
|
+
Rails.cache.fetch(['json-ld-variant-hash', *spree_base_cache_key, variant.cache_key_with_version]) do
|
|
256
|
+
offer = {
|
|
257
|
+
'@type' => 'Offer',
|
|
258
|
+
'availability' => "http://schema.org/#{variant.available? ? 'InStock' : 'OutOfStock'}",
|
|
259
|
+
'price' => variant.amount_in(current_currency),
|
|
260
|
+
'priceCurrency' => current_currency,
|
|
261
|
+
'url' => spree.product_url(product, variant_id: variant.id, host: current_store.url_or_custom_domain)
|
|
262
|
+
}
|
|
263
|
+
offer['sku'] = variant.sku if variant.sku.present?
|
|
264
|
+
offer
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
228
268
|
def option_type_colors_preview_styles(option_type)
|
|
229
269
|
return unless option_type.color_swatch?
|
|
230
270
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
class ColorsPreviewStylesPresenter
|
|
3
|
+
UNSAFE_CSS_CHARS = /[<>"'\\;{}\r\n]/
|
|
4
|
+
|
|
3
5
|
def initialize(colors)
|
|
4
6
|
@colors = colors.compact_blank.map do |color|
|
|
5
7
|
case color
|
|
@@ -17,11 +19,11 @@ module Spree
|
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
def to_s
|
|
20
|
-
@to_s ||= if
|
|
22
|
+
@to_s ||= if renderable_colors.any?
|
|
21
23
|
css = ['<style>']
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
css_color = css_colors_hash[color[:filter_name]]
|
|
25
|
+
renderable_colors.each do |color|
|
|
26
|
+
css_color = css_colors_hash[color[:filter_name]]
|
|
25
27
|
color_name = color[:name]
|
|
26
28
|
css << <<~CSS
|
|
27
29
|
@supports(background: #{css_color}) {
|
|
@@ -48,6 +50,17 @@ module Spree
|
|
|
48
50
|
|
|
49
51
|
attr_reader :colors
|
|
50
52
|
|
|
53
|
+
# We only emit CSS rules for colors we recognise via Spree::ColorNames AND whose
|
|
54
|
+
# name contains no characters that could break out of the CSS string/selector
|
|
55
|
+
# context (admins control these names; #to_s output is rendered with raw()).
|
|
56
|
+
def renderable_colors
|
|
57
|
+
@renderable_colors ||= colors.reject do |color|
|
|
58
|
+
css_colors_hash[color[:filter_name]].nil? ||
|
|
59
|
+
color[:name].match?(UNSAFE_CSS_CHARS) ||
|
|
60
|
+
color[:filter_name].match?(UNSAFE_CSS_CHARS)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
51
64
|
def css_colors_hash
|
|
52
65
|
@css_colors_hash ||= begin
|
|
53
66
|
colors_hash = {}
|
|
@@ -61,7 +74,7 @@ module Spree
|
|
|
61
74
|
colors_hash[color_name] = generate_css_color(hex_colors)
|
|
62
75
|
elsif (subcolors = color_name.split.compact) && subcolors.length > 1
|
|
63
76
|
subcolors = subcolors.map(&method(:find_color)).compact
|
|
64
|
-
colors_hash[color_name] = generate_css_color(subcolors)
|
|
77
|
+
colors_hash[color_name] = generate_css_color(subcolors) if subcolors.any?
|
|
65
78
|
end
|
|
66
79
|
end
|
|
67
80
|
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
<%= hidden_field_tag :section_id, section.id %>
|
|
29
29
|
<%= f.email_field :email, placeholder: block.preferred_placeholder, required: true, class: 'focus:border-primary focus:ring-primary pr-36 text-sm bg-accent rounded-input border-accent py-2 px-4 w-full relative z-30 !leading-[46px]' %>
|
|
30
30
|
<div class="absolute right-2 top-1/2 transform -translate-y-1/2 z-40">
|
|
31
|
-
<%= f.submit block.preferred_button_text
|
|
31
|
+
<%= f.submit block.preferred_button_text, class: "#{block.preferred_button_style == 'secondary' ? 'btn-secondary' : 'btn-primary'} content-center" %>
|
|
32
32
|
</div>
|
|
33
33
|
</div>
|
|
34
34
|
</div>
|
|
@@ -1,20 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
</script>
|
|
1
|
+
<%= json_ld_script({
|
|
2
|
+
'@context' => 'https://schema.org',
|
|
3
|
+
'@type' => 'BlogPosting',
|
|
4
|
+
'headline' => post.title,
|
|
5
|
+
'image' => post.image.attached? ? [spree_image_url(post.image, width: 1200, height: 675)] : [],
|
|
6
|
+
'datePublished' => post.published_at&.iso8601,
|
|
7
|
+
'dateModified' => post.updated_at&.iso8601,
|
|
8
|
+
'author' => [
|
|
9
|
+
{
|
|
10
|
+
'@type' => 'Person',
|
|
11
|
+
'name' => post.author_name
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}, data: { test_id: 'post-json-ld' }) %>
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
<%= posts_json_ld_breadcrumbs(post).to_json.html_safe %>
|
|
20
|
-
</script>
|
|
16
|
+
<%= json_ld_script(posts_json_ld_breadcrumbs(post), data: { test_id: 'post-breadcrumbs-json-ld' }) %>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<% description_text = strip_tags(product.storefront_description) %>
|
|
3
3
|
<div data-controller="read-more" class="flex flex-col gap-4" data-read-more-more-text-value="<%= Spree.t(:read_more) %>" data-read-more-less-text-value="Read less">
|
|
4
4
|
<div class="prose product-description text-sm <%= 'product-description-truncated' if description_text.size > 250 %>" data-read-more-target="content">
|
|
5
|
-
<%=
|
|
5
|
+
<%= sanitize(product.storefront_description) %>
|
|
6
6
|
</div>
|
|
7
7
|
<% if description_text.size > 250 %>
|
|
8
8
|
<%= button_tag Spree.t(:read_more), type: 'button', data: { action: "read-more#toggle" }, class: "font-bold underline text-sm" %>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<% description_text = strip_tags(product.storefront_description) %>
|
|
4
4
|
<div data-controller="read-more" class="py-4 flex flex-col gap-4" data-read-more-more-text-value="<%= Spree.t(:read_more) %>" data-read-more-less-text-value="Read less">
|
|
5
5
|
<div class="prose product-description text-sm <%= 'product-description-truncated' if description_text.size > 250 %>" data-read-more-target="content">
|
|
6
|
-
<%=
|
|
6
|
+
<%= sanitize(product.storefront_description) %>
|
|
7
7
|
</div>
|
|
8
8
|
<% if description_text.size > 250 %>
|
|
9
9
|
<%= button_tag Spree.t(:read_more), type: 'button', data: { action: "read-more#toggle" }, class: "font-bold underline text-sm" %>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"w-full group-hover:opacity-0 transition-opacity duration-500 z-10 relative h-full bg-background product-card !max-h-full #{object_class}" :
|
|
15
15
|
"w-full h-full !max-h-full #{object_class}" %>
|
|
16
16
|
<%= spree_image_tag(object.primary_media, width: width, height: height, variant: :medium, loading: :lazy, alt: "#{object.name} #{Spree.t('storefront.products.primary_image', default: 'primary image')}", class: image_hover_class) %>
|
|
17
|
-
<% if object.has_images? && object.
|
|
17
|
+
<% if object.has_images? && object.secondary_image.present? && object.secondary_image.attached? %>
|
|
18
18
|
<% secondary_image_class = "w-full absolute top-0 left-0 opacity-100 h-full !max-h-full #{object_class}" %>
|
|
19
19
|
<%= spree_image_tag(object.secondary_image, width: width, height: height, variant: :medium, loading: :lazy, alt: "#{object.name} #{Spree.t('storefront.products.secondary_image', default: 'secondary image')}", class: secondary_image_class) %>
|
|
20
20
|
<% end %>
|
|
@@ -1,40 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
{
|
|
4
|
-
"@context": "https://schema.org/",
|
|
5
|
-
"@type": "Product",
|
|
6
|
-
"name": <%= product.name.to_json.html_safe %>,
|
|
7
|
-
"url": <%= spree.product_url(product, host: current_store.url_or_custom_domain).to_json.html_safe %>,
|
|
8
|
-
<% if product.has_images? %>
|
|
9
|
-
"image": [
|
|
10
|
-
<%= spree_image_url(product.primary_media, variant: :large).to_json.html_safe %>
|
|
11
|
-
],
|
|
12
|
-
<% end %>
|
|
13
|
-
<% if product.description.present? %>
|
|
14
|
-
"description": <%= strip_tags(product.description).to_json.html_safe %>,
|
|
15
|
-
<% end %>
|
|
16
|
-
<% if !product.has_variants? %>
|
|
17
|
-
<% if first_or_default_variant.sku.present? %>"sku": <%= first_or_default_variant.sku.to_json.html_safe %>,<% end %>
|
|
18
|
-
<% elsif selected_variant %>
|
|
19
|
-
<% if selected_variant.sku.present? %>"sku": <%= selected_variant.sku.to_json.html_safe %>,<% end %>
|
|
20
|
-
<% end %>
|
|
21
|
-
<% if product.brand_taxon %>
|
|
22
|
-
"brand": {
|
|
23
|
-
"@type": "Brand",
|
|
24
|
-
"name": <%= product.brand_taxon.name.to_json.html_safe %>
|
|
25
|
-
},
|
|
26
|
-
<% end %>
|
|
27
|
-
"offers": [
|
|
28
|
-
<% if product.has_variants? %>
|
|
29
|
-
<%= raw(product.variants.map do |variant|
|
|
30
|
-
render partial: "spree/products/json_ld_variant", locals: { product: product, variant: variant }
|
|
31
|
-
end.join(",\n")) %>
|
|
32
|
-
<% else %>
|
|
33
|
-
<%= render "spree/products/json_ld_variant", product: product, variant: first_or_default_variant %>
|
|
34
|
-
<% end %>
|
|
35
|
-
]
|
|
36
|
-
}
|
|
37
|
-
</script>
|
|
38
|
-
<script type="application/ld+json">
|
|
39
|
-
<%= product_json_ld_breadcrumbs(product).to_json.html_safe %>
|
|
40
|
-
</script>
|
|
1
|
+
<%= json_ld_script(product_json_ld_data(product, selected_variant: selected_variant), data: { test_id: 'product-json-ld' }) %>
|
|
2
|
+
<%= json_ld_script(product_json_ld_breadcrumbs(product)) %>
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
<% cache [spree_base_cache_key, products,'json-ld-list'], expires_in: 1.day do %>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
</script>
|
|
9
|
-
<% end %>
|
|
2
|
+
<%= json_ld_script({
|
|
3
|
+
'@context' => 'https://schema.org',
|
|
4
|
+
'@type' => 'ItemList',
|
|
5
|
+
'itemListElement' => product_list_json_ld_elements(products.to_a.pluck(:slug))
|
|
6
|
+
}, data: { test_id: 'product-list-json-ld' }) %>
|
|
7
|
+
<% end %>
|
|
@@ -1,32 +1,29 @@
|
|
|
1
1
|
<% cache spree_storefront_base_cache_scope.call(current_store) do %>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
</script>
|
|
2
|
+
<% organization = {
|
|
3
|
+
'@context' => 'https://schema.org',
|
|
4
|
+
'@type' => 'Organization',
|
|
5
|
+
'url' => current_store.formatted_url_or_custom_domain,
|
|
6
|
+
'sameAs' => current_store.social_links,
|
|
7
|
+
'name' => current_store.name,
|
|
8
|
+
'email' => current_store.customer_support_email
|
|
9
|
+
} %>
|
|
10
|
+
<% if current_store.logo && current_store.logo&.attached? && current_store.logo&.variable? %>
|
|
11
|
+
<% organization['logo'] = spree_image_url(current_store.logo, width: 250, height: 250) %>
|
|
12
|
+
<% end %>
|
|
13
|
+
<%= json_ld_script(organization) %>
|
|
15
14
|
<% end %>
|
|
16
15
|
|
|
17
16
|
<% if canonical_path.include?('search') %>
|
|
18
17
|
<% potential_action_target = "#{canonical_href(current_store.url_or_custom_domain)}?q={search_term_string}" %>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
</script>
|
|
18
|
+
<%= json_ld_script({
|
|
19
|
+
'@context' => 'https://schema.org',
|
|
20
|
+
'@type' => 'WebSite',
|
|
21
|
+
'name' => current_store.name,
|
|
22
|
+
'potentialAction' => {
|
|
23
|
+
'@type' => 'SearchAction',
|
|
24
|
+
'target' => potential_action_target,
|
|
25
|
+
'query-input' => 'required name=search_term_string'
|
|
26
|
+
},
|
|
27
|
+
'url' => current_store.formatted_url_or_custom_domain
|
|
28
|
+
}) %>
|
|
32
29
|
<% end %>
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: spree_storefront
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.4.
|
|
4
|
+
version: 5.4.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vendo Connect Inc.
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 5.4.
|
|
18
|
+
version: 5.4.3
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 5.4.
|
|
25
|
+
version: 5.4.3
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: active_link_to
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -247,6 +247,7 @@ files:
|
|
|
247
247
|
- app/helpers/spree/checkout_helper.rb
|
|
248
248
|
- app/helpers/spree/filters_helper.rb
|
|
249
249
|
- app/helpers/spree/fonts_helper.rb
|
|
250
|
+
- app/helpers/spree/json_ld_helper.rb
|
|
250
251
|
- app/helpers/spree/orders_helper.rb
|
|
251
252
|
- app/helpers/spree/page_helper.rb
|
|
252
253
|
- app/helpers/spree/payment_methods_helper.rb
|
|
@@ -471,7 +472,6 @@ files:
|
|
|
471
472
|
- app/views/themes/default/spree/products/_filters.html.erb
|
|
472
473
|
- app/views/themes/default/spree/products/_json_ld.html.erb
|
|
473
474
|
- app/views/themes/default/spree/products/_json_ld_list.html.erb
|
|
474
|
-
- app/views/themes/default/spree/products/_json_ld_variant.html.erb
|
|
475
475
|
- app/views/themes/default/spree/products/_label.html.erb
|
|
476
476
|
- app/views/themes/default/spree/products/_media_gallery.html.erb
|
|
477
477
|
- app/views/themes/default/spree/products/_metafields.html.erb
|
|
@@ -592,9 +592,9 @@ licenses:
|
|
|
592
592
|
- MIT
|
|
593
593
|
metadata:
|
|
594
594
|
bug_tracker_uri: https://github.com/spree/spree-rails-storefront/issues
|
|
595
|
-
changelog_uri: https://github.com/spree/spree-rails-storefront/releases/tag/v5.4.
|
|
595
|
+
changelog_uri: https://github.com/spree/spree-rails-storefront/releases/tag/v5.4.3
|
|
596
596
|
documentation_uri: https://docs.spreecommerce.org/
|
|
597
|
-
source_code_uri: https://github.com/spree/spree-rails-storefront/tree/v5.4.
|
|
597
|
+
source_code_uri: https://github.com/spree/spree-rails-storefront/tree/v5.4.3
|
|
598
598
|
rdoc_options: []
|
|
599
599
|
require_paths:
|
|
600
600
|
- lib
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
<% cache ["json-ld-variant", spree_base_cache_scope, variant.cache_key_with_version] do %>
|
|
2
|
-
{
|
|
3
|
-
"@type": "Offer",
|
|
4
|
-
<% if variant.sku.present? %>
|
|
5
|
-
"sku": <%= variant.sku.to_json.html_safe %>,
|
|
6
|
-
<% end %>
|
|
7
|
-
"availability": "http://schema.org/<%= variant.available? ? 'InStock' : 'OutOfStock' %>",
|
|
8
|
-
"price": <%= variant.amount_in(current_currency).to_json.html_safe %>,
|
|
9
|
-
"priceCurrency": <%= current_currency.to_json.html_safe %>,
|
|
10
|
-
"url": <%= spree.product_url(product, variant_id: variant.id, host: current_store.url_or_custom_domain).to_json.html_safe %>
|
|
11
|
-
}
|
|
12
|
-
<% end %>
|