Skip to content

Instantly share code, notes, and snippets.

@tannerdolby
Last active April 16, 2025 19:58
Show Gist options
  • Save tannerdolby/0fd575a480d0299e1d6735f462799d77 to your computer and use it in GitHub Desktop.
Save tannerdolby/0fd575a480d0299e1d6735f462799d77 to your computer and use it in GitHub Desktop.
11ty filter for returning a sorted list of tags from collections. Use the it in a template like {{ collections.foo | taglist }} to get the sorted tag list.
eleventyConfig.addFilter("taglist", function(collection) {
const tags = [];
collection.forEach(post => {
tags.push(...post.data.tags);
});
const sorted = [...new Set(tags)].sort((a, b) => a.localeCompare(b));
return sorted;
});
@tannerdolby
Copy link
Author

tannerdolby commented Aug 14, 2021

More discussion based on this tweet:

Great tip but javascript syntax is so a mess to read for me. { ( => ... arrow function spread operator etc.
Would you add some comments to explain or use no shortcuts to help noobs ?

Here is an implementation with comments and less ES6 usage:

eleventyConfig.addFilter("taglist", function(collection) {
        // Creates an empty array to store tags in later on
        let tags = [];

        // iterate over the array of objects represented by the 
        // `collection` variable passed to the callback function
        for (var i = 0; i < collection.length; i++) {
            // collection[i].data.tags is an array in the form of
            // ["tag1", "tag2"] which is an iterable data structure.
            // We can use the spread operator (ES6 feature) `...` to "expand" 
            // the values present in each iterable array of tags then add them into
            // the `tags` array for later processing
            // tags.push(...collection[i].data.tags);

            // if we didn't want to use any ES6 and forego using spread syntax,
            // just loop through each iterable array of tags and push the tag values
            // into the `tags` array
            tags.push(collection[i].data.tags);
        }
        console.log(tags); // [['typescript', 'javascript'], ['scss', 'css']]

        // We pushed each tags array (which is iterable)
        // into the `tags` variable, so its now an array of arrays
        // since we want to "expand" each 1D tags array, we can simply
        // flatten the `tags` array so its only an array of tag strings
        flat = tags.flat(); 
        console.log(flat) // ['typescript', 'javascript', 'scss', 'css'] etc

        // The Set object allows us to store unique values of any type,
        // so we will convert our `tags` array to a Set and then
        // sort the unique list of tags in alphabetical order
        let set = new Set(flat.sort(function(a, b) {
            return a.localeCompare(b)
        }));

        // Returning a Set object with the alphabetically sorted taglist,
        // You could expand the set into an array if you want to return an array like I've
        // done in the first gist above, but either way works :)
        return set;
    });

as the comments introduce quite a bit of "bloat", the above code without comments looks like:

eleventyConfig.addFilter("taglist", function(collection) {
        let tags = [];
        for (var i = 0; i < collection.length; i++) {
            tags.push(collection[i].data.tags);
        }
        flat = tags.flat(); 
        let set = new Set(flat.sort(function(a, b) {
            return a.localeCompare(b)
        }));

        return set;
    });

@seezee
Copy link

seezee commented Apr 15, 2025

How would one filter specific tags so they aren't picked up by this filter?

@tannerdolby
Copy link
Author

@seezee Can you provide an example use case you're thinking of? If I understand correctly, you are looking to disallow certain tags when using the taglist filter.

Option 1:
If you know the tags you don't want the filter to output, you could provide a disallow list and then filter out disallowed tags before returning the sorted list.

eleventyConfig.addFilter("taglist", function(collection) {
    const disallowed = ["foo", "bar"];
    const tags = [];
    collection.forEach(post => {
        tags.push(...post.data.tags);
    });
    const sorted = [...new Set(tags)]
      .filter((tag) => !disallowed.includes(tag))
      .sort((a, b) => a.localeCompare(b));
    return sorted;
});

Option 2:
Filter the tags you don't want the filter to process ahead of time before utilizing the taglist filter.

@seezee
Copy link

seezee commented Apr 16, 2025

@seezee Can you provide an example use case you're thinking of? If I understand correctly, you are looking to disallow certain tags when using the taglist filter.

Option 1: If you know the tags you don't want the filter to output, you could provide a disallow list and then filter out disallowed tags before returning the sorted list.

eleventyConfig.addFilter("taglist", function(collection) {
    const disallowed = ["foo", "bar"];
    const tags = [];
    collection.forEach(post => {
        tags.push(...post.data.tags);
    });
    const sorted = [...new Set(tags)]
      .filter((tag) => !disallowed.includes(tag))
      .sort((a, b) => a.localeCompare(b));
    return sorted;
});

Option 2: Filter the tags you don't want the filter to process ahead of time before utilizing the taglist filter.

That worked a treat! Thank you!

@tannerdolby
Copy link
Author

Glad to hear it. You're welcome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment