Answers.Body: <p>Ideally, you'll use a dynamic route that can match any number of tags – negating the need to hard code the number of possible tag segments.</p>
  
  <p>You can't pull this off using the Routes admin inside the CP, so crack open your <strong>/craft/config/routes.php</strong> file and add this:</p>
  
  <pre><code>return array(
      'tags/(.+)' =&gt; 'path_to_your_tags_template',
  ); 
  </code></pre>
  
  <p>The above route can have any number of segments under <code>/tags</code>, but will require at least one. <em>Be sure to delete any conflicting routes defined in Settings -> Routes!</em></p>
  
  <p>Inside your tags template, you can get an array of all the tags in the URI like this (the <code>|slice(1)</code> part removes the first segment, i.e. "tags"):</p>
  
  <pre><code>{% set tagSegments = craft.request.segments|slice(1) %}
  </code></pre>
  
  <p>To pull the actual tags, you can do something like this:</p>
  
  <pre><code>{% set tags = craft.tags.slug(tagSegments) %}
  </code></pre>
  
  <p>Pulling it all together, here's how a (simplified) version of your template could look:</p>
  
  <pre><code>{# Get tags #}
  {% set tagSegments = craft.request.segments|slice(1) %}
  {% set tags = craft.tags.slug(tagSegments) %}
  
  {# Get entries related to tags #}
  {% set relatedTo = [] %}
  {% for tagId in tags.ids() %}
      {% set relatedTo = relatedTo|merge([{
          targetElement: tagId,
          field: 'tags'
      }]) %}
  {% endfor %}
  {% if relatedTo|length &gt; 1 %}
      {% set relatedTo = ['and']|merge(relatedTo) %}
  {% endif %}
  {% set entries = craft.entries.relatedTo(relatedTo) %}
  
  {% if entries|length %}
      &lt;h1&gt;Entries tagged with {% for tag in tags %}{{ tag.title }}{% if not loop.last %}{{ loop.revindex == 2 ? ' and' : ',' }}{% endif %}{% endfor %}&lt;/h1&gt;
      &lt;ul&gt;
          {% for entry in entries %}
              &lt;li&gt;{{ entry.getLink() }}..&lt;/li&gt;
          {% endfor %}
      &lt;/ul&gt;
  {% else %}
      &lt;p&gt;No entries could be found with {{ tagSegments|length &gt; 1 ? 'those tags' : 'that tag' }}.&lt;/p&gt;
  {% endif %}
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-12-05T00:45:30.480Z
Answers.Text: Thanks for your help! This (kinda) works. The problem is that it returns all posts that contain one of these tags. It should return posts that match all  the tags. Its returning as if the tags are being OR'd and not ANDed which seems strange since 'and' is clearly being defined inside the relatedTo() function.
Answers.UserDisplayName: Markus
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-12-05T06:41:39.850Z
Answers.Text: @Markus Yeah, that's a little strange. I've updated my answer with an alternative, more convoluted but possibly more robust solution. Another thing you could try is simply `craft.entries.relatedTo('and', tags.ids())` (i.e. without joining the array of IDs). Sorry, don't have time to test either of these solutions right now.
Answers.UserDisplayName: Mats Mikkel Rummelhoff
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-12-06T01:44:35.720Z
Answers.Text: Thank you! Your updated solution seems to work. I appreciate the help.
Answers.UserDisplayName: Markus
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-12-04T09:44:40.817Z
Answers.LastActivityDate: 2016-12-05T06:40:09.603Z
Answers.LastEditDate: 2016-12-05T06:40:09.603Z
Answers.UserDisplayName: Mats Mikkel Rummelhoff
Body: <p>how would I go about setting up a route and twig template to filter by multiple tags?</p>
  
  <pre><code>Example URL scheme: example.com/tags/tag1/tag2/tag3
  </code></pre>
  
  <p>where <code>tag1</code>, <code>tag2</code> and <code>tag3</code> are tags defined in a tag field inside an entry. The resulting entries list should only output entries with <code>tag1</code> <strong>AND</strong> <code>tag2</code> <strong>AND</strong> <code>tag3</code>. <code>tag2</code> and <code>tag3</code> should be optional. I want to avoid the use of get params such as ?tag=tag1,tag2,tag3.</p>
  
  <p>The ultimate goal is chain multiple tags to get finer results, similar to pinboard.in tag chaining. </p>
  
  <p>Example:<a href="https://pinboard.in/t:javascript/t:css/t:webdev" rel="nofollow noreferrer">https://pinboard.in/t:javascript/t:css/t:webdev</a>
  will return entries with <code>javascript</code> AND <code>css</code> AND <code>webdev</code></p>
  
  <hr>
  
  <p>My route looks as follows</p>
  
  <pre><code>URI: tags/tag-token/tag-taken2/tag-token3
  </code></pre>
  
  <p>and my twig template looks like</p>
  
  <pre><code>{% set entries = craft.entries.relatedTo(tag) %}
  
  {% if craft.request.getSegment(2) !='' %}
  &lt;h1&gt;Entries tagged with “{{ tag.title }}”&lt;/h1&gt;
  {% if entries | length %}
      &lt;ul&gt;
          {% for entry in entries %}
              &lt;li&gt;{{ entry.getLink() }}..&lt;/li&gt;
          {% endfor %}
      &lt;/ul&gt;
  {% else %}
      &lt;p&gt;No entries could be found with that tag.&lt;/p&gt;
  {% endif %}
  {% endif %}
  
  
  {% if craft.request.getSegment(3) !='' %}
  {% set tag2entries = craft.entries.relatedTo('and',
      { element: entry, field: 'tags' },
      { element: entries, field: 'tags' }
  ) %}
  {% set tag2entries = craft.entries.relatedTo(tag2-token) %}
  &lt;h1&gt;Entries tagged with “{{ tag.title }} and {{ tag-token2}}”&lt;/h1&gt;
  {% if tag2entries | length %}
      &lt;ul&gt;
          {% for entry in tag2entries %}
              &lt;li&gt;{{ entry.getLink() }}..&lt;/li&gt;
          {% endfor %}
      &lt;/ul&gt;
  {% else %}
      &lt;p&gt;No entries could be found with those tags.&lt;/p&gt;
  {% endif %}
  {% endif %}
  
  {% if craft.request.getSegment(4) !='' %}
  {% set tag3entries = craft.entries.relatedTo(tag3-token) %}
  &lt;h1&gt;Entries tagged with “{{ tag.title }} and {{ tag-token2}} and {{tag-token3}}”&lt;/h1&gt;
  {% if tag3entries | length %}
      &lt;ul&gt;
          {% for entry in tag3entries %}
              &lt;li&gt;{{ entry.getLink() }}..&lt;/li&gt;
          {% endfor %}
      &lt;/ul&gt;
  {% else %}
      &lt;p&gt;No entries could be found with those tags.&lt;/p&gt;
  {% endif %}
  {% endif %}
  </code></pre>
  
  <p>I'm am not sure how to go about using the relatedTo() function to filter entries based on those 3 tag parameters in the URL.</p>
  
  <p>Any insight on how to go about this?</p>
  
Tags: <templating><tags><filtering>
Title: Display entries that meet multiple tag params
ThreadText: # Display entries that meet multiple tag params
  
  (Asked by: username_0 on 2016-12-03)
  
  how would I go about setting up a route and twig template to filter by multiple tags?
  
  ```
  Example URL scheme: example.com/tags/tag1/tag2/tag3
  
  ```
  
  where `tag1`, `tag2` and `tag3` are tags defined in a tag field inside an entry. The resulting entries list should only output entries with `tag1` **AND** `tag2` **AND** `tag3`. `tag2` and `tag3` should be optional. I want to avoid the use of get params such as ?tag=tag1,tag2,tag3.
  
  The ultimate goal is chain multiple tags to get finer results, similar to pinboard.in tag chaining.
  
  Example:<https://pinboard.in/t:javascript/t:css/t:webdev>
  will return entries with `javascript` AND `css` AND `webdev`
  
  ---
  
  My route looks as follows
  
  ```
  URI: tags/tag-token/tag-taken2/tag-token3
  
  ```
  
  and my twig template looks like
  
  ```
  {% set entries = craft.entries.relatedTo(tag) %}
  
  {% if craft.request.getSegment(2) !='' %}
  <h1>Entries tagged with “{{ tag.title }}”</h1>
  {% 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 %}
  {% endif %}
  
  {% if craft.request.getSegment(3) !='' %}
  {% set tag2entries = craft.entries.relatedTo('and',
      { element: entry, field: 'tags' },
      { element: entries, field: 'tags' }
  ) %}
  {% set tag2entries = craft.entries.relatedTo(tag2-token) %}
  <h1>Entries tagged with “{{ tag.title }} and {{ tag-token2}}”</h1>
  {% if tag2entries | length %}
      <ul>
          {% for entry in tag2entries %}
              <li>{{ entry.getLink() }}..</li>
          {% endfor %}
      </ul>
  {% else %}
      <p>No entries could be found with those tags.</p>
  {% endif %}
  {% endif %}
  
  {% if craft.request.getSegment(4) !='' %}
  {% set tag3entries = craft.entries.relatedTo(tag3-token) %}
  <h1>Entries tagged with “{{ tag.title }} and {{ tag-token2}} and {{tag-token3}}”</h1>
  {% if tag3entries | length %}
      <ul>
          {% for entry in tag3entries %}
              <li>{{ entry.getLink() }}..</li>
          {% endfor %}
      </ul>
  {% else %}
      <p>No entries could be found with those tags.</p>
  {% endif %}
  {% endif %}
  
  ```
  
  I'm am not sure how to go about using the relatedTo() function to filter entries based on those 3 tag parameters in the URL.
  
  Any insight on how to go about this?
  
  **Tags:** templating, tags, filtering
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2016-12-04. Score: 1 | Accepted answer
  
  Ideally, you'll use a dynamic route that can match any number of tags – negating the need to hard code the number of possible tag segments.
  
  You can't pull this off using the Routes admin inside the CP, so crack open your **/craft/config/routes.php** file and add this:
  
  ```
  return array(
      'tags/(.+)' => 'path_to_your_tags_template',
  ); 
  
  ```
  
  The above route can have any number of segments under `/tags`, but will require at least one. *Be sure to delete any conflicting routes defined in Settings -> Routes!*
  
  Inside your tags template, you can get an array of all the tags in the URI like this (the `|slice(1)` part removes the first segment, i.e. "tags"):
  
  ```
  {% set tagSegments = craft.request.segments|slice(1) %}
  
  ```
  
  To pull the actual tags, you can do something like this:
  
  ```
  {% set tags = craft.tags.slug(tagSegments) %}
  
  ```
  
  Pulling it all together, here's how a (simplified) version of your template could look:
  
  ```
  {# Get tags #}
  {% set tagSegments = craft.request.segments|slice(1) %}
  {% set tags = craft.tags.slug(tagSegments) %}
  
  {# Get entries related to tags #}
  {% set relatedTo = [] %}
  {% for tagId in tags.ids() %}
      {% set relatedTo = relatedTo|merge([{
          targetElement: tagId,
          field: 'tags'
      }]) %}
  {% endfor %}
  {% if relatedTo|length > 1 %}
      {% set relatedTo = ['and']|merge(relatedTo) %}
  {% endif %}
  {% set entries = craft.entries.relatedTo(relatedTo) %}
  
  {% if entries|length %}
      <h1>Entries tagged with {% for tag in tags %}{{ tag.title }}{% if not loop.last %}{{ loop.revindex == 2 ? ' and' : ',' }}{% endif %}{% endfor %}</h1>
      <ul>
          {% for entry in entries %}
              <li>{{ entry.getLink() }}..</li>
          {% endfor %}
      </ul>
  {% else %}
      <p>No entries could be found with {{ tagSegments|length > 1 ? 'those tags' : 'that tag' }}.</p>
  {% endif %}
  
  ```
  
  > **Comments:**
  > **username_0**: Thanks for your help! This (kinda) works. The problem is that it returns all posts that contain one of these tags. It should return posts that match all  the tags. Its returning as if the tags are being OR'd and not ANDed which seems strange since 'and' is clearly being defined inside the relatedTo() function.  
  > **username_1**: @username_0 Yeah, that's a little strange. I've updated my answer with an alternative, more convoluted but possibly more robust solution. Another thing you could try is simply `craft.entries.relatedTo('and', tags.ids())` (i.e. without joining the array of IDs). Sorry, don't have time to test either of these solutions right now.  
  > **username_0**: Thank you! Your updated solution seems to work. I appreciate the help.  
  
  ---
  
  