On a SaaS platform I try to create an indexpage/sitemap for a website with a lot of categories.
Since it's a SaaS platform I'm not able to use/create custom functions whatsoever.
It have to be done at the frontend.
What I try to do is divide a list of categories into a list divided in letters and digits.
So a category name starting with A will go in category "A", a category starting with a number (eg 18 years) will go in a category called "0-9". So I will get an indexpage like so:
[A]
- Alpha
- Anton
- etc..
[B]
- Beta
- Brave
- etc..
[C]
- Charlie
- Cooking
- etc..
[0-9]
- 1 year
- 20 years
- 99 years
- etc..
I managed to get this working for all letters. However it not always put numbers in the [0-9] category. My script sometimes create a seperate index for eg 0 or 7 etc. So like:
[0]
- 1 year
- 18 years
- etc..
[1]
- 2 years
- 22 years
Also the index number is wrong. So it shows 1 under 0 and 2 under 1. Instead of:
[0-9]
- 1 year
- 18 years
- 2 years
- 22 years
I just can't see why that is. So my question is how can I put [numeric] categories in a single categorie called [0-9] instead of having them in a seperate categorie?
My code upto now looks like (some filters are specific platform filters):
{# ---------------- BEGINING ------------------- #}
{% set all_categories = [] %}
{% for category in shop.categories %}
{% set all_categories = all_categories | merge({ (0): category }) %}
{% for sub in category.subs %}
{% set all_categories = all_categories | merge({ (0): sub }) %}
{% for sub_sub in sub.subs %}
{% set all_categories = all_categories | merge({ (0): sub_sub }) %}
{% for sub_sub_sub in sub_sub.subs %}
{% set all_categories = all_categories | merge({ (0): sub_sub_sub }) %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% set categories = all_categories %}
{# ---------------- SORT LOGIC ------------------- #}
{# 'categories' array will be sorted and saved as 'grouped_categories' variable #}
{% set sorted_categories = [] %}
{% for key in categories | keys %}
{% set sorted_categories = sorted_categories | merge({ (key): categories[key].title }) %}
{% endfor %}
{% set sorted_categories = sorted_categories | sort %}
{% set first_letter = '' %}
{% set grouped_categories = [] %}
{% set new_group = [] %}
{% for i in sorted_categories | keys %}
{% if(categories[i].title) %}
{% set currect_first_letter = categories[i].title | first | upper %}
{% if(currect_first_letter != first_letter) %}
{% if(new_group) %}
{% set grouped_categories = grouped_categories | merge({ (first_letter): new_group }) %}
{% endif %}
{% set first_letter = currect_first_letter %}
{% set new_group = [categories[i]] %}
{% else %}
{% set new_group = new_group | merge({ (0): categories[i] }) %}
{% endif %}
{% endif %}
{% endfor %}
{% set grouped_categories = grouped_categories | merge({ (first_letter): new_group }) %}
{# ---------------- USING ------------------- #}
<div class="single-letter">
<span class="custom-title">{{ "All themes" }}:</span>
<ul>
{% for letter in grouped_categories[1:] | keys %}
<li>{{ letter }}</li>
{% endfor %}
{% for letter in grouped_categories[:1] | keys %}
<li>{{ '0-9' }}</li>
{% endfor %}
</ul>
</div>
{% for letter in grouped_categories[1:] | keys %}
<div id="letter-{{letter}}" class="letter-wrap">
<h3 class="title">{{ letter }}</h3>
<div class="group">
<ul>
{% for category in grouped_categories[letter] %}
<li>{{ category.title }}</li>
{% endfor %}
</ul>
</div>
</div>
{% endfor %}
{% for letter in grouped_categories[:1] | keys %}
<div id="letter-{{letter}}" class="letter-wrap">
<h3 class="title">{{ '0-9' }}</h3>
<div class="group">
<ul>
{% for category in grouped_categories[letter] %}
<li>{{ category.title }}</li>
{% endfor %}
</ul>
</div>
</div>
{% endfor %}
{# ---------------- THE END ------------------- #}
UPDATE AS PER REQUEST
Updated code
{% for category in categories %}
{% set currect_first_letter = category | first | upper %}
{% if currect_first_letter in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] %}
{% set currect_first_letter = '0-9' %}
{% endif %}
{% if not (currect_first_letter in (grouped_categories | keys)) %}
{% set grouped_categories = grouped_categories | merge({ (currect_first_letter): [], }) %}
{% endif %}
{% set grouped_categories = grouped_categories | merge({ (currect_first_letter) : grouped_categories[currect_first_letter] | merge([ category, ]), }) %}
{% endfor %}
{#{% set sorted_categories = [] %}
{% for key in categories | keys %}
{% set sorted_categories = sorted_categories | merge({ (key): categories[key].title }) %}
{% endfor %}
{% set sorted_categories = sorted_categories | sort %}
{% set first_letter = '' %}
{% set grouped_categories = [] %}
{% set new_group = [] %}
{% for i in sorted_categories | keys %}
{% if(categories[i].title) %}
{% set currect_first_letter = categories[i].title | first | upper %}
{% if(currect_first_letter != first_letter) %}
{% if(new_group) %}
{% set grouped_categories = grouped_categories | merge({ (first_letter): new_group }) %}
{% endif %}
{% set first_letter = currect_first_letter %}
{% set new_group = [categories[i]] %}
{% else %}
{% set new_group = new_group | merge({ (0): categories[i] }) %}
{% endif %}
{% endif %}
{% endfor %}
{% set grouped_categories = grouped_categories | merge({ (first_letter): new_group }) %}#}
This has as result:
The merge filter only works with arrays or hashes; NULL and array given in....
You should be able to solve this if you override the currect_first_letter.
{% set currect_first_letter = categories[i].title | first | upper %}
{% if currect_first_letter in [0, 1, 2, 3, 4, 5, 6, 7, 8 , 9, ] %}
{% set currect_first_letter = '0-9' %} {# change to same group #}
{% endif %}
demo
Okay I've gone over your code and simplified the grouping process a bit.
Here is the code I would use to combine arrays in twig
{% set grouped_categories = [] %}
{% for category in categories %}
{% set currect_first_letter = category | first | upper %}
{# ----- ADDED THIS LINE ------- #}
{% if currect_first_letter in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] %}
{% set currect_first_letter = '0-9' %}
{% endif %}
{# ----------------------------- #}
{% if not (currect_first_letter in (grouped_categories | keys)) %}
{% set grouped_categories = grouped_categories | merge({ (currect_first_letter): [], }) %}
{% endif %}
{% set grouped_categories = grouped_categories | merge({ (currect_first_letter) : grouped_categories[currect_first_letter] | merge([ category, ]), }) %}
{% endfor %}
Validation purpose:
{% for key in grouped_categories|keys %}
Key: {{ key }}
Values:
{% for value in grouped_categories[key] %}
- {{ value }}
{% endfor %}
{% endfor %}
demo
It seems if you use var in [0, 1, ...], before twig 3.X the 0 will return a false positive.
Try to use your original code, the one where everything got grouped in [0-9], but with the following statement
{% if currect_first_letter in [1, 2, 3, 4, 5, 6, 7, 8, 9] or currect_first_letter == '0' %}
Related
I'm trying to use the "AND" operator in TWIG in Opencart 3 and it doesn't work. Please tell me what I'm doing wrong.
I have some product attributes. And I want to make a condition that if two of the attribute with a specific ID are there, then the condition is met.
{% for attribute_group in attribute_groups %}
{% for attribute in attribute_group.attribute %}
{% if attribute.attribute_id == 2 and attribute.attribute_id == 3 %}
First condition
{% elseif attribute.attribute_id == 2 %}
Second condition
{% elseif attribute.attribute_id == 3 %}
Third condition
{% else %}
{% endif %}
{% endfor %}
{% endfor %
Here is text example:
if there is an attribute with ID equal 2 and an attribute with ID equal 3 then write "Floor/Number of floors".
if there is an attribute with ID equal 2 only then write "Floor"
if there is an attribute with ID equal 3 only then write "Numbers of floors".
Something can't be both X and Y at the same time. Furthermore this is something I'd advice you to test in the controller and not in the view.
Anyway if you wanted to do this in the view you will need to track of the found attributes. You could do this with two booleans or just add a counter.
{% set cnt = 0 %}
{% for attribute_group in attribute_groups %}
{% for attribute in attribute_group.attribute %}
{% if attribute.attribute_id == 2 or attribute.attribute_id == 3 %}
{% set cnt = cnt + 1 %}
{% endif %}
{% endfor %}
{% endfor %}
{% if cnt == 2 %}
{# do something #}
{% endif %}
You can simplify the if by using the test in
{% if attribute.attribute_id in [2, 3,] %}
Update of my answer because OP changed the requirements of the question
{% set words = [] %}
{% for attribute_group in attribute_groups %}
{% for attribute in attribute_group.attribute %}
{% if attribute.attribute_id == 2 %}
{% set words = words|merge(['Floor',]) %}
{% elseif attribute.attribute_id == 3 %}
{% set words = words|merge(['Numbers of floors',]) %}
{% endif %}
{% endfor %}
{% endfor %}
{% if words|default %}
{{ words|join('/') }}
{% endif %}
demo
I'm editing the following
{% for option in product.options %}
{% if option == 'Colour' %}
{% assign index = forloop.index0 %}
{% assign colorlist = '' %}
{% assign color = '' %}
{% for variant in product.variants %}
{% capture color %}{{ variant.options[index] }}{% endcapture %}
{% unless colorlist contains color %}
<button class="product-colour__item">
<label class="product-colour__item-label" style="background-image:url("{{ color | downcase | handleize | append: '.png' | file_url }}");">
</label>
</button>
{% capture tempList %}{{colorlist | append: color | append:''}}{% endcapture %}
{% assign colorlist = tempList %}
{% endunless %}
{% endfor %}
{% endif %}
{% endfor %}
and it's meant to show like:
style="background-image:url("//cdn.shopify.com/s/files/1/0584/2419/7328/products/deep-rose.png");
instead its showing like:
style="background-image:url(" cdn.shopify.com s files 1 0584 2419 7328 deep-rose.png");
I know it's missing the /products/ as well as the rest of it.
What am I doing wrong?
I'm trying to create 3 arrays of propducts which are created based on a timestamp.
I'm working on a SaaS platform so I have to create those arrays in the frontend while creating a function in the backend would be better but that's not possible.
The idea is to create 3 arrays for a lottery. So 1 is for current lotteries, 1 for upcoming ones and 1 for recent lotteries.
The problem I have is that it won't sort correctly. So for example the oputput shows 24th of april before 24th of March.
So what I have is this:
{% set curr_date = "now"| date('U') %}
{% set current_draws = [] %}
{% set upcoming_draws = [] %}
{% set recent_draws = [] %}
{% for product in products %}
{% if product.data_01 %}
{% set data_01_date = product.data_01 | date('U') %} //make timestamp for this product
{% if data_01_date > curr_date %} //check if is upcoming or current
{% if loop.first %} //if 1st in loop then it's current draw
{% set current_draws = current_draws | merge([product]) %}
{% else %}
{% set upcoming_draws = upcoming_draws | merge([product]) | sort((a, b) => a.data_01_date <=> b.data_01_date ) | reverse %}
//reverse because lowest timestamp need to be showed first
{% endif %}
{% else %}
{% set recent_draws = recent_draws | merge([ product ]) | sort((a, b) => a.data_01_date <=> b.data_01_date ) %}
{% endif %}
{% endif %}
{% endfor %}
As output for the upcoming draws array I get the following:
{% for product in upcoming_draws %}
{{ product.data_01 | date("U") }}
{% endfor %}
1648162800 // 25th March
1650751200 // 24th April
1648249200 // 26th March
1648335600 // 27th March
Why in above example is 24th of April showed before 26th of March?
Any idea how to fix that?
Any help greatly appreciated :)
Three things:
You have a typo, the property is called data_01, as seen here {% set data_01_date = product.data_01|date('U') %}
Don't sort the array during the creation of the array, that's a waste of performance
The property data_01 is a string, you shouldn't compare strings in your sort
{% set curr_date = "now"| date('U') %}
{% set current_draws = [] %}
{% set upcoming_draws = [] %}
{% set recent_draws = [] %}
{% for product in products %}
{% if product.data_01 %}
{% set data_01_date = product.data_01 | date('U') %} //make timestamp for this product
{% if data_01_date > curr_date %} //check if is upcoming or current
{% if loop.first %} //if 1st in loop then it's current draw
{% set current_draws = current_draws | merge([product]) %}
{% else %}
{% set upcoming_draws = upcoming_draws | merge([product]) %}
//reverse because lowest timestamp need to be showed first
{% endif %}
{% else %}
{% set recent_draws = recent_draws | merge([ product ]) %}
{% endif %}
{% endif %}
{% endfor %}
{% for product in upcoming_draws|sort((a, b) => a.data_01|date('U') <=> b.data_01|date('U') | reverse ) %}
{{ product.data_01 | date("d-m-Y") }}
{% endfor %}
demo
How can I use loop.index in this code.
{% for veri in data %}
<li>no: {{loop.index}}</li>
{% for inveri in datain %}
<li>no: {{loop.index}}</li>
{% endfor %}
{% endfor %}
.....
As pointed out by Goto u need to use loop.parent.loop as seen here
{% set data = [1,2,3,4,5,] %}
{% for d in data %}
{{ loop.index0 * (data|length + 1) + 1 }}
{% for d in data %}
{{ loop.parent.loop.index0 * (data|length + 1) + 1 + loop.index }}
{% endfor %}
{% endfor %}
twigfiddle
{% set data = [1,2,3,4,5,] %}
{% set data2 = [1,2,3,4,5,6,7,8,9] %}
{% for d in data %}
{{ loop.index0 * (data2|length + 1) + 1 }}
{% for d in data2 %}
{{ loop.parent.loop.index0 * (data2|length + 1) + 1 + loop.index }}
{% endfor %}
{% endfor %}
twigfiddle with 2 data-sets
Do you want something like this?
{% set data = [1, 2, 3, 4, 5] %}
{% set data2 = [1, 2, 3] %}
{% set i = 1 %}
{% for d in data %}
{{ i }}
{% set i = i + 1 %}
{% for d2 in data2 %}
{{ i }}
{% set i = i + 1 %}
{% endfor %}
{% endfor %}
See TwigFiddle
Jekyll pagination enables you to arrange posts neatly on pages. I would like to put the range of dates as a tooltip on the links to the pages, just as:
<li class="pager-item">
Page 2
</li>
The obvious way to do so would be to take the date of the first and the last post on a page. Unfortunatly jekyll-pagination only seems to deliver a list of posts for the current page via paginator.posts.
Maybe I just can't find it in the documentation, so I ask you: is it possible to access a list of posts from another page in jekyll pagination? Something like paginator.pages.2.posts?
An alternate approach would be to build my own paginaton, which should be no problem, but I would prefer to use built-in functions.
You can get the information indirectly:
paginator.previous_page and paginator.next_page give you the page number of respectively the previous and the next pagination page, or nil if the page does not exists.
paginator.per_page gives you the number of posts per page.
paginator.total_posts gives you the total number of posts in the site.
site.posts gives you a reverse chronological list of all posts.
So given the current paginator object, ensuring paginator.next_page != nil, you know the posts from the next pagination page are indexed in site.posts from a to b (included) with:
a = (paginator.next_page) * paginator.per_page
b = a + paginator.per_page - 1
Last pagination page may not be complete: remember checking b < paginator.total_posts.
Ensuring paginator.previous_page != nil, same goes for previous pagination page with:
a = (paginator.previous_page) * paginator.per_page
b = a + paginator.per_page - 1
My current approach looks like this:
{% if include.page > 0 and include.page <= paginator.total_pages %}
{% assign first = include.page | minus:1 | times:paginator.per_page %}
{% assign last = paginator.per_page | times:include.page | minus:1 %}
{% if last > paginator.total_posts %}
{% assign last = paginator.total_posts | minus:1 %}
{% endif %}
{{ site.posts[first].date | date: "%d.%m.%Y" }} bis {{ site.posts[last].date | date: "%d.%m.%Y" }}
{% else %}
OUT_OF_RANGE
{% endif %}
I really don't like the Liquid-Syntax :D
Or :
{% comment %} NOTE : shortcut "p" for "paginator" {% endcomment %}
{% assign p = paginator %}
{% comment %} date formating (see shorthand formats in Ruby's documentation : http://ruby-doc.org/core-2.3.3/Time.html#method-i-strftime) {% endcomment %}
{% assign dateFormat = "%y %b %d" %}
<ul>
{% for post in p.posts %}<li>{{ post.title }} - {{ post.date | date: dateFormat }}</li>
{% endfor %}
</ul>
{% comment %}++++++++++ if previous page == newest posts {% endcomment %}
{% if paginator.previous_page %}
{% assign prevPage = p.page | minus: 1 %}
{% assign prevPageLastIndex = prevPage | times: p.per_page | minus: 1 %}
{% assign prevPageFirstIndex = prevPageLastIndex | minus: p.per_page | plus: 1 %}
{% assign prevPagefirstPostDate = site.posts[prevPageFirstIndex].date | date: dateFormat %}
{% assign prevPagenextPageLastPostDate = site.posts[prevPageLastIndex].date | date: dateFormat %}
{% capture prevPageLink %}
<p><a href="{{ paginator.previous_page_path }}"></p>
Newest posts from
{% if prevPagefirstPostDate != prevPagenextPageLastPostDate %}
{{ prevPagenextPageLastPostDate }} to {{ prevPagefirstPostDate }}
{% else %}
{{ prevPagenextPageLastPostDate }}
{% endif %}
</a>
{% endcapture %}
{% endif %}
{% comment %} ++++++++++ if next page = oldest posts {% endcomment %}
{% if paginator.next_page %}
{% assign nextPage = p.page | plus: 1 %}
{% assign nextPageFirstIndex = p.page | times: p.per_page %}
{% comment %}>>Next page is not the last page = normal computing {% endcomment %}
{% if nextPage != p.total_pages %}
{% assign nextPageLastIndex = nextPageFirstIndex | plus: p.per_page | minus: 1 %}
{% comment %}>>Next page is the last page compute index from p.total_posts{% endcomment %}
{% else %}
{% assign nextPageLastIndex = p.total_posts | minus: 1 %}
{% endif %}
{% assign nextPagefirstPostDate = site.posts[nextPageFirstIndex].date | date: dateFormat %}
{% assign nextPageLastPostDate = site.posts[nextPageLastIndex].date | date: dateFormat %}
{% capture nextPageLink %}
<p><a href="{{ paginator.next_page_path }}"></p>
Previous posts from
{% if nextPagefirstPostDate != nextPageLastPostDate %}
{{ nextPageLastPostDate }} to {{ nextPagefirstPostDate }}
{% else %}
{{ nextPageLastPostDate }}
{% endif %}
</a>
{% endcapture %}
{% endif %}
{{ prevPageLink }}
{{ nextPageLink }}