Tag based Product Recommendation on shopify - tags

i am trying to show related products based on the tag they have in common with the product
for this created a section and used this code
https://www.shopify.com/partners/blog/related-products
i have used the same tag that is 'test'
also replaced the
{% include 'product-card-grid', max_height: max_height %}
with
{% render 'product-item', product: product %}
beacuse in prestige theme there is no snippet of product-card-grid
but nothing shows on the product page not even the heading
enter code here
{% if section.settings.show_related_products == true %}
<hr>
<div class="product-template__container page-width" itemscope itemtype="http://schema.org/Product" id="ProductSection-{{ section.id }}" data-section-id="{{ section.id }}" data-section-type="product" data-enable-history-state="true">
{% comment %}
Number of related items per row,
and number of rows.
{% endcomment %}
{% assign number_of_related_products_per_row = section.settings.related_grid_num %}
{% assign number_of_rows = section.settings.related_grid_row %}
{% comment %}
Heading.
Leave blank if you don't need one.
{% endcomment %}
{% assign heading = section.settings.related_title %}
{% comment %}
Set either or both to true, if you want
to limit yourself to items with same vendor, and/or type.
{% endcomment %}
{% assign same_vendor = false %}
{% assign same_type = false %}
{% comment %}
Collections to ignore.
Never pick related items from those.
{% endcomment %}
{% assign exclusions = 'frontpage,all' | split: ',' %}
{% comment %}
Looking for a relevant collection.
{% endcomment %}
{% if product.metafields.c_f['Related Products'] %}
{% assign collection = collections[product.metafields.c_f['Related Products']] %}
{% endif %}
{% assign found_a_collection = false %}
{% if collection and collection.all_products_count > 1 %}
{% unless exclusions contains collection.handle %}
{% assign found_a_collection = true %}
{% endunless %}
{% endif %}
{% unless found_a_collection %}
{% for c in product.collections %}
{% unless exclusions contains c.handle or c.all_products_count < 2 %}
{% assign found_a_collection = true %}
{% assign collection = c %}
{% break %}
{% endunless %}
{% endfor %}
{% endunless %}
{% comment %}
If we have a relevant collection.
{% endcomment %}
{% if found_a_collection %}
{% assign counter = 0 %}
{% assign break_at = number_of_rows | times: number_of_related_products_per_row %}
{% assign current_product = product %}
{% case number_of_related_products_per_row %}
{% when '1' %}
{% assign grid_item_width = '' %}
{%- assign max_height = 700 -%}
{% when '2' %}
{% assign grid_item_width = 'small--one-half medium-up--one-half' %}
{%- assign max_height = 530 -%}
{% when '3' %}
{% assign grid_item_width = 'small--one-half medium-up--one-third' %}
{%- assign max_height = 345 -%}
{% when '4' %}
{% assign grid_item_width = 'small--one-half medium-up--one-quarter' %}
{%- assign max_height = 250 -%}
{% when '5' %}
{% assign grid_item_width = 'small--one-half medium-up--one-fifth' %}
{%- assign max_height = 195 -%}
{% when '6' %}
{% assign grid_item_width = 'small--one-half medium-up--one-sixth' %}
{%- assign max_height = 195 -%}
{% else %}
{% assign grid_item_width = 'small--one-half medium-up--one-quarter' %}
{%- assign max_height = 195 -%}
{% endcase %}
{% capture related_items %}
<div class="grid grid--uniform{% if collection.products_count > 0 %} grid--view-items{% endif %}">
{% for product in collections.all.products %}
{% unless product.handle == current_product.handle %}
{% unless same_vendor and current_product.vendor != product.vendor %}
{% unless same_type and current_product.type != product.type %}
{% comment %}
Replace 'test' below with prefered tag
{% endcomment %}
{% if product.tags contains 'test' %}
<div class="grid__item {{ grid_item_width }}">
{% render 'product-item', product: product %}}
</div>
{% assign counter = counter | plus: 1 %}
{% if counter == break_at %}
{% break %}
{% endif %}
{% endif %}
{% endunless %}
{% endunless %}
{% endunless %}
{% endfor %}
</div>
{% endcapture %}
{% assign related_items = related_items | trim %}
{% unless related_items == blank %}
<aside class="grid">
<div class="grid__item">
{% unless heading == blank %}
<header class="section-header">
<h3>{{ heading }}</h3>
</header>
{% endunless %}
<div class="grid-uniform">
{{ related_items }}
</div>
</div>
</aside>
{% endunless %}
{% endif %}
</div>
{% endif %}
{% schema %}
{
"name": "Related products",
"settings": [
{
"type": "checkbox",
"id": "show_related_products",
"label": "Show related products",
"default": false
},
{
"id": "related_title",
"type": "text",
"label": "Section title",
"default": "Other fine products"
},
{
"type": "select",
"id": "related_grid_num",
"label": "Products per row (Desktop)",
"default": "4",
"options": [
{
"value": "2",
"label": "2"
},
{
"value": "3",
"label": "3"
},
{
"value": "4",
"label": "4"
},
{
"value": "5",
"label": "5"
}
]
},
{
"type": "select",
"id": "related_grid_row",
"label": "Number of rows (Desktop)",
"default": "1",
"options": [
{
"value": "1",
"label": "1"
},
{
"value": "2",
"label": "2"
},
{
"value": "3",
"label": "3"
}
]
}
]
}
{% endschema %} ```

I think you have a extra '}' on {% render 'product-item', product: product %}}, try removing it, you can also test your variables in this way
{{ variable | json }} This will print data on any variable.
you can add something like this to your code for better styling, easy reading.
<pre>{{ variable | json }}</pre>
Also there is no collection.all.products you need to use
collection.products

Related

Shopify linking product using SEO handle coding

I followed the directions for the second way to tag a product to a blog
This is the website I used https://happypoints.io/shopify-add-products-to-blog-post-c2-stt-66/ This is the code that was entered {% assign my_description = article.content | split: '=== split content ===' %}
{% assign my_description_size = my_description.size | minus: 2 %}
{{ my_description | first}}
<div class="show-product-list">
{% if article.tags.size > 0 %}
{% for tag in article.tags %}
{% paginate collections.all.products by 100 %}
{%- for product in collections.all.products -%}
{% if product.handle == tag %}
<div class="product_item">
{% include 'product-card-list' %}
</div>
{% endif %}
{%- endfor -%}
{% endpaginate %}
{% endfor %}
{% endif %}
</div>
{{ my_description | last}}
after following all the directions I received an error message saying
Liquid error (sections/article-template.liquid line 42): Could not find asset snippets/product-card-list.liquid
I am not sure why the product wont link to the blog using the seo handle. I have copied and pasted this code correctly and still getting this error
Collection code:
{% if collection.title == blank %}
{% assign collection_image = blank %}
{% elsif collection.image %}
{% assign collection_image = collection.image %}
{% else %}
{% assign collection_image = collection.products.first.featured_media.preview_image %}
{% endif %}
{% unless collection.title == blank %}
{% include 'card-image', type: collection_image, grid_style: grid_style %}
{% else %}
<div class="card__image-wrapper">
{% capture current %}{% cycle 1, 2, 3, 4, 5, 6 %}{% endcapture %}
{{ 'collection-' | append: current | placeholder_svg_tag: 'placeholder-svg' }}
</div>
{% endunless %}
<div class="card__info">
<h3 class="card__name h4">{% if collection.title != blank %}{{ collection.title }}{% else %}{{ 'homepage.onboarding.collection_title' | t }}{% endif %}</h3>
{% if section.settings.show_description and collection.description != blank %}
<div class="rte card__description{% if width == '2' %} card__description--padding{% endif %}">
{{ collection.description | strip_html | truncatewords: 15 }}
</div>
{% endif %}
</div>
You have correctly copy/pasted the code.
The problem is that your theme does not have a file named "product-card-list" in the snippets folder.
This is the file which contains code for the product tiles on the collection pages and the name for this file might differ in the theme that you're using.
You will need to find out the correct file name and replace "product-card-list" with that.
Can help you further if you share the code in your collection.liquid file.

Remove substring in a string with Stencil

I'm trying to play around with Sourcery to extend some library. I almost succeeded, but at some point I have a type, returned from a func and it is an optional. I want to make it non-optional instead. For this, I have to some how remove the question mark, but it seems to me language doesn't support it. My script is below if it can help somehow:
{% for type in types.structs %}
{% if type.name == "_R" %}
{% for innerType in type.containedTypes %}
{% if innerType.name == "_R.nib" %}
{% for nib in innerType.containedTypes %}
extension {{ nib.name }} {
{% for method in nib.methods %}
{% if method.selectorName == "firstView(owner:options:)" %}
func firstView(owner ownerOrNil: AnyObject?, options optionsOrNil: [NSObject : AnyObject]? = nil) ->
{{ method.returnTypeName }}
{
return instantiate(withOwner: ownerOrNil, options: optionsOrNil)[0] as? {{ method.returnTypeName }}
}
{% endif %}
{% endfor %}
}
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
At this place {{ method.returnTypeName }} I have all the return types optional. I want to remove question mark. Is it possible?
Solved the issue using .unwrappedTypeName where I want to remove ?

Symfony Bootstrap 4 Form Layout Inheritance

I'm trying to override some fields of bootstrap_4_layout.html.twig, but i found some problems with radio_widget block. I need to change the div element to label, but when I ovverride the block, the radio element is duplicated on view. The div in question is that with class custom-control
{% block radio_widget %}
{% set parent_label_class = parent_label_class|default(label_attr.class|default('')) %}
{% if 'radio-custom' in parent_label_class %}
{% set attr = attr|merge({class: (attr.class|default('') ~ ' custom-control-input')|trim}) %}
<div class="custom-control custom-radio{{ 'radio-inline' in parent_label_class ? ' custom-control-inline' }}">
{{ form_label(form, null, { widget: parent() }) }}
</div>
{% else %}
{% set attr = attr|merge({class: (attr.class|default('') ~ ' form-check-input')|trim}) %}
<div class="form-check{{ 'radio-inline' in parent_label_class ? ' form-check-inline' }}">
{{ form_label(form, null, { widget: parent() }) }}
</div>
{% endif %}
{% endblock radio_widget %}
Analizyng the dom with the console, I see that are created two element with custom-control class. Why?
I found the solution. I override the block radio_widget and changed the div element with label:
{% block radio_widget %}
{% set parent_label_class = parent_label_class|default(label_attr.class|default('')) %}
{% if 'radio-custom' in parent_label_class %}
{% set attr = attr|merge({class: (attr.class|default('') ~ ' custom-control-input')|trim}) %}
<label class="custom-control custom-radio{{ 'radio-inline' in parent_label_class ? ' custom-control-inline' }}">
{{ form_label(form, null, { widget: parent() }) }}
</label>
{% else %}
{% set attr = attr|merge({class: (attr.class|default('') ~ ' form-check-input')|trim}) %}
<div class="form-check{{ 'radio-inline' in parent_label_class ? ' form-check-inline' }}">
{{ form_label(form, null, { widget: parent() }) }}
</div>
{% endif %}
{% endblock radio_widget %}
Then I override also the block checkbox_radio_label. Inside it I substituted the base code:
// ...
{{ widget|raw }}
// ...
With:
{% set attr = attr|merge({class: (attr.class|default('') ~ ' custom-control-input')|trim}) %}
<input type="radio" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />
For reference about bootstrap 4 twig blocks see this link:
https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig

Jekyll case-insensitive sorting

I'm trying to create a tags list in Jekyll. Some of the tags are "accessibility", "CSS", and "JavaScript". So my Jekyll code to create the list looks like this:
<ul>
{% for item in (0..site.tags.size) %}{% unless forloop.last %}
{% capture this_word %}{{ tag_words[item] }}{% endcapture %}
<li>
<a href="#{{ this_word | cgi_escape }}" class="tag">{{ this_word }}
<span>({{ site.tags[this_word].size }})</span>
</a>
</li>
{% endunless %}{% endfor %}
</ul>
However, the rending of the list isn't alphabetical. It's first case-sensitive, capital words first; so my example tags above are rendered in this order:
CSS
JavaScript
accessibility
Is there a way to make the sorted list case-insensitive?
There is a sort_natural filter in liquid, but it doesn't work with site.tags.
The trick is to generate an array with all tags names
{% comment %} Creates an empty array {% endcomment %}
{% assign tags = "" | split:"" %}
{% comment %}Creates an array of tags names{% endcomment %}
{% for t in site.tags %}
{% assign tags = tags | push: t[0] %}
{% endfor %}
Sort them naturally (case insensitive)
{% assign sorted_tags = tags | sort_natural %}
Based on this sort, print tags counts
<ul>
{% for t in sorted_tags %}
<li>{{ t }} : {{ site.tags[t].size }}</li>
{% endfor %}
</ul>
This becomes more complex once you have to find a post by its name. Here's a solution to sort posts in an archive list alphabetically:
{% assign post_names = "" | split:"" %}
{% for post in tag.last %}
{% assign post_names = post_names | push: post.title %}
{% endfor %}
{% assign sorted_post_names = post_names | sort_natural %}
{% for post_name in sorted_post_names %}
{% assign matched_post = site.posts | where:"title",post_name %}
{% assign post = matched_post[0] %}
…
{% endfor %}
The trick is to find the post with where from the overall list of posts.
It seems that the mentioned issue of sort_natural filter has been fixed. You may try to use it directly:
<ul>
{% for t in site.tags sort_natural %}
<li>{{ t }} : {{ site.tags[t].size }}</li>
{% endfor %}
</ul>

Passing a macro argument to an if == test in jinja?

I'm using Tarbell to publish a formatted version of an inventory spreadsheet. Every row has a category, so I can do something like this:
<h2>Power Tools</h2>
{% for row in inventory %}
{% if row.Category == "powertools" %}
<b>{{ row.Display_Name|e }}</b> <br />
{% endif %}
{% endfor %}
<h2>A/V Gear</h2>
{% for row in inventory %}
{% if row.Category == "av" %}
<b>{{ row.Display_Name|e }}</b><br />
{% endif %}
{% endfor %}
To get a list of all the power tools followed by a list of A/V gear. I'd like to move that into a macro that I can call with a couple of arguments. I've got this:
{% macro list(cat, title='') -%}
<p>Category: {{ cat }}; Header: {{ title }}</p>
{% for row in inventory %}
{% if row.Category == "{{ cat }}" %}
<b>{{ row.Display_Name|e }}</b><br />
{% endif %}
{% endfor %}
{%- endmacro %}
When I call it with:
{{ list('av', title='Cameras and Audio Recorders')}}
{{ list('powertools', title='Power Tools')}}
I see "Category: powertools; Header: Power Tools" and "Category: av; Header: Cameras and Audio Recorders" as expected, so I know the macro can hear me, but the list itself doesn't show up. Can I use a macro argument in a comparison test? How?
There is no need for variable interpolation syntax inside of a block - you can just refer to the variable by name as you would in Python:
{# Do this #}
{% if row.Category == cat %}
{# Instead of this #}
{% if row.Category == "{{ cat }}" %}