Assigning URLs to Tags

There is currently no built-in support for giving each tag its own URL like there is with entries. That doesn’t mean you can’t do it yourself, though.

For the purposes of this guide, let’s say we want our tag URLs to look like example.com/tags/[tag title], and we want those URLs to point to a template located at tags/_tag.html.

Create the Route #

First thing’s first: let’s create a new route from *SettingsRoutes** with the following settings:

  • URI: tags/( ‘tag’ token )
  • Template: tags/_tag

Now, incoming requests pointing to example.com/tags/[anything] are going to be routed to our tags/_tag.html template, and there will be a tag variable predefined, set to whatever is in the second URL segment.

Create the Template #

The first thing we need to do in our tags/_tag.html template is fetch the requested tag:

{% set tag = craft.tags().slug(tag).one() %}

Note: Up until this line, the tag variable will be set to whatever matched our ‘tag’ Route token, but after this line, it will either be a Tag Element or null if no matching tag was found.

If someone tries to go to the page with an unknown tag title we’ll want to return a 404, so let’s do that:

{% if not tag %}
  {% exit 404 %}
{% endif %}

Any template code after that can be sure that tag is set to an actual Tag Element. So what do we do with it? Let’s output a list of entries that are tagged with it:

<h1>Entries tagged with “{{ tag.title }}”</h1>

{% set entries = craft.entries().relatedTo(tag).order('title').all() %}

{% if entries|length %}
  <ul>
    {% for entry in entries %}
      <li>{{ entry.getLink() }}</li>
    {% endfor %}
  </ul>
{% else %}
  <p>No entries could be found with that tag.</p>
{% endif %}

Link to the Tag URLs #

Now that we’re all set up to handle tags URLs, we need to link to them.

Let’s say we want to output a list of the tags an entry is tagged with, at the bottom of each entry page. And we want to link those tags to their new tag URLs. Here’s how we’d do that, assuming our Tags field has a handle called “tags”:

{% if entry.tags | length %}
  <h3>This entry is tagged with:</h3>

  <ul>
    {% for tag in entry.tags %}
      <li><a href="{{ siteUrl }}tags/{{ tag.title|url_encode }}">{{ tag.title }}</a></li>
    {% endfor %}
  </ul>
{% endif %}

We’re using the url_encode filter to ensure the tag title will be URL-safe when it’s output in the link URL.

Now our site has some nice tag support!

Applies to Craft CMS 3.