PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 1.5.21
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v1.5.21
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 / Helper.php

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

2,122 lines 74.5 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\App;
6 use FluentBooking\App\Models\Booking;
7 use FluentBooking\App\Models\Calendar;
8 use FluentBooking\App\Models\CalendarSlot;
9 use FluentBooking\App\Models\Meta;
10 use FluentBooking\App\Models\BookingMeta;
11 use FluentBooking\Framework\Support\Arr;
12
13 class Helper
14 {
15 public static $reserved = [
16 '0',
17 'about',
18 'access',
19 'account',
20 'accounts',
21 'activate',
22 'activities',
23 'activity',
24 'ad',
25 'add',
26 'address',
27 'adm',
28 'admin',
29 'administration',
30 'administrator',
31 'ads',
32 'adult',
33 'advertising',
34 'affiliate',
35 'affiliates',
36 'ajax',
37 'all',
38 'alpha',
39 'analysis',
40 'analytics',
41 'android',
42 'anon',
43 'anonymous',
44 'api',
45 'app',
46 'apps',
47 'archive',
48 'archives',
49 'article',
50 'asct',
51 'asset',
52 'atom',
53 'auth',
54 'authentication',
55 'avatar',
56 'backup',
57 'balancer-manager',
58 'banner',
59 'banners',
60 'beta',
61 'billing',
62 'bin',
63 'blog',
64 'blogs',
65 'board',
66 'book',
67 'bookmark',
68 'bot',
69 'bots',
70 'bug',
71 'business',
72 'cache',
73 'cadastro',
74 'calendar',
75 'call',
76 'campaign',
77 'cancel',
78 'captcha',
79 'career',
80 'careers',
81 'cart',
82 'categories',
83 'category',
84 'cgi',
85 'cgi-bin',
86 'changelog',
87 'chat',
88 'check',
89 'checking',
90 'checkout',
91 'client',
92 'cliente',
93 'clients',
94 'code',
95 'codereview',
96 'comercial',
97 'comment',
98 'comments',
99 'communities',
100 'community',
101 'company',
102 'compare',
103 'compras',
104 'config',
105 'configuration',
106 'connect',
107 'contact',
108 'contact-us',
109 'contact_us',
110 'contactus',
111 'contest',
112 'contribute',
113 'corp',
114 'create',
115 'css',
116 'dashboard',
117 'data',
118 'db',
119 'default',
120 'delete',
121 'demo',
122 'design',
123 'designer',
124 'destroy',
125 'dev',
126 'devel',
127 'developer',
128 'developers',
129 'diagram',
130 'diary',
131 'dict',
132 'dictionary',
133 'die',
134 'dir',
135 'direct_messages',
136 'directory',
137 'dist',
138 'doc',
139 'docs',
140 'documentation',
141 'domain',
142 'download',
143 'downloads',
144 'ecommerce',
145 'edit',
146 'editor',
147 'edu',
148 'education',
149 'email',
150 'employment',
151 'empty',
152 'end',
153 'enterprise',
154 'entries',
155 'entry',
156 'error',
157 'errors',
158 'eval',
159 'event',
160 'exit',
161 'explore',
162 'facebook',
163 'faq',
164 'favorite',
165 'favorites',
166 'feature',
167 'features',
168 'feed',
169 'feedback',
170 'feeds',
171 'file',
172 'files',
173 'first',
174 'flash',
175 'fleet',
176 'fleets',
177 'flog',
178 'follow',
179 'followers',
180 'following',
181 'forgot',
182 'form',
183 'forum',
184 'forums',
185 'founder',
186 'free',
187 'friend',
188 'friends',
189 'ftp',
190 'gadget',
191 'gadgets',
192 'game',
193 'games',
194 'get',
195 'ghost',
196 'gift',
197 'gifts',
198 'gist',
199 'github',
200 'graph',
201 'group',
202 'groups',
203 'guest',
204 'guests',
205 'help',
206 'home',
207 'homepage',
208 'host',
209 'hosting',
210 'hostmaster',
211 'hostname',
212 'howto',
213 'hpg',
214 'html',
215 'http',
216 'httpd',
217 'https',
218 'i',
219 'iamges',
220 'icon',
221 'icons',
222 'id',
223 'idea',
224 'ideas',
225 'image',
226 'images',
227 'imap',
228 'img',
229 'index',
230 'indice',
231 'info',
232 'information',
233 'inquiry',
234 'instagram',
235 'intranet',
236 'invitations',
237 'invite',
238 'ipad',
239 'iphone',
240 'irc',
241 'is',
242 'issue',
243 'issues',
244 'it',
245 'item',
246 'items',
247 'java',
248 'javascript',
249 'job',
250 'jobs',
251 'join',
252 'js',
253 'json',
254 'jump',
255 'knowledgebase',
256 'language',
257 'languages',
258 'last',
259 'ldap-status',
260 'legal',
261 'license',
262 'link',
263 'links',
264 'linux',
265 'list',
266 'lists',
267 'log',
268 'log-in',
269 'log-out',
270 'log_in',
271 'log_out',
272 'login',
273 'logout',
274 'logs',
275 'm',
276 'mac',
277 'mail',
278 'mail1',
279 'mail2',
280 'mail3',
281 'mail4',
282 'mail5',
283 'mailer',
284 'mailing',
285 'maintenance',
286 'manager',
287 'manual',
288 'map',
289 'maps',
290 'marketing',
291 'master',
292 'me',
293 'media',
294 'member',
295 'members',
296 'message',
297 'messages',
298 'messenger',
299 'microblog',
300 'microblogs',
301 'mine',
302 'mis',
303 'mob',
304 'mobile',
305 'movie',
306 'movies',
307 'mp3',
308 'msg',
309 'msn',
310 'music',
311 'musicas',
312 'mx',
313 'my',
314 'mysql',
315 'name',
316 'named',
317 'nan',
318 'navi',
319 'navigation',
320 'net',
321 'network',
322 'new',
323 'news',
324 'newsletter',
325 'nick',
326 'nickname',
327 'notes',
328 'noticias',
329 'notification',
330 'notifications',
331 'notify',
332 'ns',
333 'ns1',
334 'ns10',
335 'ns2',
336 'ns3',
337 'ns4',
338 'ns5',
339 'ns6',
340 'ns7',
341 'ns8',
342 'ns9',
343 'null',
344 'oauth',
345 'oauth_clients',
346 'offer',
347 'offers',
348 'official',
349 'old',
350 'online',
351 'openid',
352 'operator',
353 'order',
354 'orders',
355 'organization',
356 'organizations',
357 'overview',
358 'owner',
359 'owners',
360 'page',
361 'pager',
362 'pages',
363 'panel',
364 'password',
365 'payment',
366 'perl',
367 'phone',
368 'photo',
369 'photoalbum',
370 'photos',
371 'php',
372 'phpmyadmin',
373 'phppgadmin',
374 'phpredisadmin',
375 'pic',
376 'pics',
377 'ping',
378 'plan',
379 'plans',
380 'plugin',
381 'plugins',
382 'policy',
383 'pop',
384 'pop3',
385 'popular',
386 'portal',
387 'post',
388 'postfix',
389 'postmaster',
390 'posts',
391 'pr',
392 'premium',
393 'press',
394 'price',
395 'pricing',
396 'privacy',
397 'privacy-policy',
398 'privacy_policy',
399 'privacypolicy',
400 'private',
401 'product',
402 'products',
403 'profile',
404 'project',
405 'projects',
406 'promo',
407 'pub',
408 'public',
409 'purpose',
410 'put',
411 'python',
412 'query',
413 'random',
414 'ranking',
415 'read',
416 'readme',
417 'recent',
418 'recruit',
419 'recruitment',
420 'register',
421 'registration',
422 'release',
423 'remove',
424 'replies',
425 'report',
426 'reports',
427 'repositories',
428 'repository',
429 'req',
430 'request',
431 'requests',
432 'reset',
433 'roc',
434 'rss',
435 'ruby',
436 'rule',
437 'sag',
438 'sale',
439 'sales',
440 'sample',
441 'samples',
442 'save',
443 'school',
444 'script',
445 'scripts',
446 'search',
447 'secure',
448 'security',
449 'self',
450 'send',
451 'server',
452 'server-info',
453 'server-status',
454 'service',
455 'services',
456 'session',
457 'sessions',
458 'setting',
459 'settings',
460 'setup',
461 'share',
462 'shop',
463 'show',
464 'sign-in',
465 'sign-up',
466 'sign_in',
467 'sign_up',
468 'signin',
469 'signout',
470 'signup',
471 'site',
472 'sitemap',
473 'sites',
474 'smartphone',
475 'smtp',
476 'soporte',
477 'source',
478 'spec',
479 'special',
480 'sql',
481 'src',
482 'ssh',
483 'ssl',
484 'ssladmin',
485 'ssladministrator',
486 'sslwebmaster',
487 'staff',
488 'stage',
489 'staging',
490 'start',
491 'stat',
492 'state',
493 'static',
494 'stats',
495 'status',
496 'store',
497 'stores',
498 'stories',
499 'style',
500 'styleguide',
501 'stylesheet',
502 'stylesheets',
503 'subdomain',
504 'subscribe',
505 'subscriptions',
506 'suporte',
507 'support',
508 'svn',
509 'swf',
510 'sys',
511 'sysadmin',
512 'sysadministrator',
513 'system',
514 'tablet',
515 'tablets',
516 'tag',
517 'talk',
518 'task',
519 'tasks',
520 'team',
521 'teams',
522 'tech',
523 'telnet',
524 'term',
525 'terms',
526 'terms-of-service',
527 'terms_of_service',
528 'termsofservice',
529 'test',
530 'test1',
531 'test2',
532 'test3',
533 'teste',
534 'testing',
535 'tests',
536 'theme',
537 'themes',
538 'thread',
539 'threads',
540 'tmp',
541 'todo',
542 'tool',
543 'tools',
544 'top',
545 'topic',
546 'topics',
547 'tos',
548 'tour',
549 'translations',
550 'trends',
551 'tutorial',
552 'tux',
553 'tv',
554 'twitter',
555 'undef',
556 'unfollow',
557 'unsubscribe',
558 'update',
559 'upload',
560 'uploads',
561 'url',
562 'usage',
563 'user',
564 'username',
565 'users',
566 'usuario',
567 'vendas',
568 'ver',
569 'version',
570 'video',
571 'videos',
572 'visitor',
573 'watch',
574 'weather',
575 'web',
576 'webhook',
577 'webhooks',
578 'webmail',
579 'webmaster',
580 'website',
581 'websites',
582 'welcome',
583 'widget',
584 'widgets',
585 'wiki',
586 'win',
587 'windows',
588 'word',
589 'work',
590 'works',
591 'workshop',
592 'ww',
593 'wws',
594 'www',
595 'www1',
596 'www2',
597 'www3',
598 'www4',
599 'www5',
600 'www6',
601 'www7',
602 'wwws',
603 'wwww',
604 'xfn',
605 'xml',
606 'xmpp',
607 'xpg',
608 'xxx',
609 'yaml',
610 'year',
611 'yml',
612 'you',
613 'yourdomain',
614 'yourname',
615 'yoursite',
616 'yourusername'
617 ];
618
619 public static function isCalendarSlugAvailable($slug, $checkDb = true, $exceptId = false)
620 {
621 if (in_array($slug, self::$reserved)) {
622 return false;
623 }
624
625 if (strlen($slug) < 4) {
626 return false;
627 }
628
629 if ($checkDb) {
630
631 if ($exceptId) {
632 $exist = Calendar::where('slug', $slug)->where('id', '!=', $exceptId)->first();
633 } else {
634 $exist = Calendar::where('slug', $slug)->first();
635 }
636
637 if ($exist) {
638 return false;
639 }
640 }
641
642
643 if (is_numeric($slug)) {
644 return false;
645 }
646
647 // check if $slug has any special characters or any space. We will only allow alpha-numeric values
648 return preg_match('/^[a-zA-Z0-9_-]+$/', $slug);
649 }
650
651 public static function isEventSlugAvailable($slug, $checkDb = true, $calendarId = null, $exceptId = null)
652 {
653 if (in_array($slug, self::$reserved)) {
654 return false;
655 }
656
657 if (strlen($slug) < 4) {
658 return false;
659 }
660
661 if ($checkDb) {
662 $eventQuery = CalendarSlot::where('slug', $slug);
663
664 if ($exceptId) {
665 $eventQuery->where('id', '!=', $exceptId);
666 }
667
668 if ($calendarId) {
669 $eventQuery->where('calendar_id', $calendarId);
670 }
671
672 $exist = $eventQuery->first();
673
674 if ($exist) {
675 return false;
676 }
677 }
678
679 if (is_numeric($slug)) {
680 return false;
681 }
682
683 // check if $slug has any special characters or any space. We will only allow alpha-numeric values
684 return preg_match('/^[a-zA-Z0-9_-]+$/', $slug);
685 }
686
687 public static function getAppBaseUrl($extension = '')
688 {
689 return apply_filters('fluent_booking/admin_base_url', admin_url('admin.php?page=fluent-booking#/' . $extension), $extension);
690 }
691
692 public static function getAdminBookingUrl($bookingId)
693 {
694 return self::getAppBaseUrl('scheduled-events?booking_id=' . $bookingId);
695 }
696
697 public static function getUpgradeUrl()
698 {
699 return 'https://fluentbooking.com/pricing/?utm_source=plugin&utm_medium=wp_install&utm_campaign=fcal_upgrade';
700 }
701
702 public static function getNextBookingGroup()
703 {
704 $lastBooking = Booking::orderBy('group_id', 'desc')->first(['group_id']);
705
706 if ($lastBooking) {
707 return $lastBooking->group_id + 1;
708 }
709
710 return 1;
711 }
712
713 public static function getNextIndex()
714 {
715 static $index = 0;
716
717 $index += 1;
718 return $index;
719 }
720
721 public static function getGlobalPaymentSettings()
722 {
723 static $settings;
724
725 if ($settings) {
726 return $settings;
727 }
728
729 $settings = get_option('fluent_booking_global_payment_settings', []);
730
731 if (!$settings) {
732 $settings = [
733 'currency' => 'USD',
734 'is_active' => 'no'
735 ];
736 }
737
738 return $settings;
739 }
740
741 public static function isPaymentEnabled($calendarEvent = null)
742 {
743 $settings = self::getGlobalPaymentSettings();
744 if (Arr::get($settings, 'is_active') == 'yes') {
745 return true;
746 }
747
748 if ($calendarEvent) {
749 if ($calendarEvent->type != 'paid') {
750 return false;
751 }
752
753 $exist = Meta::where('object_type', 'calendar_slot')
754 ->where('object_id', $calendarEvent->id)
755 ->where('key', 'payment_settings')
756 ->first();
757
758 return $exist && $exist->value && Arr::get($exist->value, 'enabled') == 'yes';
759 }
760
761 return false;
762 }
763
764 public static function isPaymentConfigured($method = 'stripe')
765 {
766 $settings = get_option('fluent_booking_payment_settings_' . $method, []);
767
768 return Arr::get($settings, 'is_active', 'no') == 'yes';
769 }
770
771 /**
772 * Sanitize form inputs recursively.
773 *
774 * @param $input
775 *
776 * @return mixed $input
777 */
778 public static function fluentbookingSanitizer($input, $attribute = null, $fields = [])
779 {
780 if (is_string($input)) {
781 $element = Arr::get($fields, $attribute . '.element');
782
783 if (in_array($element, ['post_content', 'rich_text_input'])) {
784 return wp_kses_post($input);
785 } elseif ('textarea' === $element) {
786 $input = sanitize_textarea_field($input);
787 } elseif ('input_email' === $element) {
788 $input = strtolower(sanitize_text_field($input));
789 } elseif ('input_url' === $element) {
790 $input = sanitize_url($input);
791 } else {
792 $input = sanitize_text_field($input);
793 }
794 } elseif (is_array($input)) {
795 foreach ($input as $key => &$value) {
796 $attribute = $attribute ? $attribute . '[' . $key . ']' : $key;
797
798 $value = self::fluentbookingSanitizer($value, $attribute, $fields);
799
800 $attribute = null;
801 }
802 }
803
804 return $input;
805 }
806
807 public static function getMeta($group, $objectId, $key, $withModel = false)
808 {
809 $meta = Meta::where('object_type', $group)
810 ->where('object_id', $objectId)
811 ->where('key', $key)
812 ->first();
813
814 if ($meta) {
815 if ($withModel) {
816 return $meta;
817 }
818
819 return $meta->value;
820 }
821
822 return null;
823 }
824
825 public static function updateMeta($group, $objectId, $key, $value)
826 {
827 $meta = self::getMeta($group, $objectId, $key, true);
828
829 if ($meta) {
830 $meta->value = $value;
831 $meta->save();
832 return $meta;
833 }
834
835 return Meta::create([
836 'object_type' => $group,
837 'key' => $key,
838 'object_id' => $objectId,
839 'value' => $value
840 ]);
841 }
842
843 public static function deleteMeta($group, $objectId, $key)
844 {
845 return Meta::where('object_type', $group)
846 ->where('object_id', $objectId)
847 ->where('key', $key)
848 ->delete();
849 }
850
851 public static function getBookingMeta($eventId, $metaKey, $withModel = false)
852 {
853 $bookingMeta = BookingMeta::where('booking_id', $eventId)
854 ->where('meta_key', $metaKey)
855 ->first();
856
857 if ($bookingMeta) {
858 return $withModel ? $bookingMeta : $bookingMeta->value;
859 }
860
861 return null;
862 }
863
864 public static function updateBookingMeta($eventId, $metaKey, $value)
865 {
866 $bookingMeta = self::getBookingMeta($eventId, $metaKey, true);
867
868 if ($bookingMeta) {
869 $bookingMeta->value = $value;
870 $bookingMeta->save();
871 return $bookingMeta;
872 }
873
874 return BookingMeta::create([
875 'booking_id' => $eventId,
876 'meta_key' => $metaKey, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
877 'value' => $value
878 ]);
879 }
880
881 public static function getUserDisplayName($userId = null)
882 {
883 if (!$userId) {
884 $userId = get_current_user_id();
885 }
886
887 if (!$userId) {
888 return '';
889 }
890
891 $user = get_user_by('ID', $userId);
892
893 $name = trim($user->first_name . ' ' . $user->last_name);
894
895 if ($name) {
896 return $name;
897 }
898
899 return $user->display_name;
900 }
901
902 public static function getUserEmail($userId = null)
903 {
904 $userId = $userId ?: get_current_user_id();
905
906 if (!$userId) {
907 return '';
908 }
909
910 $user = get_user_by('ID', $userId);
911
912 return $user->user_email;
913 }
914
915 public static function excerpt($text, $max_length = 160)
916 {
917 // Strip HTML tags and convert entities to their corresponding characters
918 $text = html_entity_decode(wp_strip_all_tags($text));
919
920 // Remove any line breaks, tabs, or extra whitespace
921 $text = preg_replace('/\s+/', ' ', trim($text));
922
923 if (mb_strlen($text) > $max_length) {
924 $text = mb_substr($text, 0, $max_length);
925 $text = preg_replace('/\s+\S+$/', '', $text) . '...';
926 }
927
928 return $text;
929 }
930
931 public static function generateSlotSlug($default, $calendar)
932 {
933 $original = sanitize_title($default, $default, 'display');
934
935 $default = $original;
936
937 $counter = 1;
938
939 while (CalendarSlot::where('calendar_id', $calendar->id)->where('slug', $default)->first()) {
940 $default = $original . '-' . $counter;
941 $counter += 1;
942 }
943
944 return apply_filters('fluent_booking/slot_slug', $default, $original);
945 }
946
947 public static function getIp()
948 {
949 $server = $_SERVER;
950
951 $clientIp = Arr::get($server, 'HTTP_CLIENT_IP');
952 $xForwarded = Arr::get($server, 'HTTP_X_FORWARDED_FOR');
953
954 if (!empty($clientIp)) {
955 $ip = $clientIp;
956 } elseif (!empty($xForwarded)) {
957 $ip = $clientIp;
958 } else {
959 $ip = $clientIp;
960 }
961
962 return sanitize_text_field($ip);
963 }
964
965 public static function fcal_sanitize_html($html)
966 {
967 if (!$html) {
968 return $html;
969 }
970
971 // Return $html if it's just a plain text
972 if (!preg_match('/<[^>]*>/', $html)) {
973 return $html;
974 }
975
976 $tags = wp_kses_allowed_html('post');
977 $tags['style'] = [
978 'types' => [],
979 ];
980 // iframe
981 $tags['iframe'] = [
982 'width' => [],
983 'height' => [],
984 'src' => [],
985 'srcdoc' => [],
986 'title' => [],
987 'frameborder' => [],
988 'allow' => [],
989 'class' => [],
990 'id' => [],
991 'allowfullscreen' => [],
992 'style' => [],
993 ];
994 //button
995 $tags['button']['onclick'] = [];
996
997 //svg
998 if (empty($tags['svg'])) {
999 $svg_args = [
1000 'svg' => [
1001 'class' => true,
1002 'aria-hidden' => true,
1003 'aria-labelledby' => true,
1004 'role' => true,
1005 'xmlns' => true,
1006 'width' => true,
1007 'height' => true,
1008 'viewbox' => true,
1009 ],
1010 'g' => ['fill' => true],
1011 'title' => ['title' => true],
1012 'path' => [
1013 'd' => true,
1014 'fill' => true,
1015 'transform' => true,
1016 ],
1017 ];
1018 $tags = array_merge($tags, $svg_args);
1019 }
1020
1021 $tags = apply_filters('fluent_booking/allowed_html_tags', $tags);
1022
1023 return wp_kses($html, $tags);
1024 }
1025
1026 /**
1027 * Sanitize inputs recursively.
1028 *
1029 * @param array $input
1030 * @param array $sanitizeMap
1031 *
1032 * @return array $input
1033 */
1034 public static function fcal_backend_sanitizer($inputs, $sanitizeMap = [])
1035 {
1036 $originalValues = $inputs;
1037 foreach ($inputs as $key => &$value) {
1038 if (is_array($value)) {
1039 $value = self::fcal_backend_sanitizer($value, $sanitizeMap);
1040 } else {
1041 $method = Arr::get($sanitizeMap, $key);
1042 if (!$method) {
1043 continue;
1044 }
1045 if (is_callable($method)) {
1046 $value = call_user_func($method, $value);
1047 } elseif (method_exists(self::class, $method)) {
1048 $value = call_user_func([self::class, $method], $value);
1049 }
1050 }
1051 }
1052
1053 return apply_filters('fluent_booking/backend_sanitized_values', $inputs, $originalValues);
1054 }
1055
1056 /**
1057 * Recursively implode a multi-dimentional array
1058 *
1059 * @param string $glue
1060 * @param array $array
1061 *
1062 * @return string
1063 */
1064 public static function fcalImplodeRecursive($glue, array $array)
1065 {
1066 $fn = function ($glue, array $array) use (&$fn) {
1067 $result = '';
1068 foreach ($array as $item) {
1069 if (is_array($item)) {
1070 $result .= $fn($glue, $item);
1071 } else {
1072 $result .= $glue . $item;
1073 }
1074 }
1075
1076 return $result;
1077 };
1078
1079 return ltrim($fn($glue, $array), $glue);
1080 }
1081
1082 public static function getEventColors()
1083 {
1084 return apply_filters('fluent_booking/event_colors', [
1085 [
1086 'label' => __('Red-Orange', 'fluent-booking'),
1087 'value' => '#ff4f00'
1088 ],
1089 [
1090 'label' => __('Deep Lilac', 'fluent-booking'),
1091 'value' => '#e55cff'
1092 ],
1093 [
1094 'label' => __('Purple', 'fluent-booking'),
1095 'value' => '#8247f5'
1096 ],
1097 [
1098 'label' => __('Vivid Blue', 'fluent-booking'),
1099 'value' => '#0099ff'
1100 ],
1101 [
1102 'label' => __('Cyan', 'fluent-booking'),
1103 'value' => '#0ae8f0'
1104 ],
1105 [
1106 'label' => __('Emerald Green', 'fluent-booking'),
1107 'value' => '#17e885'
1108 ],
1109 [
1110 'label' => __('Lime Green', 'fluent-booking'),
1111 'value' => '#ccf000'
1112 ],
1113 [
1114 'label' => __('Amber', 'fluent-booking'),
1115 'value' => '#ffa600'
1116 ]
1117 ]);
1118 }
1119
1120 public static function getMeetingDurations()
1121 {
1122 return apply_filters('fluent_booking/meeting_durations_schema', [
1123 [
1124 'value' => '15',
1125 'label' => __('15 Minutes', 'fluent-booking')
1126 ],
1127 [
1128 'value' => '30',
1129 'label' => __('30 Minutes', 'fluent-booking')
1130 ],
1131 [
1132 'value' => '45',
1133 'label' => __('45 Minutes', 'fluent-booking')
1134 ],
1135 [
1136 'value' => '60',
1137 'label' => __('60 Minutes', 'fluent-booking')
1138 ],
1139 [
1140 'value' => 'custom',
1141 'label' => __('Custom', 'fluent-booking')
1142 ]
1143 ]);
1144 }
1145
1146 public static function getMeetingMultiDurations()
1147 {
1148 return apply_filters('fluent_booking/meeting_multi_durations_schema', [
1149 [
1150 'value' => '5',
1151 'label' => __('5 Minutes', 'fluent-booking')
1152 ],
1153 [
1154 'value' => '10',
1155 'label' => __('10 Minutes', 'fluent-booking')
1156 ],
1157 [
1158 'value' => '15',
1159 'label' => __('15 Minutes', 'fluent-booking')
1160 ],
1161 [
1162 'value' => '30',
1163 'label' => __('30 Minutes', 'fluent-booking')
1164 ],
1165 [
1166 'value' => '45',
1167 'label' => __('45 Minutes', 'fluent-booking')
1168 ],
1169 [
1170 'value' => '50',
1171 'label' => __('50 Minutes', 'fluent-booking')
1172 ],
1173 [
1174 'value' => '60',
1175 'label' => __('60 Minutes', 'fluent-booking')
1176 ],
1177 [
1178 'value' => '90',
1179 'label' => __('90 Minutes', 'fluent-booking')
1180 ],
1181 [
1182 'value' => '120',
1183 'label' => __('120 Minutes', 'fluent-booking')
1184 ],
1185 [
1186 'value' => '150',
1187 'label' => __('150 Minutes', 'fluent-booking')
1188 ],
1189 [
1190 'value' => '180',
1191 'label' => __('180 Minutes', 'fluent-booking')
1192 ],
1193 [
1194 'value' => '240',
1195 'label' => __('240 Minutes', 'fluent-booking')
1196 ],
1197 [
1198 'value' => '480',
1199 'label' => __('480 Minutes', 'fluent-booking')
1200 ]
1201 ]);
1202 }
1203
1204 public static function getDurationLookup($multiDuration = false)
1205 {
1206 $durations = $multiDuration ? self::getMeetingMultiDurations() : self::getMeetingDurations();
1207
1208 $durationLookup = [];
1209 foreach ($durations as $duration) {
1210 $durationLookup[$duration['value']] = $duration['label'];
1211 }
1212
1213 return $durationLookup;
1214 }
1215
1216 public static function formatDuration($totalMinutes) {
1217 $days = floor($totalMinutes / 1440); // 1440 minutes in a day
1218 $hours = floor(($totalMinutes % 1440) / 60);
1219 $minutes = $totalMinutes % 60;
1220
1221 $formattedDuration = [];
1222 if ($days > 0) {
1223 $unit = $days > 1 ? __('Days', 'fluent-booking') : __('Day', 'fluent-booking');
1224 $formattedDuration[] = $days . ' ' . $unit;
1225 }
1226
1227 if ($hours > 0) {
1228 $unit = $hours > 1 ? __('Hours', 'fluent-booking') : __('Hour', 'fluent-booking');
1229 $formattedDuration[] = $hours . ' ' . $unit;
1230 }
1231
1232 if ($minutes > 0 || empty($formattedDuration)) {
1233 $unit = $minutes > 1 ? __('Minutes', 'fluent-booking') : __('Minute', 'fluent-booking');
1234 $formattedDuration[] = $minutes . ' ' . $unit;
1235 }
1236
1237 return implode(' ', $formattedDuration);
1238 }
1239
1240 public static function getBufferTimes()
1241 {
1242 return apply_filters('fluent_booking/buffer_times_schema', [
1243 [
1244 'value' => '0',
1245 'label' => __('No buffer time', 'fluent-booking')
1246 ],
1247 [
1248 'value' => '5',
1249 'label' => __('5 Minutes', 'fluent-booking')
1250 ],
1251 [
1252 'value' => '10',
1253 'label' => __('10 Minutes', 'fluent-booking')
1254 ],
1255 [
1256 'value' => '15',
1257 'label' => __('15 Minutes', 'fluent-booking')
1258 ],
1259 [
1260 'value' => '20',
1261 'label' => __('20 Minutes', 'fluent-booking')
1262 ],
1263 [
1264 'value' => '30',
1265 'label' => __('30 Minutes', 'fluent-booking')
1266 ],
1267 [
1268 'value' => '45',
1269 'label' => __('45 Minutes', 'fluent-booking')
1270 ],
1271 [
1272 'value' => '60',
1273 'label' => __('60 Minutes', 'fluent-booking')
1274 ],
1275 [
1276 'value' => '90',
1277 'label' => __('90 Minutes', 'fluent-booking')
1278 ],
1279 [
1280 'value' => '120',
1281 'label' => __('120 Minutes', 'fluent-booking')
1282 ]
1283 ]);
1284 }
1285
1286 public static function getSlotIntervals()
1287 {
1288 return apply_filters('fluent_booking/slot_intervals_schema', [
1289 [
1290 'value' => '',
1291 'label' => __('Use event length (default)', 'fluent-booking')
1292 ],
1293 [
1294 'value' => '5',
1295 'label' => __('5 Minutes', 'fluent-booking')
1296 ],
1297 [
1298 'value' => '10',
1299 'label' => __('10 Minutes', 'fluent-booking')
1300 ],
1301 [
1302 'value' => '15',
1303 'label' => __('15 Minutes', 'fluent-booking')
1304 ],
1305 [
1306 'value' => '20',
1307 'label' => __('20 Minutes', 'fluent-booking')
1308 ],
1309 [
1310 'value' => '30',
1311 'label' => __('30 Minutes', 'fluent-booking')
1312 ],
1313 [
1314 'value' => '45',
1315 'label' => __('45 Minutes', 'fluent-booking')
1316 ],
1317 [
1318 'value' => '60',
1319 'label' => __('60 Minutes', 'fluent-booking')
1320 ],
1321 [
1322 'value' => '75',
1323 'label' => __('75 Minutes', 'fluent-booking')
1324 ],
1325 [
1326 'value' => '90',
1327 'label' => __('90 Minutes', 'fluent-booking')
1328 ],
1329 [
1330 'value' => '105',
1331 'label' => __('105 Minutes', 'fluent-booking')
1332 ],
1333 [
1334 'value' => '120',
1335 'label' => __('120 Minutes', 'fluent-booking')
1336 ]
1337 ]);
1338 }
1339
1340 public static function getBookingStatusChangingTimes()
1341 {
1342 return apply_filters('fluent_booking/booking_status_changing_times_schema', [
1343 [
1344 'value' => '5',
1345 'label' => __('5 Minutes', 'fluent-booking')
1346 ],
1347 [
1348 'value' => '10',
1349 'label' => __('10 Minutes', 'fluent-booking')
1350 ],
1351 [
1352 'value' => '20',
1353 'label' => __('20 Minutes', 'fluent-booking')
1354 ],
1355 [
1356 'value' => '30',
1357 'label' => __('30 Minutes', 'fluent-booking')
1358 ],
1359 [
1360 'value' => '40',
1361 'label' => __('40 Minutes', 'fluent-booking')
1362 ],
1363 [
1364 'value' => '50',
1365 'label' => __('50 Minutes', 'fluent-booking')
1366 ],
1367 [
1368 'value' => '60',
1369 'label' => __('1 Hour', 'fluent-booking')
1370 ],
1371 [
1372 'value' => '120',
1373 'label' => __('2 Hours', 'fluent-booking')
1374 ],
1375 [
1376 'value' => '180',
1377 'label' => __('3 Hours', 'fluent-booking')
1378 ],
1379 [
1380 'value' => '360',
1381 'label' => __('6 Hours', 'fluent-booking')
1382 ],
1383 [
1384 'value' => '720',
1385 'label' => __('12 Hours', 'fluent-booking')
1386 ],
1387 [
1388 'value' => '1440',
1389 'label' => __('1 Day', 'fluent-booking')
1390 ],
1391 [
1392 'value' => '2880',
1393 'label' => __('2 Days', 'fluent-booking')
1394 ]
1395 ]);
1396 }
1397
1398 public static function getBookingPeriodOptions()
1399 {
1400 return apply_filters('fluent_booking/booking_period_options', [
1401 'upcoming' => __('Upcoming', 'fluent-booking'),
1402 'completed' => __('Completed', 'fluent-booking'),
1403 'pending' => __('Pending', 'fluent-booking'),
1404 'cancelled' => __('Cancelled', 'fluent-booking'),
1405 'all' => __('All', 'fluent-booking'),
1406 ]);
1407 }
1408
1409 public static function getWeekSelectTimes()
1410 {
1411 return apply_filters('fluent_booking/week_select_times_schema', [
1412 'start' => '00:00',
1413 'step' => '00:15',
1414 'end' => '23:45'
1415 ]);
1416 }
1417
1418 public static function getOverrideSelectTimes()
1419 {
1420 return apply_filters('fluent_booking/override_select_times_schema', [
1421 'start' => '00:00',
1422 'step' => '00:15',
1423 'end' => '23:45'
1424 ]);
1425 }
1426
1427 public static function getWeeklyScheduleSchema()
1428 {
1429 return apply_filters('fluent_booking/weekly_schedule_schema', [
1430 'sun' => [
1431 'enabled' => false,
1432 'slots' => []
1433 ],
1434 'mon' => [
1435 'enabled' => true,
1436 'slots' => [
1437 ['start' => '09:00', 'end' => '17:00']
1438 ],
1439 ],
1440 'tue' => [
1441 'enabled' => true,
1442 'slots' => [
1443 ['start' => '09:00', 'end' => '17:00']
1444 ],
1445 ],
1446 'wed' => [
1447 'enabled' => true,
1448 'slots' => [
1449 ['start' => '09:00', 'end' => '17:00']
1450 ],
1451 ],
1452 'thu' => [
1453 'enabled' => true,
1454 'slots' => [
1455 ['start' => '09:00', 'end' => '17:00']
1456 ],
1457 ],
1458 'fri' => [
1459 'enabled' => true,
1460 'slots' => [
1461 ['start' => '09:00', 'end' => '17:00']
1462 ],
1463 ],
1464 'sat' => [
1465 'enabled' => false,
1466 'slots' => []
1467 ],
1468 ]);
1469 }
1470
1471 public static function getCustomFieldTypes()
1472 {
1473 return apply_filters('fluent_booking/custom_fields_types', [
1474 [
1475 'value' => 'email',
1476 'label' => __('Email', 'fluent-booking')
1477 ],
1478 [
1479 'value' => 'text',
1480 'label' => __('Text', 'fluent-booking')
1481 ],
1482 [
1483 'value' => 'textarea',
1484 'label' => __('Textarea', 'fluent-booking')
1485 ],
1486 [
1487 'value' => 'number',
1488 'label' => __('Number', 'fluent-booking')
1489 ],
1490 [
1491 'value' => 'phone',
1492 'label' => __('Phone', 'fluent-booking')
1493 ],
1494 [
1495 'value' => 'radio',
1496 'label' => __('Radio', 'fluent-booking')
1497 ],
1498 [
1499 'value' => 'dropdown',
1500 'label' => __('Select', 'fluent-booking')
1501 ],
1502 [
1503 'value' => 'multi-select',
1504 'label' => __('Multi Select', 'fluent-booking')
1505 ],
1506 [
1507 'value' => 'checkbox',
1508 'label' => __('Checkbox', 'fluent-booking')
1509 ],
1510 [
1511 'value' => 'checkbox-group',
1512 'label' => __('Checkbox Group', 'fluent-booking')
1513 ],
1514 [
1515 'value' => 'date',
1516 'label' => __('Date', 'fluent-booking')
1517 ]
1518 ]);
1519 }
1520
1521 public static function getDefaultEmailNotificationSettings()
1522 {
1523 $assetUrl = App::getInstance()['url.assets'];
1524
1525 $checkImage = $assetUrl . 'images/check-mark.png';
1526 $cancelImage = $assetUrl . 'images/cancel-mark.png';
1527 $scheduleImage = $assetUrl . 'images/schedule-mark.png';
1528
1529 return apply_filters('fluent_booking/default_email_notification_settings', [
1530 'booking_conf_attendee' => [
1531 'enabled' => true,
1532 'title' => __('Booking Confirmation Email to Attendee', 'fluent-booking'),
1533 'email' => [
1534 'subject' => 'Booking Confirmation between {{host.name}} & {{guest.full_name}}',
1535 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $checkImage . '" alt="" width="60" height="60" /></p><h2 class="p1" style="text-align: center;">Your event has been scheduled</h2><hr /><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{host.name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_guest_timezone}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} - you</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Additional notes</strong></p><p>{{guest.note}}</p><hr /><p style="text-align: center;">' . __('Need to make a change?', 'fluent-booking') . ' <a href="##booking.reschedule_url##">' . __('Reschedule', 'fluent-booking') . '</a> or <a href="##booking.cancelation_url##">' . __('Cancel', 'fluent-booking') . '</p><hr/>' . self::getAddToCalendarHtml($assetUrl)
1536 ],
1537 ],
1538 'booking_conf_host' => [
1539 'enabled' => true,
1540 'is_host' => true,
1541 'title' => __('Booking Confirmation Email to Organizer (You)', 'fluent-booking'),
1542 'email' => [
1543 'additional_recipients' => '',
1544 'subject' => 'New Booking: {{guest.full_name}} @ {{booking.start_date_time_for_host}}',
1545 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $checkImage . '" alt="" width="60" height="60" /></p><h2 class="p1" style="text-align: center;">A new event has been scheduled</h2><hr /><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} ({{guest.email}}) - Guest</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Note</strong></p><p>{{guest.note}}</p><p><strong>Additional Data</strong></p><p>{{guest.form_data_html}}</p><hr /><p style="text-align: center;"><a href="##booking.admin_booking_url##">View on the Website</a></p>'
1546 ],
1547 ],
1548 'reminder_to_attendee' => [
1549 'enabled' => false,
1550 'title' => __('Configure Meeting Reminder to Attendee', 'fluent-booking'),
1551 'email' => [
1552 'subject' => 'Meeting Reminder with {{host.name}} @ {{booking.start_date_time_for_attendee}}',
1553 'body' => '<h2 style="text-align: center;">Reminder: Your meeting will start in {{booking.start_time_human_format}}</h2><hr /><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{host.name}}</p><h3><strong>When</strong></h3><p>{{booking.full_start_end_guest_timezone}}</p><h3><strong>Who</strong></h3><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} - you</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Additional notes</strong></p><p>{{guest.note}}</p><hr /><p style="text-align: center;">' . __('Need to make a change?', 'fluent-booking') . ' <a href="##booking.reschedule_url##">' . __('Reschedule', 'fluent-booking') . '</a> or <a href="##booking.cancelation_url##">' . __('Cancel', 'fluent-booking') . '</a></p>',
1554 'times' => [
1555 [
1556 'unit' => 'minutes',
1557 'value' => 15,
1558 ]
1559 ]
1560 ],
1561 ],
1562 'reminder_to_host' => [
1563 'enabled' => false,
1564 'is_host' => true,
1565 'title' => __('Configure Meeting Reminder to Organizer (You)', 'fluent-booking'),
1566 'email' => [
1567 'additional_recipients' => '',
1568 'subject' => 'Meeting Reminder with {{host.name}} @ {{booking.start_date_time_for_host}}',
1569 'body' => '<h2 style="text-align: center;">Reminder: Your meeting will start in {{booking.start_time_human_format}}</h2><hr /><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} ({{guest.email}}) - Guest</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Note</strong></p><p>{{guest.note}}</p><p><strong>Additional Data</strong></p><p>{{guest.form_data_html}}</p><hr /><p style="text-align: center;"><a href="##booking.admin_booking_url##">View on the Website</a></p>',
1570 'times' => [
1571 [
1572 'unit' => 'minutes',
1573 'value' => 15,
1574 ]
1575 ]
1576 ],
1577 ],
1578 'cancelled_by_attendee' => [
1579 'enabled' => true,
1580 'is_host' => true,
1581 'title' => __('Booking Cancelled by Attendee (email to Organizer)', 'fluent-booking'),
1582 'email' => [
1583 'additional_recipients' => '',
1584 'subject' => 'A booking was cancelled with {{guest.full_name}}',
1585 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $cancelImage . '" alt="" width="60" height="60" /></p><h2 style="text-align: center;">Booking Cancellation</h2><hr /><p>A scheduled meeting has been canceled. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}} <span style="color: #ff0000;"><strong>(cancelled)</strong></span></p><p><strong>Cancellation Reason</strong></p><p>{{booking.cancel_reason}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} ({{guest.email}}) - Guest</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Note</strong></p><p>{{guest.note}}</p><p><strong>Additional Data</strong></p><p>{{guest.form_data_html}}</p><hr /><p style="text-align: center;"><a href="##booking.admin_booking_url##">View on the Website</a></p>'
1586 ],
1587 ],
1588 'cancelled_by_host' => [
1589 'enabled' => true,
1590 'title' => __('Booking Cancelled by Organizer (email to Attendee)', 'fluent-booking'),
1591 'email' => [
1592 'subject' => 'Your booking was cancelled with {{host.name}}',
1593 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $cancelImage . '" alt="" width="60" height="60" /></p><h2 style="text-align: center;">Booking Cancellation</h2><hr /><p>Your scheduled meeting has been canceled. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}} <span style="color: #ff0000;"><strong>(cancelled)</strong></span></p><p><strong>Cancellation Reason</strong></p><p>{{booking.cancel_reason}}</p>'
1594 ],
1595 ],
1596 'rescheduled_by_attendee' => [
1597 'enabled' => true,
1598 'is_host' => true,
1599 'title' => __('Booking Rescheduled by Attendee (email to Organizer)', 'fluent-booking'),
1600 'email' => [
1601 'additional_recipients' => '',
1602 'subject' => 'A booking was rescheduled with {{guest.full_name}}',
1603 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $scheduleImage . '" alt="" width="60" height="60" /></p><h2 style="text-align: center;">Booking Rescheduled</h2><hr /><p>A scheduled meeting has been rescheduled. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>New Time: {{booking.full_start_end_host_timezone}} <span style="color: #ff0000;"><strong>(new)</strong></span></p><p>Previous Time: {{booking.previous_meeting_time}}</p><p><strong>Rescheduling Reason</strong></p><p>{{booking.reschedule_reason}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} ({{guest.email}}) - Guest</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Note</strong></p><p>{{guest.note}}</p><p><strong>Additional Data</strong></p><p>{{guest.form_data_html}}</p><hr /><p style="text-align: center;"><a href="##booking.admin_booking_url##">View on the Website</a></p>'
1604 ],
1605 ],
1606 'rescheduled_by_host' => [
1607 'enabled' => true,
1608 'title' => __('Booking Rescheduled by Organizer (email to Attendee)', 'fluent-booking'),
1609 'email' => [
1610 'subject' => 'Your booking was rescheduled with {{host.name}}',
1611 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $scheduleImage . '" alt="" width="60" height="60" /></p><h2 style="text-align: center;">Booking Rescheduled</h2><hr /><p>Your scheduled meeting has been rescheduled. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>New Time: {{booking.full_start_end_host_timezone}} <span style="color: #ff0000;"><strong>(new)</strong></span></p><p>Previous Time: {{booking.previous_meeting_time}}</p><p><strong>Rescheduling Reason</strong></p><p>{{booking.reschedule_reason}}</p><hr /><p style="text-align: center;">' . __('Need to make a change?', 'fluent-booking') . ' <a href="##booking.reschedule_url##">' . __('Reschedule', 'fluent-booking') . '</a> or <a href="##booking.cancelation_url##">' . __('Cancel', 'fluent-booking') . '</a></p><hr/>' . self::getAddToCalendarHtml($assetUrl)
1612 ],
1613 ],
1614 'booking_request_host' => [
1615 'enabled' => true,
1616 'is_host' => true,
1617 'title' => __('Booking Approval Request to Host (email to Organizer)', 'fluent-booking'),
1618 'email' => [
1619 'additional_recipients' => '',
1620 'subject' => 'Awaiting Approval: {{guest.full_name}} @ {{booking.start_date_time_for_host}}',
1621 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $scheduleImage . '" alt="" width="60" height="60" /></p><h2 class="p1" style="text-align: center;">A booking is still waiting for your approval</h2><hr /><p>Someone has requested to schedule an event on your calendar. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} ({{guest.email}}) - Guest</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Note</strong></p><p>{{guest.note}}</p><p><strong>Additional Data</strong></p><p>{{guest.form_data_html}}</p><hr />' . self::getConfirmAndRejectButton($assetUrl) . '<p style="text-align: center;"><a href="##booking.admin_booking_url##">View on the Website</a></p>'
1622 ],
1623 ],
1624 'booking_request_attendee' => [
1625 'enabled' => true,
1626 'title' => __('Booking Submission Confirmation (email to Attendee)', 'fluent-booking'),
1627 'email' => [
1628 'subject' => 'Booking Submitted: Meeting between {{host.name}} & {{guest.full_name}}',
1629 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $scheduleImage . '" alt="" width="60" height="60" /></p><h2 class="p1" style="text-align: center;">Your booking has been submitted</h2><hr /><p>Please wait for the host to confirm your booking.</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{host.name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_guest_timezone}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} - you</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Additional notes</strong></p><p>{{guest.note}}</p><hr /><p style="text-align: center;">' . __('Need to make a change?', 'fluent-booking') . ' <a href="##booking.reschedule_url##">' . __('Reschedule', 'fluent-booking') . '</a> or <a href="##booking.cancelation_url##">' . __('Cancel', 'fluent-booking') . '</p>'
1630 ],
1631 ],
1632 'declined_by_host' => [
1633 'enabled' => true,
1634 'title' => __('Booking Declined by Organizer (email to Attendee)', 'fluent-booking'),
1635 'email' => [
1636 'subject' => 'Booking Declined: Your booking was declined with {{host.name}}',
1637 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $cancelImage . '" alt="" width="60" height="60" /></p><h2 style="text-align: center;">Booking Declined</h2><hr /><p>Your booking request has been declined. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}} <span style="color: #ff0000;"><strong>(declined)</strong></span></p><p><strong>Reason</strong></p><p>{{booking.reject_reason}}</p>'
1638 ],
1639 ],
1640 ]);
1641 }
1642
1643 public static function getAddToCalendarHtml($assetUrl = '')
1644 {
1645 $assetUrl = $assetUrl ?: App::getInstance()['url.assets'];
1646
1647 $html = '<table style="margin: 0 auto; border: none;"><tbody><tr><td style="border: none; font-size: 1rem;">' . __('Add to calendar', 'fluent-booking') . '</td><td style="border: 1px solid black; padding: 5px 5px 0 5px;"><a href="##add_to_g_calendar_url##"><img width="20" height="20" src="' . $assetUrl . 'images/g-icon.png" alt="Google Calendar" /></a></td><td style="border: 1px solid black; padding: 5px 5px 0 5px;"><a href="##add_to_ol_calendar_url##"><img width="20" height="20" src="' . $assetUrl . 'images/ol-icon.png" alt="Outlook" /></a></td><td style="border: 1px solid black; padding: 5px 5px 0 5px;"><a href="##add_to_ms_calendar_url##"><img width="20" height="20" src="' . $assetUrl . 'images/msoffice.png" alt="Microsoft Office" /></a></td><td style="border: 1px solid black; padding: 5px 5px 0 5px;"><a href="##add_to_ics_calendar_url##"><img width="20" height="20" src="' . $assetUrl . 'images/ics.png" alt="Other Calendar" /></a></td></tr></tbody></table>';
1648
1649 return apply_filters('fluent_booking/add_to_calendar_html', $html);
1650 }
1651
1652 public static function getConfirmAndRejectButton($assetUrl = '')
1653 {
1654 $assetUrl = $assetUrl ?: App::getInstance()['url.assets'];
1655
1656 $html = '<table style="margin: 16px auto; border: none;"><tbody><tr><td style="border: none; border-radius: 3px;" align="center" valign="middle"><p style="display: inline-block; background: #292929; color: #ffffff; font-size: 14px; font-weight: 500; line-height: 16px; margin: 0; text-decoration: none; text-transform: none; padding: 10px 16px 10px 14px; border-radius: 6px; box-sizing: border-box; height: 36px;"><a href="##booking.booking_confirm_url##" style="color: #ffffff; text-decoration: none; display: flex; margin: auto;"><img src="' . $assetUrl . 'images/confirm-mark.png" style="height: 16px; width: 16px; margin-left: 0; margin-right: 0.5rem;" alt="" width="16px" data-bit="iit" />' . __('Confirm', 'fluent-booking') . '</a></p><p style="width: 16px; height: 16px; display: inline-block;"> </p><p style="display: inline-block; background: #ffffff; border: 1px solid #d1d5db; color: #ffffff; font-size: 14px; font-weight: 500; line-height: 16px; margin: 0; text-decoration: none; text-transform: none; padding: 10px 16px 10px 14px; border-radius: 6px; box-sizing: border-box; height: 36px;"><a href="##booking.booking_reject_url##" style="color: #292929; text-decoration: none; display: flex; margin: auto;"><img src="' . $assetUrl . 'images/reject-mark.png" style="height: 16px; width: 16px; margin-left: 0; margin-right: 8px;" alt="" width="16px" data-bit="iit" />' . __('Reject', 'fluent-booking') . '</a></p></td></tr></tbody></table>';
1657
1658 return apply_filters('fluent_booking/confirm_and_reject_button_html', $html);
1659 }
1660
1661 public static function getEditorShortCodes($calendarEvent = null, $isHtmlSupported = false)
1662 {
1663 if (!$isHtmlSupported) {
1664 $groups = [
1665 'guest' => [
1666 'title' => __('Attendee Data', 'fluent-booking'),
1667 'key' => 'guest',
1668 'shortcodes' => [
1669 '{{guest.first_name}}' => __('Guest First Name', 'fluent-booking'),
1670 '{{guest.last_name}}' => __('Guest Last Name', 'fluent-booking'),
1671 '{{guest.full_name}}' => __('Guest Full Name', 'fluent-booking'),
1672 '{{guest.email}}' => __('Guest Email', 'fluent-booking'),
1673 '{{guest.note}}' => __('Guest Note', 'fluent-booking'),
1674 '{{booking.phone}}' => __('Guest Main Phone Number (if provided)', 'fluent-booking'),
1675 '{{guest.timezone}}' => __('Guest Timezone', 'fluent-booking')
1676 ]
1677 ],
1678 'booking' => [
1679 'title' => __('Booking Data', 'fluent-booking'),
1680 'key' => 'booking',
1681 'shortcodes' => [
1682 '{{booking.event_name}}' => __('Event Name', 'fluent-booking'),
1683 '{{booking.description}}' => __('Event Description', 'fluent-booking'),
1684 '{{booking.booking_title}}' => __('Booking Title', 'fluent-booking'),
1685 '{{booking.additional_guests}}' => __('Additional Guests', 'fluent-booking'),
1686 '{{booking.full_start_end_guest_timezone}}' => __('Full Start Date Time (with guest timezone)', 'fluent-booking'),
1687 '{{booking.full_start_end_host_timezone}}' => __('Full Start Date Time (with host timezone)', 'fluent-booking'),
1688 '{{booking.full_start_and_end_guest_timezone}}' => __('Full Start & End Date Time (with guest timezone)', 'fluent-booking'),
1689 '{{booking.full_start_and_end_host_timezone}}' => __('Full Start & End Date Time (with host timezone)', 'fluent-booking'),
1690 '{{booking.start_date_time}}' => __('Event Date Time (UTC)', 'fluent-booking'),
1691 '{{booking.start_date_time_for_attendee}}' => __('Event Date Time (with attendee timezone)', 'fluent-booking'),
1692 '{{booking.start_date_time_for_host}}' => __('Event Date Time (with host timezone)', 'fluent-booking'),
1693 '{{booking.location_details_text}}' => __('Event Location Details', 'fluent-booking'),
1694 '{{booking.cancel_reason}}' => __('Event Cancel Reason', 'fluent-booking'),
1695 '{{booking.start_time_human_format}}' => __('Event Start Time (ex: 2 hours from now)', 'fluent-booking'),
1696 '##booking.cancelation_url##' => __('Booking Cancellation URL', 'fluent-booking'),
1697 '##booking.reschedule_url##' => __('Booking Reschedule URL', 'fluent-booking'),
1698 '##booking.admin_booking_url##' => __('Booking Details Admin URL', 'fluent-booking'),
1699 '{{booking.booking_hash}}' => __('Unique Booking Hash', 'fluent-booking'),
1700 '{{booking.reschedule_reason}}' => __('Event Reschedule Reason', 'fluent-booking')
1701 ]
1702 ],
1703 'host' => [
1704 'title' => __('Host Data', 'fluent-booking'),
1705 'key' => 'host',
1706 'shortcodes' => [
1707 '{{host.name}}' => __('Host Name', 'fluent-booking'),
1708 '{{host.email}}' => __('Host Email', 'fluent-booking'),
1709 '{{host.timezone}}' => __('Host Timezone', 'fluent-booking'),
1710 ]
1711 ],
1712 'other' => [
1713 'title' => __('Other', 'fluent-booking'),
1714 'key' => 'other',
1715 'shortcodes' => [
1716 '{{event.id}}' => __('Event ID', 'fluent-booking'),
1717 '{{calendar.id}}' => __('Calendar ID', 'fluent-booking'),
1718 '{{event.title}}' => __('Event Title', 'fluent-booking'),
1719 '{{calendar.title}}' => __('Calendar Title', 'fluent-booking'),
1720 '{{calendar.description}}' => __('Calendar Description', 'fluent-booking'),
1721 '{{add_booking_to_calendar}}' => __('Add Booking to Calendar', 'fluent-booking'),
1722 ]
1723 ]
1724 ];
1725 } else {
1726 $groups = [
1727 'guest' => [
1728 'title' => __('Attendee Data', 'fluent-booking'),
1729 'key' => 'guest',
1730 'shortcodes' => [
1731 '{{guest.first_name}}' => __('Guest First Name', 'fluent-booking'),
1732 '{{guest.last_name}}' => __('Guest Last Name', 'fluent-booking'),
1733 '{{guest.full_name}}' => __('Guest Full Name', 'fluent-booking'),
1734 '{{guest.email}}' => __('Guest Email', 'fluent-booking'),
1735 '{{booking.phone}}' => __('Guest Main Phone Number (if provided)', 'fluent-booking'),
1736 '{{guest.note}}' => __('Guest Note', 'fluent-booking'),
1737 '{{guest.timezone}}' => __('Guest Timezone', 'fluent-booking'),
1738 '{{guest.form_data_html}}' => __('Guest Form Submitted Data (HTML)', 'fluent-booking')
1739 ]
1740 ],
1741 'booking' => [
1742 'title' => __('Booking Data', 'fluent-booking'),
1743 'key' => 'booking',
1744 'shortcodes' => [
1745 '{{booking.event_name}}' => __('Event Name', 'fluent-booking'),
1746 '{{booking.description}}' => __('Event Description', 'fluent-booking'),
1747 '{{booking.booking_title}}' => __('Booking Title', 'fluent-booking'),
1748 '{{booking.additional_guests}}' => __('Additional Guests', 'fluent-booking'),
1749 '{{booking.full_start_end_guest_timezone}}' => __('Full Start Date Time (with guest timezone)', 'fluent-booking'),
1750 '{{booking.full_start_end_host_timezone}}' => __('Full Start Date Time (with host timezone)', 'fluent-booking'),
1751 '{{booking.full_start_and_end_guest_timezone}}' => __('Full Start & End Date Time (with guest timezone)', 'fluent-booking'),
1752 '{{booking.full_start_and_end_host_timezone}}' => __('Full Start & End Date Time (with host timezone)', 'fluent-booking'),
1753 '{{booking.start_date_time}}' => __('Event Date Time (UTC)', 'fluent-booking'),
1754 '{{booking.start_date_time_for_attendee}}' => __('Event Date time (with guest timezone)', 'fluent-booking'),
1755 '{{booking.start_date_time_for_host}}' => __('Event Date time (with host timezone)', 'fluent-booking'),
1756 '{{booking.location_details_html}}' => __('Event Location Details (HTML)', 'fluent-booking'),
1757 '{{booking.cancel_reason}}' => __('Event Cancel Reason', 'fluent-booking'),
1758 '{{booking.start_time_human_format}}' => __('Event Start Time (ex: 2 hours from now)', 'fluent-booking'),
1759 '##booking.cancelation_url##' => __('Booking Cancellation URL', 'fluent-booking'),
1760 '##booking.reschedule_url##' => __('Booking Reschedule URL', 'fluent-booking'),
1761 '##booking.admin_booking_url##' => __('Booking Details Admin URL', 'fluent-booking'),
1762 '{{booking.booking_hash}}' => __('Unique Booking Hash', 'fluent-booking'),
1763 '{{booking.reschedule_reason}}' => __('Event Reschedule Reason', 'fluent-booking')
1764 ]
1765 ],
1766 'host' => [
1767 'title' => __('Host Data', 'fluent-booking'),
1768 'key' => 'host',
1769 'shortcodes' => [
1770 '{{host.name}}' => __('Host Name', 'fluent-booking'),
1771 '{{host.email}}' => __('Host Email', 'fluent-booking'),
1772 '{{host.timezone}}' => __('Host Timezone', 'fluent-booking'),
1773 ]
1774 ],
1775 'other' => [
1776 'title' => __('Other', 'fluent-booking'),
1777 'key' => 'other',
1778 'shortcodes' => [
1779 '{{event.id}}' => __('Event ID', 'fluent-booking'),
1780 '{{event.calendar_id}}' => __('Calendar ID', 'fluent-booking'),
1781 '{{event.title}}' => __('Event Title', 'fluent-booking'),
1782 '{{calendar.title}}' => __('Calendar Title', 'fluent-booking'),
1783 '{{calendar.description}}' => __('Calendar Description', 'fluent-booking'),
1784 '{{add_booking_to_calendar}}' => __('Add Booking to Calendar', 'fluent-booking'),
1785 ]
1786 ]
1787 ];
1788 }
1789
1790 if ($calendarEvent) {
1791 $customFields = BookingFieldService::getCustomFields($calendarEvent, true);
1792 foreach ($customFields as $fieldKey => $field) {
1793 $groups['booking']['shortcodes']['{{booking.custom.' . $fieldKey . '}}'] = $field['label'];
1794 if ($field['type'] == 'date') {
1795 $groups['booking']['shortcodes']['{{booking.custom.' . $fieldKey . '.format.Y-m-d}}'] = $field['label'] . ' (Ex: 2024-05-20)';
1796 }
1797 }
1798
1799 if (Helper::isPaymentEnabled($calendarEvent)) {
1800 $groups['payment'] = [
1801 'title' => __('Payment Data', 'fluent-booking'),
1802 'key' => 'payment',
1803 'shortcodes' => [
1804 '{{payment.payment_total}}' => __('Payment Total', 'fluent-booking'),
1805 '{{payment.payment_status}}' => __('Payment Status', 'fluent-booking'),
1806 '{{payment.payment_method}}' => __('Payment Method', 'fluent-booking'),
1807 '{{payment.currency}}' => __('Currency', 'fluent-booking'),
1808 '{{payment.payment_date}}' => __('Payment Date', 'fluent-booking'),
1809 ]
1810 ];
1811
1812 if ($isHtmlSupported) {
1813 $groups['payment']['shortcodes']['{{payment.receipt_html}}'] = __('Payment Receipt (HTML)', 'fluent-booking');
1814 }
1815 }
1816
1817 if ($calendarEvent->isMultiHostsEvent()) {
1818 $totalhost = count($calendarEvent->getHostIds());
1819 for ($i = 1; $i < $totalhost; $i++) {
1820 $groups['host']['shortcodes']['{{team_member.' . $i . '.name}}'] = __('Team Member ', 'fluent-booking') . $i . __(' Name', 'fluent-booking');
1821 $groups['host']['shortcodes']['{{team_member.' . $i . '.email}}'] = __('Team Member ', 'fluent-booking') . $i . __(' Email', 'fluent-booking');
1822 }
1823 }
1824 }
1825
1826 return apply_filters('fluent_booking/editor_shortcodes_groups', $groups, $calendarEvent, $isHtmlSupported);
1827 }
1828
1829 public static function encryptKey($value)
1830 {
1831 if (!$value) {
1832 return $value;
1833 }
1834
1835 if (!extension_loaded('openssl')) {
1836 return $value;
1837 }
1838
1839 $salt = (defined('LOGGED_IN_SALT') && '' !== LOGGED_IN_SALT) ? LOGGED_IN_SALT : 'this-is-a-fallback-salt-but-not-secure';
1840
1841 if (defined('FLUENT_BOOKING_ENCRYPTION_KEY')) {
1842 $key = FLUENT_BOOKING_ENCRYPTION_KEY;
1843 } else {
1844 $key = (defined('LOGGED_IN_KEY') && '' !== LOGGED_IN_KEY) ? LOGGED_IN_KEY : 'this-is-a-fallback-key-but-not-secure';
1845 }
1846
1847 $method = 'aes-256-ctr';
1848 $ivlen = openssl_cipher_iv_length($method);
1849 $iv = openssl_random_pseudo_bytes($ivlen);
1850
1851 $raw_value = openssl_encrypt($value . $salt, $method, $key, 0, $iv);
1852 if (!$raw_value) {
1853 return false;
1854 }
1855
1856 return base64_encode($iv . $raw_value); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
1857 }
1858
1859 public static function decryptKey($raw_value)
1860 {
1861
1862 if (!$raw_value) {
1863 return $raw_value;
1864 }
1865
1866 if (!extension_loaded('openssl')) {
1867 return $raw_value;
1868 }
1869
1870 $raw_value = base64_decode($raw_value, true); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
1871
1872 $method = 'aes-256-ctr';
1873 $ivlen = openssl_cipher_iv_length($method);
1874 $iv = substr($raw_value, 0, $ivlen);
1875
1876 $raw_value = substr($raw_value, $ivlen);
1877
1878 if (defined('FLUENT_BOOKING_ENCRYPTION_KEY')) {
1879 $key = FLUENT_BOOKING_ENCRYPTION_KEY;
1880 } else {
1881 $key = (defined('LOGGED_IN_KEY') && '' !== LOGGED_IN_KEY) ? LOGGED_IN_KEY : 'this-is-a-fallback-key-but-not-secure';
1882 }
1883
1884 $salt = (defined('LOGGED_IN_SALT') && '' !== LOGGED_IN_SALT) ? LOGGED_IN_SALT : 'this-is-a-fallback-salt-but-not-secure';
1885
1886 $value = openssl_decrypt($raw_value, $method, $key, 0, $iv);
1887 if (!$value || substr($value, -strlen($salt)) !== $salt) {
1888 return false;
1889 }
1890
1891 return substr($value, 0, -strlen($salt));
1892 }
1893
1894 public static function debugLog($data)
1895 {
1896 if (defined('FLUENT_BOOKING_DEBUG') && FLUENT_BOOKING_DEBUG) {
1897 error_log(print_r($data, true));
1898 }
1899 }
1900
1901 public static function getGlobalSettings($settingsKey = null)
1902 {
1903 $defaults = [
1904 'payments' => [
1905 'currency' => 'USD',
1906 'is_active' => 'no'
1907 ],
1908 'emailing' => [
1909 'from_name' => '',
1910 'from_email' => '',
1911 'reply_to_name' => '',
1912 'reply_to_email' => '',
1913 'use_host_name' => '',
1914 'use_host_email_on_reply' => '',
1915 'attach_ics_on_confirmation' => '',
1916 'email_footer' => ''
1917 ],
1918 'administration' => [
1919 'admin_email' => '{{wp.admin_email}}',
1920 'summary_notification' => 'no',
1921 'notification_frequency' => 'daily',
1922 'notification_day' => 'mon',
1923 'start_day' => 'sun',
1924 'auto_cancel_timing' => '10',
1925 'auto_complete_timing' => '60',
1926 'default_phone_country' => ''
1927 ],
1928 'time_format' => '12',
1929 'theme' => 'system-default'
1930 ];
1931
1932 $settings = get_option('_fluent_booking_settings', []);
1933
1934 if (empty($settings)) {
1935 $settings = [];
1936 }
1937
1938 $paymentSettings = get_option('fluent_booking_global_payment_settings', []);
1939
1940 if ($paymentSettings) {
1941 $settings['payments'] = $paymentSettings;
1942 }
1943
1944 $settings = wp_parse_args($settings, $defaults);
1945
1946 $emailSettings = $settings['emailing'];
1947
1948 if (empty($settings['administration']['auto_cancel_timing'])) {
1949 $settings['administration']['auto_cancel_timing'] = '10';
1950 }
1951
1952 if (empty($settings['administration']['auto_complete_timing'])) {
1953 $settings['administration']['auto_complete_timing'] = '10';
1954 }
1955
1956 if (empty($emailSettings['from_name']) && defined('FLUENTCRM')) {
1957 $crmSettings = fluentcrmGetGlobalSettings('email_settings', []);
1958 $emailSettings['from_name'] = Arr::get($crmSettings, 'from_name');
1959 if (empty($emailSettings['from_email'])) {
1960 $emailSettings['from_email'] = Arr::get($crmSettings, 'from_email');
1961 }
1962 if (empty($emailSettings['reply_to_name'])) {
1963 $emailSettings['reply_to_name'] = Arr::get($crmSettings, 'reply_to_name');
1964 }
1965 if (empty($emailSettings['reply_to_email'])) {
1966 $emailSettings['reply_to_email'] = Arr::get($crmSettings, 'reply_to_email');
1967 }
1968
1969 $settings['emailing'] = $emailSettings;
1970 }
1971
1972 if ($settingsKey) {
1973 return Arr::get($settings, $settingsKey, []);
1974 }
1975
1976 return $settings;
1977
1978 }
1979
1980 public static function getGlobalAdminSetting($key = null, $default = null)
1981 {
1982 static $settings;
1983 if ($settings) {
1984
1985 if ($key) {
1986 return Arr::get($settings, $key, $default);
1987 }
1988
1989 return $settings;
1990 }
1991
1992 $globalSettings = self::getGlobalSettings();
1993 $settings = Arr::get($globalSettings, 'administration', []);
1994
1995 if ($key) {
1996 return Arr::get($settings, $key, $default);
1997 }
1998
1999 return $settings;
2000 }
2001
2002 public static function getDefaultTimeFormat()
2003 {
2004 static $format;
2005
2006 if ($format) {
2007 return $format;
2008 }
2009
2010 $settings = self::getGlobalSettings();
2011 $format = Arr::get($settings, 'time_format', '24');
2012 return $format;
2013 }
2014
2015 public static function getVerifiedSenders()
2016 {
2017 $verifiedSenders = [];
2018 if (defined('FLUENTMAIL')) {
2019 $smtpSettings = get_option('fluentmail-settings', []);
2020 if ($smtpSettings && count($smtpSettings['mappings'])) {
2021 $verifiedSenders = array_keys($smtpSettings['mappings']);
2022 }
2023 }
2024 /**
2025 * Filter the verified email senders
2026 * @param array $verifiedSenders
2027 */
2028 return apply_filters('fluent_booking/verfied_email_senders', $verifiedSenders);
2029 }
2030
2031 public static function getBookingReceiptLandingBaseUrl()
2032 {
2033 return apply_filters('fluent_booking/booking_receipt_landing_base_url', site_url('/'));
2034 }
2035
2036 public static function getGlobalModuleSettings($cached = true)
2037 {
2038 static $settings = null;
2039
2040 if ($cached && $settings !== null) {
2041 return $settings;
2042 }
2043
2044 $settings = get_option('_fluent_booking_enabled_modules', []);
2045
2046 if (empty($settings) || !\is_array($settings)) {
2047 $settings = [];
2048 }
2049
2050 return $settings;
2051 }
2052
2053 public static function updateGlobalModuleSettings($settings = [])
2054 {
2055 if (!is_array($settings)) {
2056 $settings = [];
2057 }
2058
2059 update_option('_fluent_booking_enabled_modules', $settings);
2060
2061 return self::getGlobalModuleSettings(false);
2062 }
2063
2064 public static function isModuleEnabled($module)
2065 {
2066 $settings = self::getGlobalModuleSettings();
2067
2068 return isset($settings[$module]) && $settings[$module] === 'yes';
2069 }
2070
2071 /**
2072 * @return mixed|void
2073 */
2074 public static function fluentbooking_is_rtl()
2075 {
2076 /**
2077 * If FluentBooking is running on RTL Mode
2078 *
2079 * @param bool $is_rtl
2080 */
2081 return apply_filters('fluent_booking/is_rtl', is_rtl());
2082 }
2083
2084 public static function fluentBookingUserAvatar($id_or_email, $args)
2085 {
2086 if (empty($id_or_email)) {
2087 return '';
2088 }
2089 return apply_filters('fluent_booking/author_photo', get_avatar_url($id_or_email), $args);
2090 }
2091
2092 public static function getPrefSettins($cached = true)
2093 {
2094 static $pref = null;
2095
2096 if ($cached && $pref) {
2097 return $pref;
2098 }
2099
2100 $settings = [
2101 'frontend' => [
2102 'enabled' => 'no',
2103 'slug' => 'my-bookings',
2104 'render_type' => 'standalone',
2105 'page_id' => ''
2106 ]
2107 ];
2108
2109 $storedSettings = get_option('fluent_booking_modules', []);
2110
2111 if ($storedSettings && is_array($storedSettings)) {
2112 $settings = wp_parse_args($storedSettings, $settings);
2113 } else {
2114 update_option('fluent_booking_modules', $settings, 'yes');
2115 }
2116
2117 $pref = $settings;
2118
2119 return $settings;
2120 }
2121 }
2122