Modifiable .ics files

👍 Gathering votes

It would be great if you could add the information within the .ics file that is sent after a booked appointment.

Currently, only the appointment name, time and date are stored there.

We would at least like to add the address and name of the company and the telephone number.

It would also be nice if the cancellation link could be stored there.

The same applies to the manually downloadable calendar entries for Google Calendar, Yahoo Calendar etc. after the appointment has been booked.

Translated with DeepL.com (free version)

Karen Lebowski

1 year ago

Activity
Nicholas

I was able to modify the ics output using the following in a custom plugin. This should be fairly easy to add for most anyone and allow you to modify it with some basic PHP skills. Modifications are all within the last function of this code.

Note that the generated ics files work perfectly on the Customer "On Approval" and "On Rescheduled" notifications, other ics file generation may not all run through the same filter I attached this to so they did not seem to work in my testing:


<?php
/**
 * Apply folding compliant with RFC 5545
 * See https://www.rfc-editor.org/rfc/rfc5545#section-3.1
 *
 * @param   string  $line       One line of the ical file including the property at the beginning
 * @param   bool    $strip_tags Strip HTML tags from the value
 *
 * @return  string              Returns the folded string with the property name at the beginning
 */
if (!function_exists('ical_split')) {
  function ical_split($value, $strip_tags = FALSE) {
    $value = trim($value);
    $value = preg_replace('/[\r\n]+/', ' ', $value);
    $value = preg_replace('/\s{2,}/', ' ', $value);
    list($preamble, $value) = explode(':', $value, 2);

    if ($strip_tags) {
      $value = strip_tags($value);
    }

    $value = $preamble . ':' . $value;
    $offset = 0;
    $chunkSize = 75;
    $lines = [];
    while ($line = mb_strcut($value, $offset, $chunkSize)) {
      $lines[] = $line;
      $offset += $chunkSize;
    }

    return $preamble . ':' . substr(join("\r\n\t", $lines), strlen($preamble) + 1);
  }
}

function tlp_replace_tokens(array $replace, $subject, $extra_replace) {
  $replacement_tokens = [];
  $replacements = array_merge($replace, $extra_replace);

  foreach($replacements as $key => $value) {
    $replacement_tokens['%' . $key . '%'] = $value;
  }

  $line = str_replace(array_keys($replacement_tokens), array_values($replacement_tokens), $subject);

  return $line;
}

/**
 * Get category name from service ID
 *
 * @param  mixed $service_id
 * @return string $category_name
 */
function tlp_bookingpress_get_category_name_by_service_id($service_id) {
  global $wpdb;

  $services_table = $wpdb->prefix . 'bookingpress_services';
  $categories_table = $wpdb->prefix . 'bookingpress_categories';
  $category_name = '';

  if (!empty($service_id)) {
    $category_name = $wpdb->get_var($wpdb->prepare("SELECT c.bookingpress_category_name FROM {$services_table} s, {$categories_table} c WHERE s.bookingpress_category_id = c.bookingpress_category_id AND s.bookingpress_service_id = %d", $service_id));
  }

  return stripslashes($category_name);
}

function tlp_get_bookingpress_appointment_extras($appointment_data) {
  $extras = json_decode($appointment_data['bookingpress_extra_service_details']);
  $extra_string = '';

  foreach ($extras as $extra) {
    $extra_string .= $extra->bookingpress_extra_service_details->bookingpress_extra_service_name . ', ';
  }

  return preg_replace('/,+\s*$/', '', $extra_string);
}

function tlp_parse_ics_string($string, $appointment_data, $more_ics = []) {
  $total_lines = array_filter(preg_split("/[\r\n]+/", $string));
  $starting_ics = array_slice($total_lines, 0, count($total_lines) - 4);
  $closing_ics = array_slice($total_lines, -4);

  $combined_ics = array_merge(array_values($starting_ics), array_values($more_ics), array_values($closing_ics));

  $extra_data = [];
  if (array_key_exists('bookingpress_staff_member_details', $appointment_data)) {
    $extra_data = (array) json_decode($appointment_data['bookingpress_staff_member_details']);
  }

  $extra_data['bookingpress_category_name'] = tlp_bookingpress_get_category_name_by_service_id($appointment_data['bookingpress_service_id']);
  $extra_data['bookingpress_appointment_extras'] = tlp_get_bookingpress_appointment_extras($appointment_data);

  $ics_string = '';
  foreach ($combined_ics as $ics_line) {
    $ics_line = tlp_replace_tokens($appointment_data, $ics_line, $extra_data);
    $split_ics_line = ical_split($ics_line);
    $ics_string .= "{$split_ics_line}\r\n";
  }

  return $ics_string;
}

