I am fairly new to twig and templating with Craft (and I have inherited this code, so that makes it even more fun).

I have a calendar page that lets you filter the events in the calendar based on a venti group (using the Venti Calendar plugin to create those groups).

How it currently works is that whatever group filter is selected, the url updates to have that group ID as the last segment.

Filter Names and their IDs: Cinema = 1, Theatre = 2, Events = 3, Education = 4

If a user is looking at the events for the month of December 2017 with no filters, the url looks like this:


If a user is looking at the events for the same date, but has a filter applied (in this case, the "Cinema" filter), the url looks like this:

example.com/month/2017/12/1 Cinema has group ID of 1 so 1 is the last segment.

In order to change the applied filter without resetting the date, I want to trim the last segment from the url, and replace with the new ID as the last segment. Doing this works completely as expected unless the last segment and the last character of the previous segment are the same number (e.g., example.com/month/2017/12/2).

In this case, if I am currently on this URL, and I want to change to a different filter (in this example we change to use Cinema Filter = 1), the following happens.

example.com/month/2017/1/1 where it should actually be example.com/month/2017/12/1

So what is happening is that it is trimming the 2 from the last segment and the segment before the last segment.

Here's the code for the filter buttons:

    {% set groups = craft.venti.groups() %}
    {% for group in groups %}      
        <a class="button" href="
            {% spaceless %}
            {% if craft.request.getLastSegment() in ['1','2','3','4'] %}       
                {{url(craft.request.path)|trim('/' ~ 
            {% else %}
            {% endif %}
            {% endspaceless %}">
            {{ group }}
    {% endfor %}

If I remove '/' ~ from this: {{url(craft.request.path)|trim('/' ~ craft.request.getLastSegment())}}/{{group.id}}

It actually works perfectly, save for the fact that the new url looks like this: example.com/month/2017/12//1 With the addition of that second backslash.

Can anyone see what I am doing wrong here, or provide any help? If you need more of my code, please let me know.

Thank you!

3 Answers 3


Twig's |trim filter is just a wrapper for PHP's trim() method, which says:

Strip whitespace (or other characters) from the beginning and end of a string

So in your example, you're telling it to strip all / and 2 from the beginning and end of the given string, which explains the output you're seeing.

I think you'll be better off by installing something like the Twig PCRE plugin, which gives Twig full access to the PHP preg_ regex methods.

Then you'd just do a preg_match to target exactly what you're looking for and replacing it with new values as necessary.

  • Ahhh I see! Ok yeah, this isn't going to work then. The better solution obviously is to use the filter names/handles instead of ids in the url, but I didn't want to start doing larger changes like that if I didn't have to. But, it looks like that'll be the way to go. I'll mark this as accepted answer.
    – jkilp
    Nov 28, 2017 at 14:31

Instead of doing complicated things with the result of getLastSegment(), can't you just get the 4th segment using getSegment(4)?

If the segment you’re interested in is not always in the same position, you could use getSegments() and conditionally grab a part depending on count of segments returned.

{% set segments = craft.request.getSegments() %}
{% set filter = segments|length == 4 ? segments[3] : segments[1] %}
  • Unfortunately, no. The number of segments changes. The default url when you load the page (with filters applied) would be example.com/month/1 So it omits the date segments from the url. You don't see the date segments until you start changing the date on the calendar.
    – jkilp
    Nov 28, 2017 at 14:29
  • @jkilp updated my answer to account for that case
    – carlcs
    Nov 28, 2017 at 17:23
{{ entry.url|split('/')[:-1]|join('/') }}

This splits the url string into an array, uses the syntactic sugar version of the slice filter to cut the last item off, then joins them back together as a string.

Could also do /{{ craft.app.request.segments[:-1]|join('/') }} depending on your use case.

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.