How do i array a collection in 3 cols in liquid by a status - arrays

I wanna array my collection in 3 cols, for 3 different statuses. And if there isn't any gig/item with that status, it has to say ' No projects'
I have tried this:
<div class="col-sm">
<h2>Up next</h2>
{% assign next = site.gigs | gig.status == 'Next' | sort: gig.date %}
{% if next.gigs.size == 0 %}
No projects
{% else %}
{% for gig in next %}
{{ gig.title }}
{% endfor %}
{% endif %}
</div>
<div class="col-sm">
<h2>Working on</h2>
{% assign on = site.gigs | gig.status == 'On' | sort: gig.date %}
{% if on.gigs.size == 0 %}
No projects
{% else %}
{% for gig in on %}
{{ gig.title }}
{% endfor %}
{% endif %}
</div>
<div class="col-sm">
<h2>Done</h2>
{% assign done = site.gigs | gig.status == 'Done' | sort: gig.date %}
{% if done.gigs.size == 0 %}
No projects
{% else %}
{% for gig in done %}
{{ gig.title }}
{% endfor %}
{% endif %}
</div>
But it just arrays all of the gigs/items :(
Maybe it can be done in a way more simple way.
I don't know if you could make one compact liquid code and array 3 columns by counting the number of different statuses.
Help!

Ordering
Our statuses are "Next", "On" and "Done". They must be ordered in such order.
As this is not an alphabetical sort order, we need to define this order by ourself.
In _config.yml :
status-order:
-
name: "Next" ### status as it is set on gigs (!!! Case-Sensitive !!!)
display: "Up Next" ### status column header to display
-
name: "On"
display: "Working On"
-
name: "Done"
display: "Done"
We can now loop over site.status-order and get our gigs in desired status order.
{% for status in site.status-order %}
{{ status.name }} - {{ status.display }}
{% endfor %}
Presenting
As your current code is a little repetitive, we can factor it like this :
{% for status in site.status-order %}
{% assign items = site.gigs | where: 'status', status.name | sort: date %}
<div class="col-sm">
<h2>{{ status.display }} ({{ items.size }})</h2>
{% if items.size > 0 %}
<ul>
{% for item in items %}
<li>{{ item.title }}</li>
{% endfor %}
</ul>
{% else %}
No project
{% endif %}
</div>
{% endfor %}
Note
You must be sure to set status with the right case (eg : "Next" an not "next").
And the right type. If you set status: On it is understood as the true boolean value, not the string "on". In this case the correct status expression is status: "On". It must be quoted or double quoted to be understood as "On" string.
Any item with incorrectly cased or typed status expression will not appear in our listing.

Related

Wagtail Uploaded Document direct URL

I am trying to generate a url to an uploaded document (PDF, DOC...etc) on my search results page. Search is returning the items but there seems to be no url field. There is a file field which seems to have the file name, but I am unable to get a link back to this file. I am using the stock document model. Is there some sort of special tag that needs to be used like with the images?? At my wits end.
Search view
if search_query:
results = []
page_results = Page.objects.live().search(search_query)
if page_results:
results.append({'page': page_results})
doc_results = Document.objects.all().search(search_query)
if doc_results:
results.append({'docs': doc_results})
img_results = Image.objects.all().search(search_query)
if img_results:
results.append({'image': img_results})
search_results = list(chain(page_results, doc_results, img_results))
query = Query.get(search_query)
# Record hit
query.add_hit()
and the template page.
{% for result in search_results %}
{% for k, v in result.items %}
{% if k == 'page' %}
{% for item in v %}
<p>
<h4>{{ item }}</h4>
Type: Article<br>
Author: {{ item.specific.owner.get_full_name }}<br>
Publish Date: {{ item.specific.last_published_at}}
</p>
{% endfor %}
{% elif k == 'docs' %}
{% for item in v %}
<p>
<h4>{{ item.title }}</h4>
Type: Document<br>
Publish Date: {{ item.created_at }}
</p>
{% endfor %}
{% elif k == 'image' %}
{% for item in v %}
<p>
{% image item original as item_img %}
<h4>{{ item.title }}</h4>
Type: Image<br>
Publish Date: {{ item.created_at }}
</p>
{% endfor %}
{% endif%}
{% endfor %}
{% endfor %}

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>

Shopify liquid product.thumbnail.liquid repeats block even there is no loops

[![enter image description here][1]][1]My job Is too simple i.e just to add Amazon url in a div block in product thumbnail.liquid.I Have added just simple div, then I found that same div is repeated twice. I have also checked that there is no forloop found still how does it is repeating .Today I found the file called product-loop.liquid which has for loop and product thumbnail.liquid is included. What I need to do if I need to show amazon link block only once? Entire file is in gist link.Thanks.
product-loop.liquid
{% assign product_found = false %}
{% assign skip = false %}
{% assign collection_group = products | map: 'id' %}
{% assign collection_group_thumb = collection_group | append : 'thumb' %}
{% assign collection_group_mobile = collection_group | append : 'mobile' %}
{% capture new_row %}
<br class="clear product_clear" />
{% endcapture %}
<div itemtype="http://schema.org/ItemList" class="products">
{% for product in products limit: limit %}
{% if product.id == skip_product.id or skip == true %}
{% assign product_found = true %}
{% else %}
{% if forloop.rindex0 == 0 and product_found == false and forloop.length != products.count and template != 'search' %}
{% assign skip = true %}
{% else %}
{% include 'product-thumbnail', sidebar: sidebar %}
{% if products_per_row == 2 %}
{% cycle collection_group: '', new_row %}
{% elsif products_per_row == 3 %}
{% cycle collection_group: '', '', new_row %}
{% elsif products_per_row == 4 %}
{% cycle collection_group: '', '', '', new_row %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
</div>
may be you including product.thumbnail in a section and that section have loop or conditional logics.

Twig check if value is in array

I'm having trouble to check if a value is present in an array with Twig.
I want to hide a shipping method in a checkout if there's a certain product in the cart.
I can only use Twig code so I have to find a logic in that.
So let's say when product ID 1234 is in cart then I want to hide #certain_div
So what I have is this ->
{% if checkout %}
{% set array = theme.sku_shipping_rule | split(',') %}
// theme.sku_shipping_rule = a text string like 1234, 4321, 5478
{% if checkout.products %}
{% for product in checkout.products %}
{% if product.sku in array %}
<style>
#certain_div {
display: none;
}
</style>
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
The problem I'm facing is that it seems my code always returns true. So even if the product.sku doens't match a value in the array it still hides #certain_div. I've tested that with placing {{ product.sku }} just before <style>.
What do I wrong?
Any help greatly appreciated!
UPDATE:
I've updated the question/code to show what's happening
{% if checkout %}
{% set skuToCheck = theme.sku_shipping_rule | split(',') %}
{% set skuInCart = [] %}
{% if checkout.quote.products %}
{% for product in checkout.quote.products %}
{% set skuInCart = skuInCart | merge([product.sku]) %}
{% endfor %}
{% endif %}
{% for myVar in skuInCart %}
{{ myVar }}<br/>
{% endfor %}
// this prints
PSYGA1 // where this sku should NOT match
FP32MA4
{% for myVar in skuToCheck %}
{{ myVar }}<br/>
// this prints
FP32LY4
FP32STR4
FP32MA4
{% if myVar in skuInCart %} // also tried with | keys filter
{{ myVar }} is found
{% endif %}
{% endfor %}
{% endif %}
So what I did is placing the sku's from the products which are in the cart in an array skuInCart. Next I want to check if myVar is present in the skuInCart array. If so print myVar is found.
What happens is that you should expect that it prints only the matching results. However it actually prints all values present skuInCart (using keys filter) or completely blank without using keys filter.
What you are doing in theory should work, have a look a this fiddle example to show you a working demonstration:
https://twigfiddle.com/yvpbac
Basically:
<div id="certain_div">
This should not show up
</div>
{% set searchForSku = "890" %}
{% set productSkuArrayString = "1234,4567,890" %}
{% set productSkuArray = productSkuArrayString|split(',') %}
{% if searchForSku in productSkuArray %}
<style>
#certain_div {
display: none;
}
</style>
{% endif %}
<!-- New Trial -->
<div id="certain_div">
This should show up
</div>
{% set searchForSku = "891" %}
{% set productSkuArrayString = "1234,4567,890" %}
{% set productSkuArray = productSkuArrayString|split(',') %}
{% if searchForSku in productSkuArray %}
<style>
#certain_div {
display: none;
}
</style>
{% endif %}
Will result in:
<div id="certain_div">
This should not show up
</div>
<style>
#certain_div {
display: none;
}
</style>
<!-- New Trial -->
<div id="certain_div">
This should show up
</div>
You can use iterable to check if a variable is an array or a traversable object:
{% if items is iterable %}
{# stuff #}
{% endif %}

Twig : translation for element of array displayed via split

Let's say I have this kind of arrays :
<?php
$monsterOne['statistics'] = array('attack' => 15, 'defense' => 20, 'speed' => 5);
$monsterTwo['statistics'] = array('attack' => 10, 'defense' => 0, 'speed' => 7);
And I want to display, via twig :
monsterOne : 15 en Attaque, 20 en Défense, 5 en Vitesse
monsterTwo : 10 en Attaque, 7 en Vitesse
How can I achieve this ?
I tried this, and it worked, but the commas between each statistic are not present.
{% if statistics.attack is defined %} {{statistics.attack}} {{"en Attaque" | trans}} {% endif %}
{% if statistics.defense is defined %} {{statistics.defense}} {{"en Défense" | trans}} {% endif %}
{% if statistics.escape is defined %} {{statistics.escape}} {{"en Vitesse" | trans}} {% endif %}
I think that I should use something like this, but I don't know how to put the translation inside :
{{ statistics|join(', ') }}
I found the answer. The trick was to parse the array via a loop and use loop.last :
{% for statistic, value in statistics %}
{% if statistic == 'attack' %} {{ value }} {{ 'en Attaque' | trans }}{% endif %}
{% if statistic == 'defense' %} {{ value }} {{ 'en Defense' | trans }}{% endif %}
{% if statistic == 'speed' %} {{ value }} {{ 'en Vitesse' | trans }}{% endif %}
{% if loop.last == false %}, {% endif %}
{% endfor %}">

Resources