Replace strings from one array with another in Liquid - arrays

I need to translate some country names to their denonyms in Liquid, but I'm having a little trouble.
I think I have the underlying logic correct here, however it is only working on products where the "country_of_origin" the last element in each array. So, at the moment a product with country of origin "Australia" will output "Australian", but the transformation doesn't happen on products from any other country.
{% assign countries = "France, Chile, Spain, Australia" | split: ", "%}
{% assign denonyms = "French, Chilean, Spanish, Australian" | split: ", "%}
{% assign d = countries.size | minus:1 %}
{% for i in (0..d) %}
{% assign denonized = product.metafields.custom.country_of_origin.value | replace: countries[i],denonyms[i] %}
{% endfor %}
{{ denonized }}
If anyone were to take a look here I would really appreciate it!

The problem is that you reassign the variable in the loop, so only the last replacement is working.
This is your version but with a correct assignment:
% assign countries = "France, Chile, Spain, Australia" | split: ", "%}
{% assign denonyms = "French, Chilean, Spanish, Australian" | split: ", "%}
{% assign d = countries.size | minus:1 %}
{% assign denonized = product.metafields.custom.country_of_origin.value %}
{% for i in (0..d) %}
{% assign denonized = denonized | replace: countries[i],denonyms[i] %}
{% endfor %}
{{ denonized }}
And this is an example using forloop instead of another variable:
{% assign countries = "France, Chile, Spain, Australia" | split: ", " %}
{% assign denonyms = "French, Chilean, Spanish, Australian" | split: ", " %}
{% assign denonized = product.metafields.custom.country_of_origin.value %}
{% for country in countries %}
{% assign denonized = replaced | replace: country, denonyms[forloop.index0] %}
{% endfor %}
{{ denonized }}
If you have many countries you could add a if previous_value!=new_value break to avoid looping for all the possible countries after you have already replaced.

Related

In Liquid (Shopify) how am I able to get the index position of a specific array object?

In a snippet called 'sb' I have this content
{% assign seller_id = 'another_seller_shop_name,test_seller' | split: ',' %}
{% assign seller_html = 'Another Seller Desc,Seller Description' | split: ',' %}
In the template page - in this case, collection-list I have referenced this snippet
{% include 'sb' %}{% assign seller_id_page = collection.title | replace: ' ','_' | downcase %}
'seller_id_page' will equal to one of the values in 'seller_id'. I just want to be able to return the position of this value, so I can then assign seller_html[x] an index value and render field correctly.
You will need to loop the array and get the index of the corresponding equality.
In code:
{% for item in seller_id %}
{% if item == seller_id_page %}
{% assign position = forloop.index0 %}
{% break %}
{% endif %}
{% endfor %}
{{ seller_html[position] }}
That's the just of it.

How to specify multiple authors for a single post, then count the posts each author is related to?

