Downloadable iCalendar Files

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.

  1. Install the “Download Content” plugin.
  2. Create your iCalendar format template.
  3. 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.

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'}
{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:

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.

Derek Jones's avatar
Derek Jones

Derek has been making software since age six, crossing over into video and music production, graphic design, and even retail management before helping build ExpressionEngine at EllisLab.

Comments 0

Be the first to comment!