I'm using Craft 3, and I'm struggling to make sense of how to address the following. (I've not had need to venture into a third URL segment before.)

I have a url of the form:


served by a template:


I'm aware that the 'entry' variable gets set automatically. So far so basic.

But I also want to address urls of the form:


…where variable is used to fetch content from a specific Matrix row in the entry that matches slug.

It is important that variable forms a third segment addressable as its own page, and not just a URL query parameter.

I have tried 2 approaches:

  1. Getting segment 3 and then using it in a conditional inside of stories/_entry:

{% set seg3 = craft.app.request.getSegment(3) %} {% if seg3|length %} {% include 'partials/extract' %} {% else %} {% include 'partials/story' %} {% endif %}

…but when seg3 is not empty Craft says:

Template not found

  1. Setting a route to a different template:


…is processed by:


…in which, as a basic test I have:

{% block meta %}
    <title>{{ entry.title }}</title>
{% endblock %}

…but Craft then reports a Twig runtime error, saying:

Variable "entry" does not exist

So I tried using:

{% set seg2 = craft.app.request.getSegment(2) %}
{% for entry in craft.entries.section('stories').slug(seg2).all() %}
    {% block meta %}
        <title>{{ entry.title }}</title>
    {% endblock %}
{% endfor %}

…but that makes no difference.

Is my approach 2 definition of entry wrong?

Why does a non-empty value in segment 3 cause approach 1 to fail?

I'm obviously missing something fundamental here. Any pointers much appreciated.


1 Answer 1


I would suggest you look into using Craft's Advanced Routing functionality to accomplish this.

For instance, add the following to your config/routes.php:

'stories/<slug:\w+>/?<option:\w+>?' => ['template' => '_extract'],

This will then populate the _extract template with the twig variable {{ slug }} and also the {{ option }} variable, if it exists.

Then in your twig template you can grab the entry and check for the existence of the option variable thus:

    {% set entry = craft.entries.section('stories').slug(slug).one() %}

    {% if entry %}
            <h1>Entry title is: {{ entry.title }}</h1>
    {% endif %}

    <h2>Slug is: {{ slug }} </h2>

    {% if option is defined %}
            <h3>Option is: {{ option }}</h3>
    {% endif %}

I'd recommend reading the docs on Advanced routing as it's quite a powerful feature: https://docs.craftcms.com/v3/routing.html#advanced-routing

  • Belated thanks for this, Piaras. With Brad @ P&T's help on a support ticket, I'd already arrived at my fundamental mistake which was setting entry with .all() instead of .one(), and then everything fell into place. I just hadn't properly grasped when to use those methods, but the newly revised v3 docs are a lot clearer. May 16, 2018 at 13:45

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.