What I'm trying to do:
I'm trying to create a list for the posts each author has written. This is a problem since each post should be able to specify multiple authors.
Let's say we have 3 posts in total and 3 authors in total.
Edit 1: as suggested in the answers this is best done by listing the authors in a front matter list instead of a CSV string. So,
Like this
Post:
---
title: post
authors:
- foo
- bar
---
instead of like this:
Post:
---
title: post
authors: [foo, bar]
---
Problem setup:
(edited, according to Edit 1)
Post 1:
---
title: post1
authors:
- foo
- bar
---
Post 2:
---
title: post2
authors:
- foo
- bar
---
Post 3:
---
title: post3
authors:
- john doe
- bar
---
Out:
bar (3)
john doe (1)
foo (2)
A click on the author should then result in all posts getting displayed.
Alternatively an array can be displayed like this, but it's not helping the case, just an equivalent style.
What I tried
I did the same with categories and tags and this algorithm worked like a charm. However, replacing site.categories with site.authors is somehow not supported.
returns:
Liquid Exception: 0 is not a symbol nor a string in authors.html
I suppose this is due to the nature of categories and tags being arrays by default.
I think it would help to be able to set the front matter tag authors as an array somehow. I suppose this is done in _config.yml, but I busted by head in with it.
As of now I got as far as coming up with a way to target individual authors in an array, but I'm far from being able to list them individually and counting them up. I suppose I'm limited due to the nature of authors not being an array by default, otherwise implementations like this one would work with custom front matter variables like authors, but they don't.
What I meant (when I said "As of now"):
{% for post in site.posts %}
<li>{{ post.authors }} ({{ post.authors[0] }})</li>
{% endfor %}
Out:
foobar (foo)
foobar (foo)
john doebar (john doe)
Afterall, I think I'm missing something here. I'm probably not the first one who tried this but the only documentation I found was from people who attempted what I'm trying but didn't really get there.
This user for example created a way to count users, but when used with site.authors
it returns the array size == 0-if clause:
No author
It seems like a simple thing, but for some reason isn't. At least for me.
Edit 2:
based on Kieths answer I came closer to getting there, but I have issues with creating an emphty array. According to this issue in Jekyll this seems to be a problem in general. However a workaround seems to be to assign a variable and split it with an emphty tag.
Currently I struggle with adding authors to the array so I can assess it's size.
{% assign authors = site.posts | map: 'authors' | uniq %}
{% assign authorCount = '' | split: '' %}
<div class="softwaretitle">
{% for author in authors %}
<a>{{ author }}</a>
{% for post in site.posts %}
{% for post_author in post.authors %}
{% if post_author == author %}
{% assign authorCount = authorCount | push author %}
<a>({{ page.authorCount | size }})</a>
{% endif %}
{% endfor %Edit 2:}
{% endfor %}
{% endfor %}
</div>
Out:
Error: Liquid error (.../_includes/authors.html line 14): wrong number of arguments (given 1, expected 2) included
Error: Run jekyll build --trace for more information.
Line 14:
{% assign authorCount = authorCount | push author %}
Edit 3:
At last, the final result (without link to the post list, but thats details)
<!-- Get a list of unique authors -->
{% assign authors = site.posts | map: 'authors' | uniq | sort%}
{% assign author_post_count = 0 %}
{% for author in authors %}
{% assign author_post_count = 0 %}
<div class="">
<li><a>{{ author }}
{% for post in site.posts %}
{% for post_author in post.authors %}
{% if post_author == author %}
{% assign author_post_count = author_post_count | | plus: 1 %}
{% endif %}
{% endfor %}
{% endfor %}
<span>&nbsp ({{ author_post_count }})</span></a></li>
</div>
{% endfor %}
Out:
bar (3)
john doe (1)
foo (2)
Updated answer:
To get a list of authors (without duplicates) and including the total number of posts the author has contributed to, together with a list of posts' titles and a link to the posts.
{% assign authors = site.posts | map: 'authors' | uniq %}
{% for author in authors %}
{% assign author_post_count = 0 %}
{% for post in site.posts %}
{% if post.authors %}
{% for post_author in post.authors %}
{% if post_author == author %}
{% assign author_post_count = author_post_count | plus: 1 %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
<h2>{{ author }} - {{ author_post_count }}</h2>
{% for post in site.posts %}
{% if post.authors %}
{% for post_author in post.authors %}
{% if post_author == author %}
{% assign author_url_query = author | replace: ' ', '-' %}
<a href="{{ post.url }}" title="A posts {{ author }}">
{{ post.title }}
</a>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}
If instead, you want to have a page per author that includes a list of posts written by them (automatically generated), you will need to extend Jekyll through a custom plugin. This is very possible if you have experience with the Ruby programming language. This is a very close example: https://github.com/avillafiorita/jekyll-datapage_gen and you can simply remove the _config data requirements and hardcode the directory names and permalinks :)
Problem :
on a post : print author(s) + number of posts written and link to the authors page
on an author's page : print author's datas + list written posts
Solution
We already have posts that are described like this :
---
title: post2
authors: [foo, bar]
# or with the alternate YAML array syntax
authors:
- foo
- bar
---
For authors, we can user a specific collection that will automatically generate author's page.
In _config.yml :
collections:
authors:
output: true
defaults:
- scope:
type: authors
values:
layout: authors
An author's page can be described like this :
_authors/foo.md
---
uid : foo
firstname: John
lastname: Foo
---
Some bio here ...
Posts List (index or any page):
{% assign posts = site.posts %}
{% comment %}
or {% assign posts = paginator.posts %} if you use pagination
{% endcomment %}
<ul>
{% for post in posts %}
<li>
{{ p.title }}
<br>{% include authors.html post=post %}
</li>
{% endfor %}
</ul>
We will also use our authors include in _layouts/post.html
...
<h1 class="post-title" itemprop="name headline">{{ page.title | escape }}</h1>
<p>{% include authors.html post=page %}</p>
...
Now the magic : _includes/authors.html
{% assign post = include.post %}
{% comment %}## if we have a least one author in post authors array {% endcomment %}
{% if post.authors and post.authors != empty %}
{% comment %} ## We will build a string for each author,
store it in authorsArray
then reassemble it at the end {% endcomment %}
{% assign authorsArray = "" | split: "" %}
{% for author in post.authors %}
{% comment %}## Count posts for current author {% endcomment %}
{% assign authorsPostsCount = site.posts | where_exp: "post", "post.authors contains author" | size %}
{% comment %}## Get authors data based on uid matching in the collection {% endcomment %}
{% assign authorsDatas = site.authors | where: "uid", author | first %}
{% if authorsDatas %}
{% capture authorString %}
{{ authorsDatas.firstname }} {{ authorsDatas.lastname }} ({{ authorsPostsCount }})
{% endcapture %}
{% else %}
{% comment %}## No entry for this author in the collection
## or author spelling is wrong {% endcomment %}
{% capture authorString %}
{{ author | capitalize }} ({{ authorsPostsCount }})
{% endcapture %}
{% endif %}
{% comment %}## Push result in authorsArray {% endcomment %}
{% assign authorsArray = authorsArray | push: authorString %}
{% endfor %}
{% comment %}## Create a sentence with array elements {% endcomment %}
by {{ authorsArray | array_to_sentence_string }}
{% endif %}
_layouts/author.html
---
layout: default
---
<h1>{{ page.firstname }} - {{ page. lastname }}</h1>
{% assign authorsPosts = site.posts | where_exp: "post", "post.authors contains page.uid" %}
<ul>
{% for p in authorsPosts %}
<li>{{ p.title }}</li>
{% endfor %}
</ul>

