PluginProbe
Booking Manager – Sync WP Booking Calendar – Import Events, Export Bookings to ICS Calendar / 2.0.20
Booking Manager – Sync WP Booking Calendar – Import Events, Export Bookings to ICS Calendar v2.0.20
2.1.22 2.1.21 2.1.20 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 trunk 1.1 2.0 2.0.1 2.0.10.2 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.16 2.0.17 2.0.18 2.0.2 2.0.20 2.0.21 All 56 releases
booking-manager / core / wpbc / wpbm-bc-export.php

wpbm-bc-export.php in Booking Manager – Sync WP Booking Calendar – Import Events, Export Bookings to ICS Calendar 2.0.20, at core/wpbc/wpbm-bc-export.php

479 lines 18.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @version 1.0
4 * @description Booking Calendar integration - Export
5 *
6 * @author wpdevelop
7 * @link https://oplugins.com/
8 * @email [email protected]
9 *
10 * @modified 2017-06-28
11 */
12
13 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
14
15
16
17 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
18 // E X P O R T
19 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
20
21 /** Define ICS Feeds names
22 *
23 * wpbm-ics - Example of Feed Name.
24 *
25 * Have to work correctly immediately: http://beta/?feed=wpbm-ics
26 * Nice looking link: http://beta/feed/wpbm-ics -- require to update permalink structure at WordPress > Settings > Permalink Settings page by clicking on "Save changes" button.
27 * Finally, to display your feed, you’ll first need to flush your WordPress rewrite rules.
28 * The easiest way to do this is by logging in to the WordPress admin, and clicking Settings -> Permalinks.
29 * Once here, just click Save Changes, which will flush the rewrite rules.
30 *
31 * Otherwsie need to run ONLY once this:
32 *
33 * global $wp_rewrite;
34 * $wp_rewrite->flush_rules();
35 *
36 */
37 function wpbm_make_export_ics_feeds(){
38
39 if ( function_exists( 'wp_parse_url' ) )
40 $my_parsed_url = wp_parse_url( $_SERVER[ 'REQUEST_URI' ] );
41 else
42 $my_parsed_url = @parse_url( $_SERVER[ 'REQUEST_URI' ] );
43
44 if ( false === $my_parsed_url ) { // seriously malformed URLs, parse_url() may return FALSE.
45 return;
46 }
47
48 $my_parsed_url_path = trim( $my_parsed_url[ 'path' ] );
49 $my_parsed_url_path = trim( $my_parsed_url_path, '/' );
50
51 //FixIn: 2.0.5.4
52 // check internal subfolder of WP, like http://server.com/my-website/ ... link ...
53 $server_url_sufix = '';
54 if ( function_exists( 'wp_parse_url' ) )
55 $wp_home_server_url = wp_parse_url( home_url() );
56 else
57 $wp_home_server_url = @parse_url( home_url() );
58
59 if ( ( false !== $wp_home_server_url ) && (! empty( $wp_home_server_url[ 'path' ] ) ) ){ // seriously malformed URLs, parse_url() may return FALSE.
60 $server_url_sufix = trim( $wp_home_server_url[ 'path' ] ); // [path] => /my-website
61 $server_url_sufix = trim( $server_url_sufix, '/' ); // my-website
62 if ( ! empty( $server_url_sufix ) ) {
63 $check_sufix = substr( $my_parsed_url_path, 0, strlen( $server_url_sufix ) );
64 if ( $check_sufix === $server_url_sufix ) {
65 $my_parsed_url_path = substr( $my_parsed_url_path, strlen( $server_url_sufix ) );
66 $my_parsed_url_path = trim( $my_parsed_url_path, '/' );
67 }
68 }
69 }
70 //End FixIn: 2.0.5.4
71
72
73
74 // Get booking resources and Export Feed URLS
75 $is_continue = false;
76 if ( function_exists( 'wpbc_br_cache' ) ) {
77
78 $resources_cache = wpbc_br_cache(); // Get booking resources from cache
79 $resource_list = $resources_cache->get_resources();
80
81 foreach ( $resource_list as $res_id => $res_arr) {
82
83 if ( ! empty( $res_arr[ 'export' ] ) ) {
84 $resource_feed_url = $res_arr[ 'export' ];
85 } else {
86 $resource_feed_url = '';
87 }
88
89 $resource_feed_url = trim( $resource_feed_url, '/' );
90 if ( ! empty( $resource_feed_url ) ) {
91 // if ( 0 === strpos( $my_parsed_url_path, $resource_feed_url ) ) { // First coocurence of $download_url_path in URL, like 'wpbm-ics-export' in 'http://beta/wpbm-ics-export/my-feed/'
92 if ( $my_parsed_url_path === $resource_feed_url ) {
93 $is_continue = true;
94 break;
95 }
96 }
97 }
98 } else if ( function_exists( 'get_bk_option' ) ) {
99
100 //TODO: cehck for Free version.
101 $res_id = 1;
102 $resource_feed_url = get_bk_option( 'booking_resource_export_ics_url' );
103
104 $resource_feed_url = trim( $resource_feed_url, '/' );
105
106 if ( ! empty( $resource_feed_url ) ) {
107 if ( $my_parsed_url_path === $resource_feed_url ) {
108 $is_continue = true;
109 }
110 }
111
112 } else {
113 return; // No Booking Calendar active, so ust opening some other page
114 }
115
116
117 if ( true === $is_continue) {
118
119 $download_url_path = $resource_feed_url;
120
121 $ics_export = wpbm_export_ics_feed__wpbm_ics( array( 'wh_booking_type' => $res_id ) );
122
123 if ( headers_sent() ){
124 die( 'headers_sent_before_download' );
125 }
126
127 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
128 // Prepare system before downloading set time limits, server output options
129 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
130 $disabled = explode( ',', ini_get( 'disable_functions' ) );
131 $is_func_disabled = in_array( 'set_time_limit', $disabled );
132 if ( ! $is_func_disabled && ! ini_get( 'safe_mode' ) ) {
133 @set_time_limit( 0 );
134 }
135 //FixIn: 2.0.18.2
136 // if ( function_exists( 'get_magic_quotes_runtime' ) && get_magic_quotes_runtime() && version_compare( phpversion(), '5.4', '<' ) ) {
137 // set_magic_quotes_runtime( 0 );
138 // }
139
140 @session_write_close();
141 if ( function_exists( 'apache_setenv' ) ) {
142 @apache_setenv( 'no-gzip', 1 );
143 }
144 @ini_set( 'zlib.output_compression', 'Off' );
145
146 @ob_end_clean(); // In case, if somewhere opeded output buffer, may be required for working fpassthru with large files
147
148
149 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
150 // Set Headers before file download
151 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
152 $file = array();
153 $file['content_type'] = 'text/calendar';
154 $file['name'] = 'wpbm.ics';
155
156 if ( function_exists( 'mb_detect_encoding' ) ) //FixIn: 2.0.5.3
157 $text_encoding = mb_detect_encoding( $ics_export );
158 else
159 $text_encoding = ''; //Unknown
160
161 //debuge( mb_detect_encoding( $ics_export ) );die;
162
163 if ( ( is_array( $text_encoding ) )
164 && ( ! in_array( 'UTF-8', $text_encoding ) )
165 ){
166 $file['size'] = wpbm_get_bytes_from_str( $ics_export );
167 } else {
168 $file['size'] = 0; // UTF-8 encoding, so size alculated incorrectly, probabaly
169 }
170
171 nocache_headers();
172 header( "Robots: none" . "\n" );
173 @header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 200 OK' . "\n" );
174 header( "Content-Type: " . $file['content_type'] . "\n" );
175 header( "Content-Description: File Transfer" . "\n" );
176 header( "Content-Disposition: attachment; filename=\"" . $file['name'] . "\"" . "\n" );
177 header( "Content-Transfer-Encoding: binary" . "\n" );
178
179 if ( (int) $file['size'] > 0 )
180 header( "Content-Length: " . $file['size'] . "\n" );
181
182
183 echo $ics_export;
184
185 exit;
186 }
187 // Unknown error, or just opening some other page
188
189
190 }
191 add_action( 'template_redirect', 'wpbm_make_export_ics_feeds' );
192
193
194
195 /** Define export ICS here
196 * For testing: http://beta/?feed=wpbm-ics
197 */
198 function wpbm_export_ics_feed__wpbm_ics( $param = array( 'wh_booking_type' => '1', 'wh_trash' => '' ) ) { //FixIn: 2.0.2.3
199
200 if ( ! function_exists( 'wpbc_api_get_bookings_arr' ) )
201 return '';
202
203 // // Start date of getting bookings
204 // $real_date = strtotime( '-1 year' );
205 // $wh_booking_date = date_i18n( "Y-m-d", $real_date );
206 // $param['wh_booking_date'] = $wh_booking_date;
207 // End date of getting bookings
208 $real_date = strtotime( '+2 years' ); //FixIn: 2.0.7.1
209 $wh_booking_date2 = date_i18n( "Y-m-d", $real_date );
210 $param['wh_booking_date2' ] = $wh_booking_date2;
211
212 // Export only approved bookings //FixIn: 2.0.11.1 //FixIn: 8.5.2.3
213 $booking_is_ics_export_only_approved = get_bk_option( 'booking_is_ics_export_only_approved' );
214 if ( 'On' == $booking_is_ics_export_only_approved ) {
215 $param['wh_approved'] = '1';
216 } else {
217 $param['wh_approved'] = '';
218 }
219
220 //'' | 'imported' | 'plugin' //FixIn: 8.8.3.19 //FixIn: 2.0.20.2
221 if ( 'imported' == get_bk_option( 'booking_is_ics_export_imported_bookings' ) ) {
222 $param['wh_sync_gid'] = 'imported';
223 }
224 if ( 'plugin' == get_bk_option( 'booking_is_ics_export_imported_bookings' ) ) {
225 $param['wh_sync_gid'] = 'plugin';
226 }
227
228
229
230 $_REQUEST['view_mode']= 'vm_calendar'; //FixIn: 8.5.2.15 2.0.11.2
231 // Get array of bookings.
232 $bookings_arr = wpbc_api_get_bookings_arr( $param );
233
234
235 ob_start();
236
237 // create the ical object
238 $icalobj = new ZCiCal();
239
240
241 foreach ( $bookings_arr['bookings'] as $bk_id => $bk_arr ) {
242
243 // create the event within the ical object
244 $eventobj = new ZCiCalNode( 'VEVENT', $icalobj->curnode );
245
246 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
247 // SUMMARY [Title]
248 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
249
250 if ( function_exists( 'get_title_for_showing_in_day' ) ) { // Get title of booking pipiline in "Calendar Overview" page
251
252 if ( true ) { // admin
253 $what_show_in_day_template = get_bk_option( 'booking_default_title_in_day_for_calendar_view_mode' );
254 } else { // front-end
255 $what_show_in_day_template = get_bk_option( 'booking_default_title_in_day_for_timeline_front_end' );
256 }
257 //$title = esc_textarea( get_title_for_showing_in_day( $bk_id, $bookings_arr['bookings'], $what_show_in_day_template ) );
258 $title = get_title_for_showing_in_day( $bk_id, $bookings_arr['bookings'], $what_show_in_day_template ); //FixIn: 2.0.1.6.1
259
260 } else {
261
262 $title = ( ( isset( $bk_arr->form_data['name'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['name'] ) : '' )
263 . ( ( isset( $bk_arr->form_data['firstname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['firstname'] ) : '' )
264 . ( ( isset( $bk_arr->form_data['secondname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['secondname'] ) : '' )
265 . ( ( isset( $bk_arr->form_data['lastname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['lastname'] ) : '' );
266 }
267
268 // Insert the name of booking resource into title of .ics event
269 //$title = $bk_arr->form_data['_all_fields_']['resource_title']->title . ' - ' . $title;
270
271 $is_hide_details = get_wpbm_option( 'wpbm_is_hide_details' );
272 if ( 'On' === $is_hide_details ) { //FixIn: 2.0.12.3
273 $title = '';
274 }
275 $title = wpbm_esc_to_plain_text( $title ); //FixIn: 2.0.1.6.1
276
277 //$title = substr($title, 0, 5);
278 $eventobj->addNode( new ZCiCalDataNode( 'SUMMARY:' . trim( $title ) ) );
279
280 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
281 // DESCRIPTION
282 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
283 $description = $bk_arr->form_show;
284 // if ( ( ! empty($bk_arr->dates) ) && ( $bk_arr->dates[0]->approved ) ){
285 // $description .= '<br>Status: Approved';
286 // } else {
287 // $description .= '<br>Status: Pending';
288 // }
289
290 //$description = html_entity_decode( sanitize_text_field( $description ) );
291 //$description = trim( wp_specialchars_decode( esc_html( stripslashes( $description ) ), ENT_QUOTES ) );
292 if ( 'On' === $is_hide_details ) { //FixIn: 2.0.12.3
293 $description = '';
294 }
295 $description = wpbm_esc_to_plain_text( $description );
296
297 //debuge($description . '!');die;
298 //$description = substr($description, 0, 1);
299 $description = preg_replace( array( "/\n/" ), array( '' ), $description );
300 //debuge( ZCiCal::formatContent( $description ) );die;
301 $eventobj->addNode( new ZCiCalDataNode( 'DESCRIPTION:' . ZCiCal::formatContent( $description ) ) );
302
303 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
304 // START & END DATES
305 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
306 $event_start = $bk_arr->dates_short[ 0 ];
307 if ( ( count($bk_arr->dates_short) > 1 ) && ( '-' === $bk_arr->dates_short[ 1 ] ) ) {
308
309 $event_end = $bk_arr->dates_short[ 2 ];
310
311 $event_end = wpbm_get_next_date_if_it_full_date( $event_end );
312
313 $period_start_index = 3;
314 } else { // comma
315 $event_end = $bk_arr->dates_short[ 0 ];
316
317 $event_end = wpbm_get_next_date_if_it_full_date( $event_end );
318
319 $period_start_index = 1;
320 }
321
322 // add start date
323 $eventobj->addNode( new ZCiCalDataNode( "DTSTART:" . ZCiCal::fromSqlDateTime( $event_start ) ) );
324
325 // add end date
326 $eventobj->addNode( new ZCiCalDataNode( "DTEND:" . ZCiCal::fromSqlDateTime( $event_end ) ) );
327
328 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
329 // RDATE - Rule for other different dates.
330 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
331 //
332 // RDATE;VALUE=PERIOD:19960403T020000Z/19960403T040000Z,
333 // 19960404T010000Z/PT3H
334 //
335 $rdate = array();
336 $previos_value = '';
337 foreach ( $bk_arr->dates_short as $short_ind => $bk_date ) {
338
339 if ( $short_ind < $period_start_index )
340 continue;
341
342 if ( ( $bk_date !== ',' ) && ( $bk_date !== '-' ) ) {
343
344 if ( $previos_value == '-' ) {
345 $bk_date = wpbm_get_next_date_if_it_full_date( $bk_date );
346 } else {
347 $bk_date = wpbm_get_only_date_if_it_full_date( $bk_date );
348 }
349
350 $rdate[]= ZCiCal::fromSqlDateTime( $bk_date );
351
352 } else if ( ( $bk_date === '-' ) && ( count($rdate) > 0 ) ) {
353
354 $rdate[] = '/'; // PERIOD
355
356 } else if ( ( $bk_date === ',' ) && ( count($rdate) > 0 ) ) {
357
358 $rdate[] = ','; // Other date
359
360 }
361 $previos_value = $bk_date;
362 }
363 if ( ! empty( $rdate ) ) {
364 $rdate = implode( '', $rdate );
365 // add RDATE
366 $eventobj->addNode( new ZCiCalDataNode( "RDATE;VALUE=PERIOD:" . $rdate ) );
367
368 }
369
370 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
371 // Timezone
372 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
373 /* Timezone must be a supported PHP timezone (see http://php.net/manual/en/timezones.php )
374 * Note: multi-word timezones must use underscore "_" separator
375 * Example: $tzid = "America/New_York";
376 */
377
378 $tzid = get_bk_option( 'booking_gcal_timezone' );
379
380 if ( ! empty( $tzid ) ) {
381 // Add timezone data
382 ZCTimeZoneHelper::getTZNode( substr( $event_start, 0, 4 ), substr( $event_end, 0, 4 ), $tzid, $icalobj->curnode ); //FixIn: 2.0.3.3
383 }
384
385 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
386 // UID
387 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
388 $uid = $event_start . '_' . $bk_id . "@demo.icalendar.org";
389 $eventobj->addNode( new ZCiCalDataNode( "UID:" . $uid ) );
390
391 // DTSTAMP is a required item in VEVENT
392 $eventobj->addNode( new ZCiCalDataNode( "DTSTAMP:" . ZCiCal::fromSqlDateTime() ) );
393
394 $eventobj->addNode( new ZCiCalDataNode( "CREATED:" . ZCiCal::fromSqlDateTime( $bk_arr->modification_date ) ) );
395 $eventobj->addNode( new ZCiCalDataNode( "LAST-MODIFIED:" . ZCiCal::fromSqlDateTime( $bk_arr->modification_date ) ) );
396
397
398 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
399 // STATUS:CONFIRMED ( "TENTATIVE" / "CONFIRMED" / "CANCELLED" ) // This property defines the overall status for EVENT
400 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
401
402 $ics_status = 'TENTATIVE';
403 if ( ! ( empty( $bk_arr->trash ) ) ) {
404 $ics_status = 'CANCELLED';
405 } elseif ( ! ( empty( $bk_arr->dates[0]->approved ) ) ) {
406 $ics_status = 'CONFIRMED';
407 }
408 $eventobj->addNode( new ZCiCalDataNode( "STATUS:" . $ics_status ) ); //FixIn: 2.0.11.3 //FixIn: 2.0.12.2
409
410 //FixIn: 2.0.20.1
411 //ATTENDEE;SENT-BY=MAILTO:[email protected];CN=John Smith:MAILTO:[email protected] // More here https://www.kanzaki.com/docs/ical/attendee.html
412 if ( isset( $bk_arr->form_data['email'] ) ) {
413
414 $cn_title = ( ( isset( $bk_arr->form_data['name'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['name'] ) : '' )
415 . ( ( isset( $bk_arr->form_data['firstname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['firstname'] ) : '' )
416 . ( ( isset( $bk_arr->form_data['secondname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['secondname'] ) : '' )
417 . ( ( isset( $bk_arr->form_data['lastname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['lastname'] ) : '' );
418
419 $attendee_email = $bk_arr->form_data['email'];
420
421 $eventobj->addNode( new ZCiCalDataNode( "ATTENDEE;CN=" . $cn_title . ":MAILTO:" . $attendee_email ) );
422 }
423
424 // RRULE:FREQ=WEEKLY;COUNT=3;BYDAY=WE,SA
425 // LOCATION:South Australia\, Australia
426 // SEQUENCE:1 // defines the revision sequence number of the calendar component within a sequence of revisions
427 // TRANSP:OPAQUE // This property defines whether or not an event is transparent to busy time searches ;Default value is OPAQUE
428 // OPAQUE - Blocks or opaque on busy time searches.
429 // TRANSPARENT - Transparent on busy time searches.
430
431 }
432
433 echo $icalobj->export(); // write iCalendar feed to stdout
434
435 $ics_export = ob_get_contents();
436
437 ob_end_clean();
438
439 return $ics_export;
440 }
441
442
443 /** Get Next day in MySQL format without time, if current day its Full day - ending with 00:00:00
444 *
445 * @param string $mysql_date - 2017-07-12 00:00:00
446 * @return string - 2017-07-13
447 */
448 function wpbm_get_next_date_if_it_full_date( $mysql_date ) {
449
450 // Check if this date ending with 00:00:00 its means that it full day,
451 // so we need to add 24 hours for ending at 23:59:59 (basically 00:00:00 of next day) instead of at start of current day 00:00:00
452 if ( ( strlen( $mysql_date ) > 10 ) // , like 2017-07-12 00:00:00
453 && ( substr( $mysql_date, 11 ) == '00:00:00' )
454 ) {
455
456 $mysql_date = date_i18n( "Y-m-d 00:00:00", strtotime( $mysql_date ) );
457 $mysql_date = strtotime( $mysql_date );
458 $mysql_date = date_i18n( "Y-m-d", strtotime( '+1 day', $mysql_date ) );
459 }
460
461 return $mysql_date;
462 }
463
464
465 /** Get day in MySQL format without time, if current day its Full day - ending with 00:00:00
466 *
467 * @param string $mysql_date - 2017-07-12 00:00:00
468 * @return string - 2017-07-12
469 */
470 function wpbm_get_only_date_if_it_full_date( $mysql_date ) {
471
472 if ( ( strlen( $mysql_date ) > 10 ) // , like 2017-07-12 00:00:00
473 && ( substr( $mysql_date, 11) == '00:00:00' )
474 ) {
475 $mysql_date = substr( $mysql_date, 0, 10 );
476 }
477
478 return $mysql_date;
479 }