jinja2 nested for loops two lists - for-loop

I have the following code that is not rendering the way I would like on the html front end.
{% for image in images %}
{% for title in titles %}
<div class="card" style="width: 18rem;">
<img src="{{image}}" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">{{title}}</h5>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
Go somewhere
</div>
{% endfor %}
{% endfor %}
Essentially, images and titles are both lists of URLS. The images works correctly when on it's own to redner the HTML with all the images.
However, when I try to add titles, which is basically the image URL sliced to give only part of the URL text, in the above format, it messes up the formatting, displaying only one image.
I have tried various different ways but it doesn't work.
I want the code to display all the images in the cards, and in the TITLE field, display the corresponding title, and title in this case is the sliced string (or so I think)
The python (Flask) route, function that scrapes the images URLS and slicing code is shown here:
#app.route('/') #this is what we type into our browser to go to pages. we create these using routes
#app.route('/home')
def home():
images=imagescrape()
titles=(images[58:])
#gettitles=gettitle()
#titles=(gettitles[58:93])
return render_template('home.html',images=images,titles=titles)
def imagescrape():
result_images=[]
#html = urlopen('https://en.wikipedia.org/wiki/Prince_Harry,_Duke_of_Sussex')
html = urlopen('https://en.wikipedia.org/wiki/Rembrandt')
bs = BeautifulSoup(html, 'html.parser')
images = bs.find_all('img', {'src':re.compile('.jpg')})
for image in images:
result_images.append("https:"+image['src']+'\n') #concatenation!
return result_images
UPDATE:
I've got this which NEARLY Works but not quite. It displays an image, then ALL the image urls text, instead of the corresponding one.
{% for image in images %}
<div class="card" style="width: 18rem;">
<img src="{{image}}" class="card-img-top" alt="...">
<div class="card-body">
{% for title in titles %}
<h5 class="card-title">{{title}}</h5>
{% endfor %}
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
Go somewhere
</div>
</div>
{% endfor %}
I think only a small change is needed for it to work but I don't know what.

Combine the two lists of images and titles one by one.
For the iteration, unpack the two variables of the respective tuple.
import re # regular expressions used to match strings
from bs4 import BeautifulSoup # web scraping library
from urllib.request import urlopen # open a url connection
from urllib.parse import unquote # decode special url characters
#app.route('/')
#app.route('/home')
def home():
images=imagescrape()
# Iterate over all sources and extract the title from the URL
titles=(titleextract(src) for src in images)
# zip combines two lists into one.
# It goes through all elements and takes one element from the first
# and one element from the second list, combines them into a tuple
# and adds them to a sequence / generator.
images_titles = zip(images, titles)
return render_template('home.html', image_titles=images_titles)
def imagescrape():
result_images=[]
#html = urlopen('https://en.wikipedia.org/wiki/Prince_Harry,_Duke_of_Sussex')
html = urlopen('https://en.wikipedia.org/wiki/Rembrandt')
bs = BeautifulSoup(html, 'html.parser')
images = bs.find_all('img', {'src':re.compile('.jpg')})
for image in images:
result_images.append("https:"+image['src']+'\n') #concatenation!
return result_images
def titleextract(url):
# Extract the part of the string between the last two "/" characters
# Decode special URL characters and cut off the suffix
# Replace all "_" with spaces
return unquote(url[58:url.rindex("/", 58)-4]).replace('_', ' ')
{% for image, title in images_titles %}
<div class="card" style="width: 18rem;">
<img src="{{image}}" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">{{title}}</h5>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
Go somewhere
</div>
</div>
{% endfor %}

Related

Shopify Liquid variant label background image

I have a variant option named "Trim" and it has values Brass, Bronze, Chrome, and Nickel. For each of these labels, I want to have a dynamic background image. Please see the image below.
I want to have background image on Trim option like this
So far, to achieve this, I have created a metafield named "trim_variant_bg" that takes a list of images and have written the following code.
{%- if option.name == "Trim" -%}
<label
style = "background-image:url(
{% for var_img in product.metafields.custom.trim_variant_bg.value %}
{{ var_img | img_url:"master" }}
{% endfor %}
)">
</label>
{% endif %}
However, the code is not working. How can I achieve the desired output? Please help.
If you structure your metafields like this
{"Bronze" : "your_url", "Gold" : ...}
You can just write
<label
style = 'background-image:url("{{product.metafields.custom.trim_variant_bg[option.value] | img_url: 'master'}}")'>
</label>
Be careful that you're using img_url so your URL in the metafields should take that into consideration. Otherwise you can save the final URL and not use any filter.

