Business Catalyst Liquid sorting - sorting

I can see that Liquid allows you to sort a collection using the below syntax:
{% assign sorted_items = items.all|sort:'Email' %}
{% for item in sorted_items %}
<div>Name: {{item.name}}</div>
<div>Email: {{item.email}}</div>
{% endfor %}
However this does not appear to work in Business Catalyst.
If I use this to render the result to the page it simply renders "null".
{{sorted_items | json }}
Should I be able to do this in Business Catalyst, or am I completely wasting my time trying to find a solution to sort my WebApp data?

You can sort the data like this:
{module_data resource="customers" version="v3" fields="firstName,email1" collection="myData"}
<pre>{{myData|json}}</pre>
{% capture emails -%}
{% for item in myData.items -%}
,{{ item.email1.value }} - {{ item.firstName }};
{% endfor %}
{% endcapture %}
<pre>{{ emails | split: "," | sort }}</pre>
The comma is not spelling mistake : )
After you split the string in array you can do whatever you need to do with it.

The answer from Daut is not good. Any solution in the for loop will only sort the number of items fetched from the module and the max amount for that is 500.
If you are using module_data you just use its actual sort!
{module_data resource="customers" version="v3" order="firstName" fields="firstName,email1" collection="myData"}
module_data supports both WHERE for filtering and ORDER to order the results.

Related

Shopify Theme Development | Creating a 're-order' link for previous orders | Unable to chain multiple ID:quantity query strings

I am using Shopify and creating a re-order button within the file named order.liquid.
while trying to create the re-order button I have had a moderate level of success.
The script I attach does indeed add the items to the cart that were previously ordered. However, I have tried without adding the quantity (just adds 1 of each). Without the [] after the &quantityHERE= (just adds two of each even if it was previously only one item bought).
Heres the code that creates my half-working URL:
{% assign line_items_string = '/cart/' %}
{% for line_item in order.line_items %}
{% if forloop.first == true %}
{% assign line_items_string = line_items_string | append: 'add?id[]=' %}
{% assign line_items_string = line_items_string | append: line_item.variant_id %}
{% assign line_items_string = line_items_string | append: '&quantity[]=' %}
{% assign line_items_string = line_items_string | append: line_item.quantity %}
{% else %}
{% assign line_items_string = line_items_string | append: '&id[]=' %}
{% assign line_items_string = line_items_string | append: line_item.variant_id %}
{% assign line_items_string = line_items_string | append: '&quantity[]=' %}
{% assign line_items_string = line_items_string | append: line_item.quantity %}
{% endif %}
{% endfor %}
Re-order
I am unable to get it to add the correct amount of items per line item even though the URL appears correct:
/cart/add?id[]=16220586868785&quantity[]=3&id[]=16220587360305&quantity[]=6&id[]=16220587622449&quantity[]=4&id[]=16221376479281&quantity[]=11&id[]=16221376348209&quantity[]=2&id[]=16221063938097&quantity[]=1&id[]=16221393682481&quantity[]=2
The fact the string ends with quantity 2 and will then add 2 of each item suggests it only uses the last declaration of quantity when dealing with the link. Therefore there must be a separator that can be used to distinguish between line items.
What is the separator that would go between each line items addition to the query string please? What goes after?
add?id[]=16220586868785&quantity[]=3**HERE**
I have tried using a , but admittedly this looks out of place followed by an &.
Edit
To help describe further what I have tried.
I am able to use the format ID:quantity if I:
want to go straight to checkout, the format is ID:quantity,ID:quantity.. so on.
only wish to add one item of a certain quantity to cart using add?ID:Quantity.
I need to know how to chain multiple to only add to cart. I don't know the separator (that is a comma when pushing straight to checkout).
Using permalinks to re-order things is always the ID:quantity. Have you tried that?
I would consider implementing this using jquery or javascript. You can create an ajax post using the cart/add.js call described here: https://help.shopify.com/en/themes/development/getting-started/using-ajax-api#add-to-cart

Expanding variables into Jekyll Front-End

