This shows how to generate “Add to Calendar” links for Google, Outlook, iCalendar (.ics), etc. using fields from a Drupal entity. 

Back to top

We are going to use the Spatie Calendar Links library (https://github.com/spatie/calendar-links) to generate "Add to Calendar" links from entity fields. 

From your project root run :

composer require spatie/calendar-links

The main class you’ll use is: Spatie\CalendarLinks\Link;

Back to top

Load the Entity and Resolve the Event Dates

Assume you’re passing $entity_type_id, $entity_id, and a datetime field name (e.g. field_event_date):

$entity_id = 123;
$entity_type = 'node';

// Load the entity.
$storage = $this->entityTypeManager->getStorage($entity_type);
$entity = $storage->load($entity_id);

Now extract the start/end from a date field on a fieldable entity:

use Drupal\Core\Entity\FieldableEntityInterface;

$field_name = 'field_event_date';

if ($entity instanceof FieldableEntityInterface && $entity->hasField($field_name) {
  $start = ($entity->get($field_name)->value ?? NULL));
  $end = ($entity->get($field_name)->end_value ?? $entity->get($field_name)->value ?? NULL));

  $label = preg_replace('/[\n\r]+/', ' ', $entity->label());
  $uid = $entity->uuid();

  // Normalize to UTC for the calendar providers.
  $tz = new \DateTimeZone('UTC');
  $startDate = new \DateTime($start, $tz);
  $endDate = new \DateTime($end, $tz);
} 
else {
  throw new \Symfony\Component\HttpKernel\Exception\NotFoundHttpException();
}
Back to top

Use Spatie’s Link::create() to build the calendar link:

use Spatie\CalendarLinks\Link;

$link = Link::create($label, $startDate, $endDate)
  ->description('Event generated from Drupal.') // Optional
  ->address('Your event address here');        // Optional

You now have a Link object that can output URLs or ICS content for multiple calendar systems.

Back to top

Generate an ICS File or Calendar Provider URL

For ICS, you may want to force a file download from a controller:

use Symfony\Component\HttpFoundation\Response;

$ics = $link->ics(['UID' => $uid], ['format' => 'file']);
return new Response($ics, 200, [
  'Content-Type'        => 'text/calendar; charset=utf-8',
  'Content-Disposition' => "attachment; filename=\"{$label}.ics\"",
]);

For other providers (google, outlook, yahoo), you can generate an "add to calendar" link:

// Google Calendar
$url = $link->google();

// Outlook
$url = $link->webOutlook();

// Office365
$url = $link->webOffice();

// Yahoo
$url = $link->yahoo();
Back to top