1

I need to setup a cron task in order to generate a list of bookings.ics from my Bookings Calendar plugin. My function which is located inside my functions.php is this one. It is processing my bookings through my Wordpress database and exports them to /wp-content/uplodas/bookings.ics

Nevertheless, in order to execute that, I have made a GET request which is located in this corresponding URL here: https://mywebsite.com/booking?ical=1

What I want to avoid is firstly, try and hide that URL from the public and also add a token to that request at any time that it has to generate the booking calendar in .ics format.

Therefore, maybe

CODE

Function which generates the bookings.ics file

/** * Generate ICS feed for approved bookings, FULL COMPLIANT ICS FEED GENERATOR */ function generate_booking_ics_feed() { if (isset($_GET['ical']) && $_GET['ical'] == '1' ) { global $wpdb; // start output buffering ob_start(); // Clear all output buffers while (ob_get_level()) { ob_end_clean(); } // Get timezone data $timezone = wp_timezone(); $timezone_string = $timezone->getName(); $timezone_offset = $timezone->getOffset(new DateTime()); $timezone_offset_hours = $timezone_offset / 3600; $timezone_offset_formatted = sprintf('%+03d%02d', floor($timezone_offset_hours), ($timezone_offset_hours - floor($timezone_offset_hours)) * 60 ); // Get timezone abbreviation alternative way $timezone_abbr = (new DateTime())->format('T'); // Begin VCALENDAR with required properties echo "BEGIN:VCALENDAR\r\n"; echo "VERSION:2.0\r\n"; echo "PRODID:-//".get_bloginfo('name')."//Bookings//EN\r\n"; echo "CALSCALE:GREGORIAN\r\n"; echo "METHOD:PUBLISH\r\n"; // Query approved bookings from WP Booking Calendar tables $bookings = $wpdb->get_results(" SELECT b.booking_id, b.form, b.booking_type, d.booking_date FROM {$wpdb->prefix}booking as b JOIN {$wpdb->prefix}bookingdates as d ON b.booking_id = d.booking_id WHERE d.approved = 1 ORDER BY d.booking_date "); // Generate DTSTAMP once for all events $dtstamp = gmdate('Ymd\THis\Z'); foreach ($bookings as $booking) { // Debug output (view source to see raw data) // Try multiple methods to extract name $name = 'Booking #'.$booking->booking_id; // Default fallback // Method 1: Parse form data $form_data = array(); $form_data = $booking->form; $name = extract_name_from_form($form_data); // Returns "John" $surname = extract_surname_from_form($form_data); $email = extract_email_from_form($form_data); // Format dates with timezone $start = new DateTime($booking->booking_date, new DateTimeZone('UTC')); $end = clone $start; $end->add(new DateInterval('PT1H')); // 1 hour duration // Generate unique UID with timestamp // Generate unique UID with timestamp and random component $uid = uniqid($booking->booking_id.'-', true).'@'.parse_url(home_url(), PHP_URL_HOST); echo "BEGIN:VEVENT\r\n"; echo "UID:".$uid."\r\n"; echo "DTSTAMP:".$dtstamp."\r\n"; echo "DTSTART:".$start->format('Ymd\THis\Z')."\r\n"; echo "DTEND:".$end->format('Ymd\THis\Z')."\r\n"; echo "SUMMARY:".$name. " ". $surname . " ". $email. " - ".$booking->booking_type."\r\n"; echo "DESCRIPTION:Booking ID: ".$booking->booking_id."\r\n"; echo "STATUS:CONFIRMED\r\n"; echo "TRANSP:OPAQUE\r\n"; // Blocks time on calendar echo "SEQUENCE:0\r\n"; echo "CREATED:".$dtstamp."\r\n"; echo "LAST-MODIFIED:".$dtstamp."\r\n"; echo "END:VEVENT\r\n"; } echo "END:VCALENDAR\r\n"; // 2. Save to file (with debug logging) $file_info = save_ics_file($ics_content); error_log("ICS file saved to: {$file_info['path']}, Size: {$file_info['size']} bytes"); // 3. Output to browser output_ics_headers(); } } 

Function which saves the file to my directory:

function save_ics_file($content) { $upload_dir = wp_upload_dir(); $path = $upload_dir['basedir'] . '/bookings.ics'; // Verify upload directory is writable if (!wp_is_writable($upload_dir['basedir'])) { throw new Exception("Upload directory not writable: " . $upload_dir['basedir']); } // Write to temporary file first $temp_path = $path . '.tmp'; $bytes = file_put_contents($temp_path, $content); if ($bytes === false) { throw new Exception("Failed to write temporary file"); } // Verify temporary file if (!file_exists($temp_path) || filesize($temp_path) === 0) { throw new Exception("Temporary file creation failed"); } // Move to final location if (!rename($temp_path, $path)) { throw new Exception("Failed to move file to final destination"); } // Set permissions chmod($path, 0644); return [ 'path' => $path, 'size' => filesize($path), 'url' => $upload_dir['baseurl'] . '/bookings.ics' ]; } 

Finally, the goal create the cron task that it will be triggered every 10-15 minutes which it will rewrite the bookings.ics file every time and therefore the link which will be provided must be hidden from the public view but be exposed only in my Google Calendar settings so that it can be read and rendered into the Google calendar's view. Any help would be really appreciating.

Thank you

7
  • Do you have access to the server's crontab? That would be a lot more reliable than WP's shonky "run if there's a request around the right time" pseudo-cron. Commented Jul 14 at 11:26
  • to clarify on Chris' comment, you can run the cron via WP CLI and avoid URLs and PHP time limits, Alternatively you can implement it as a WP CLI command and trigger it directly Commented Jul 14 at 11:44
  • 2
    As an aside, have you considered instead of writing this to an ICS file in your uploads, just outputting it directly? Then putting https://mywebsite.com/booking?ical=1 into google cal rather than wp-content/uploads/booking.ics? Then you can remove cron entirely, and cache the result in the DB to speed things up. Put it in a transient that expires after 15/20 minutes and you've sidestepped the problem entirely! Commented Jul 14 at 11:47
  • @ChrisCox well, I am not quite sure about that. I can enter into my hosting but I suppose I have to subscribe to a new service for being able to use the crontab if I am not mistaken. As I wanted an API service, it would take more money and a VPS in order to connect Google Calendar with my Calendar service which is feeded through Wordpress. Commented Jul 14 at 12:25
  • @TomJNowell I am actually doing that at the moment but I am not storing it in my WP database. Would I have to store it in a separate new table of my WP database ? Because I am not really database connoisseur of MySql databases, what does it mean "Put it in a transient" ? Do you mean that developer.wordpress.org/reference/functions/get_transient ? Thanks in advance Commented Jul 14 at 12:28

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.