Best way to approach an events calendar

I am trying to build an events calendar into a project, and am struggling how to approach it. I am pretty new to Kirby, but I have looked through the forums and can’t quite find the answer to what I am looking for. Apologies for the wall of text!

tldr; I can’t figure out a good way to create an events calendar with repeating events and a list/detail setup that doesn’t create duplicate page URLs or require manual intervention from the editor.

At the most basic, each event requires:

  • eventTitle
  • eventStartDate
  • eventStartTime

It’s important to note, though, that some events repeat, and so wouldn’t have a unique Title. Think “Quarterly review”.

I went down the path of using mzur’s calendar plugin, and this seems promising. The plugin is based around the structure field, which is a good option for a bunch of repeating events mixed in with more detailed events. It’s easy to duplicate rows and modify the non-common data, like the date, which makes adding a bunch of events easy for the editor. I have that working just fine, but I end up with just a basic list view, where ideally I also need a detail page view, with a unique shareable URL and a place to output the sometimes blog-like post info for some “flagship” events.

My actual question:

Here’s where I get stuck: how would I then generate a separate (virtual) page for every item within the events structure field? (Is that even the right question to be asking?)

I thought about trying to generate a slug, but it appears the slug “sync” option only works with a single field, so entries with the same title would generate the same slug.

I have also tried a different approach using pages:

While trying to implement the events calendar using pages (/events/eventPage) rather than the structure field I run into a similar problem: unless the editor types the date into the title field when creating the page (or otherwise makes it unique) I can’t have the page url be /events/eventStartDate-eventTitle. I have looked at a page model that appends today’s date to the field, but that doesn’t really solve the problem as I need the URL/slug to be made unique by combining the event start date with the event title, so I end up with ex:

/events/2023-09-08-review-meeting
/events/2023-10-10-review-meeting
/events/2023-11-06-review-meeting
etc.

It may be possible to use the Custom Add Fields Plugin – I haven’t tried this yet – but this I presume only works when generating a new page. So if duplicating a page the URL would have to be manually updated, rather than being dynamically regenerated from the event_start field within the page’s blueprint.

Am I missing something obvious?

So far my experience with Kirby has been fantastic, and there’s always been a solution to whatever I am trying to do. This seems like an obvious use case, so what am I missing here? :thinking:

Thanks!

When you are using the page approach, you should get a new uuid for each page, I think. And each page then also comes with a permalink using the uuid: Unique IDs & Permalinks | Kirby CMS

Maybe that is a solution, if you do not need to use speaking urls

On a side note, made a plugin for generating repeating dates you might find useful GitHub - HashandSalt/kirby-recurr: Plugin for listing recurring dates

and its partner in crime

GitHub - HashandSalt/kirby3-yasumi which will let generate a list of public holidays for a year / country. Theres an example in the read me for filtering out Recurr events that fall on a public holiday when the venue will closed, for example.

1 Like

Hi Maurice!

I think I still run into the same issue when creating the event pages, I.e that I would still require the editor to create a unique title in order to generate the file name. So while two events with the same title would theoretically each have a unique identifier, I don’t get that far because the folder names themselves end up clashing.

Perhaps it’s possible perhaps to have the UID be the folder name upon page creation, (which I might achieve with a page model?), though I would certainly prefer a readable URL if possible. But it is something to consider, thanks for your input!

I did see those plugins, they look very helpful. In this case the ‘recurring’ nature of these particular meetings reads like a regex pattern (“the monthly meeting is held every 3-1/2 to 5 weeks but not if it falls on the 2nd, 11th, or Friday the 13th, nor days that being with a T, and certainly not in June but always in August, unless Mercury is in retrograde…”) :upside_down_face:

But I’ll certainly have a closer look I’m sure! Thanks for the input.

A little update: the structure field proved to be workable by creating a virtual page for each structure item:

'routes' => [
  // EVENT PAGE ROUTES
  [
    'pattern' => 'event/(:any)',
    'action' => function ($slug) {
        $parentPage = page('calendar');
        $event = null;

        foreach ($parentPage->calendar()->toStructure() as $item) {
            if ($item->event_slug() == $slug) {
                $event = $item;
                break;
            }
        }
        if ($event) {
            return new Page([
                'slug' => 'event/' . $slug,
                'template' => 'event',
                'content' => [
                  'beginDate'   => $event->_begin_date(),
                  'beginTime'   => $event->_begin_time(),
                  'endDate'     => $event->_end_date(),
                  'endTime'     => $event->_end_time(),
                  'title'       => $event->event_title(),
                  'text'        => $event->description()->kt(),
                ]
            ]);
        }
        return false; // Location not found
    }
  ]
]

In the structure blueprint, I am generating the slug based on the _begin_date:

calendar:
    label: Events
    type: structure
    fields:
    _begin_date:
        label: Start date
        type: date
        display: YYYY-MM-DD
        required: true
    # truncated for brevity
    event_title:
        label: Title
        type: text
        required: true
    event_slug:
        label: Slug
        type: slug
        sync: _begin_date

This is so very close, and I am able to successfully generate event detail pages at URLs like domain.com/event/event_slug.

Now I am back to the original issue: if two events have the same _begin_date, it generates the same slug and requires the editor to a) notice this and b) modify the slug.

Is there any way I can use two fields to generate the slug?, such as _begin_date + event_title? The slug doesn’t have to be visible to the editor, but it does need to update in real-time, like the sync feature of the slug field does (i.e., if the _begin_date or event_title fields change the slug should update to match).

Thanks again!

There’s no direct built-in feature to get you that. However, I could imagine that using page hooks would be a way to generate something unique on create and make sure it stays in sync on each update. Hooks | Kirby CMS