Drupal 7 Feeds Tutorials - Importing iCal

I'm going to go through a basic tutorial here today on importing iCal addresses into your Drupal 7 site as nodes. While there are already several modules that allow you to show your google (or other) calendar data on your site, importing your calendar with those modules usually has a few restrictions, such as limiting the specific data you can show, and not having very good methods for customizing your style. Using Feeds to import the data as nodes allows you to bring an events calendar to your site that is 100% customizable by you, the same way any other nodes on your site are customized.

Note: Drupal 7 uses mostly different modules from Drupal 6, however the modules work very similarly. So while I will not be going over D6 options in this tutorial, a lot of what you see here can be used in Drupal 6.

Here are the specific modules related to this tutorial you will need to install to make this work:

Several of these modules have required modules to make them work - make sure you also have those installed.

You will also need to make sure the iCalCreator library is installed in your /sites/all/libraries directory.

Note: As of this writing (Oct, 2013), the most recent version of Feeds (2.0-alpha8) has a minor issue with some servers. The issue is described here, and if you run into the same issue, you may be able to use the solution in post #6 to bypass the issue until the module is updated.

Enable your modules, make sure there are no errors & bugs, and let's begin.

1 - Create an Event content type

The first thing we want to do is make sure we have a content type to import our iCal into. To make it into a proper event feed, there is only 1 necessary additional field other than title - and that is date. We'll use a few more, so that you can see some other cool options with the importer.

Create a new content type called "Event". I usually rename the title under the content type settings to "Event Name," just to be a bit more descriptive in case it's ever someone other than myself creating content, but that's entirely up to you. I also usually immediately delete the default body field, but you can definitely use that for the Description field I will detail below. Your choice.

We'll create three new fields.

Event Date and Time

Name it whatever you want, again, I typically try to be pretty descriptive. Make sure to use a proper machine name - good practices usually include the nodetype name (for instance, I gave this field a machine name of " field_event_date_time " ). Select Date as the field type, and for the widget, use the pop up. For this tutorial, just use all the default settings.

Event Location

Again, name it how you will. Set this to be a text field, and use the default settings.

Event Description

If you used the default body field, skip this. Otherwise, create a field called "Event Description," and set it to the text area field type. Default settings.

Here is what mine looks like:
Event Node Type

Now, let's grab your calendar address and create a feed.

2 - Create a Feed Importer

We will now create the feed importer. Before we begin, let's go ahead and grab your calendar address.

Get your iCal Address

Go to your public google calendar (or any other calendar that uses ical addresses), head into that calendar's settings, and get the ical address. (Note - make sure you have some dates filled out, or you won't be importing anything!) This is what your calendar settings page should look like:

Google Calendar Settings

In the image above, you see I've hilighted the ical link you're looking for with a bright red box. Click that link and then copy the full address.

Now, let's create the feed itself.

Main Feed Settings

Go to /admin/structure/feeds/create

Give the feed a title. I titled mine: iCal Feed Importer. Very clever, eh?

Once created, it takes you to a feed settings page. This page can be a bit confusing if you don't know what you're doing, so we'll go through each detail relating to our iCal setup.

Feed - Basic Settings

Under Basic Settings, you will see that you have quite a few options. You have the opportunity to rename your importer, and you also have a few others. The first, "Attach to Content Type" can be a bit misleading if you're not aware of all the other options. This selection will add a feed importer to every new node edit created with the selected content type. So for instance, if you were to select "Event" from that list, every time you created a new "Event" node, it would ask you for a feed address. This is not the preferred method for what we're doing, since it requires you to create a node just to import other nodes. We may go through this option in a later tutorial, but for now, leave on "Use Standalone Form."

The next few options should be pretty self-explanatory.

The "Periodic Import" just names the amount of time that the importer waits before checking the iCal address for new content. On most smaller sites, you could probably set this to "12 hours" or "1 day" with no problems.

The "Import on Submission" checkbox is just what it says. If you have it checked (which it is, by default), then as soon as you create a new import, it will immediately import all the data, instead of waiting for the amount of time in the "Periodic Import" above. If unchecked, the feed will not import the data until the next scheduled time.

Finally, the "Process in background" checkbox has a pretty detailed description of what it does. We'll leave it blank for this.

Feed - Fetcher

Leave all these settings to default for this tutorial.

Feed - Parser

Select "Change" next to Parser, and select "iCal parser". Save.

Now you will see that below Parser, you have settings for "iCal Parser." By default, there are no extra settings to configure here.

Feed - Processor

Make sure the main Processor settings are set to "Node processor." Save.

