Jekyll case-insensitive sorting - tags

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>

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.

How to display tags in jekyll and get the tag to click through to all relevant collection posts

I am looking to display all the tags from my collection posts in a sidebar, and have each tag click through to all the relevant posts. I would also like to display the number of times the tag has been used like this:
tag_name (10)
This is what I have currently which has got all the tags as a list but I cant figure out how to get the tag to click through to all relevant pages and also display the size.
<ul class="">
{% assign tags = site.vacancies | map: 'tags' | join: ',' | split: ',' | uniq %}
{% for tag in tags %}
<li class="text-capitalize">
{{ tag }}
</li>
{% endfor %}
</ul>
First, retrieve all tags into an list by using site.tags provide by Jekyll Variables
{% capture site_tags %}{% for tag in site.tags %}{{ tag | first }}{% unless forloop.last %},{% endunless %}{% endfor %}{% endcapture %}
{% assign tags_list = site_tags | split:',' | sort_natural %}
Secondly, get a link for each Tag with its post count correspondingly
<ul>
{% for item in (0..site.tags.size) %}{% unless forloop.last %}
{% capture this_word %}{{ tags_list[item] | strip_newlines }}{% endcapture %}
<li><span class="tag-name">{{ this_word }}</span> <span class="count">{{ site.tags[this_word].size }}</span></li>
{% endunless %}{% endfor %}
</ul>
Thirdly, show each tag's name and its posts' name and date.
{% for item in (0..site.tags.size) %}{% unless forloop.last %}
{% capture this_word %}{{ tags_list[item] | strip_newlines }}{% endcapture %}
<article id="{{ this_word }}">
<h2 class="tag-heading tag-name">{{ this_word }}</h2>
<ul>
{% for post in site.tags[this_word] %}{% if post.title != null %}
<li><a href="{{ site.url }}{{ post.url }}" title="{{ post.title }}" >{{ post.date | date: '%m/%d/%Y' }} ---- {{ post.title }}</a></li>
{% endif %}{% endfor %}
</ul>
</article>
{% endunless %}{% endfor %}
So there's a way to do it by creating an array of tags while iterating through posts in the collection and using lots of liquid... and I decided to do my own workaround.
I have a master list of all the tags that I use stored in /_data/tagList.yml. Each tag has a name and slug, and you can add more fields like a description if you want to. I iterate through the data in tagList, and for each tag have a link to a dedicated page that lists all the posts that contain that tag.
If you followed the Jekyll docs and used tags in the front matter and you are consistent in naming your tags, then you can use the site.tags[tag.name] | size filter to get a count on how many posts have that tag.
Drawbacks of this workaround are:
you need to update tagList.yml any time you make a new tag
you need to make a new page for that tag (not a big deal since you can just copy/paste code from other tag pages and just change the tag you're looking for)
you need to ensure you are consistent in naming and using tags
// /_data/tagList.yml
- name: Coding
slug: coding
- name: UnpopularOpinion
slug: unpopular-opinion
// /_posts/2019-01-01-example.html
---
tags: [Coding, UnpopularOpinion]
---
// /blog/tags.html
{% for tag in site.data.tagList %}
<div>
<h2>{{tag.name}}</h2>
{% assign postCount = site.tags[tag.name] | size %}
<em>
{% if postCount == 1 %}
{{postCount}} post
{% else %}
{{postCount}} posts
{% endif %}
</em>
</div>
{% endfor %}
// /blog/tags/coding.html
{% assign numPosts = site.tags.Coding | size %}
{% if numPosts == 0 %}
<p>No posts have this tag...yet.</p>
{% endif %}
{% for post in site.tags.Coding %}
...code to display a post...
{% endfor %}

Tag count automatically changing while clicking on the product tag

I am using Shopify. I am in collection page where I am getting all the filter with tag count something like,
All Products
Apple(4)
Banana(2)
Orange(1)
Mango(8)
Now when I click on any of the tag(For example I clicked on Banana) then It will display the banana products.
Now my issue is by clicking on the tag it's changing the tag count.
All Products
Apple(0)
Banana(2)
Orange(0)
Mango(4)
I am using below code
{% for tag in collection.all_tags %}
{% assign products_count = 0 %}
{% for product in collection.products %}
{% if product.tags contains tag %}
{% assign products_count = products_count | plus: 1 %}
{% endif %}
{% endfor %}
<a class="filter__link" href="/collections/{% if collection.handle != blank %}{{ collection.handle }}{% else %}all{% endif %}/{{ tag | handleize }}"{% if current_tags contains tag %} selected="selected" id="tag_active"{% endif %}>{{ tag }} ({{products_count }})</a>
{% endfor %}
Thanks in advance.
It looks like the step you're missing is the first line here:
{% assign collection = collections.all %}
You're iterating over the current collection, so as you've noticed when you click on a tag the results change.
If you don't have a collection with the handle all, you can create one by following this process:
Go to Products > Collections.
Click Add a collection.
Create the collection:
Give your collection the Title All.
In the Conditions section, select "Automatically select products based on conditions".
Set the product condition "Product price is greater than $0".
Save
Edit:
This fixes the issue where the product count changes when you click on a tag link:
{% for tag in collection.all_tags %}
{% assign products_count = 0 %}
{% for product in collections[collection.handle].products %}
{% if product.tags contains tag %}
{% assign products_count = products_count | plus: 1 %}
{% endif %}
{% endfor %}
<a class="filter__link" href="/collections/{% if collection.handle != blank %}{{ collection.handle }}{% else %}all{% endif %}/{{ tag | handleize }}"{% if current_tags contains tag %} selected="selected" id="tag_active"{% endif %}>{{ tag }} ({{products_count }})</a>
{% endfor %}
The key part is:
{% for product in collections[collection.handle].products %}
It looks like when you're filtering by tag with a URL like collections/collection_1/tag_1 then collection.products is also filtered by the selected tag. The line above looks a bit messy, but it appears to return the full set of products.
As I was saying in comment, the issue comes from your secondary loop:
{% for product in collection.products %}
Which accesses only to the current view and not the full collection products.
I've not tested it but I guess it worthes a try:
{% assign whole_collection = collections[collection.handle] %}
{% for product in whole_collection.products %}
{% if product.tags contains tag %}
{% assign products_count = products_count | plus: 1 %}
{% endif %}
{% endfor %}
Explanation, a code like this {{ collections['the-handle'].url }} allows access to any specific collection and its attributes.
HTH
Memo : this won't work accurately if your collection has more than 50 items.

Jekyll -- number of posts by custom yml tags

I am working on a jekyll / gh-pages site. I'd like to build a side bar that lists the number of posts according to a CUSTOM tag. So i can sort posts using different yml elements. It works just fine using the tags yml element and this code
<h3>Activities By Topic</h3>
{% for tag in site.tags %}
{% assign t = tag | first %}
{% for atag in site.data.tags %}
{% if atag.slug == t %}
<h5><a href="{{ site.baseurl }}/{{ atag.slug }}">{{ atag.name }}
{% endif %}
{% endfor %}
({{ tag | last | size }})
</a></h5>
{% endfor %}
But what i'd like is another block that is "Activities by Type" (we are trying to sort posts in different ways. I setup a topic-tag yml element and a `topic-tag.yml file'
_data folder
https://github.com/lwasser/data-lesson-catalog/blob/gh-pages/_data/topic-tags.yml
org folder:
https://github.com/lwasser/data-lesson-catalog/tree/gh-pages/org/topic-tag
sample post:
https://github.com/lwasser/data-lesson-catalog/edit/gh-pages/_posts/lessons/2015-09-10_dc-R.md
relevant YML from sample post
---
layout: post
catalog-entry-type: lesson
title: Data Carpentry R for Ecology
topic-tag: ["Analysis", "Vizualization"]
---
Code that is not working:
<h3>Data Activities By Topic Tag</h3>
{% for tag in site.topic-tag %}
{% assign t = tag | first %}
{% for atag in site.data.topic-tags %}
{% if atag.slug == t %}
<h5><a href="{{ site.baseurl }}/{{ atag.slug }}">{{ atag.name }}</h5>
{% endif %}
{% endfor %}
({{ tag | last | size }})
{% endfor %}
Can i sort posts by other tags (not just the tags yml element)?
The output that i'd like is something like:
Analysis (2)
Visualization (3)
If so, any suggestions as to why the code above doesn't work? I found another post on here asking something similar but the resolution was to use the yaml "tags"element which will not work for my use case.
Many thanks,
Leah
You can use categories. They are working just like tags and can be another way to sort posts.
Hi to anyone who is struggling with this same thing. This is what i've learned.
Tags and categories are built into the jekyll build. You can thus call site.tags or site.categories without adding anything to your config file. Other custom tags that you create like topic-tags, are not inherently understood by jekyl as variables that can be called at the site level. My work-around -- use a counter to count posts by custom variable. the code looks like this
{% for member in site.data.topic-tags %}
{% assign counter = 0 %}
<!-- this code counts the number of posts associated with the member -->
{% for post in site.posts %}
{% if post.topic-tag contains member.slug %}
{% assign counter = counter | plus: 1 %}
{% endif %}
{% endfor %}
<h5><a href="{{ site.baseurl }}/topic-tag/{{ member.slug }}">{{ member.name }} ({{ counter }})</h5>
{% endfor %}
This works like a charm albeit it is looking through all of the posts to see if it contains the member tag in the yaml.
I hope this helps someone!
Here the code I use to display number of post on each categories. You may change site.categories to site.tags to display them by tags.
<h2 class="question">Topics ({{ site.posts | size }} total)</h2>
<ul class="topics">
{% capture tags %}
{% for tag in site.categories %}
{{ tag[0] }}
{% endfor %}
{% endcapture %}
{% assign sortedtags = tags | split:' ' | sort %}
{% for tag in sortedtags %}
<li class="topic-header"><b>{{ tag }} ({{ site.categories[tag] | size }} topics)</b>
<ul class='subnavlist'>
{% for post in site.categories[tag] %}
<li class='recipe'>
{{ post.title }}
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
Check it on action here.

How do you support per-page sidebar content in Zotonic?

I would like to have per-page sidebar content in Zotonic:
Links
White papers
Webinars
What is a good way to do this and what kind of template snippets would I need to make it work?
Log into the Zotonic admin interface.
Create Predicates:
Links (text->text)
White papers (text->document)
Webinars (text->text)
These predicates then show up in Page Connections in the Page editor. Add Links to other pages, links to White papers and links to Webinar pages in this way.
Add the following to _article_sidebar.tpl:
{% with m.rsc[id].links as texts %}
{% if texts %}
<h2>See also:</h2>
<ul>
{% for text in texts %}
<li><a href="{{ m.rsc[text].page_url }}" {% ifequal text id %}class="current"{% endifequal %}>{{ m.rsc[text].title }}</a></li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% with m.rsc[id].white_papers as texts %}
{% if texts %}
<h2>White papers:</h2>
<ul>
{% for text in texts %}
<li><a href="{{ m.rsc[text].page_url }}" {% ifequal text id %}class="current"{% endifequal %}>{{ m.rsc[text].title }}</a></li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% with m.rsc[id].webinars as texts %}
{% if texts %}
<h2>Related webinars:</h2>
<ul>
{% for text in texts %}
<li><a href="{{ m.rsc[text].page_url }}" {% ifequal text id %}class="current"{% endifequal %}>{{ m.rsc[text].title }}</a></li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
When you add a Predicate it lets you add metadata to your RSCs (Pages, Media, etc.) in Zotonic. Each Predicate allows you to connect a collection of RSCs to a RSC in the Zotonic interface. This collection is stored and accessed as IDs of RSCs.
Predicate metadata are then accessible within templates. The expression m.rsc[id].links selects the collection of IDs of RSCs connected to the current page as Links.
The expression m.rsc[id] selects the RSC for the page being rendered. The expression m.rsc[text] selects the RSC for a onnected RSC.
The expression {% ifequal text id %}class="current"{% endifequal %} conditionally renders a CSS class attribute that alters the link style to indicate that it is the current page.