It doesn't appear that tags are handled the same way as categories in the sense that categories have a slug (which results to a URI). I'd like to use tags to link to a "tag" page, similar to a category page, but "Really Cool Tag Name" doesn't work/look right as part of a URL. I've used the Slugify plugin to turn the tag in to a slug, however, I'm not sure the best approach to return the relationship of that tag as that slug is not related to the tag at all. Would the best practice be to add an additional slug field to the tag group? Then I'd be able to make that relationship. Thoughts?

4 Answers 4


Here's a really DRY way to do it.

Setup a route, something like "news/tags/(tag)" to load the "news/index" template (the same one used for listing all entries).

In the "news/index" template:

{# If there is a tag token in the URL, set a filtered variable. #}
{% if tag is defined %}

    <h2>Tag: {{ tag }}</h2>

    {% set tag = craft.tags.name(tag).first() %}

    {% set entriesToShow = craft.entries.section('news').relatedTo(tag) %}

{% else %} {# No tag token in URL, assume unfiltered overview page. #}

    {% set entriesToShow = craft.entries.section('news') %}

{% endif %}

{# the entry loop for both filtered and unfiltered entries #}
{% for entry in entriesToShow %} 
    {# display entry #}
{% endfor %}

When templating tag links to this system use:

{{ siteUrl }}news/tag/{{ tag.name|url_encode }}

This method allows you to reuse your entry loop and you don't even need a "tags" template. I can also be expanded to filter by categories as well without needing another template.


There is a detailed help article dedicated to that in the help section of the Craft website.

In short

  • create a route
  • get all entries related to the tag
  • use {{ tag.name | url_encode }} to create the URL pointing to the tag page

I setup a route, in my case "news/tag/[tag]" with a template news/_tag. Then in the template I find the tag:

{% set actualTag = craft.tags.name(tag).first() %}
{% if not actualTag %}{% exit 404 %}{% endif %}

and get the entries related to the tag (could additionally restrict this by section):

{% set relevantEntries = craft.entries
    targetElement: actualTag,
    field: 'tags'

[edited to add:] To get the list of tags with links to the tag pages (twig url_encode to translate tag name to url):

{% for tag in craft.tags.relatedTo({
    sourceElement: entries,
    field: 'tags'
  {% set tagUrl = '/news/tag/'~(tag.name|url_encode) %}
  <a href="{{tagUrl}}">{{tag.name}}</a>
{% endfor %}
  • Do you use the tag as is in the URL or do you "slugify" it or create a secondary field for the "slug" field?
    – Ryan Shrum
    Jul 8, 2014 at 17:25
  • I use the tag as is. My theory is that is what tags are designed for. Jul 8, 2014 at 17:28
  • So you use it with spaces if applies? i.e. "this is my tag" Which would render ".com/news/tag/this is my tag"
    – Ryan Shrum
    Jul 8, 2014 at 17:28
  • craft turns that into "this+is+my+tag", and I use that Jul 8, 2014 at 17:31
  • Actually, I pass it through url_encode, and use that:{{tag.name|url_encode}}. Editing my original answer to include that... Jul 8, 2014 at 17:55

Not sure if this is the best way to go, but thus far I've used a custom route (in Settings->Routes) to setup tag listing/landing pages. Something like tags/* so the wildcard catches the tag slug.

{% set tagId = "" %} {# set the initial tagID variable outside of your loop to access it later in the template #}

{% if craft.request.getSegment(1) == "tags" %} {# if you're on the tag listing template #}
    {% set tags = craft.tags.find() %} {# get all tags in the system #}
    {% for tag in tags %}
        {% set tagUrl = tag.name|lower|replace({' ': '-'}) %} {# do the same string manipulation that you did to create the slug that links to this page #}
        {% if (tagUrl == craft.request.getSegment(2)) %} {# grab the tag that matches your URL #}
            {% set tagId = tag.id %}
        {% endif %}
    {% endfor %}
{% endif %}

Then, grab entries that are related to this tag:

{% set tag = craft.tags.id(tagId) %}
{% set entries = craft.entries.section('blog').relatedTo(tag).find() %}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.