Next to "Node Processor" you should see a settings link. Click it.

For "Bundle", select your event node type. The next few settings can be a bit confusing, so we'll look at them one at a time.

Under "Update Existing Nodes", you see three options. The first option, Do not update existing nodes, is selected by default. This means that whenever your importer imports data, it will simply create all new nodes for everything it imports. This is not the preferred method. The second option, Replace existing nodes, is slightly better. This option will delete existing nodes with the same title, and create new nodes of that title. This is an acceptable method, but we will use the third option, Update existing nodes. This option will take any new, updated, or changed data from the import, and update the nodes that already exist. Note - the helper text mentions "Unique target." This is very important, and we will get to it in the mapping section.

The "Skip hash check" checkbox is empty by default. We will leave it this way. If checked, then every time the importer ran, it would update (node_save) the content that exists, even if no changes were made.

"Text Format" should be pretty self explanatory. I leave mine to Plain Text, as I like full control of my styling through css.

"Author" will simply automatically assign the user to the nodes created. I typically assign to my user 1 account.

"Authorize" does exactly what it says. It checks that the person creating the import has permissions to do so. For security's sake, I always leave this checked.

"Expire Nodes" is also pretty self explanatory. Note - The date it uses to decide whether to expire the node is based on the node published date, not the event date field. Keep that in mind if you use this option.

Now let's look at the most important part, mapping.

3 - Mapping the Data

Under the Node Processor settings, there is a link for "Mapping." Click it.

This is the settings page where we determine how exactly our importer reads the data, and maps to our node fields. There is actually a certain order that they need to go in for them to work correctly.

The "Source" column is used to select from where the mapping occurs. It relates specifically to the actual calendar you are importing from. The "Target" colum is used to select to where the data is mapped, in your nodes.

In the Source column, select "Date start." In your Target column, select the field name you used for your event date field - make sure you use the "Start" option provided (you will see in the screenshot below). Mine says: "Event Date and Time: Start." Save. You will need to save after each step of the process.

Now in the Source column, select "Date end." Then in your Target column, select the same field name from before, but choose the "End" option. Mine says: "Event Date and Time: End." Save again.

In Source column, select "Summary." This is typically what the calendar uses for the title. In the Target column, map it to "Title." Save.

Once you save it, you will see that this particular section has a new settings option - "Not used as unique." Click the settings icon and check the "Unique" box, then Update. This will make sure that each node created is using a unique title - it will check against previous titles, and if a similar title already exists, it will update that node, instead of creating a new node.

In the Source column, select "Location text," and in the Target column, map this to whatever you named your location field. Mine says: "Event Location." Save.

Finally, in the Source column, select "Description," and in the Target column, map this to whatever you named your description field (or your body field, if you used the default body field for your node). Mine says: "Event Description." Save.

Here is what my mapping page looks like:

This wraps all the mapping we will be doing, but as you can see, there are plenty of other options available, such as using date repeat options, mapping a url for the calendar item, etc. You can play around with these, but most of them are typically not used in events calendars.

Now let's import the data and see what happens.

4 - Importing

Using the "Standalone Importer" option we set up in the feed means that there is one specific place from which we will do all our importing: /import (www.example.com/import).

If you go to that page, you will see a list of all the importers you have available as standalone importers. If this is your first time doing this, you should only see one, but you can have as many separate importers as you want. Select the importer.

You will go to a small form that should say "No imported feeds," and has a field for you to input a URL. Remember the iCal address we had from way up above? Paste that in here, then click "Import." You will see an "initializing" box, and then when the page reloads, you should see a notice of a number of items imported. Let's look at them. Go to /admin/content, and select one of them.

If you followed the steps correctly, you should see a node that has all the data from the calendar. Here's what mine looks like:

Now that you have multiple nodes, you can do with them anything you would typically do with nodes - create views (or Calendar Views!), blocks, panels, whatever you want. You now have full control over your events, and if you have your cron set up properly, you should only ever have to update your calendar, and this importer will automatically bring in any new events whenever cron is run.

A few notes:

  • As of the time of this writing (Oct, 2013), there was a potential bug with date_ical where the date fields were not being filled in. This has been solved in the dev version of the module, and the new version should have the fix implemented
  • When mapping the fields, the Date start time must always come before the Date end time, due to the way the parser functions. This may seem obvious, but if you ever have dates not showing up, check first that Date start is above Date end.
  • I mentioned at the beginning of the tutorial that much of this process works for Drupal 6, but uses different specific modules. Here are the modules you will need if using D6: Feed API, iCal Feed Parser, Date