Assuming I have a list of tags: iFix_6.3, iFix_7.0, iFix_7.1, iFix_8.0, announcement, and so on... and I want to run an operation only on certain several tags. How can I check for these multiple values?
There is contains, but I'm looking for the opposite of it and for multiple values...
Here is an example where I actually filter out all posts that contain the iFix_6.3 tag, thus display all other posts. This actually does not work yet... plus needs to be extended to work for multiple tags.
// posts with iFix_xxx tag should be filtered from the main posts view.
{% assign postUpdates = site.posts | where_exp:"item", "item.tags != 'iFix_6.3'" %}
{% for post in postUpdates limit:10 %}
<div class="postItem inline">
<p class="postDate">{% if post.pinned %}<span class="glyphicon glyphicon-pushpin"></span>{% endif %}{{post.date | date: '%B %d, %Y'}}</p>
<p class="postTitle">{{post.title}}</p>
</div>
{% endfor %}
You can do this by building an array of excluded tags (excluded_tags) using split and a string of the comma-separated tags. Then for each post, you iterate on the post's tags. Check if the tag is in excluded_tags using contains, if it is then raise the flag filtered_out to not display the post, using the unless control flow tag.
{% assign excluded_tags = "iFix_6.2,iFix_6.3,announcement" | split : "," %}
{% for post in site.posts limit:10 %}
{% assign filtered_out = False %}
{% for tag in post.tags %}
{% if excluded_tags contains tag %}
{% assign filtered_out = True %}
{% break %}
{% endif %}
{% endfor %}
{% unless filtered_out %}
...
{% endunless %}
{% endfor %}
Seems unless would solve the case.
{% assign postUpdates = site.posts | where_exp:"item", "unless item.tags contains 'iFix_6.3'" %}
Related
I'm having an issue with a for loop in Shopify. I'm sure it used to work, but I can't get it to work over the number 9 now.
{% assign productTag1 = Availability14 %} (in this example, the product has only 1 tag, which is Availability14)
{% assign avail_stop = false %}
{% for j in (0..15) %}
{% assign check_avail = 'Availability' | append:j %}
{% if productTag1 contains check_avail %}
{% assign avail_stop = true %}
{% capture tag_name %}{{check_avail}}{% endcapture %}
{% break %}
{% endif %}
{% endfor %}
{% if avail_stop %}
{% assign availability = check_avail | remove:'Availability' | plus:0 %}
{% endif %}
At the moment, I'm returning 1, not 14. I imagine it's something to do with the fact 14 includes a 1, but I can't wrap my head around it.
Any help is appreciated.
You have a {% break %} statement in your if. Once the if becomes true it will exit the loop instantly.
If you want to skip the next code you must use {% continue %} not {% break %}.
On my mind this is an issue with conditional operator. As you said, 14 contains 1, so why not simply use strict conditional operator like this:
{% if productTag1 == check_avail %}
{% assign has_stop = true %}
{% break %}
{% endif %}
(or did I miss something?)
I'm trying to use relative_url in most of the links of my Jekyll theme, so if someone wants to have this theme working in a subdirectory he can do it.
I have a problem with the list of categories of the post, each of which should link to the archive.
In _layouts/post.html I have this code:
{% if site.data.settings.categories.active %}
{% include categories.html %}
{% endif %}
categories.html has this code:
<div class="categories">
<span><p>Categories:</p>
{% if post %}
{% assign categories = post.categories %}
{% else %}
{% assign categories = page.categories %}
{% endif %}
{% for category in categories %}
{{category}}
{% unless forloop.last %} {% endunless %}
{% endfor %}
</span>
</div>
Here's the problem:
{{category}}
Somehow, this returns the current post url.
{{category}}
This returns the correct link, but does not work in case the site is in a subdirectory.
Why it returns the post url?
There are multiple problems here.
First off, Liquid doesn't evaluate nested constructs.
Therefore, the following code:
{{ "/categories/#{{category | slugify}}" | relative_url}}
needs to be rewritten into:
{% capture url %}/categories/{{ category | slugify }}{% endcapture %}
{{ url | relative_url }}
Secondly, there is no global post object. Therefore {% if post %} is always going to evaluate to a negative. i.e., it is redundant.
I would like to get the list of posts having a specific tag in their front matter (*)
I tried the code below, which iterates over all the tags of the current post pages (the current tag is t), then iterates over all the posts (p) to check if they have this tag (and just outputs the title, for debugging reasons):
{% for t in page.tags %}
{% for p in site.posts %}
{% if t in p.tags %}
{{ p.title }}
{% endif %}
{% endfor %}
{% endfor %}
The line {% if t in p.tags %} seems to fail (I come form a Python background so I gave it a try) and I cannot find the in operator in liquid. Does it exits?
(*) I am mentioning what I want to achieve in case there is a more straightforward way to do that but I am still interested in the general question.
Following your example it can be done with the contains tag:
contains can also check for the presence of a string in an array of
strings.
{% if product.tags contains "outdoor" %}
This product is great for
using outdoors!
{% endif %}
So to get the list of posts having a specific tag in their front matter (in this case the posts with the tag mytag):
{% assign posts_with_mytag = site.posts | where_exp:"item",
"item.tags contains 'mytag'" %}
{% for post in posts_with_mytag %}
{{post.title}}
{% endfor %}
Following-up on #maracuny's answer, the corrected code from my question for completeness:
{% for t in page.tags %}
{% for p in site.posts %}
{% if p.tags contains t %}
{{ p.title }}
{% endif %}
{% endfor %}
{% endfor %}
I am migrating my Wordpress blog to Jekyll, which I like a lot so far. The current setup in the new site is like this:
use category to distinguish two types of posts (e.g., blog and portfolio)
use tag as normal
The challenge right now is to display all tags within a category because I want to create two separate tag clouds for two types of posts.
As far as I know, Liquid supports looping over all tags in a site like this:
{% for tag in site.tags %}
{{ tag | first }}
{% endfor %}
But I want to limit the scope to a specific category and am wishing to do something like this:
{% for tag in site['category'].tags %}
{{ tag | first }}
{% endfor %}
Any advice will be appreciated.
This seems to work for all kinds of filters like category or other front matter variables - like "type" so I can have type: article or type: video and this seems to get tags from just one of them if I put that in the 'where' part.
{% assign sorted_tags = site.tags | sort %}
{% for tag in sorted_tags %}
{% assign zz = tag[1] | where: "category", "Photoshop" | sort %}
{% if zz != empty %}
<li><span class="tag">{{ tag[0] }}</span>
<ul>
{% for p in zz %}
<li>{{ p.title }}</li>
{% endfor %}
</ul>
</li>
{% endif %}
{% endfor %}
zz is just something to use to filter above the first tag[0] since all it seems to have is the tag itself, so you can filter anything else with it. tag[1] has all of the other stuff.
Initially I was using if zz != null or if zz != "" but neither of them worked.
This will work, it will list only the tags on post of category 'X'. Replace X with the name of the category.
{% for post in site.categories['X'] %}
{% for tag in post.tags %}
{{ tag }}
{% endfor %}
{% endfor %}
I want to loop over all posts that are assigned category "foo" and category "bar" ..
{% for post in site.categories.foo and in site.categories.bar %}
Is this possible?
In my case "foo" as a "parent" category to "bar" ... /foo/bar/_posts
Thanks
Instead of looking through every post and matching with an or, you can filter by the first tag and then look for the second (and third, fourth, fifth...) tags:
{% for post in site.categories.fizz%}
{% if post.categories contains "buzz" and post.categories contains "bang" %}
<!--post has categories fizz AND buzz AND bang-->
<li>{{ post.title }}</li>
{% endif %}
{% endfor %}
This is a little more efficient than iterating over every single post, and it sets up an and relationship instead of an or relationship.
It is fully possible: loop over all posts, and then select the wanted posts:
{% for post in site.posts %}
{% if post.categories contains "foo" or post.categories contains "bar" %}
<li>{{ post.title }}</li>
{% endif %}
{% endfor %}
Using the Where Expression filter in Jekyll.
Jekyll Liquid Filter Docs
Where Expression,
Select all the objects in an array where the expression is true.
3.2.0
{{ site.members | where_exp:"item", "item.projects contains 'foo'" }}
So on my site I did:
_includes/clippings.html
...
{% capture _filter %}item.tags contains '{{ include.tag }}'{% endcapture %}
{% for clip in site.clippings | where_exp: 'item', _filter %}
{{ clip.do_stuff }}
# more html and stuff
{ endfor }
{% include clippings.html tag='foo' %}
In this case I need to specify the filter tag dynamically. And clippings is just a collection like posts.
If you want to filter by multiple static tags you could do something like:
{% for post in site.posts | where_exp: 'item', "item.tags contains 'foo'" | where_exp: 'item', "item.tags contains 'bar'" %}
{{ post.do_stuff }}
{ endfor }
If you want to do multiple dynamic filter tags then you will need to do something similar to the capture stuff I did above.
I have not tested this, but it should filter posts by an arbitrary amount of filter tags.
{% assign posts = site.posts %}
{% filter_tags = 'foo, bar, buzz' | slipt: ', ' %}
{% for tag in filter_tags %}
{% capture _filter %}item.tags contains '{{ tag }}'{% endcapture %}
{% assign posts = posts | where_exp: 'items', _filter %}
{% endfor %}
{% for post in posts %}
{{ post.do_stuff }}
{% endfor %}
However looping over the whole thing once and checking each post might be more efficient at that point.