How can I find all the tags used by all my content?
I'm looking to get an array of tags that I can then iterate over and then use getFilteredByTag() to get the content of the tag. Like grouping my content by tag.
@richardherbert Possibly this? https://www.11ty.dev/docs/quicktips/tag-pages/
Thanks @pdehaan I hadn't found that page. On the surface using collections[ tags ] looked like a good find but I'm using Liquid for my templating and all I get is an empty array...
<ul>
{% assign taglist = collections[ tag ] %}
{%- for tag in taglist -%}
<li>tags: {{ tag.data.title }}</li>
{%- endfor -%}
</ul>
tags:
tags:
tags:
tags:
tags:
tags:
tags:
tags:
In fact using {% assign taglist = collections %} gives the same result.
I don't seem to be able to access the objects in the array?
Sorry, I don't know Liquid (I'm generally a Nunjucks guy), but it looks like you're finding 8 tags/collections, based on your loop output above.
I'd start by dumping the {{ tag.data }} or {{ tag }} and see if you can see any output. It's possible that Liquid just isn't finding tag.data.title for some reason.
Yes, I tried dumping {{ tag }} but there was nothing there - strange??
Yes, I tried dumping
{{ tag }}but there was nothing there - strange??
A little strange. I'm not sure why it's looping if it isn't finding anything. If you have the code in GitHub or similar, I can try pulling the repo and taking a quick look.
I did get a bit closer on this (using Nunjucks still though, haven't tried w/ Liquid).
But here's my Nunjucks file:
{# eleventyConfig.addFilter("keys", obj => Object.keys(obj)); #}
<p>{{ collections | keys | dump(2) | safe }}</p>
<section>
{%- for tag, posts in collections %}
tag: {{ tag }}, posts: {{ posts | length }}<br/>
{%- endfor %}
</section>
<hr>
<section>
{%- for tag2, posts2 in collections | dictsort %}
tag: {{ tag2 }}, posts: {{ posts2 | length }};<br/>
{%- endfor %}
</section>
Where the custom keys filter is just this:
eleventyConfig.addFilter("keys", obj => Object.keys(obj));
And the output is:
<p>[ 'all', 'page', 'contact', 'post', 'about' ]</p>
<section>
tag: all, posts: 7<br/>
tag: page, posts: 2<br/>
tag: contact, posts: 1<br/>
tag: post, posts: 2<br/>
tag: about, posts: 1<br/>
</section>
<hr>
<section>
tag: about, posts: 1;<br/>
tag: all, posts: 7;<br/>
tag: contact, posts: 1;<br/>
tag: page, posts: 2;<br/>
tag: post, posts: 2;<br/>
</section>
The one interesting thing about the output, is that it seems like the tag order isn't guaranteed. Each time I regenerated the site, the order of the keys was slightly different. So if you want a specific sorting (ie: sort by number of posts descending), you might need to get a bit creative. Sorting alphabetically is probably trivial since you could probably just do:
<p>{{ collections | keys | sort }}</p>
I can also try cleaning up my repo and push it to GitHub if that'd help. I started with that, and then for some reason got distracted and started porting all the built-in Liquid filters so they'd work with Nunjucks.
That's a good lead, thanks. I'll try and translate that into Liquid and knock up a sample repo.
I did think I'd have to drop into JavaScript, not one of my core skills, to write a filter but I was hoping that the issue was me not being about to find the right page in the documentation, being new to this project.
Like you, I'm spinning several project plates atm so I will get back to you later.
This issue provides some interesting input. I am looking for a similar thing.
{%- for tag, posts in collections.tech | group %}
<h2>{{tag}}</h2>
{%- for post in posts %}
{{ post.url }}
{%- endfor %}
{%- endfor %}
or
{%- for tag in collections.tech | uniqueTags %}
<h2>{{ tag }}</h2>
{%- for post in collections.tech | selectTag(tag) %}
{{ post.url }}
{%- endfor %}
{%- endfor %}
What I came up with:
eleventyConfig.addFilter("uniqueTags", (array) => {
let tags = new Set()
for (const p of array) {
if (p.data && p.data.tags) {
for (const tag of p.data.tags) {
tags.add(tag)
}
}
}
return [...tags]
})
eleventyConfig.addFilter("selectTag", (array, tag) => {
return array.filter((p) => {
return p.data && p.data.tags && p.data.tags.includes(tag)
})
})
Probably not the fastest approach but reasonable flexible.
Excuse me ignorance @tcurdt but I don't understand what youe uniqueTags filter is returning?
@richardherbert all the tags of the pages passed into the filter. I use the same pattern for my post archive. Maybe that helps to make it clear:
{%- for year in collections.tech | uniqueYears | reverse %}
<h2>{{ year }}</h2>
...
I'm currently using this code, and am wondering how to sort it alphabetically. Haven't yet found anything in nunjucks documentation:
<ol>
{% for tag in collections.tagList %}
<li> {% set tagUrl %}/tags/{{ tag }}/{% endset %}
<a href="{{ tagUrl | url }}" class="tag">{{ tag | title }}</a>
</li>
{% endfor %}
</ol>
@dixonge I'm trying to do this with Liquid, which I didn't make clear at the start, and there doesn't seem to be anything like collections.tagList to get me an array of tags. @pdehaan has a good snippet eleventyConfig.addFilter("keys", obj => Object.keys(obj)); which gets an array of tags but unfortunately also include the all tag which I'm struggling to filter out.
Simply what I'm trying to do is get an array of content objects grouped by tags that I can iterate over and display.
which gets an array of tags but unfortunately also include the
alltag which I'm struggling to filter out.
You could create another custom filter which removes unwanted items from an array. I randomly chose to convert to a Set and then back to an Array, but you could probably do a bit of extra work and leave it as an array.
eleventyConfig.addFilter("keys", obj => Object.keys(obj));
eleventyConfig.addFilter("except", (arr=[], ...values) => {
const data = new Set(arr);
for (const item of values) {
data.delete(item);
}
return [...data].sort();
});
And if you're using liquid, you could use the filters like this:
{{ collections | keys | except "all", "Home", "About", "Legal" }}
I'm currently using this code, and am wondering how to sort it alphabetically. Haven't yet found anything in nunjucks documentation:
@dixonge: Nunjucks has a built-in sort filter you could probably use (depending on what the collections.tagList looks like, ie: array of strings, or something else):
https://mozilla.github.io/nunjucks/templating.html#sort-arr-reverse-casesens-attr
sort(arr=[], reverse=false, caseSens=false, attr=undefined)
<ol>
{% for tag in collections.tagList | sort %}
<li> {% set tagUrl %}/tags/{{ tag }}/{% endset %}
<a href="{{ tagUrl | url }}" class="tag">{{ tag | title }}</a>
</li>
{% endfor %}
</ol>
If tagList is an array of _objects_, you should be able to pass a value to "attr" for the key you want to sort by. If the key is nested, I think you're out of luck and would need to write your own custom sort filter/function since I think Nunjucks will only look 1 level deep, last I looked.
{% for tag in collections.tagList | sort(false, false, "objectPropToSortBy") %}
Nunjucks has a built-in
sortfilter you could probably use (depending on what thecollections.tagListlooks like, ie: array of strings, or something else):
Wow, that was it! Thank you! I had seen a reference to that, but no good examples for usage I could wrap my brain around.
@dixonge Yeah, I had to dig into the Nunjucks source to try and figure it out.
I have a few examples of strings-vs-numbers at https://github.com/pdehaan/11ty-nunjucks-sort-test but I'm realizing it isn't super useful when browsing through GitHub and it's a bit of a pain to clone the repo and build locally to see all the generated output.
@pdehaan @dixonge Thank you for your thoughts. So after much thrashing around, Googling, trial and error I think I have a Liquid working solution!
In my .eleventy.js...
eleventyConfig.addFilter( 'keys', obj => Object.keys( obj ) );
eleventyConfig.addFilter( 'except', ( arr=[] ) => {
return arr.filter( function( value ) {
return value != 'all';
} ).sort();
} );
...then in my md page...
{% assign tags = collections | keys | except 'all' %}
<ul>
{%- for tag in tags -%}
<li>tag: {{ tag }}</li>
<ol>
{%- for tag in collections[tag] -%}
<li>title: {{ tag.data.title }}</li>
{%- endfor -%}
</ol>
{%- endfor -%}
</ul>
...gives me...

Result!
Any suggestions to tighten this up would be more than welcome!
sorry if I'm interrupting, but I've noticed the eleventy-base-blog achieves something similar by creating a custom collection: https://github.com/11ty/eleventy-base-blog/blob/master/_11ty/getTagList.js
Dunno if that was what you were looking for.
Once you have the tag you can access the collection for that tag and iterate over the items and extract whatever you need from there. I guess.
@ThePeach - Thanks, I'll take a look at that.
just referencing @ThePeach suggestion with little improving (less code and sorting) you could include the code bellow in your eleventy config
eleventyConfig.addCollection("tagList", collection => {
const tagsSet = new Set();
collection.getAll().forEach(item => {
if (!item.data.tags) return;
item.data.tags
.filter(tag => !['post', 'all'].includes(tag))
.forEach(tag => tagsSet.add(tag));
});
return Array.from(tagsSet).sort();
});
and access it in your templates:
<section>
tags list
{% for tag in collections.tagList %}
{{ tag }}
{% endfor %}
</section>
Most helpful comment
just referencing @ThePeach suggestion with little improving (less code and sorting) you could include the code bellow in your eleventy config
and access it in your templates: