Search code examples
tagsblogspostsnunjuckseleventy

11ty - How to display post tags in my post.njk file?


I've used the 11ty/eleventy-base-blog template and have things working well - but I am trying to display the tags nicely within my post.njk file.

At the top of my post (.md) file I have this:

tags: ['Tag 1', 'Tag 2']

Within _includes/layouts/postslist.njk I'm using the following code:

{% for tag in post.data.tags %}
  {%- if collections.tagList.indexOf(tag) != -1 -%}
  {% set tagUrl %}/tags/{{ tag }}/{% endset %}
    <span class="tag">{{ tag }}</span>
  {%- endif -%}
{% endfor %}

This template is then used in the index.njk file (my homepage) using this code:

{% set postslist = collections.posts | head(-3) %}
{% set postslistCounter = collections.posts | length %}
{% include "postslist.njk" %}

The output of this is:

<span class="tag">Tag 1</span>
<span class="tag">Tag 2</span>

However, if I use {{ tags }} in my post.njk file I get the following output:

posts,Tag 1,Tag 2

I have also tried using the same code from the 'postslist.njk' file and putting it in my 'post.njk' file but that doesn't work.

How can I display the tags on my post in separated 'span' tags and also remove the 'posts' tag?

If you want me to open up my git repo then let me know.

Thanks!


Solution

  • Why is the posts tag in your tags?

    In the starter template you're using (11ty/eleventy-base-blog), the posts/ directory includes a directory data file (posts.json), which gets applied too all files in that directory – i.e. to all posts. Since the .eleventy.js config file uses the Data Deep Merge option, the tags you set in each post get merged with the posts tag. This is why the tags of your post are ['posts', 'Tag 1', 'Tag 2'].

    You can solve this in multiple ways. Either use two different frontmatter fields for collection and display purposes, or just filter out the posts tag when displaying the tags of a post.

    How to output a list of tags?

    If you just do {{ tags }}, you're telling Nunjucks to output an array, so it has to figure out how to convert an array to a string. Apparently, the default behaviour in this case is to simply join them with commas. You can make this more explicit (and include a space after the comma while you're at it):

    {{ posts | join(', ') }}
    

    Or, if you want to wrap the items in HTML tags, you can use a loop, optionally with a joiner:

    {% set comma = joiner() %}
    {% for tag in tags -%}
      {% if tag !== 'posts' %}
        {{ comma() }} <span class="tag">{{ tag }}</span>
      {% endif %}
    {%- endfor %}