How to apply correct filter to {{ current_tags }} to display tag names not tag slugs

I want to alter this code to display the text within the anchor in readable format. I wish to display the tags name or title but it is currently displaying the tags as slugs.
Here is the snippet:
<!-- Creates the link as a variable, which is in 'tag_slug+tag_slug' format -->
{%- capture tag_url -%}{{ collection.url }}/{{ current_tags | join: "+"}}{%- endcapture -%}
<!-- HELP ME display the text inside the anchor in 'tag_title + tag_title' format. It currently displays the text of the anchor in 'tag_slug + tag_slug' format which is not very readable -->
<a class="breadcrumbs__link" href="{{ tag_url }}" aria-current="page">{{ current_tags | join: " + "}}</a>
I have tried a handful of things but have been unsuccessful. One of which was:
{{ current_tags.title | join: " + " }}
What is the equivalent to current_tags.title in liquid?
Here is an example output of the link:
<a class="breadcrumbs__link" href="/collections/example/tag-one+tag-two" aria-current="page">tag-one + tag-two</a>
This would be much easier to follow as a user if it was:
<a class="breadcrumbs__link" href="/collections/example/tag-one+tag-two" aria-current="page">Tag one + Tag two</a>
Where the tags would not have spaces removed, and the first letter will be capitalised. One thing to consider is that some tags require the dash to remain if it is already present in the tag title. So replacing dashes for spaces will not work. It will just create another issue.
EDIT - Another method that does not work:
{%- capture tag_url -%}{{ collection.url }}/{{ current_tags | join: "+"}}{%- endcapture -%}
<a class="breadcrumbs__link" href="{{ tag_url }}" aria-current="page">
{% for tag in collection.all_tags %}
{% if current_tags contains tag %}
<div class="current-tag">{{ tag.title }}</div>
{% endif %}
{% endfor %}
</a>
EDIT 2 - Another failed attempt:
{% for tag in current_tags %}
<div class="current-tag">{{ tag.title }}</div>
{% endfor %}
This solution is not by the book. I have not been able to find any documentation on how to iterate through the current_tags, display the tags by their readable name & add a join value such as ' + '.
However I have managed to loop through the current tags, then use CSS to change their appearance to better suit the style we wished for. So again this is not the textbook way of acheiving this and the results will not be 100% correct all the time but it is a substantial improvement on the previous display.
This will take the value of for example 'balances-scales-accessories+bench-scales' and convert it into 'Balances Scales Accessories + Bench Scales'. The 100% answer would look a little more like 'Balances, Scales & Accessories + Bench Scales'.
Where this solution fails is:
The ',' and '&' characters are removed.
The '-' are removed when in very niche situations these are actually a desired character like in the word 'Semi-gloss'.
Liquid:
<!-- Generate link as previously achieved -->
{%- capture tag_url -%}{{ collection.url }}/{{ current_tags | join: "+"}}{%- endcapture -%}
<!-- Add generated link to anchor tag -->
<a class="breadcrumbs__link" href="{{ tag_url }}" aria-current="page">
<!-- Loop through tags present in current tags list -->
{% for tag in current_tags %}
<!-- Wrap echoed tag in a span so it is targetable, replace the dashes for spaces, and make the whole thing lowercase -->
<span class="breadcrumb-tag">{{ tag | replace: '-', ' ' | downcase }}</span>
{% endfor %}
</a>
CSS:
/* Capitalise first letter of each word of the breadcrumb */
.breadcrumbs__link .breadcrumb-tag {
text-transform: capitalize;
}
/* Add a before on each tag that is not the first, to display a '+' symbol indicating there are multiple tags selected */
.breadcrumbs__link .breadcrumb-tag + .breadcrumb-tag:before {
content: ' + ';
}
Again not perfect but will do until someone can create a more reliable solution in liquid.

How do I create a loop that display each category and its post count?