/**
 * Manipulate how ics files are generated in bookingpress email attachments.
 */
function tlp_adjust_bookingpress_ics_data($string, $appointment_data) {
  $string = preg_replace('/SUMMARY\:[^\r\n]+/', 'SUMMARY:Company Name: %bookingpress_category_name% %bookingpress_service_name%', $string);

  $more_ics = [
    'LOCATION:Address',
    'DESCRIPTION:Stylist: %bookingpress_staff_first_name% %bookingpress_staff_last_name%\nService: %bookingpress_category_name% %bookingpress_service_name%',
//    'X-ALT-DESC;FMTTYPE=text/html:<html><body>Scheduled service: %bookingpress_service_name% <br />Link: <a href="#">Google Map</a></body></html>',
  ];

  $ics_string = tlp_parse_ics_string($string, $appointment_data, $more_ics);

  return $ics_string;
}

add_filter('bpa_add_timezone_parameters_for_ics', 'tlp_adjust_bookingpress_ics_data', 10, 2);

0    2 weeks ago    Reply

Comment must be at least 20 characters.
Cancel

We love to listen to our customers.

Nicholas

There is some token replacement that I use in the strings. The tokens are as follows with % signs around them. These are not the same as the notification interface.

    [bookingpress_appointment_booking_id] => 53
    [bookingpress_order_id] => 0
    [bookingpress_is_cart] => 0
    [bookingpress_booking_id] => 28
    [bookingpress_entry_id] => 53
    [bookingpress_payment_id] => 28
    [bookingpress_customer_id] => 25
    [bookingpress_customer_name] => First Last
    [bookingpress_username] => 
    [bookingpress_customer_phone] =>  123 456 7890
    [bookingpress_customer_firstname] => First
    [bookingpress_customer_lastname] => Last
    [bookingpress_customer_country] => US
    [bookingpress_customer_phone_dial_code] => 1
    [bookingpress_customer_email] => [redacted]
    [bookingpress_staff_member_id] => 3
    [bookingpress_staff_member_price] => 50
    [bookingpress_staff_first_name] => First
    [bookingpress_staff_last_name] => Last
    [bookingpress_staff_email_address] => [redacted]
    [bookingpress_service_id] => 6
    [bookingpress_service_name] => Service name
    [bookingpress_service_price] => 50
    [bookingpress_service_currency] => USD
    [bookingpress_service_duration_val] => 45
    [bookingpress_service_duration_unit] => m
    [bookingpress_appointment_date] => 2025-06-06
    [bookingpress_appointment_end_date] => 2025-06-09
    [bookingpress_appointment_time] => 18:30:00
    [bookingpress_appointment_end_time] => 19:15:00
    [bookingpress_edit_user_id] => 1
    [bookingpress_is_edited] => 1
    [bookingpress_buffer_end_time] => 
    [bookingpress_buffer_start_time] => 
    [bookingpress_appointment_customize_timing] => 0
    [bookingpress_appointment_internal_note] => 
    [bookingpress_appointment_send_notification] => 1
    [bookingpress_appointment_status] => 1
    [bookingpress_tip_amount] => 0
    [bookingpress_coupon_details] => []
    [bookingpress_coupon_discount_amount] => 0
    [bookingpress_tax_percentage] => 0
    [bookingpress_tax_amount] => 0
    [bookingpress_deposit_payment_details] => 
    [bookingpress_deposit_amount] => 0
    [bookingpress_selected_extra_members] => 1
    [bookingpress_extra_service_details] => []
    [bookingpress_price_display_setting] => exclude_taxes
    [bookingpress_display_tax_order_summary] => 1
    [bookingpress_included_tax_label] => (Inc. GST)
    [bookingpress_paid_amount] => 50
    [bookingpress_due_amount] => 78
    [bookingpress_total_amount] => 50
    [bookingpress_mark_as_paid] => 1
    [bookingpress_complete_payment_url_selection] => mark_as_paid
    [bookingpress_complete_payment_url_selection_method] => 
    [bookingpress_complete_payment_token] => 
    [bookingpress_purchase_type] => 1
    [bookingpress_package_id] => 0
    [bookingpress_applied_package_data] => 
    [bookingpress_package_discount_amount] => 0
    [bookingpress_offer_payment_discount_detail] => 
    [bookingpress_offer_payment_discount] => 0
    [bookingpress_online_payment_discount_detail] => 
    [bookingpress_online_payment_discount] => 0
    [bookingpress_location_id] => 0
    [bookingpress_location_service_price] => 0
    [bookingpress_location_service_capacity] => 0
    [bookingpress_location_staff_price] => 0
    [bookingpress_location_staff_capacity] => 0
    [bookingpress_waiting_payment_token] => 
    [bookingpress_is_recurring] => 0
    [bookingpress_is_reschedule] => 1
    [bookingpress_appointment_timezone] => 
    [bookingpress_selected_appointment_date] => 2025-06-06
    [bookingpress_selected_appointment_end_date] => 2025-06-09
    [bookingpress_selected_appointment_time] => 18:30:00
    [bookingpress_selected_appointment_end_time] => 19:15:00
    [bookingpress_dst_timezone] => 0
    [bookingpress_appointment_token] => L3RIJnp7dmYxNzQ5MjQ0NjA2
    [bookingpress_created_at] => 2025-06-06 14:16:46
    [bookingpress_google_calendar_event_id] => 
    [bookingpress_google_calendar_event_link] => 
    [bookingpress_outlook_calendar_event_id] => 
    [bookingpress_is_next_day_booking] => 0
    [bookingpress_customer_is_next_day_booking] => 0
    [bookingpress_is_past_appointment_edited] => 1
    [bookingpress_google_calendar_staff_id] => 0
    [bookingpress_outlook_calendar_staff_id] => 0
    [bookingpress_staffmember_id] => 3
    [bookingpress_wpuser_id] => 4
    [bookingpress_staffmember_position] => 1
    [bookingpress_staffmember_rating] => 0
    [bookingpress_staffmember_total_rating] => 0
    [bookingpress_staffmember_login] => [redacted]
    [bookingpress_staffmember_status] => 0
    [bookingpress_staffmember_firstname] => First
    [bookingpress_staffmember_lastname] => Last
    [bookingpress_staffmember_email] => [redacted]
    [bookingpress_staffmember_phone] =>  123 456 7890
    [bookingpress_staffmember_country_phone] => US
    [bookingpress_staffmember_country_dial_code] => 1
    [bookingpress_staffmember_created] => 2025-06-06 12:31:37
    [bookingpress_service_id] => 6
    [bookingpress_service_price] => 50
    [bookingpress_category_name] => Category name

0    2 weeks ago    Reply

Comment must be at least 20 characters.
Cancel

We love to listen to our customers.

Occo

I see this as a bug, it now creates an appointment in the customers calender which is more confusing then anything else.

Just give us some options which we want to have in there, maybe even a specific field where we can give parking instruction or something like that.

0    9 months ago    Reply

Comment must be at least 20 characters.
Cancel

We love to listen to our customers.

Khalil Antoun

Hello,

I think this is one of the urgent featured that should be there.
It's very confusing to have the ICS attached with nothing in it, it should be at least able to pick up the Event description, the slots.
When the bookings are virtual on zoom, it's important to have the zoom link attached in the ics.
I hope this feature will be worked on the soonest.
Thanks Karen
Looking forward that the amazing team at BookingPress fixes this issue

1    11 months ago    Reply

Comment must be at least 20 characters.
Cancel

We love to listen to our customers.

5 votes
Categories
🎉 Feature