Shopify Theme Development - For loop that checks if article.tags contains a sections variable - variables

I am trying to pull through related blog posts if the article.tags == the string given within the section settings.
I have tried a few different variations but to no effect. My code looks like this (don't worry about the content within the if loop, this is all fixed into shape by the CSS):
{% for article in blogs.news.articles limit:1 %}
{% if article.tags == section.settings.brand-news-tag | strip_html %}
{% assign image_src = article.image.src | img_url: 'large' %}
<div class="brand-page-featured-news-blogs">
<div class="brand-page-featured-news-article">
<div class="brand-page-featured-news-article-image" style="background-image: url({{ image_src }})">
<div class="brand-page-featured-news-article-image-contain">
<div class="brand-page-featured-news-article-image-overlay">
</div>
</div>
</div>
<div class="brand-page-featured-news-article-contain">
<h6 class="brand-page-featured-news-article-title">{{ article.title }}</h6>
<div class="brand-page-featured-news-article-content">
<p class="brand-page-featured-news-article-published">{{ article.published_at | date: "%d %B 20%y" }}</p>
<p class="brand-page-featured-news-article-text">{{ article.content }}</p>
<div class="brand-page-featured-news-article-button">
<div class="brand-page-featured-news-article-button-text">
Read More
</div>
</div>
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
{% schema %}
{
"name": "Featured News",
"settings": [
{
"id": "brand-news-tag",
"type": "text",
"label": "Brand News Tag",
"default": "brandnametag"
}
]
}
{% endschema %}
{% stylesheet %}
{% endstylesheet %}
{% javascript %}
{% endjavascript %}
This is the line in question:
{% if article.tags == section.settings.brand-news-tag | strip_html %}
I have tried to use a few other variations like without the '| strip_html'. I have tried to put it inside quotes like this {% if article.tags == "'" and section.settings.brand-news-tag and "'" %}. I have also tried to use 'contains' opposed to an '=='.
How can I use a variable within the if statement?
I have tried using -
{% if article.tags contains section.settings.brand-news-tag %}
I have also tried without any if statement narrowing down the blogs.news. this works as expected. Meaning it is something to do with this if statement not comparing to the blog tags. Although I have directly copied the blog tag in from the blog post to go into the variable within the section.
This also doesn't work -
{% for article in blogs.news.articles limit:1 %}
{% if section.settings.brand-news-tag != '' %}
{% assign blogfilter = section.settings.brand-news-tag | strip %}
{% endif %}
{% if article.tags contains blogfilter %}
This also doesn't work (Goodfellow is the tag copied) -
{% for article in blogs.news.articles limit:1 %}
{% if article.tags contains 'Goodfellow' %}
Here are some images of the blog side of things:

If you look at the article object in Shopify documentation then article.tags return an array. So an array cannot be compared with a string using == equals operator. You are looking for contains as explained in the logical and comparison operators documentation.
So your code will become
{% if article.tags contains section.settings.brand-news-tag %}
Moreover, you don't need strip_html as the field type is text. So Shopify will take care of it. You can use strip filter to remove any space and tabs from the start and end of string just to be extra sure.
String Filters
For your particular scenario, you don't need the limit: 1 inside for loop because you don't know that first object will contain the tag. So you need to iterate over all the objects and break out of loop if condition is satisfied. Sample code
{% for article in blogs.news.articles %}
{% if article.tags contains 'Goodfellow' %}
{{article.tags}}
{% break %}
{% endif %}
{% endfor %}

Related

Shopify Liquid tag nested in liquid tag - any workaround?

I'm new to Shopify and Liquid. I know that you can't nest a liquid tag within another liquid tag ie:
{% something {{ something_else }} %}
I was wondering if there is a workaround for this kind of scenario? Possibly involving 'capture' or clever use of 'raw'?
I'm building a site that uses product tags to denote which chocolates go in which products (collection of chocolates). On the product page I can easily return the tags as a list:
<ul class="chocolates-menu">
{% for tag in product.tags %}
<li>{{ tag }}</li>
{% endfor %}
</ul>
However, I'd like to render snippets with file names to match the names of the tags (these will contain an image, chocolate name and chocolate description) ie:
<li>{% render '{{ tag }}' %}</li>
The closest I've got is:
{% for tag in product.tags %}
{% capture chocolate_tag %}
{% raw %}{% render{% endraw %} {% raw %}'{% endraw %}{{ tag }}{% raw %}' %}{% endraw %}
{% endcapture %}
<li>{{ chocolate_tag }}</li>
{% endfor %}
This will output the correct code but as text on the page (rather than parsing it). ie: {% render 'Tag Name Here' %} simply as the text of the list item. Any help from brighter folk, is much appreciated. Thanks.
I would suggest creating a snippet for all your chocolates and using the tag as a variable to output what is needed.
Here is a visual representation of what I mean and is kinda clearer from your discussion with #Fabio Filippi
snippets/chocolate.liquid
{% assign tag_image = tag | append: '.png' %}
{% case tag %}
{% when 'diet' %}
<img src="{{ tag_image | file_img_url: '100x' }}" class="responsive" />
{% when 'dark' %}
<div>My dark chocolate HTML</div>
{% when 'white' %}
<div>My white chocolate HTML</div>
{% endcase %}
and how to use:
{% render 'chocolate', tag: tag %}

Shopify LinkList Loop Using Dynamic Variables

I have a block of code that I use on several pages. The only thing that changes in this block of code is the variable for the linklist. How do I refactor this code so that I can use a variable instead of static code?
<div class="featured-collections">
<div class="frow justify-start">
{% for link in linklists.book.links %}
<div class="collection-thumb">
<img class="collection-thumb-img" src="{{ link.object.featured_image | img_url: 'medium' }}">
<h3 class="collection-thumb-title">
{{ link.object.title | escape }}<br/>
</h3>
{{ link.object.price | money }}<br/>
<p>Book Now</p>
</div>
{% endfor %}
</div>
</div>
I tried this:
// Code for Variable Component - variable-linklist.liquid
{% for link in linklists.c.links %}
...
{% endfor %}
// Code for Book Page - page.book.liquid
{% assign c = "book" %}
{% include "variable-linklist" with "c" %}
but this did not work.
Code for Book Page - page.book.liquid
{% assign c = "book" %}
{% include "variable-linklist" with linklistHandle: c %}
Code for Variable Component - variable-linklist.liquid
{% for link in linklists[linklistHandle].links %}
...
{% endfor %}
or
Code for Book Page - page.book.liquid
{% assign c = "book" %}
{% include "variable-linklist" with c %}
Code for Variable Component - variable-linklist.liquid
{% for link in linklists[variable-linklist].links %}
...
{% endfor %}
When you use just with c the value is assigned to the variable with a name that is equal to the snippet name.

Assigning a collection to a custom created collection page in Shopify?

I am using a free Venture theme on Shopify and i am trying to make a custom collection page.
I found a solution in stackoverflow but it was able to help someplace.
How to add collection.liquid to an existing page?
The summery of the solution is:
Copy everything that's in collection.liquid and paste it into a new snippet (let's say you call it collection-copy.liquid).
Then, in the page you want to add the collections page to, just add {% include 'collection-copy' %}
This solution worked well but there is one more issue for me. In the custom created page it says "Sorry, there are no products in this collection" In the customization of the same page there is a "collection" section. But in the "collection" section there is no option to choose a collection. There is only "Enable tag filtering" and "Enable sorting" check boxes.
Webpage: https://mottomfreedom.com/pages/less-is-more
Do you have any idea of assigning a collection with this custom created snippet?
{% paginate collections[settings.frontpage_collection].products by 20 %}
<div class="page-width">
<header class="grid medium-up--grid--table section-header small--text-center">
<div class="grid__item medium-up--one-half section-header__item">
<h1 class="section-header__title">
{{ collection.title }}
{% if current_tags %}
– {% assign title_tags = current_tags | join: ', ' %}
{{ title_tags }}
{% endif %}
</h1>
{% if collection.description != blank %}
<div class="section-header__subtext rte">
{{ collection.description }}
</div>
{% endif %}
</div>
<div class="grid__item medium-up--one-half medium-up--text-right section-header__item">
{% section 'collection-filters' %}
</div>
</header>
<div class="grid grid--no-gutters grid--uniform">
{% for product in collection.products %}
<div class="grid__item small--one- medium-up--one-third">
{% include 'product-card', product: product %}
</div>
{% else %}
{% comment %}
Add default products to help with onboarding for collections/all only.
The onboarding styles and products are only loaded if the
store has no products.
{% endcomment %}
{% if shop.products_count == 0 %}
<div class="grid__item">
<div class="grid grid--no-gutters grid--uniform">
{% assign collection_index = 1 %}
{% for i in (1..10) %}
{% case i %}
{% when 7 %}
{% assign collection_index = 1 %}
{% when 8 %}
{% assign collection_index = 2 %}
{% when 9 %}
{% assign collection_index = 3 %}
{% when 10 %}
{% assign collection_index = 4 %}
{% endcase %}
<div class="grid__item small--one-half medium-up--one-fifth">
<a href="/admin/products" class="product-card">
<div class="product-card__image-container">
<div class="product-card__image-wrapper">
<div class="product-card__image">
{% capture current %}{% cycle 1, 2, 3, 4, 5, 6 %}{% endcapture %}
{{ 'product-' | append: current | placeholder_svg_tag: 'placeholder-svg' }}
</div>
</div>
</div>
<div class="product-card__info">
<div class="product-card__name">{{ 'homepage.onboarding.product_title' | t }}</div>
<div class="product-card__price">
$19.99
</div>
</div>
<div class="product-card__overlay">
{% assign view_string_length = 'products.product.view' | t | size %}
<span class="btn product-card__overlay-btn {% if view_string_length > 8 %} btn--narrow{% endif %}">{{ 'products.product.view' | t }}</span>
</div>
</a>
</div>
{% assign collection_index = collection_index | plus: 1 %}
{% endfor %}
</div>
</div>
{% else %}
{% comment %}
If collection exists but is empty, display message
{% endcomment %}
<div class="grid__item small--text-center">
<p>{{ 'collections.general.no_matches' | t }}</p>
</div>
{% endif %}
{% endfor %}
</div>
{% if paginate.pages > 1 %}
<div class="pagination">
{{ paginate | default_pagination | replace: '« Previous', '←' | replace: 'Next »', '→' }}
</div>
{% endif %}
</div>
{% endpaginate %}
You are right about giving some time before accepting an answer :)) The solution worked but forced me to create 1 page and 4 liquid files per collection. And at the end, i figured out that some sections like "collection.list" doesn't directs to the page which i have created. I think you were talking about this at the beginning of the answer :)
After that, i found a much better solution. Just creating a new section.liquid file and placing it in "collection.liquid" with an "if" statement solved my problem.
{% if collection.handle == 'less-is-more' %}
{% section 'custom-featured-products-LESSisMORE' %}
{% endif %}
But in any way, i'm grateful for your interest. Thank you very much Dave.
It looks like there's nothing defining the collection variable anywhere.
I would suggest changing the beginning of your code snippet from:
{% paginate collections[settings.frontpage_collection].products by 20 %}
To:
{% assign collection = collections[settings.frontpage_collection] %}
{% paginate collection.products by 20 %}
There is an implicit collections variable whenever you're on a page that includes /collections/[something] in the URL, but when you're on a URL that's /page/[something], you have an implicit page variable in Liquid instead.
Note: if the collection set in your theme's value for settings.frontpage_collection isn't the one you want, you can possibly:
a. Change the value using the 'Customize' link beside your theme (most easily found on the /admin/themes page), useful if you're not going to use that setting for anything else;
b. Hard-code a collection handle, eg: collections['i-am-sure-this-will-never-change'], but hard-coded strings are ugly and should generally be avoided;
c. Create your own theme setting by adding an entry to config/settings_schema.json - see https://help.shopify.com/en/themes/development/theme-editor/settings-schema if you're still getting up to speed with custom theme settings; or
d. If all your content is in a section, you can use section settings (similar to theme settings) to make a variable that's tied specifically to just that block of code.
If you need to make these special pages for multiple collections, and each of these pages is largely reusing the same code, you can make your life easier by moving the common code to a snippet and passing variables to it from your page template. To do so:
Create a file in the 'snippets' folder of your theme. (For this example, let's say the file is called collection-in-page.liquid. We will be passing a collection into this snippet, so you can remove the assign statement.
In your page-specific template, figure out what the collection handle is going to be
a. This might be hard-coded, or it might be something you could look up by using metafields or tags on the page. Examples:
{% assign collection_handle = 'hardcoded-handle' %}, {% assign collection_handle = page.metafields.related_items.collection %}
In your page template, include the snippet you created. I find it helps to explicitly pass any variables I want to use, like so:
{% include 'collection-in-page', collection: collections[collection_handle] %}
Hope this helps!

Shopify show collection description on conditions

I want to display a description of "Test" collection's page.
If the url is mysite.com/collections/test then it will show the description part.
But if the url have extra tags, example: mysite.com/collections/test/big it won't show the description.
I tried with this code below but it didn't work:
{% if collection.description != blank %}
{% if collection.url == '/collections/test' %}
<div class="collection-description regular-content mb30">
{{ collection.description }}
</div>
{% endif %}
{% endif %}
Please help me with this. Thank you.
Just add an extra condition to the first if, which will check if you have added any tags.
{% if collection.description != blank and current_tags == blank %}
<div class="collection-description regular-content mb30">
{{ collection.description }}
</div>
{% endif %}
The current_tags object lists all tags used in product/articles filtering.
More info here: https://help.shopify.com/themes/liquid/objects/current-tags

Django template inheritance the other way round

Django template system lets you easily specify a template and fill it with different data using extends and blocks.
What I need to do is to have several templates, filled with the same data (blocks) while avoiding code repetition. It sounds like a usecase for templatetags but consider this example:
<div class="container">
{% get_tags page as tags %}
{% if tags %}
<div class="ribbon">
<span class="ribbon-inner">{{ tags|join:' | ' }}</span>
</div>
{% endif %}
</div>
If I wanted to display the tags in another template using a different html elements/classes I would have to create at least two templatetags (has_tags and get_tags) or include html in templatetags code.
I'd like to have something like this:
#common.html
{% block tags %}
{% get_tags page as tags %}
{% if tags %}
<div class="ribbon">
<span class="ribbon-inner">{{ tags|join:' | ' }}</span>
</div>
{% endif %}
{% endblock %}
#template_A.html
{% include common.html %}
<div class="container-1">
{% block tags %}
{{ block.super }}
{% endblock %}
</div>
#template_B.html
{% include common.html %}
{% block tags %}
{% get_tags page as tags %}
{{ tags|join:', ' }}
{% endblock %}
The problem is that include renders the template first, therefore it doesn't work this way. There are a lot of similar points in the file I'm editing, so creating and including template for each of them is not a great solution either.
Any thoughts?
Well, this is my solution:
#templateA.html
{% include "_common.html" with parent_file="_templateA.html" %}
#templateB.html
{% include "_common.html" with parent_file="_templateB.html" %}
#_templateA.html
<i>{% block tags %}{% endblock %}</i>
#_templateB.html
<b>{% block tags %}{{ tags|join:' & ' }}{% endblock %}</b>
#_common.html
{% extends parent_file %}
{% block tags %}
{% if not block.super %} # this does the trick
{{ tags|join:' I ' }}
{% else %}
{{ block.super }}
{% endif %}
{% endblock %}
This allows having HTML templates in _templateA.html and _templateB.html. If the block is left empty, it is filled with default from _common.html, while it can be overriden in _template.
It would be nice to override the block tag to avoid code repetition in _common.html but the following implementation fails on block.super() because of missing context.
#register.tag('overridable_block')
def overridable_block(parser, token):
from django.template.loader_tags import do_block
block = do_block(parser, token)
if block.super():
return block.parent
return block
Haven't found a way past this yet.