PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / trunk
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution vtrunk
2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 1.7.2 All 33 releases
fluent-booking / app / Services / EditorShortCodeParser.php

EditorShortCodeParser.php in Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution trunk, at app/Services/EditorShortCodeParser.php

553 lines 18.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBooking\App\Services;
4
5 use FluentBooking\App\Models\Booking;
6 use FluentBooking\App\Models\Calendar;
7 use FluentBooking\App\Models\CalendarSlot;
8 use FluentBooking\Framework\Support\Arr;
9
10 class EditorShortCodeParser
11 {
12 protected static $requireHtml = true;
13
14 protected static $store = [
15 'booking' => null,
16 'calendar_booking' => null,
17 'calendar' => null,
18 'host' => null,
19 'user' => null,
20 'custom_booking_data' => null,
21 'payment_order' => null
22 ];
23
24 public static function parse($parsable, $booking, $requireHtml = true)
25 {
26 try {
27 static::$requireHtml = $requireHtml;
28 static::setData($booking);
29 return static::parseShortCodes($parsable);
30 } catch (\Exception $e) {
31 if (defined('WP_DEBUG') && WP_DEBUG) {
32 error_log($e->getTraceAsString()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
33 }
34 return '';
35 }
36 }
37
38 protected static function setData($booking)
39 {
40 static::$store['booking'] = $booking;
41 static::$store['booking_event'] = $booking->calendar_event;
42 static::$store['calendar'] = $booking->calendar;
43 static::$store['host'] = $booking->getHostDetails(false);
44 static::$store['team_members'] = $booking->getHostsDetails(false, $booking->host_user_id);
45 static::$store['custom_booking_data'] = null;
46 static::$store['payment_order'] = null;
47 static::$store['meeting_bookmarks'] = null;
48 }
49
50 protected static function getBookingData($key)
51 {
52 $bookingEvent = static::$store['booking_event'];
53 $calendar = static::$store['calendar'];
54 $booking = static::$store['booking'];
55
56 if (!$bookingEvent || !$calendar || !$booking) {
57 return '';
58 }
59
60 if ($key == 'event_name') {
61 return $bookingEvent->title;
62 }
63
64 if ($key == 'description') {
65 return $bookingEvent->description;
66 }
67
68 if ($key == 'booking_title') {
69 return $booking->getBookingTitle();
70 }
71
72 if ($key == 'additional_guests') {
73 return $booking->getAdditionalGuests(true);
74 }
75
76 if ($key == 'full_start_end_guest_timezone') {
77 return $booking->getShortBookingDateTime($booking->person_time_zone) . ' (' . $booking->person_time_zone . ')';
78 }
79
80 if ($key == 'full_start_end_host_timezone') {
81 return $booking->getShortBookingDateTime($booking->getHostTimezone()) . ' (' . $booking->getHostTimezone() . ')';
82 }
83
84 if ($key == 'full_start_and_end_guest_timezone') {
85 return $booking->getFullBookingDateTimeText($booking->person_time_zone) . ' (' . $booking->person_time_zone . ')';
86 }
87
88 if ($key == 'full_start_and_end_host_timezone') {
89 return $booking->getFullBookingDateTimeText($booking->getHostTimezone()) . ' (' . $booking->getHostTimezone() . ')';
90 }
91
92 if ($key == 'all_bookings_short_times_guest_timezone') {
93 return implode("<br>", $booking->getAllBookingShortTimes($booking->person_time_zone, true));
94 }
95
96 if ($key == 'all_bookings_short_times_host_timezone') {
97 return implode("<br>", $booking->getAllBookingShortTimes($booking->getHostTimezone(), true));
98 }
99
100 if ($key == 'all_bookings_full_times_guest_timezone') {
101 return implode("<br>", $booking->getAllBookingFullTimes($booking->person_time_zone, true));
102 }
103
104 if ($key == 'all_bookings_full_times_host_timezone') {
105 return implode("<br>", $booking->getAllBookingFullTimes($booking->getHostTimezone(), true));
106 }
107
108 if ($key == 'start_date_time') {
109 return $booking->start_time;
110 }
111
112 if (strpos($key, 'start_date_time_for_attendee') === 0) {
113 $format = preg_match('/format\.([a-zA-Z\-: ]+)/', $key, $matches) ? $matches[1] : 'Y-m-d H:i:s';
114 $dateTime = DateTimeHelper::convertFromUtc($booking->start_time, $booking->person_time_zone, 'Y-m-d H:i:s');
115 return date_i18n($format, strtotime($dateTime));
116 }
117
118 if (strpos($key, 'start_date_time_for_host') === 0) {
119 $format = preg_match('/format\.([a-zA-Z\-: ]+)/', $key, $matches) ? $matches[1] : 'Y-m-d H:i:s';
120 $dateTime = DateTimeHelper::convertFromUtc($booking->start_time, $booking->getHostTimezone(), 'Y-m-d H:i:s');
121 return date_i18n($format, strtotime($dateTime));
122 }
123
124 if ($key == 'cancel_reason') {
125 return $booking->getCancelReason(false, true);
126 }
127
128 if ($key == 'reject_reason') {
129 return $booking->getRejectReason(false, true);
130 }
131
132 if ($key == 'reschedule_reason') {
133 return $booking->getRescheduleReason(true);
134 }
135
136 if ($key == 'previous_meeting_time') {
137 return $booking->getPreviousMeetingTime($booking->getHostTimezone()) . ' (' . $booking->getHostTimezone() . ')';
138 }
139
140 if ($key == 'previous_meeting_time_guest_timezone') {
141 return $booking->getPreviousMeetingTime($booking->person_time_zone) . ' (' . $booking->person_time_zone . ')';
142 }
143
144 if ($key == 'previous_meeting_date_time_host_timezone') {
145 return $booking->getPreviousMeetingDateTimeText($booking->getHostTimezone()) . ' (' . $booking->getHostTimezone() . ')';
146 }
147
148 if ($key == 'previous_meeting_date_time_guest_timezone') {
149 return $booking->getPreviousMeetingDateTimeText($booking->person_time_zone) . ' (' . $booking->person_time_zone . ')';
150 }
151
152 if ($key == 'start_time_human_format') {
153 if (time() > strtotime($booking->start_time)) {
154 $suffix = __(' ago', 'fluent-booking');
155 } else {
156 $suffix = __(' from now', 'fluent-booking');
157 }
158
159 return human_time_diff(time(), strtotime($booking->start_time)) . ' ' . $suffix;
160 }
161
162 if ($key == 'cancelation_url') {
163 return $booking->getCancelUrl();
164 }
165
166 if ($key == 'reschedule_url') {
167 return $booking->getRescheduleUrl();
168 }
169
170 if ($key == 'admin_booking_url') {
171 return Helper::getAdminBookingUrl($booking->id) . '&period=upcoming';
172 }
173
174 if ($key == 'booking_confirm_url') {
175 return Helper::getAdminBookingUrl($booking->id) . '&period=pending&confirm_booking=true';
176 }
177
178 if ($key == 'booking_reject_url') {
179 return Helper::getAdminBookingUrl($booking->id) . '&period=pending&reject_booking=true';
180 }
181
182 if ($key == 'location_details_html') {
183 return $booking->getLocationDetailsHtml();
184 }
185
186 if ($key == 'location_details_text') {
187 return $booking->getLocationAsText();
188 }
189
190 if ($key == 'booking_hash') {
191 return $booking->hash;
192 }
193
194 $fillables = (new Booking())->getFillable();
195 $fillables[] = 'id';
196 $fillables[] = 'created_at';
197 $fillables[] = 'updated_at';
198
199 if (in_array($key, $fillables)) {
200 return $booking->{$key};
201 }
202
203 return '';
204 }
205
206 protected static function getBookingCustomData($key)
207 {
208 $booking = static::$store['booking'];
209 if (!$booking) {
210 return '';
211 }
212
213 if (self::$store['custom_booking_data'] === null) {
214 self::$store['custom_booking_data'] = $booking->getMeta('custom_fields_data', []);
215 }
216
217 if (self::$store['custom_booking_data']) {
218 if (preg_match('/format\.([a-zA-Z\-: ]+)/', $key, $matches)) {
219 $fieldKey = preg_split('/\.format\./', $key)[0];
220 $value = Arr::get(self::$store['custom_booking_data'], $fieldKey);
221 $customField = BookingFieldService::getBookingFieldByName($booking->calendar_event, $fieldKey);
222 $formattedDate = DateTimeHelper::getFormattedDate($value, Arr::get($customField, 'date_format'));
223 return $formattedDate ? date_i18n($matches[1], strtotime($formattedDate)) : '';
224 }
225
226 $customField = BookingFieldService::getBookingFieldByName($booking->calendar_event, $key);
227
228 if (Arr::get($customField, 'type') == 'file') {
229 return self::getUploadedFileUrl(Arr::get(self::$store['custom_booking_data'], $key));
230 }
231
232 if (Arr::get($customField, 'type') == 'hidden') {
233 static $resolving = [];
234
235 // Guest-supplied hidden values are parsed again, so a self-reference would recurse until the stack runs out.
236 if (isset($resolving[$key])) {
237 return Arr::get(self::$store['custom_booking_data'], $key);
238 }
239
240 $resolving[$key] = true;
241
242 try {
243 return self::parseShortCodes(Arr::get(self::$store['custom_booking_data'], $key));
244 } finally {
245 unset($resolving[$key]);
246 }
247 }
248
249 return Arr::get(self::$store['custom_booking_data'], $key);
250 }
251
252 return '';
253 }
254
255 protected static function getHostData($key)
256 {
257 $host = static::$store['host'];
258
259 if (is_null($host)) {
260 return '';
261 }
262
263 if ($key == 'timezone') {
264 $booking = static::$store['booking'];
265 return $booking ? $booking->getHostTimezone() : null;
266 }
267
268 return Arr::get($host, $key, '');
269 }
270
271 protected static function getTeamMembersData($key)
272 {
273 $teamMembers = static::$store['team_members'];
274
275 if (empty($teamMembers)) {
276 return '';
277 }
278
279 list($key, $value) = explode('.', $key);
280
281 return Arr::get($teamMembers, $key - 1 . '.' . $value, '');
282 }
283
284 protected static function getGuestData($key)
285 {
286 $guest = static::$store['booking'];
287 if (is_null($guest)) {
288 return '';
289 }
290
291 if ('full_name' == $key) {
292 return $guest['first_name'] . ' ' . $guest['last_name'];
293 }
294 if ('timezone' == $key) {
295 return $guest->person_time_zone;
296 }
297 if ('note' == $key) {
298 return $guest->getMessage();
299 }
300
301 if ($key == 'total_guest') {
302 return $guest->getTotalGuestCount();
303 }
304
305 if ($key == 'form_data_html') {
306 return __('will be available soon', 'fluent-booking');
307 }
308
309 return self::resolveScalarAttribute($guest, $key);
310 }
311
312 protected static function getBookingEventData($key)
313 {
314 $bookingEvent = static::$store['booking_event'];
315
316 if (is_null($bookingEvent)) {
317 return '';
318 }
319
320 $fillables = (new CalendarSlot())->getFillable();
321
322 if (in_array($key, $fillables)) {
323 return $bookingEvent->{$key};
324 }
325
326 return self::resolveScalarAttribute($bookingEvent, $key);
327 }
328
329 protected static function getCalendarData($key)
330 {
331 $calendar = static::$store['calendar'];
332
333 if (is_null($calendar)) {
334 return '';
335 }
336
337 $fillables = (new Calendar())->getFillable();
338
339 if (in_array($key, $fillables)) {
340 return $calendar->{$key};
341 }
342
343 return self::resolveScalarAttribute($calendar, $key);
344 }
345
346 /**
347 * Resolve a scalar attribute only; never a relation (dumps as JSON) or a
348 * dotted hop into a relation's columns.
349 */
350 protected static function resolveScalarAttribute($model, $key)
351 {
352 if (strpos($key, '.') !== false) {
353 return '';
354 }
355
356 $value = isset($model[$key]) ? $model[$key] : '';
357
358 return is_scalar($value) ? $value : '';
359 }
360
361 protected static function getPaymentData($key)
362 {
363 $booking = static::$store['booking'];
364
365 if (is_null($booking)) {
366 return '';
367 }
368
369 if (!$booking->payment_status) {
370 return '';
371 }
372
373 if (is_null(static::$store['payment_order'])) {
374 static::$store['payment_order'] = $booking->payment_order;
375 }
376
377 if (!static::$store['payment_order']) {
378 return '';
379 }
380
381 $order = static::$store['payment_order'];
382
383 if ($key == 'payment_total' && $order) {
384 $isZeroDecimal = CurrenciesHelper::isZeroDecimal($order->currency);
385 if ($isZeroDecimal) {
386 return $order->total_amount;
387 } else {
388 return $order->total_amount / 100;
389 }
390 }
391
392 if ($key == 'receipt_html') {
393 return apply_filters('fluent_booking/payment_receipt_html', '', $booking->hash);
394 }
395
396 if ($key == 'payment_status') {
397 return $order ? $order->status : '';
398 }
399
400 if ($key == 'payment_currency') {
401 return $order ? $order->currency : '';
402 }
403
404 if ($key == 'payment_date') {
405 return $order ? $order->created_at : '';
406 }
407
408 $fillables = (new \FluentBookingPro\App\Models\Order())->getFillable();
409
410 if (in_array($key, $fillables)) {
411 return $order ? $order->{$key} : '';
412 }
413
414 return '';
415 }
416
417 protected static function getUserData($key)
418 {
419 $user = static::$store['user'];
420 if (is_null($user)) {
421 $user = wp_get_current_user();
422 }
423 return $user ? $user->{$key} : '';
424 }
425
426 protected static function getWPData($key)
427 {
428 if ('site_url' == $key) {
429 return site_url();
430 }
431 if ('admin_email' == $key) {
432 return get_option('admin_email');
433 }
434 if ('site_title' == $key) {
435 return get_option('blogname');
436 }
437 return $key;
438 }
439
440 protected static function getOtherData($key)
441 {
442 $meetingBookmarks = self::$store['meeting_bookmarks'];
443 if (!$meetingBookmarks) {
444 $booking = static::$store['booking'];
445 $meetingBookmarks = $booking ? $booking->getMeetingBookmarks() : null;
446 self::$store['meeting_bookmarks'] = $meetingBookmarks;
447 }
448
449 if (0 === strpos($key, 'date.')) {
450 $format = str_replace('date.', '', $key);
451 return gmdate($format, strtotime(current_time('mysql'))); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
452 } elseif ('add_booking_to_calendar' === $key) {
453 return static::parseShortCodes(Helper::getAddToCalendarHtml());
454 } elseif ('add_to_g_calendar_url' === $key) {
455 return Arr::get($meetingBookmarks, 'google.url');
456 } elseif ('add_to_ol_calendar_url' === $key) {
457 return Arr::get($meetingBookmarks, 'outlook.url');
458 } elseif ('add_to_ms_calendar_url' === $key) {
459 return Arr::get($meetingBookmarks, 'msoffice.url');
460 } elseif ('add_to_ics_calendar_url' === $key) {
461 return Arr::get($meetingBookmarks, 'other.url');
462 }
463
464 return $key;
465 }
466
467 protected static function getUploadedFileUrl($fieldValue)
468 {
469 if (empty($fieldValue)) {
470 return '';
471 }
472
473 $files = array_map(function($file) {
474 return '<a href="' . esc_url($file) . '" style="color:#222;font-size:15px;" target="_blank" download="' . esc_attr(basename($file)) . '">' . esc_html(basename($file)) . '</a>';
475 }, $fieldValue);
476
477 return '<ul><li>' . implode('</li><li>', $files) . '</li></ul>';
478 }
479
480 protected static function parseShortCodes($parsable)
481 {
482 if (is_array($parsable)) {
483 return static::parseFromArray($parsable);
484 }
485
486 return static::parseFromString($parsable);
487 }
488
489 protected static function parseFromArray($parsable)
490 {
491 foreach ($parsable as $key => $value) {
492 if (is_array($value)) {
493 $parsable[$key] = static::parseFromArray($value);
494 } else {
495 $parsable[$key] = static::parseFromString($value);
496 }
497 }
498
499 return $parsable;
500 }
501
502 protected static function parseFromString($parsable)
503 {
504 if (!$parsable) {
505 return '';
506 }
507
508 return preg_replace_callback('/({{|##)+(.*?)(}}|##)/', function ($matches) {
509 $value = '';
510
511 if (empty($matches[2])) {
512 return '';
513 }
514
515 $match = $matches[2];
516
517 if (false !== strpos($match, 'guest.')) {
518 $guestProperty = substr($match, strlen('guest.'));
519 $value = static::getGuestData($guestProperty);
520 } elseif (false !== strpos($match, 'booking.custom.')) {
521 $customBookingProp = substr($match, strlen('booking.custom.'));
522 $value = static::getBookingCustomData($customBookingProp);
523 } elseif (false !== strpos($match, 'booking.')) {
524 $bookingProperty = substr($match, strlen('booking.'));
525 $value = static::getBookingData($bookingProperty);
526 } elseif (false !== strpos($match, 'host.')) {
527 $hostProperty = substr($match, strlen('host.'));
528 $value = static::getHostData($hostProperty);
529 } elseif (false !== strpos($match, 'team_member.')) {
530 $teamMemberProperty = substr($match, strlen('team_member.'));
531 $value = static::getTeamMembersData($teamMemberProperty);
532 } elseif (false !== strpos($match, 'event.')) {
533 $eventProperty = substr($match, strlen('event.'));
534 $value = static::getBookingEventData($eventProperty);
535 } elseif (false !== strpos($match, 'calendar.')) {
536 $calendarProperty = substr($match, strlen('calendar.'));
537 $value = static::getCalendarData($calendarProperty);
538 } elseif (false !== strpos($match, 'payment.')) {
539 $paymentProperty = substr($match, strlen('payment.'));
540 $value = static::getPaymentData($paymentProperty);
541 } else {
542 $value = static::getOtherData($match);
543 }
544
545 if (static::$requireHtml && is_array($value)) {
546 $value = Helper::fcalImplodeRecursive(', ', $value);
547 }
548
549 return $value;
550 }, $parsable);
551 }
552 }
553