Generate and send ICS file through WordPress

I'm writing a custom plugin for reservations. I need to generate an .ics file that needs to be sent to a predefined email address.

I've tried some library like ZContent iCalendar and a PHP script that I found on github that I've included inside my plugin code. The script works well and I can obtain a valid output. The problem is I can't figure out how to generate the ics file and attach it to an email using the wp_mail function.

Here is my code:

?php
/**
 * ICS.php
 * =======
 * Use this class to create an .ics file.
 *
 * Usage
 * -----
 * Basic usage - generate ics file contents (see below for available properties):
 *   $ics = new ICS($props);
 *   $ics_file_contents = $ics-to_string();
 *
 * Setting properties after instantiation
 *   $ics = new ICS();
 *   $ics-set('summary', 'My awesome event');
 *
 * You can also set multiple properties at the same time by using an array:
 *   $ics-set(array(
 *     'dtstart' = 'now + 30 minutes',
 *     'dtend' = 'now + 1 hour'
 *   ));
 *
 * Available properties
 * --------------------
 * description
 *   String description of the event.
 * dtend
 *   A date/time stamp designating the end of the event. You can use either a
 *   DateTime object or a PHP datetime format string (e.g. "now + 1 hour").
 * dtstart
 *   A date/time stamp designating the start of the event. You can use either a
 *   DateTime object or a PHP datetime format string (e.g. "now + 1 hour").
 * location
 *   String address or description of the location of the event.
 * summary
 *   String short summary of the event - usually used as the title.
 * url
 *   A url to attach to the the event. Make sure to add the protocol (http://
 *   or https://).
 */
class WP_ICS{
  const DT_FORMAT = 'Ymd\THis\Z';
  protected $properties = array();
  private $available_properties = array(
    'description',
    'dtend',
    'dtstart',
    'location',
    'summary',
    'url'
  );
  public function __construct($props) {
    $this-set($props);
  }
  public function set($key, $val = false) {
    if (is_array($key)) {
      foreach ($key as $k = $v) {
        $this-set($k, $v);
      }
    } else {
      if (in_array($key, $this-available_properties)) {
        $this-properties[$key] = $this-sanitize_val($val, $key);
      }
    }
  }
  public function to_string() {
    $rows = $this-build_props();
    return implode("\r\n", $rows);
  }
  private function build_props() {
    // Build ICS properties - add header
    $ics_props = array(
      'BEGIN:VCALENDAR',
      'VERSION:2.0',
      'PRODID:-//hacksw/handcal//NONSGML v1.0//EN',
      'CALSCALE:GREGORIAN',
      'BEGIN:VEVENT'
    );
    // Build ICS properties - add header
    $props = array();
    foreach($this-properties as $k = $v) {
      $props[strtoupper($k . ($k === 'url' ? ';VALUE=URI' : ''))] = $v;
    }
    // Set some default values
    $props['DTSTAMP'] = $this-format_timestamp('now');
    $props['UID'] = uniqid();
    // Append properties
    foreach ($props as $k = $v) {
      $ics_props[] = "$k:$v";
    }
    // Build ICS properties - add footer
    $ics_props[] = 'END:VEVENT';
    $ics_props[] = 'END:VCALENDAR';
    return $ics_props;
  }
  private function sanitize_val($val, $key = false) {
    switch($key) {
      case 'dtend':
      case 'dtstamp':
      case 'dtstart':
        $val = $this-format_timestamp($val);
        break;
      default:
        $val = $this-escape_string($val);
    }
    return $val;
  }
  private function format_timestamp($timestamp) {
    $dt = new DateTime($timestamp);
    return $dt-format(self::DT_FORMAT);
  }
  private function escape_string($str) {
    return preg_replace('/([\,;])/','\\\$1', $str);
  }
}


class iCalBooking{

  public function init(){
    add_action('admin_post_forward_booking_request', array($this, 'send_booking_request'));
    add_action('admin_post_nopriv_forward_booking_request', array($this, 'send_booking_request'));
    #add_action();
    add_shortcode('booking', array($this, 'display_booking_form'));
  }

  public function display_booking_form(){
    include_once 'booking-form.php';
  }

  private function has_valid_nonce() {
      if(!isset( $_POST['booking_nonce'] )){
        return false;
      }
      $field  = wp_unslash( $_POST['booking_nonce'] );
      $action = 'validate_booking_request';
      return wp_verify_nonce( $field, $action );
  }

  public function send_booking_request(){
    if(! ( $this-has_valid_nonce() ) ){
      return;
    }
    $fname = $_POST['client_fname'];
    $lname = $_POST['client_lname'];
    $phone = $_POS['client_phone'];
    $email = $_POST['client_email'];

    $title = 'Prenotazione';

    $description = $fname . $lname . $phone . $email;


    $ics = new WP_ICS(array(
      'location' = '',
      'description' = $description,
      'dtstart' = $_POST['client_checkin'],
      'dtend' = $_POST['client_checkout'],
      'summary' = '',
      'url' = ''
    ));

    file_put_contents('reservation.ics', $ics-to_string() );

    #header('Content-Type: text/calendar; charset=utf-8');
    #header('Content-Disposition: attachment; filename=reservation.ics');


  }

}

$booking = new iCalBooking;
$booking-init();
? 

Topic wp-mail php plugin-development plugins Wordpress

Category Web


This is untested, but it's kind of the approach you need to take. I'm just dealing with the last method in your class.

Here's how I would approach it:

  1. You need to specify a file path when you save the file so you can use that later to get the file to attach.
  2. Set up the values for your email (the "to" address, subject, message, headers, and path to the attachment).
  3. Use the variables from #2 for wp_mail() to send your message.

Here's the function from your class with my additions:

public function send_booking_request(){
    if(! ( $this->has_valid_nonce() ) ){
      return;
    }
    $fname = $_POST['client_fname'];
    $lname = $_POST['client_lname'];
    $phone = $_POS['client_phone'];
    $email = $_POST['client_email'];

    $title = 'Prenotazione';

    $description = $fname . $lname . $phone . $email;


    $ics = new WP_ICS(array(
      'location' => '',
      'description' => $description,
      'dtstart' => $_POST['client_checkin'],
      'dtend' => $_POST['client_checkout'],
      'summary' => '',
      'url' => ''
    ));


    // You need to specify the path here so you can use it later to get the attachment
    $uploads = wp_upload_dir();
    $path = $uploads['path'];

    file_put_contents( $path . '/reservation.ics', $ics->to_string() );

    // Set up email
    $to = '[email protected]';
    $subject = "reservation file";
    $message = "Please see attached reservation.";
    $headers = 'From: My Name <[email protected]>' . "\r\n";
    $attachments = array( $path . '/reservation.ics' );

    // Send the email.
    wp_mail( $to, $subject, $message, $headers, $attachments );

    #header('Content-Type: text/calendar; charset=utf-8');
    #header('Content-Disposition: attachment; filename=reservation.ics');

}

Assuming the rest of your code is OK and the file is created, this should be able to get it and attach it to an email.

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.