Jekyll - split an array into subarrays given n items

This question has been addressed within the context of javascript and ruby by this community, but how would you accomplish the same thing using Jekyll / Liquid templating? Hypothetically, something along the lines of:
{% assign subarrays = array | split_items_by: 3 %}
Verbose code :
{% assign subArraySize = 3 %}
{% assign myArray = "one,two,three,four,five,six,seven" | split: "," %}
myArray = {{ myArray | inspect }}
{% assign multiArray = "" | split: "/" %}
multiArray = {{ multiArray | inspect }}
{% for element in myArray %}
looping in myArray - forloop.index = {{ forloop.index }}
{% assign reminder = forloop.index | modulo: subArraySize %}
reminder : {{ reminder | inspect }}
{% if reminder == 1 %}
create a new empty sub array
{% assign subArray = "" | split: "/" %}
subArray = {{ subArray | inspect }}
{% endif %}
push current element in subArray
{% assign subArray = subArray | push: element %}
subArray = {{ subArray | inspect }}
{% if reminder == 0 or forloop.last %}
push subArray in multiArray if subarray length is
{% assign multiArray = multiArray | push: subArray %}
multiArray = {{ multiArray | inspect }}
{% endif %}
{% endfor %}
{% for subArray in multiArray %}
subArray :{{ subArray | inspect }}
{% endfor %}
If you already have ruby code available, you can write a tag plugin

How to create an array in a for loop in Liquid?

I'm trying to create an array from a list of objects using Liquid syntax:
{% for operation in menuItems %}
{% assign words1 = operation.Title | split: '_' %}
{% assign controllerName = words1 | first %}
{% assign controllersTmp = controllersTmp | append: '_' | append: controllerName %}
{% endfor %}
I want to split the controllersTmp to get my array, but at this point my controllersTmp is empty.
Any help ?
You can directly create a new empty array controllers and concat to it your controllerName converted into an array using the workaround split:''. The result is directly an array, without the extra string manipulations.
{% assign controllers = '' | split: '' %}
{% for operation in menuItems %}
{% assign controllerName = operation.Title | split: '_' | first | split: '' %}
{% assign controllers = controllers | concat: controllerName %}
{% endfor %}
What worked for me
{% assign otherarticles = "" | split: ',' %}
{% assign software_engineering = "" | split: ',' %}
{% for file in site.static_files %}
{% if file.extname == ".html" %}
{% if file.path contains "software_engineering" %}
{% assign software_engineering = software_engineering | push: file %}
{% else %}
{% assign otherarticles = otherarticles | push: file %}
{% endif %}
{% endif %}
{% endfor %}
you have to init your variable controllersTmp :
{% assign controllersTmp = '' %}

Comma Separate Jekyll Posts

I want to list all my posts within site.categories.projects as a comma separated sentence. There's documentation for displaying {{ site.tags }} as array_to_sentence_string but how can I use the filter with a for loop?
# empty array
{% assign postsTitlesArray = '' | split:':' %}
# pushing categorie posts title in our array
{% for post in site.categories.one %}
{% assign postsTitlesArray = postsTitlesArray | push: post.title %}
{% endfor %}
{{ postsTitlesArray | array_to_sentence_string }}

Resources