It is possible to expand a variable into a post Front-Matter?
I use a series of items for links into my template, like:
related_links:
- text: foo
link: bar
But sometimes I need to refer to other posts into my site. Normally I would use just /bar into link, but this is also used as shownotes into a podcast, I want to expand the link for http://example.com/bar. But using {% post_url YYYY-MM-DD-bar %} results into:
Error: could not read file [REDACTED]: (<unknown>): found character that cannot start any token while scanning for the next token at line 33 column 12
Any tips?
If you use
related_links:
- text: foo
link: {% post_url YYYY-MM-DD-bar %}
you will get an error because the { will start a flow style mapping and % cannot start a token in YAML. You have to put the whole scalar in (double) quotes:
related_links:
- text: foo
link: "{% post_url YYYY-MM-DD-bar %}"
What you want to do does not work because of Jekyll's pipeline:
parse YAML front matter
process rest of document with Liquid
parse result of previous step with Markdown
{% post_url YYYY-MM-DD-bar %} is a Liquid command. As you see, Liquid processes just the part of your file below the YAML front matter. Therefore, no Liquid replacement takes place there.
You can instead write something like this below the front matter:
{% assign link = post_url YYYY-MM-DD-bar %}
And then use {{link}} elsewhere. If you have multiple links, things get hacky. Something like this might work, but I am not enough of a Liquid user to know for sure:
{% capture nl %}
{% endcapture %}
{% capture rawlinks %}
{% post_url YYYY-MM-DD-bar %}
{% post_url YYYY-MM-DD-bar %}
{% endcapture %}
{% assign links = rawlinks | split nl %}
You can then specify indexes in your YAML front matter:
related_links:
- text: foo
linkindex: 0
And finally, somewhere in your document:
{{ links[related_link.linkindex] }}
YMMV if this level of uglyness is justified for your use-case.
I found a more elegant at my own:
{% assign real_link=link.link %}
{% assign link_start = real_link | slice: 0 %}
{% if link_start == "/" %}{% assign real_link = real_link | prepend: site.url %}{% endif %}
As I start al my locak links with a / to warrant that the link will be related with the root in the site, that was a better way for me.

Jekyll: How to use for loop to generate table row within the same table inside markdown

I am trying to generate a table, based on the posts that I have. Now, the challenge here is that this is inside a markdown file, so for each row that I generate, liquid seems to generate a new table for each generated row. Is there a way to fit all rows inside one single table?
Here is my code:
|Title |Link |
|---|---|
{% for my_post in site.posts %}
{% if my_post.title %}
|{{ my_post.title }} |[Click Here]({{ my_post.url }}) |
{% endif %}
{% endfor %}
The generated output looks like this
As you can see, the outcome is actually a messed-up table header row + two separate tables. Can I really generate rows and fit them all inside one table? or am I better off switching to html code?
The liquid markup introduces line breaks in markdown.
Edit : you can now manage use whitespace control in Liquid
In Liquid, you can include a hyphen in your tag syntax {{-, -}}, {%-, and -%} to strip whitespace from the left or right side of a rendered tag.
|Title |Link |
|---|---|
{% for my_post in site.posts -%}
{% if my_post.title -%}
|{{ my_post.title }} |[Click Here]({{ my_post.url }}) |
{% endif %}
{%- endfor -%}
old answer
If you put your liquid tags on same line you'll have a valid table outputed.
| Title | Link |
|---|---|{% for my_post in site.posts %}{% if my_post.title %}
|{{ my_post.title }} |[Click Here]({{ my_post.url }}) |{% endif %}{% endfor %}

Capturing Item Index in Collection

I was wondering what is the proper way of finding the index of an item in an array is in a Liquid template, and selected related items based off of the index. Currently I'm able to calculate the value, but it seems to be a string and I can't then find other items in the array with the string. For example in a CMS:
{% for site_page in site.pages.all %}
{% if site_page.id == page.id %}
{% assign page_index = forloop.index0 %}
{% capture previous_page_index %}
{{ page_index | minus: 1 }}
{% endcapture %}
{% break %}
{% endif %}
{% endfor %}
The expected value can be found in previous_page_index (in this case 0) however, if i try to do something like site.pages.all[previous_page_index] I receive no output. If I do the same thing with a hardcoded index value: site.pages.all[0] it does yield an output. Does anyone have an idea/example on how this is supposed to be done in liquid?
Best I can figure is to use {% for item in array limit:1 offset:forloop.index0 %}. For example:
require 'liquid'
chars = %w[a b c]
names = %w[alpha bravo charlie]
puts Liquid::Template.parse(<<DONE).render( 'chars'=>chars, 'names'=>names )
{% for c in chars %}
{{c}} is
{% for n in names limit:1 offset:forloop.index0 %}{{n}}{% endfor %}
{% endfor %}
DONE
…which produces…
a is
alpha
b is
bravo
c is
charlie
Editorial aside: ouch. What an ugly tempting language. I understand its goals, but the burden it places on users is heinous.

How can I use Jinja2 to generate an index-like list?

In an index, references are listed alphabetically and grouped by letter. Also, instead of a simple alphabetical sort, leading articles and punctuation are removed before sorting. The result would look like this:
A
Abba
The Archer
Away From Here
B
"Bangkok" Mike
Bullets
I'm using the Pelican static site generator, which uses Jinja2 in its templates, and I'd like to create an index like this of TV shows that I've blogged about on my site.
TV show names are listed in a metadata field {{ article.showname }} (only one show per post, so only one show in the metadata field) and so are easily retrieved. But stripping the leading article/punctuation, grouping by first letter and inserting the correct letter of the alphabet is more than I know how to do.
Possible steps I could take
I could strip the leading article/punctuation and create another metadata field with the show name that's ready to be sorted, called, say, {{ article.shownamesort }}. For that matter, if there's not an easy way to group the names by their first letter, I could create a metadata field with the show's first (sortable) letter, {{ article.shownameletter }}.
For each letter, I could create a loop that begins by grabbing that letter's posts:
{% if article.shownameletter == "A" %}
Once that's done, I don't know how to sort the text from one metadata field based on the text of a different metadata field. That is, I don't know how to print the {{ article.showname }} list that's sorted by the {{ article.shownamesort }} list. Can this be done in Jinja2? For the record, if there's a solution that takes a completely different approach, I'd be very happy with it, including if it required different/more metadata fields.
I did something like that on the tags and categories pages. It iterates over all the characters and then prints the results
Iterate over the letters:
{% for char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"|list %}
...
{% endfor %}
Comparison for show or not show the tag:
{% if char == tag|upper|truncate(1, True, end='') %}
...
{% endif %}
Full example:
{% for char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"|list %}
<h2>{{char}}</h2>
{% for tag, articles in tags|sort %}
{% if char == tag|upper|truncate(1, True, end='') %}
<dt>{{ tag }}</dt>
{% for article in articles|sort %}
<dd>{{ article.title }}</dd>
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}

Resources