PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 1.5.22
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v1.5.22
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.22, at app/Services/Helper.php

2,130 lines 74.7 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 'value' => 'file',
1520 'label' => __('File', 'fluent-booking')
1521 ],
1522 [
1523 'value' => 'hidden',
1524 'label' => __('Hidden', 'fluent-booking')
1525 ]
1526 ]);
1527 }
1528
1529 public static function getDefaultEmailNotificationSettings()
1530 {
1531 $assetUrl = App::getInstance()['url.assets'];
1532
1533 $checkImage = $assetUrl . 'images/check-mark.png';
1534 $cancelImage = $assetUrl . 'images/cancel-mark.png';
1535 $scheduleImage = $assetUrl . 'images/schedule-mark.png';
1536
1537 return apply_filters('fluent_booking/default_email_notification_settings', [
1538 'booking_conf_attendee' => [
1539 'enabled' => true,
1540 'title' => __('Booking Confirmation Email to Attendee', 'fluent-booking'),
1541 'email' => [
1542 'subject' => 'Booking Confirmation between {{host.name}} & {{guest.full_name}}',
1543 '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)
1544 ],
1545 ],
1546 'booking_conf_host' => [
1547 'enabled' => true,
1548 'is_host' => true,
1549 'title' => __('Booking Confirmation Email to Organizer (You)', 'fluent-booking'),
1550 'email' => [
1551 'additional_recipients' => '',
1552 'subject' => 'New Booking: {{guest.full_name}} @ {{booking.start_date_time_for_host}}',
1553 '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>'
1554 ],
1555 ],
1556 'reminder_to_attendee' => [
1557 'enabled' => false,
1558 'title' => __('Configure Meeting Reminder to Attendee', 'fluent-booking'),
1559 'email' => [
1560 'subject' => 'Meeting Reminder with {{host.name}} @ {{booking.start_date_time_for_attendee}}',
1561 '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>',
1562 'times' => [
1563 [
1564 'unit' => 'minutes',
1565 'value' => 15,
1566 ]
1567 ]
1568 ],
1569 ],
1570 'reminder_to_host' => [
1571 'enabled' => false,
1572 'is_host' => true,
1573 'title' => __('Configure Meeting Reminder to Organizer (You)', 'fluent-booking'),
1574 'email' => [
1575 'additional_recipients' => '',
1576 'subject' => 'Meeting Reminder with {{host.name}} @ {{booking.start_date_time_for_host}}',
1577 '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>',
1578 'times' => [
1579 [
1580 'unit' => 'minutes',
1581 'value' => 15,
1582 ]
1583 ]
1584 ],
1585 ],
1586 'cancelled_by_attendee' => [
1587 'enabled' => true,
1588 'is_host' => true,
1589 'title' => __('Booking Cancelled by Attendee (email to Organizer)', 'fluent-booking'),
1590 'email' => [
1591 'additional_recipients' => '',
1592 'subject' => 'A booking was cancelled with {{guest.full_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>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>'
1594 ],
1595 ],
1596 'cancelled_by_host' => [
1597 'enabled' => true,
1598 'title' => __('Booking Cancelled by Organizer (email to Attendee)', 'fluent-booking'),
1599 'email' => [
1600 'subject' => 'Your booking was cancelled with {{host.name}}',
1601 '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>'
1602 ],
1603 ],
1604 'rescheduled_by_attendee' => [
1605 'enabled' => true,
1606 'is_host' => true,
1607 'title' => __('Booking Rescheduled by Attendee (email to Organizer)', 'fluent-booking'),
1608 'email' => [
1609 'additional_recipients' => '',
1610 'subject' => 'A booking was rescheduled with {{guest.full_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>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>'
1612 ],
1613 ],
1614 'rescheduled_by_host' => [
1615 'enabled' => true,
1616 'title' => __('Booking Rescheduled by Organizer (email to Attendee)', 'fluent-booking'),
1617 'email' => [
1618 'subject' => 'Your booking was rescheduled with {{host.name}}',
1619 '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)
1620 ],
1621 ],
1622 'booking_request_host' => [
1623 'enabled' => true,
1624 'is_host' => true,
1625 'title' => __('Booking Approval Request to Host (email to Organizer)', 'fluent-booking'),
1626 'email' => [
1627 'additional_recipients' => '',
1628 'subject' => 'Awaiting Approval: {{guest.full_name}} @ {{booking.start_date_time_for_host}}',
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;">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>'
1630 ],
1631 ],
1632 'booking_request_attendee' => [
1633 'enabled' => true,
1634 'title' => __('Booking Submission Confirmation (email to Attendee)', 'fluent-booking'),
1635 'email' => [
1636 'subject' => 'Booking Submitted: Meeting between {{host.name}} & {{guest.full_name}}',
1637 '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>'
1638 ],
1639 ],
1640 'declined_by_host' => [
1641 'enabled' => true,
1642 'title' => __('Booking Declined by Organizer (email to Attendee)', 'fluent-booking'),
1643 'email' => [
1644 'subject' => 'Booking Declined: Your booking was declined with {{host.name}}',
1645 '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>'
1646 ],
1647 ],
1648 ]);
1649 }
1650
1651 public static function getAddToCalendarHtml($assetUrl = '')
1652 {
1653 $assetUrl = $assetUrl ?: App::getInstance()['url.assets'];
1654
1655 $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>';
1656
1657 return apply_filters('fluent_booking/add_to_calendar_html', $html);
1658 }
1659
1660 public static function getConfirmAndRejectButton($assetUrl = '')
1661 {
1662 $assetUrl = $assetUrl ?: App::getInstance()['url.assets'];
1663
1664 $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>';
1665
1666 return apply_filters('fluent_booking/confirm_and_reject_button_html', $html);
1667 }
1668
1669 public static function getEditorShortCodes($calendarEvent = null, $isHtmlSupported = false)
1670 {
1671 if (!$isHtmlSupported) {
1672 $groups = [
1673 'guest' => [
1674 'title' => __('Attendee Data', 'fluent-booking'),
1675 'key' => 'guest',
1676 'shortcodes' => [
1677 '{{guest.first_name}}' => __('Guest First Name', 'fluent-booking'),
1678 '{{guest.last_name}}' => __('Guest Last Name', 'fluent-booking'),
1679 '{{guest.full_name}}' => __('Guest Full Name', 'fluent-booking'),
1680 '{{guest.email}}' => __('Guest Email', 'fluent-booking'),
1681 '{{guest.note}}' => __('Guest Note', 'fluent-booking'),
1682 '{{booking.phone}}' => __('Guest Main Phone Number (if provided)', 'fluent-booking'),
1683 '{{guest.timezone}}' => __('Guest Timezone', 'fluent-booking')
1684 ]
1685 ],
1686 'booking' => [
1687 'title' => __('Booking Data', 'fluent-booking'),
1688 'key' => 'booking',
1689 'shortcodes' => [
1690 '{{booking.event_name}}' => __('Event Name', 'fluent-booking'),
1691 '{{booking.description}}' => __('Event Description', 'fluent-booking'),
1692 '{{booking.booking_title}}' => __('Booking Title', 'fluent-booking'),
1693 '{{booking.additional_guests}}' => __('Additional Guests', 'fluent-booking'),
1694 '{{booking.full_start_end_guest_timezone}}' => __('Full Start Date Time (with guest timezone)', 'fluent-booking'),
1695 '{{booking.full_start_end_host_timezone}}' => __('Full Start Date Time (with host timezone)', 'fluent-booking'),
1696 '{{booking.full_start_and_end_guest_timezone}}' => __('Full Start & End Date Time (with guest timezone)', 'fluent-booking'),
1697 '{{booking.full_start_and_end_host_timezone}}' => __('Full Start & End Date Time (with host timezone)', 'fluent-booking'),
1698 '{{booking.start_date_time}}' => __('Event Date Time (UTC)', 'fluent-booking'),
1699 '{{booking.start_date_time_for_attendee}}' => __('Event Date Time (with attendee timezone)', 'fluent-booking'),
1700 '{{booking.start_date_time_for_host}}' => __('Event Date Time (with host timezone)', 'fluent-booking'),
1701 '{{booking.location_details_text}}' => __('Event Location Details', 'fluent-booking'),
1702 '{{booking.cancel_reason}}' => __('Event Cancel Reason', 'fluent-booking'),
1703 '{{booking.start_time_human_format}}' => __('Event Start Time (ex: 2 hours from now)', 'fluent-booking'),
1704 '##booking.cancelation_url##' => __('Booking Cancellation URL', 'fluent-booking'),
1705 '##booking.reschedule_url##' => __('Booking Reschedule URL', 'fluent-booking'),
1706 '##booking.admin_booking_url##' => __('Booking Details Admin URL', 'fluent-booking'),
1707 '{{booking.booking_hash}}' => __('Unique Booking Hash', 'fluent-booking'),
1708 '{{booking.reschedule_reason}}' => __('Event Reschedule Reason', 'fluent-booking')
1709 ]
1710 ],
1711 'host' => [
1712 'title' => __('Host Data', 'fluent-booking'),
1713 'key' => 'host',
1714 'shortcodes' => [
1715 '{{host.name}}' => __('Host Name', 'fluent-booking'),
1716 '{{host.email}}' => __('Host Email', 'fluent-booking'),
1717 '{{host.timezone}}' => __('Host Timezone', 'fluent-booking'),
1718 ]
1719 ],
1720 'other' => [
1721 'title' => __('Other', 'fluent-booking'),
1722 'key' => 'other',
1723 'shortcodes' => [
1724 '{{event.id}}' => __('Event ID', 'fluent-booking'),
1725 '{{calendar.id}}' => __('Calendar ID', 'fluent-booking'),
1726 '{{event.title}}' => __('Event Title', 'fluent-booking'),
1727 '{{calendar.title}}' => __('Calendar Title', 'fluent-booking'),
1728 '{{calendar.description}}' => __('Calendar Description', 'fluent-booking'),
1729 '{{add_booking_to_calendar}}' => __('Add Booking to Calendar', 'fluent-booking'),
1730 ]
1731 ]
1732 ];
1733 } else {
1734 $groups = [
1735 'guest' => [
1736 'title' => __('Attendee Data', 'fluent-booking'),
1737 'key' => 'guest',
1738 'shortcodes' => [
1739 '{{guest.first_name}}' => __('Guest First Name', 'fluent-booking'),
1740 '{{guest.last_name}}' => __('Guest Last Name', 'fluent-booking'),
1741 '{{guest.full_name}}' => __('Guest Full Name', 'fluent-booking'),
1742 '{{guest.email}}' => __('Guest Email', 'fluent-booking'),
1743 '{{booking.phone}}' => __('Guest Main Phone Number (if provided)', 'fluent-booking'),
1744 '{{guest.note}}' => __('Guest Note', 'fluent-booking'),
1745 '{{guest.timezone}}' => __('Guest Timezone', 'fluent-booking'),
1746 '{{guest.form_data_html}}' => __('Guest Form Submitted Data (HTML)', 'fluent-booking')
1747 ]
1748 ],
1749 'booking' => [
1750 'title' => __('Booking Data', 'fluent-booking'),
1751 'key' => 'booking',
1752 'shortcodes' => [
1753 '{{booking.event_name}}' => __('Event Name', 'fluent-booking'),
1754 '{{booking.description}}' => __('Event Description', 'fluent-booking'),
1755 '{{booking.booking_title}}' => __('Booking Title', 'fluent-booking'),
1756 '{{booking.additional_guests}}' => __('Additional Guests', 'fluent-booking'),
1757 '{{booking.full_start_end_guest_timezone}}' => __('Full Start Date Time (with guest timezone)', 'fluent-booking'),
1758 '{{booking.full_start_end_host_timezone}}' => __('Full Start Date Time (with host timezone)', 'fluent-booking'),
1759 '{{booking.full_start_and_end_guest_timezone}}' => __('Full Start & End Date Time (with guest timezone)', 'fluent-booking'),
1760 '{{booking.full_start_and_end_host_timezone}}' => __('Full Start & End Date Time (with host timezone)', 'fluent-booking'),
1761 '{{booking.start_date_time}}' => __('Event Date Time (UTC)', 'fluent-booking'),
1762 '{{booking.start_date_time_for_attendee}}' => __('Event Date time (with guest timezone)', 'fluent-booking'),
1763 '{{booking.start_date_time_for_host}}' => __('Event Date time (with host timezone)', 'fluent-booking'),
1764 '{{booking.location_details_html}}' => __('Event Location Details (HTML)', 'fluent-booking'),
1765 '{{booking.cancel_reason}}' => __('Event Cancel Reason', 'fluent-booking'),
1766 '{{booking.start_time_human_format}}' => __('Event Start Time (ex: 2 hours from now)', 'fluent-booking'),
1767 '##booking.cancelation_url##' => __('Booking Cancellation URL', 'fluent-booking'),
1768 '##booking.reschedule_url##' => __('Booking Reschedule URL', 'fluent-booking'),
1769 '##booking.admin_booking_url##' => __('Booking Details Admin URL', 'fluent-booking'),
1770 '{{booking.booking_hash}}' => __('Unique Booking Hash', 'fluent-booking'),
1771 '{{booking.reschedule_reason}}' => __('Event Reschedule Reason', 'fluent-booking')
1772 ]
1773 ],
1774 'host' => [
1775 'title' => __('Host Data', 'fluent-booking'),
1776 'key' => 'host',
1777 'shortcodes' => [
1778 '{{host.name}}' => __('Host Name', 'fluent-booking'),
1779 '{{host.email}}' => __('Host Email', 'fluent-booking'),
1780 '{{host.timezone}}' => __('Host Timezone', 'fluent-booking'),
1781 ]
1782 ],
1783 'other' => [
1784 'title' => __('Other', 'fluent-booking'),
1785 'key' => 'other',
1786 'shortcodes' => [
1787 '{{event.id}}' => __('Event ID', 'fluent-booking'),
1788 '{{event.calendar_id}}' => __('Calendar ID', 'fluent-booking'),
1789 '{{event.title}}' => __('Event Title', 'fluent-booking'),
1790 '{{calendar.title}}' => __('Calendar Title', 'fluent-booking'),
1791 '{{calendar.description}}' => __('Calendar Description', 'fluent-booking'),
1792 '{{add_booking_to_calendar}}' => __('Add Booking to Calendar', 'fluent-booking'),
1793 ]
1794 ]
1795 ];
1796 }
1797
1798 if ($calendarEvent) {
1799 $customFields = BookingFieldService::getCustomFields($calendarEvent, true);
1800 foreach ($customFields as $fieldKey => $field) {
1801 $groups['booking']['shortcodes']['{{booking.custom.' . $fieldKey . '}}'] = $field['label'];
1802 if ($field['type'] == 'date') {
1803 $groups['booking']['shortcodes']['{{booking.custom.' . $fieldKey . '.format.Y-m-d}}'] = $field['label'] . ' (Ex: 2024-05-20)';
1804 }
1805 }
1806
1807 if (Helper::isPaymentEnabled($calendarEvent)) {
1808 $groups['payment'] = [
1809 'title' => __('Payment Data', 'fluent-booking'),
1810 'key' => 'payment',
1811 'shortcodes' => [
1812 '{{payment.payment_total}}' => __('Payment Total', 'fluent-booking'),
1813 '{{payment.payment_status}}' => __('Payment Status', 'fluent-booking'),
1814 '{{payment.payment_method}}' => __('Payment Method', 'fluent-booking'),
1815 '{{payment.currency}}' => __('Currency', 'fluent-booking'),
1816 '{{payment.payment_date}}' => __('Payment Date', 'fluent-booking'),
1817 ]
1818 ];
1819
1820 if ($isHtmlSupported) {
1821 $groups['payment']['shortcodes']['{{payment.receipt_html}}'] = __('Payment Receipt (HTML)', 'fluent-booking');
1822 }
1823 }
1824
1825 if ($calendarEvent->isMultiHostsEvent()) {
1826 $totalhost = count($calendarEvent->getHostIds());
1827 for ($i = 1; $i < $totalhost; $i++) {
1828 $groups['host']['shortcodes']['{{team_member.' . $i . '.name}}'] = __('Team Member ', 'fluent-booking') . $i . __(' Name', 'fluent-booking');
1829 $groups['host']['shortcodes']['{{team_member.' . $i . '.email}}'] = __('Team Member ', 'fluent-booking') . $i . __(' Email', 'fluent-booking');
1830 }
1831 }
1832 }
1833
1834 return apply_filters('fluent_booking/editor_shortcodes_groups', $groups, $calendarEvent, $isHtmlSupported);
1835 }
1836
1837 public static function encryptKey($value)
1838 {
1839 if (!$value) {
1840 return $value;
1841 }
1842
1843 if (!extension_loaded('openssl')) {
1844 return $value;
1845 }
1846
1847 $salt = (defined('LOGGED_IN_SALT') && '' !== LOGGED_IN_SALT) ? LOGGED_IN_SALT : 'this-is-a-fallback-salt-but-not-secure';
1848
1849 if (defined('FLUENT_BOOKING_ENCRYPTION_KEY')) {
1850 $key = FLUENT_BOOKING_ENCRYPTION_KEY;
1851 } else {
1852 $key = (defined('LOGGED_IN_KEY') && '' !== LOGGED_IN_KEY) ? LOGGED_IN_KEY : 'this-is-a-fallback-key-but-not-secure';
1853 }
1854
1855 $method = 'aes-256-ctr';
1856 $ivlen = openssl_cipher_iv_length($method);
1857 $iv = openssl_random_pseudo_bytes($ivlen);
1858
1859 $raw_value = openssl_encrypt($value . $salt, $method, $key, 0, $iv);
1860 if (!$raw_value) {
1861 return false;
1862 }
1863
1864 return base64_encode($iv . $raw_value); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
1865 }
1866
1867 public static function decryptKey($raw_value)
1868 {
1869
1870 if (!$raw_value) {
1871 return $raw_value;
1872 }
1873
1874 if (!extension_loaded('openssl')) {
1875 return $raw_value;
1876 }
1877
1878 $raw_value = base64_decode($raw_value, true); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
1879
1880 $method = 'aes-256-ctr';
1881 $ivlen = openssl_cipher_iv_length($method);
1882 $iv = substr($raw_value, 0, $ivlen);
1883
1884 $raw_value = substr($raw_value, $ivlen);
1885
1886 if (defined('FLUENT_BOOKING_ENCRYPTION_KEY')) {
1887 $key = FLUENT_BOOKING_ENCRYPTION_KEY;
1888 } else {
1889 $key = (defined('LOGGED_IN_KEY') && '' !== LOGGED_IN_KEY) ? LOGGED_IN_KEY : 'this-is-a-fallback-key-but-not-secure';
1890 }
1891
1892 $salt = (defined('LOGGED_IN_SALT') && '' !== LOGGED_IN_SALT) ? LOGGED_IN_SALT : 'this-is-a-fallback-salt-but-not-secure';
1893
1894 $value = openssl_decrypt($raw_value, $method, $key, 0, $iv);
1895 if (!$value || substr($value, -strlen($salt)) !== $salt) {
1896 return false;
1897 }
1898
1899 return substr($value, 0, -strlen($salt));
1900 }
1901
1902 public static function debugLog($data)
1903 {
1904 if (defined('FLUENT_BOOKING_DEBUG') && FLUENT_BOOKING_DEBUG) {
1905 error_log(print_r($data, true));
1906 }
1907 }
1908
1909 public static function getGlobalSettings($settingsKey = null)
1910 {
1911 $defaults = [
1912 'payments' => [
1913 'currency' => 'USD',
1914 'is_active' => 'no'
1915 ],
1916 'emailing' => [
1917 'from_name' => '',
1918 'from_email' => '',
1919 'reply_to_name' => '',
1920 'reply_to_email' => '',
1921 'use_host_name' => '',
1922 'use_host_email_on_reply' => '',
1923 'attach_ics_on_confirmation' => '',
1924 'email_footer' => ''
1925 ],
1926 'administration' => [
1927 'admin_email' => '{{wp.admin_email}}',
1928 'summary_notification' => 'no',
1929 'notification_frequency' => 'daily',
1930 'notification_day' => 'mon',
1931 'start_day' => 'sun',
1932 'auto_cancel_timing' => '10',
1933 'auto_complete_timing' => '60',
1934 'default_phone_country' => ''
1935 ],
1936 'time_format' => '12',
1937 'theme' => 'system-default'
1938 ];
1939
1940 $settings = get_option('_fluent_booking_settings', []);
1941
1942 if (empty($settings)) {
1943 $settings = [];
1944 }
1945
1946 $paymentSettings = get_option('fluent_booking_global_payment_settings', []);
1947
1948 if ($paymentSettings) {
1949 $settings['payments'] = $paymentSettings;
1950 }
1951
1952 $settings = wp_parse_args($settings, $defaults);
1953
1954 $emailSettings = $settings['emailing'];
1955
1956 if (empty($settings['administration']['auto_cancel_timing'])) {
1957 $settings['administration']['auto_cancel_timing'] = '10';
1958 }
1959
1960 if (empty($settings['administration']['auto_complete_timing'])) {
1961 $settings['administration']['auto_complete_timing'] = '10';
1962 }
1963
1964 if (empty($emailSettings['from_name']) && defined('FLUENTCRM')) {
1965 $crmSettings = fluentcrmGetGlobalSettings('email_settings', []);
1966 $emailSettings['from_name'] = Arr::get($crmSettings, 'from_name');
1967 if (empty($emailSettings['from_email'])) {
1968 $emailSettings['from_email'] = Arr::get($crmSettings, 'from_email');
1969 }
1970 if (empty($emailSettings['reply_to_name'])) {
1971 $emailSettings['reply_to_name'] = Arr::get($crmSettings, 'reply_to_name');
1972 }
1973 if (empty($emailSettings['reply_to_email'])) {
1974 $emailSettings['reply_to_email'] = Arr::get($crmSettings, 'reply_to_email');
1975 }
1976
1977 $settings['emailing'] = $emailSettings;
1978 }
1979
1980 if ($settingsKey) {
1981 return Arr::get($settings, $settingsKey, []);
1982 }
1983
1984 return $settings;
1985
1986 }
1987
1988 public static function getGlobalAdminSetting($key = null, $default = null)
1989 {
1990 static $settings;
1991 if ($settings) {
1992
1993 if ($key) {
1994 return Arr::get($settings, $key, $default);
1995 }
1996
1997 return $settings;
1998 }
1999
2000 $globalSettings = self::getGlobalSettings();
2001 $settings = Arr::get($globalSettings, 'administration', []);
2002
2003 if ($key) {
2004 return Arr::get($settings, $key, $default);
2005 }
2006
2007 return $settings;
2008 }
2009
2010 public static function getDefaultTimeFormat()
2011 {
2012 static $format;
2013
2014 if ($format) {
2015 return $format;
2016 }
2017
2018 $settings = self::getGlobalSettings();
2019 $format = Arr::get($settings, 'time_format', '24');
2020 return $format;
2021 }
2022
2023 public static function getVerifiedSenders()
2024 {
2025 $verifiedSenders = [];
2026 if (defined('FLUENTMAIL')) {
2027 $smtpSettings = get_option('fluentmail-settings', []);
2028 if ($smtpSettings && count($smtpSettings['mappings'])) {
2029 $verifiedSenders = array_keys($smtpSettings['mappings']);
2030 }
2031 }
2032 /**
2033 * Filter the verified email senders
2034 * @param array $verifiedSenders
2035 */
2036 return apply_filters('fluent_booking/verfied_email_senders', $verifiedSenders);
2037 }
2038
2039 public static function getBookingReceiptLandingBaseUrl()
2040 {
2041 return apply_filters('fluent_booking/booking_receipt_landing_base_url', site_url('/'));
2042 }
2043
2044 public static function getGlobalModuleSettings($cached = true)
2045 {
2046 static $settings = null;
2047
2048 if ($cached && $settings !== null) {
2049 return $settings;
2050 }
2051
2052 $settings = get_option('_fluent_booking_enabled_modules', []);
2053
2054 if (empty($settings) || !\is_array($settings)) {
2055 $settings = [];
2056 }
2057
2058 return $settings;
2059 }
2060
2061 public static function updateGlobalModuleSettings($settings = [])
2062 {
2063 if (!is_array($settings)) {
2064 $settings = [];
2065 }
2066
2067 update_option('_fluent_booking_enabled_modules', $settings);
2068
2069 return self::getGlobalModuleSettings(false);
2070 }
2071
2072 public static function isModuleEnabled($module)
2073 {
2074 $settings = self::getGlobalModuleSettings();
2075
2076 return isset($settings[$module]) && $settings[$module] === 'yes';
2077 }
2078
2079 /**
2080 * @return mixed|void
2081 */
2082 public static function fluentbooking_is_rtl()
2083 {
2084 /**
2085 * If FluentBooking is running on RTL Mode
2086 *
2087 * @param bool $is_rtl
2088 */
2089 return apply_filters('fluent_booking/is_rtl', is_rtl());
2090 }
2091
2092 public static function fluentBookingUserAvatar($id_or_email, $args)
2093 {
2094 if (empty($id_or_email)) {
2095 return '';
2096 }
2097 return apply_filters('fluent_booking/author_photo', get_avatar_url($id_or_email), $args);
2098 }
2099
2100 public static function getPrefSettins($cached = true)
2101 {
2102 static $pref = null;
2103
2104 if ($cached && $pref) {
2105 return $pref;
2106 }
2107
2108 $settings = [
2109 'frontend' => [
2110 'enabled' => 'no',
2111 'slug' => 'my-bookings',
2112 'render_type' => 'standalone',
2113 'page_id' => ''
2114 ]
2115 ];
2116
2117 $storedSettings = get_option('fluent_booking_modules', []);
2118
2119 if ($storedSettings && is_array($storedSettings)) {
2120 $settings = wp_parse_args($storedSettings, $settings);
2121 } else {
2122 update_option('fluent_booking_modules', $settings, 'yes');
2123 }
2124
2125 $pref = $settings;
2126
2127 return $settings;
2128 }
2129 }
2130