Display entries that meet multiple tag params 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) !='' %}
&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 %}


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?
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/(.+)' =&gt; '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 &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 %}