Formatting a Streamfield image block - wagtail

I want to specify the HTML for each streamfield block with a for loop in my template. However, the image part is getting complaints, and I'm sure I'm not doing it the right way.
Invalid block tag on line 15: 'image', expected 'elif', 'else' or 'endif'. Did you forget to register or load this tag?
{% extends "base.html" %}
{% load wagtailcore_tags %}
{% load wagtailuserbar %}
{% block content %}
<h1>{{page.title}}</h1>
<small>{{page.date}}</small>
{% for block in page.body %}
{% if block.block_type == 'heading' %}
<h2>{{ block.value }}</h2>
{% elif block.block_type == 'quote' %}
<blockquote class="blockquote text-center"><p class="mb-0">{{ block.value }}</p></blockquote>
{% elif block.block_type == 'image' %}
{% image block.value width-1200 class="img-fluid" alt="Responsive image" %}
{% endif %}
{% endfor %}
{% endblock %}
{% wagtailuserbar %}

I forgot to include:
{% load wagtailimages_tags %}
My bad :)

Related

Shopify loop - Skipping a product variant if variant has no image

I need to do two things; add products with extra colours to the collections loop (which I've done below, via a snippet elsewhere), however I need to skip when the variant doesn't have its own image which I've yet to figure out.
The break I attempted is in the preview code:
{% for option in product.options %}
{% if option == 'Colour' %}
{% assign index = forloop.index0 %}
{% assign colourlist = '' %}
{% assign colour = '' %}
{% for variant in product.variants %}
{% capture colour %}
{{ variant.options[index] }}
{% endcapture %}
{% if variant.image.src %}
{% break %}
{% endif %}
{% unless colourlist contains colour %}
{% include 'product-grid-item' %}
{% capture tempList %}
{{colourlist | append: colour | append: " " }}
{% endcapture %}
{% assign colourlist = tempList %}
{% endunless %}
{% endfor %}
{% endif %}
{% else %}
<div class="grid-item">
<p>{{ 'collections.results.no_products' | t }}</p>
</div>
{% endfor %}
{% endfor %}
The keyword you're looking for, to skip the current iteration of the loop and move to the next, is {% continue %}
For example:
{% for variant in product.variants %}
{% if variant.featured_image == blank %}
{% continue %}
{% endif %}
<!-- HTML STUFF -->
{% endfor %}

Checking for tag duplicates with jekyll excludes tags that are contained in other tags

I am trying to build a (simple, unweighted) tag cloud with liquid in my jekyll site. The tag cloud renders fine when I use this code:
{% assign sitetags = "" %}
{% for page in site.pages %}
{% for tag in page.tags %}
{% unless sitetags contains tag %}
{% assign sitetags = sitetags | append:tag | append:', ' %}
{% endunless %}
{% endfor %}
{% endfor %}
{% assign sitetags = sitetags | split:', ' | sort %}
{% for tag in sitetags %}
{% capture tag_name %}{{ tag }}{% endcapture %}
<div>
{{ tag_name }}
</div>
{% endfor %}
However, there is one issue: if the name of a tag is contained within another tag, it won't show up in the tag cloud. For example, "art" is contained in "art-history" so it does not show up. In order to deal with this, I tried to fix it, however, it is not working. Here is my code:
{% assign sitetags = "" %}
{% for page in site.pages %}
{% for tag in page.tags %}
{% if sitetags contains tag %}
{% assign sitetags = sitetags | split:', ' %}
{% assign truetag = true %}
{% for taggo in sitetags %}
{% if taggo != tag %}
{% continue %}
{% else %}
{% assign truetag = false %}
{% break %}
{% endif %}
{% endfor %}
{% if truetag == true %}
{% assign sitetags = sitetags | append:tag | append:', ' %}
{% endif %}
{% else %}
{% assign sitetags = sitetags | append:tag | append:', ' %}
{% endif %}
{% endfor %}
{% endfor %}
{% assign sitetags = sitetags | split:', ' | sort %}
{% for tag in sitetags %}
{% capture tag_name %}{{ tag }}{% endcapture %}
<div>
{{ tag }}
</div>
{% endfor %}
The reason I am attempting it this way as opposed to just using site.tags is because I have articles/essays in other directories that I am trying to include. When I use site.tags, it only includes the tags that are on the blog posts but not the essays. Essentially, my site has both regular blog posts under /_blog and also essays in a different location, but I want to aggregate the tags of all of these in the same tag cloud.
I would really appreciate advice on what I am doing wrong or how to fix it. Thanks!
Instead of using a string to store your tags, you can use an array.
{% assign sitetags = "" | split:"" %}
{% for page in site.pages %}
{% if page.tags.size %}
{% assign sitetags = sitetags | concat: page.tags %}
{{ sitetags | inspect }} <br>
{% endif %}
{% endfor %}
{% assign sitetags = sitetags | sort | uniq %}
{{ sitetags | inspect }} <br>
{% for tag in sitetags %}
<div>
{{ tag }}
</div>
{% endfor %}
I was able to figure this out myself actually. Part of the issue was in initializing the array, so I ended up working with a string instead because I just couldn't get the arrays to work for some reason. I skipped over initialization and went straight to adding items to it. After that all I had to do was just run the uniq filter and it filtered out all the duplicates, so I didn't have to do any string comparison or anything like that.
Here is the solution:
{% for post in site.pages %}
{% for tag in post.tags %}
{% assign tagcloud = tagcloud | append:tag | append:', ' %}
{% endfor %}
{% endfor %}
{% assign tagcloud = tagcloud | split:", " | uniq | sort %}
{% for tag in tagcloud %}
{% capture tag_name %}{{ tag }}{% endcapture %}
<div>
{{ tag_name }}
</div>
{% endfor %}

How do I iterate over a `page` object's properties in a template?

I have a Django template page that looks something like this.
{% extends "base.html" %}
{% load wagtailcore_tags static %}
{% block body_class %}template-bidpage{% endblock %}
{% block content %}
{% for prp in page %}
<p>{{ prp }}</p>
{% endfor %}
{% endblock content %}
But loading this page up gives me the error 'MyPage' object is not iterable. How do I display each proeprty of my MyPage object?
You should write a method inside your model class to return the properties.
class MyPage(Page):
# your fields go here
def get_properties(self):
# return all properties
Then in your templates
{% extends "base.html" %}
{% load wagtailcore_tags static %}
{% block body_class %}template-bidpage{% endblock %}
{% block content %}
{% for prp in page.get_properties %}
<p>{{ prp }}</p>
{% endfor %}
{% endblock content %}

Twig for loop - output only parent if any children exists

These lines prints all categories and the products within. But if the category has no products the category title is still printed.
{% for category in categories %}
<h1>{{ category.title }}</h1>
{% for product in products if products.category|first == category.title|lower %}
<h2>{{ product.title }}</h2>
{% endfor %}
{% endfor %}
How can I optimize this so category titles are printed only when the category contains products?
There are (imo) 2 solution for this. The first one is pure twig-based, but is the worst of the two methods.
In order to skip categories without children, this would require a second loop and flag variable to determine wether to skip the category or not. As twig can't break out of loops this means u would need to foreach the products twice completely
{% for category in categories %}
{% set flag = false %}
{% for product in products if products.category|first == category.title|lower %}
{% set flag = true %}
{% endfor %}
{% if flag %}
<h1>{{ category.title }}</h1>
{% for product in products if products.category|first == category.title|lower %}
<h2>{{ product.title }}</h2>
{% endfor %}
{% endif %}
{% endfor %}
The second and better solution is just to add an extra method to your category-model and do something like
{% for category in categories if category.hasProducts() %}
<h1>{{ category.title }}</h1>
{% for product in products if products.category|first == category.title|lower %}
<h2>{{ product.title }}</h2>
{% endfor %}
{% endfor %}
An easy solution would be to add a is defined condition to your twig loop.
Example:
{% for category in categories if categories is defined %}
<h1>{{ category.title }}</h1>
{% for product in products if products.category|first == category.title|lower %}
<h2>{{ product.title }}</h2>
{% endfor %}
{% endfor %}

Overriding app engine template block inside an if

I have a block 'left_area' defined in a base appengine template
{% block left_area %}
<div class="span3">
Left area content
</div>
{% endblock %}
In a child template, I want to override this block inside an if
{% if not user %}
{% block left_area %}
<div class="span2">
</div>
{% endblock %}
{% endif %}
This is not working for some reason. Any suggestion?
In jinja you can solve it with super(), which renders the parent block:
{% block left_area %}
{% if not user %}
<div class="span2">
</div>
{% else %}
{{ super() }}
{% endif %}
{% endblock %}

Resources