I have a blog that I built with Jekyll. On the side bar I want to include a nav bar that list each category along with total number of posts for each. This is what I have right now:
<h2>Post Categories</h2>
<nav>
{% for category in site.categories %}
<h3>{{ category }} ({{ category | size }})</h3>
{% endfor %}
</nav>
I'm not on my computer that has Ruby and Jekyll installed so I can't build the site locally. But is this something that will work?
From the Liquid docs for the size filter:
Size: Returns the number of characters in a string or the number of items in an array.
Here's a full listing of the available vars using Jekyll, including site.categories.
Instead of calling size on your category var itself, you need to call it on the last argument, which is where the array of posts are hiding:
<h2>Post Categories</h2>
<nav>
{% for category in site.categories %}
<h3>{{ category | first }} ({{ category | last | size }})</h3>
{% endfor %}
</nav>

jekyll filename for current file

The title says it all. Is there a way to access the current filename in Jekyll? Before you jump the gun and try to mark it as duplicate, keep in mind that I'm asking for the current filename, not for the generated filepath which can be access by page.url.
As an example, lets say that there is a file1.html which include file2.html. I want to be be able to get file1.html if I'm inside file1.html and file2.html vice-versa. page.path only returns the filename for the generated file as in I will get file1.html even from within file2.html.
A concrete example:
file2.html:
<div>
{{ page.name }}
</div>
file1.html:
<div>
{% include file2.html %}
</div>
index.html:
{% include file1.html %}
rendered:
<div>
<div>
index.html
</div>
</div>
Instead of index.html, I want it to return file2.html
Thanks
Edit : An include is just a fragment that is inserted into a page. Once every include are made, the page is then processed as a single block of code.
There is no way to get any info from liquid about an include name.b

If product tags contains - in shopify

So i'm basically trying to use the logic of shopify to show an image if the tags of the product contains the words "related"
(there is a json query that picks up the tags containing 'related-x' where x is the name of the product and it uses this to show the related products.)
Preceding the Json query is an image that says "related products" basically. what i would like to do is to only display this when there are "related" tags present.
I have tried this:
{% if product.tags contains 'related' %}
<img src="{{ 'complete-this-look.gif' | asset_url }}" alt="" align="left;" style="vertical-align:top; margin-right:8px; padding-top:0px;" width="130" height="175"/>
{% endif %}
Which doesnt display anything. I also tried:
{% for t in product.tags %}
{% if t contains 'related-' %}
<img src="{{ 'complete-this-look.gif' | asset_url }}" alt="" align="left;" style="vertical-align:top; margin-right:8px; padding-top:0px;" width="130" height="175"/>
{% endif %}
{% endfor %}
However this will display the image every time a related product is returned by the query.
What im after is for it to go (Image) (Query Results) - and if there is no query results then it displays nothing.
Any ideas?
The reason your first piece of code is not working is because contains is looking for a tag called 'related', not a tag containing the substring 'related'.
See the Shopify Wiki for contains where it states:
It can check for the presence of a string in another string, or it can check for the presence of a string in an array of simple strings.
In your instance, contains is checking for a string in an array of simple strings (and is looking for the whole string, not a string containing the specified string as a substring).
See also the Shopify wiki for product.tags:
Returns a list of the product's tags (represented by simple strings).
You can use the contains keyword with an array of simple strings, so
you can use this with a product's tags:
{% if product.tags contains 'custom to order' %}
<!-- Output custom to order form HTML here -->
{% endif %}
So, Gerard Westerhof's suggestion to use Join in the comment above is a good one. If you first join the product.tags array, then contains will search for the 'related' string inside the string of tags returned by join.
Try this:
{% if product.tags | join: ' ' contains 'related' %}
<img src="{{ 'complete-this-look.gif' | asset_url }}" alt="" align="left;" style="vertical-align:top; margin-right:8px; padding-top:0px;" width="130" height="175"/>
{% endif %}
EDIT:
Try this instead:
{% assign product_tags_string = product.tags | join: ' ' %}
{% if product_tags_string contains 'related' %}
<img src="{{ 'complete-this-look.gif' | asset_url }}" alt="" align="left;" style="vertical-align:top; margin-right:8px; padding-top:0px;" width="130" height="175"/>
{% endif %}

Resources