I have a template, /calendar, which outputs a list of all entries from the events channel. If a user clicks a link for "July 2015", I want the same template to load showing only the events for July 2015. I can fetch the entries for a given month with something like this.

{% set setMonth = '2015-07' %}

{% set firstDay, lastDay
   setMonth ~ '-01', 
   setMonth ~ '-' ~ setMonth|date('t')
{% set after, before
   firstDay|date_modify('-1 day')|date('Y-m'), 
   lastDay|date_modify('+1 day')|date('Y-m')

{% set events = craft.entries.section('events').after(after).before(before)

I want to pass the date that will be assigned to setMonth in the URL using something like /calendar/2015-07, but I currently get a 404 error.

How can I pass the date in the URL without throwing a 404?

To make it even more complex, this template can also be filtered by category, so there would also be times the URL would look something like /calendar/catslug/2015-07. In this case, the template should display only the July events from the catslug category.

Assuming I can conquer the aforementioned 404 problem, will Craft still recognize /calendar/catslug/2015-07 as a category-triggering URL, or will the addition of the date segment break that functionality?

I suspect this isn't as difficult as I'm making it, so any assistance is appreciated.

Thanks in advance.

  • This answer might answer your question. If not, leave a comment, and I can try and clarify. Commented Jun 27, 2015 at 17:03
  • I agree with @DouglasMcDonald: you should look into routes for this. Commented Jun 28, 2015 at 6:18
  • I have the date filter working with routes now, so thanks for that pointer. For the second part of my question, is there any way to do this without breaking category functionality. /calendar/catslug/2015-07 causes Craft to no longer recognize catslug as a category indicator, so any category-based filtering is lost. Commented Jun 29, 2015 at 14:22

1 Answer 1


As mentioned in the comments, using a dynamic route is good method to create a date based uri (i.e. 'calendar/[year]-[month]'). See this answer for an example.

Adding 'category' into the route is a little more difficult, since there is no 'category' tag built into the dynamic route settings. However, you can use the wildcard * as part of the route for what would be the category (or anything else for that matter) — and then retrieve it using craft.request.segment method.

Dynamic route (which points to your 'calendar' template)


(note: using calendar/[slug]/[year]-[month] might also resolve to a category entry — don't know, but worth a try.)

Calendar template

{% set categorySlug = craft.request.segment(2) %}
{% set category = craft.category.slug(categorySlug).first %}
{% if year is defined and month is defined %}
    {% set startMonth = year ~ '-' ~ month ~ '-' ~ 1 %}
{% else %}
    {% set startMonth = now|date_modify("first day of this month") %}
{% endif %}
{% set nextMonth = startMonth|date_modify('+1 month')) %}
{% set previousMonth = startMonth|date_modify('-1 month')) %}

{% set entries = craft.entries.section('calendar').postDate('and', '>= ' ~ startMonth, '< ' ~ nextMonth).relatedTo(category) %}

{% for entry in entries %}
    {{ entry.title }}
{% endfor %}

<div class="pagination">
    <a href="{{ 'events/' ~ category ~ '/' ~ nextMonth|date("Y-n") }}">next month</a>
    <a href="{{ 'events/' ~ category ~ '/' ~ previousMonth|date("Y-n") }} ">previous month</a>

Advanced route method

If you want to be more specific in your route, then you can also set up an advanced route using named sub-patterns, which you can add to craft/config/routes.php, that will provide named variables to your template for 'category', 'year' and 'month'. Something like,

'calendar/(?P<category>\w+)/(?P<year>\d{4})/(?P<month>\d{2})' => 'calendar/_index',

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.