PluginProbe
Booking Manager – Sync WP Booking Calendar – Import Events, Export Bookings to ICS Calendar / 2.0.18
Booking Manager – Sync WP Booking Calendar – Import Events, Export Bookings to ICS Calendar v2.0.18
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.18, at core/wpbc/wpbm-bc-export.php

453 lines 17.0 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 $_REQUEST['view_mode']= 'vm_calendar'; //FixIn: 8.5.2.15 2.0.11.2
221 // Get array of bookings.
222 $bookings_arr = wpbc_api_get_bookings_arr( $param );
223
224
225 ob_start();
226
227 // create the ical object
228 $icalobj = new ZCiCal();
229
230
231 foreach ( $bookings_arr['bookings'] as $bk_id => $bk_arr ) {
232
233 // create the event within the ical object
234 $eventobj = new ZCiCalNode( 'VEVENT', $icalobj->curnode );
235
236 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
237 // SUMMARY [Title]
238 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
239
240 if ( function_exists( 'get_title_for_showing_in_day' ) ) { // Get title of booking pipiline in "Calendar Overview" page
241
242 if ( true ) { // admin
243 $what_show_in_day_template = get_bk_option( 'booking_default_title_in_day_for_calendar_view_mode' );
244 } else { // front-end
245 $what_show_in_day_template = get_bk_option( 'booking_default_title_in_day_for_timeline_front_end' );
246 }
247 //$title = esc_textarea( get_title_for_showing_in_day( $bk_id, $bookings_arr['bookings'], $what_show_in_day_template ) );
248 $title = get_title_for_showing_in_day( $bk_id, $bookings_arr['bookings'], $what_show_in_day_template ); //FixIn: 2.0.1.6.1
249
250 } else {
251
252 $title = ( ( isset( $bk_arr->form_data['name'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['name'] ) : '' )
253 . ( ( isset( $bk_arr->form_data['firstname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['firstname'] ) : '' )
254 . ( ( isset( $bk_arr->form_data['secondname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['secondname'] ) : '' )
255 . ( ( isset( $bk_arr->form_data['lastname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['lastname'] ) : '' );
256 }
257
258 $is_hide_details = get_wpbm_option( 'wpbm_is_hide_details' );
259 if ( 'On' === $is_hide_details ) { //FixIn: 2.0.12.3
260 $title = '';
261 }
262 $title = wpbm_esc_to_plain_text( $title ); //FixIn: 2.0.1.6.1
263
264 //$title = substr($title, 0, 5);
265 $eventobj->addNode( new ZCiCalDataNode( 'SUMMARY:' . trim( $title ) ) );
266
267 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
268 // DESCRIPTION
269 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
270 $description = $bk_arr->form_show;
271 // if ( ( ! empty($bk_arr->dates) ) && ( $bk_arr->dates[0]->approved ) ){
272 // $description .= '<br>Status: Approved';
273 // } else {
274 // $description .= '<br>Status: Pending';
275 // }
276
277 //$description = html_entity_decode( sanitize_text_field( $description ) );
278 //$description = trim( wp_specialchars_decode( esc_html( stripslashes( $description ) ), ENT_QUOTES ) );
279 if ( 'On' === $is_hide_details ) { //FixIn: 2.0.12.3
280 $description = '';
281 }
282 $description = wpbm_esc_to_plain_text( $description );
283
284 //debuge($description . '!');die;
285 //$description = substr($description, 0, 1);
286 $description = preg_replace( array( "/\n/" ), array( '' ), $description );
287 //debuge( ZCiCal::formatContent( $description ) );die;
288 $eventobj->addNode( new ZCiCalDataNode( 'DESCRIPTION:' . ZCiCal::formatContent( $description ) ) );
289
290 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
291 // START & END DATES
292 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
293 $event_start = $bk_arr->dates_short[ 0 ];
294 if ( ( count($bk_arr->dates_short) > 1 ) && ( '-' === $bk_arr->dates_short[ 1 ] ) ) {
295
296 $event_end = $bk_arr->dates_short[ 2 ];
297
298 $event_end = wpbm_get_next_date_if_it_full_date( $event_end );
299
300 $period_start_index = 3;
301 } else { // comma
302 $event_end = $bk_arr->dates_short[ 0 ];
303
304 $event_end = wpbm_get_next_date_if_it_full_date( $event_end );
305
306 $period_start_index = 1;
307 }
308
309 // add start date
310 $eventobj->addNode( new ZCiCalDataNode( "DTSTART:" . ZCiCal::fromSqlDateTime( $event_start ) ) );
311
312 // add end date
313 $eventobj->addNode( new ZCiCalDataNode( "DTEND:" . ZCiCal::fromSqlDateTime( $event_end ) ) );
314
315 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
316 // RDATE - Rule for other different dates.
317 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
318 //
319 // RDATE;VALUE=PERIOD:19960403T020000Z/19960403T040000Z,
320 // 19960404T010000Z/PT3H
321 //
322 $rdate = array();
323 $previos_value = '';
324 foreach ( $bk_arr->dates_short as $short_ind => $bk_date ) {
325
326 if ( $short_ind < $period_start_index )
327 continue;
328
329 if ( ( $bk_date !== ',' ) && ( $bk_date !== '-' ) ) {
330
331 if ( $previos_value == '-' ) {
332 $bk_date = wpbm_get_next_date_if_it_full_date( $bk_date );
333 } else {
334 $bk_date = wpbm_get_only_date_if_it_full_date( $bk_date );
335 }
336
337 $rdate[]= ZCiCal::fromSqlDateTime( $bk_date );
338
339 } else if ( ( $bk_date === '-' ) && ( count($rdate) > 0 ) ) {
340
341 $rdate[] = '/'; // PERIOD
342
343 } else if ( ( $bk_date === ',' ) && ( count($rdate) > 0 ) ) {
344
345 $rdate[] = ','; // Other date
346
347 }
348 $previos_value = $bk_date;
349 }
350 if ( ! empty( $rdate ) ) {
351 $rdate = implode( '', $rdate );
352 // add RDATE
353 $eventobj->addNode( new ZCiCalDataNode( "RDATE;VALUE=PERIOD:" . $rdate ) );
354
355 }
356
357 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
358 // Timezone
359 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
360 /* Timezone must be a supported PHP timezone (see http://php.net/manual/en/timezones.php )
361 * Note: multi-word timezones must use underscore "_" separator
362 * Example: $tzid = "America/New_York";
363 */
364
365 $tzid = get_bk_option( 'booking_gcal_timezone' );
366
367 if ( ! empty( $tzid ) ) {
368 // Add timezone data
369 ZCTimeZoneHelper::getTZNode( substr( $event_start, 0, 4 ), substr( $event_end, 0, 4 ), $tzid, $icalobj->curnode ); //FixIn: 2.0.3.3
370 }
371
372 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
373 // UID
374 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
375 $uid = $event_start . '_' . $bk_id . "@demo.icalendar.org";
376 $eventobj->addNode( new ZCiCalDataNode( "UID:" . $uid ) );
377
378 // DTSTAMP is a required item in VEVENT
379 $eventobj->addNode( new ZCiCalDataNode( "DTSTAMP:" . ZCiCal::fromSqlDateTime() ) );
380
381 $eventobj->addNode( new ZCiCalDataNode( "CREATED:" . ZCiCal::fromSqlDateTime( $bk_arr->modification_date ) ) );
382 $eventobj->addNode( new ZCiCalDataNode( "LAST-MODIFIED:" . ZCiCal::fromSqlDateTime( $bk_arr->modification_date ) ) );
383
384
385 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
386 // STATUS:CONFIRMED ( "TENTATIVE" / "CONFIRMED" / "CANCELLED" ) // This property defines the overall status for EVENT
387 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
388
389 $ics_status = 'TENTATIVE';
390 if ( ! ( empty( $bk_arr->trash ) ) ) {
391 $ics_status = 'CANCELLED';
392 } elseif ( ! ( empty( $bk_arr->dates[0]->approved ) ) ) {
393 $ics_status = 'CONFIRMED';
394 }
395 $eventobj->addNode( new ZCiCalDataNode( "STATUS:" . $ics_status ) ); //FixIn: 2.0.11.3 //FixIn: 2.0.12.2
396
397
398 // RRULE:FREQ=WEEKLY;COUNT=3;BYDAY=WE,SA
399 // LOCATION:South Australia\, Australia
400 // SEQUENCE:1 // defines the revision sequence number of the calendar component within a sequence of revisions
401 // TRANSP:OPAQUE // This property defines whether or not an event is transparent to busy time searches ;Default value is OPAQUE
402 // OPAQUE - Blocks or opaque on busy time searches.
403 // TRANSPARENT - Transparent on busy time searches.
404
405 }
406
407 echo $icalobj->export(); // write iCalendar feed to stdout
408
409 $ics_export = ob_get_contents();
410
411 ob_end_clean();
412
413 return $ics_export;
414 }
415
416
417 /** Get Next day in MySQL format without time, if current day its Full day - ending with 00:00:00
418 *
419 * @param string $mysql_date - 2017-07-12 00:00:00
420 * @return string - 2017-07-13
421 */
422 function wpbm_get_next_date_if_it_full_date( $mysql_date ) {
423
424 // Check if this date ending with 00:00:00 its means that it full day,
425 // 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
426 if ( ( strlen( $mysql_date ) > 10 ) // , like 2017-07-12 00:00:00
427 && ( substr( $mysql_date, 11 ) == '00:00:00' )
428 ) {
429
430 $mysql_date = date_i18n( "Y-m-d 00:00:00", strtotime( $mysql_date ) );
431 $mysql_date = strtotime( $mysql_date );
432 $mysql_date = date_i18n( "Y-m-d", strtotime( '+1 day', $mysql_date ) );
433 }
434
435 return $mysql_date;
436 }
437
438
439 /** Get day in MySQL format without time, if current day its Full day - ending with 00:00:00
440 *
441 * @param string $mysql_date - 2017-07-12 00:00:00
442 * @return string - 2017-07-12
443 */
444 function wpbm_get_only_date_if_it_full_date( $mysql_date ) {
445
446 if ( ( strlen( $mysql_date ) > 10 ) // , like 2017-07-12 00:00:00
447 && ( substr( $mysql_date, 11) == '00:00:00' )
448 ) {
449 $mysql_date = substr( $mysql_date, 0, 10 );
450 }
451
452 return $mysql_date;
453 }