This tutorial will show you how to create downloadable iCalendar files. With ExpressionEngine, it’s easy-peasy because you can use your well-structured content however you need. You can use the same entries you use for your web site to create shareable .ics
iCalendar format files. Here’s how in three easy steps.
- Install the “Download Content” plugin.
- Create your iCalendar format template.
- Build a link to your iCalendar template.
Install the free Download Content plugin
In order to make your ExpressionEngine-generated .ics
files be treated like a downloadable file, grab and install the free Download Content plugin.
- Download the plugin from GitHub.
- Unzip and upload the enclosed download_content folder to
/system/user/addons
. - Visit the Add-on Manager in your control panel, and click Install for the “Download Content” plugin.
Create your download template
Now we need to create an endpoint that we will link to that allows our visitors to download our .ics
file. In this example, I’m creating an iCalendar file for a free concert the local brewpub is putting on. I have created a template named add-to-my-calendar
inside my concerts
template group.
It uses the entry date and expiration date of the concert, the title, and a custom field called meta_description
. Side note: meta_description
is part of my standard set of SEO fields that I add to every channel. Repurposing it for the description of the calendar event makes sense. I’m also going to take advantage of a few iCalendar fields to setup a default alarm two hours before the event.
{exp:channel:entries channel='concerts' limit='1' show_future_entries='yes' require_entry='yes'}
{if no_results}
{redirect='404'}
{/if}
{exp:download_content filename='{url_title}.ics'}
BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
UID:{url_title}-{entry_date format='%Y%m%d'}@{site_name:url_slug}
DTSTART;TZID={entry_date format='%e:%Y%m%dT%H%i%s'}
DTEND;TZID={expiration_date format='%e:%Y%m%dT%H%i%s'}
SUMMARY:{title}
X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC
LOCATION:The BrewPub\n62950 NE 18th St\nBend\, OR 97701
BEGIN:VALARM
X-WR-ALARMUID:{url_title}-{entry_date format='%Y%m%d'}@{site_name:url_slug}
TRIGGER:-PT120M
DESCRIPTION:{meta_description}
ACTION:DISPLAY
END:VALARM
END:VEVENT
END:VCALENDAR
{/exp:download_content}
{/exp:channel:entries}
Let’s break down the tags:
{exp:channel:entries channel='concerts' show_future_entries='yes' limit='1' require_entry='yes'}
-
show_future_entries=
lets us use the Entry Date as the start time of the event. Since we want people to see events that haven’t happened yet, we tell the Channel Entries tag to show future events. -
limit='1' require_entry='yes'
is a common design pattern for single-entry templates. This makes sure we only show one entry, and we don’t want it to display anything if the URL title is invalid. We combine it with:
{if no_results}
{redirect='404'}
{/if}
If there are no results—an invalid URL, an entry that’s already expired, a closed status, etc.—we will have proper 404 behavior.
The next tag is the Download Content plugin we installed earlier.
{exp:download_content filename='{url_title}.ics'}
Using the entry’s URL title for the filename isn’t a requirement, but it will help the visitor identify the file’s purpose after downloading. It needs an .ics
extension so desktop and mobile calendar apps know that the file is for them. This plugin makes sure the output only contains what’s inside the plugin’s tag, and gets treated as a download instead of displaying it on the screen.
Note: iCalendar files are picky about whitespace. This is why the code is not indented like we would normally encourage.
The rest of the contents are made from standard iCalendar file format attributes. You can read more about that file format and its attributes here: iCalendar file format. Here are some notes to help dissect our template decisions:
-
UID:
Providing a UID allows the calendar app to change the existing event if it is updated. Otherwise adding a new version will create a new event. The URL title, date, and site name should give us a unique ID. The:url_slug
variable modifier replaces spaces with slashes and so forth so we can use the site’s name here. -
DTSTART/DTEND:
The format parameter used here (%e:%Y%m%dT%H%i%s
) will output:America/Los_Angeles:20180827T105300
- We use the
entry_date
for the start date and the expiration_date for the end date. -
SUMMARY
uses the entry’s title for the event’s name - Some calendar apps may not use the DESCRIPTION, but we add it for those that do. - Likewise, we add
DTSTAMP
because Outlook demands it. -
TRIGGER:-PT120M
sets an alarm for 120 minutes (2 hours) before the event -
X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC
sets an alarm for Apple clients when the person needs to leave their current location to make it to the event on time.
Create a download link
Now all we need to do is link to our .ics
file and we’re good to go! From my concert listing page, I’ll add:
<a href="{url_title_path='concerts/add-to-my-calendar'}">Add this concert to my calendar!</a>
Now when I click the link, it downloads a properly formatted .ics
file that I can add to my calendar!
With this knowledge you can create events, todos, journal entries, and any other kind of iCalendar file you can imagine. Use these same principles to output your content in other file formats, too; the sky’s the limit! With ExpressionEngine, you never have to work hard to make your content work hard for you.
Top comments (0)