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

2,157 lines 76.4 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&theme=' . self::getActiveThemeName();
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 {
1218 $days = floor($totalMinutes / 1440); // 1440 minutes in a day
1219 $hours = floor(($totalMinutes % 1440) / 60);
1220 $minutes = $totalMinutes % 60;
1221
1222 $formattedDuration = [];
1223 if ($days > 0) {
1224 $unit = $days > 1 ? __('Days', 'fluent-booking') : __('Day', 'fluent-booking');
1225 $formattedDuration[] = $days . ' ' . $unit;
1226 }
1227
1228 if ($hours > 0) {
1229 $unit = $hours > 1 ? __('Hours', 'fluent-booking') : __('Hour', 'fluent-booking');
1230 $formattedDuration[] = $hours . ' ' . $unit;
1231 }
1232
1233 if ($minutes > 0 || empty($formattedDuration)) {
1234 $unit = $minutes > 1 ? __('Minutes', 'fluent-booking') : __('Minute', 'fluent-booking');
1235 $formattedDuration[] = $minutes . ' ' . $unit;
1236 }
1237
1238 return implode(' ', $formattedDuration);
1239 }
1240
1241 public static function getBufferTimes()
1242 {
1243 return apply_filters('fluent_booking/buffer_times_schema', [
1244 [
1245 'value' => '0',
1246 'label' => __('No buffer time', 'fluent-booking')
1247 ],
1248 [
1249 'value' => '5',
1250 'label' => __('5 Minutes', 'fluent-booking')
1251 ],
1252 [
1253 'value' => '10',
1254 'label' => __('10 Minutes', 'fluent-booking')
1255 ],
1256 [
1257 'value' => '15',
1258 'label' => __('15 Minutes', 'fluent-booking')
1259 ],
1260 [
1261 'value' => '20',
1262 'label' => __('20 Minutes', 'fluent-booking')
1263 ],
1264 [
1265 'value' => '30',
1266 'label' => __('30 Minutes', 'fluent-booking')
1267 ],
1268 [
1269 'value' => '45',
1270 'label' => __('45 Minutes', 'fluent-booking')
1271 ],
1272 [
1273 'value' => '60',
1274 'label' => __('60 Minutes', 'fluent-booking')
1275 ],
1276 [
1277 'value' => '90',
1278 'label' => __('90 Minutes', 'fluent-booking')
1279 ],
1280 [
1281 'value' => '120',
1282 'label' => __('120 Minutes', 'fluent-booking')
1283 ]
1284 ]);
1285 }
1286
1287 public static function getSlotIntervals()
1288 {
1289 return apply_filters('fluent_booking/slot_intervals_schema', [
1290 [
1291 'value' => '',
1292 'label' => __('Use event length (default)', 'fluent-booking')
1293 ],
1294 [
1295 'value' => '5',
1296 'label' => __('5 Minutes', 'fluent-booking')
1297 ],
1298 [
1299 'value' => '10',
1300 'label' => __('10 Minutes', 'fluent-booking')
1301 ],
1302 [
1303 'value' => '15',
1304 'label' => __('15 Minutes', 'fluent-booking')
1305 ],
1306 [
1307 'value' => '20',
1308 'label' => __('20 Minutes', 'fluent-booking')
1309 ],
1310 [
1311 'value' => '30',
1312 'label' => __('30 Minutes', 'fluent-booking')
1313 ],
1314 [
1315 'value' => '45',
1316 'label' => __('45 Minutes', 'fluent-booking')
1317 ],
1318 [
1319 'value' => '60',
1320 'label' => __('60 Minutes', 'fluent-booking')
1321 ],
1322 [
1323 'value' => '75',
1324 'label' => __('75 Minutes', 'fluent-booking')
1325 ],
1326 [
1327 'value' => '90',
1328 'label' => __('90 Minutes', 'fluent-booking')
1329 ],
1330 [
1331 'value' => '105',
1332 'label' => __('105 Minutes', 'fluent-booking')
1333 ],
1334 [
1335 'value' => '120',
1336 'label' => __('120 Minutes', 'fluent-booking')
1337 ]
1338 ]);
1339 }
1340
1341 public static function getBookingStatusChangingTimes()
1342 {
1343 return apply_filters('fluent_booking/booking_status_changing_times_schema', [
1344 [
1345 'value' => '5',
1346 'label' => __('5 Minutes', 'fluent-booking')
1347 ],
1348 [
1349 'value' => '10',
1350 'label' => __('10 Minutes', 'fluent-booking')
1351 ],
1352 [
1353 'value' => '20',
1354 'label' => __('20 Minutes', 'fluent-booking')
1355 ],
1356 [
1357 'value' => '30',
1358 'label' => __('30 Minutes', 'fluent-booking')
1359 ],
1360 [
1361 'value' => '40',
1362 'label' => __('40 Minutes', 'fluent-booking')
1363 ],
1364 [
1365 'value' => '50',
1366 'label' => __('50 Minutes', 'fluent-booking')
1367 ],
1368 [
1369 'value' => '60',
1370 'label' => __('1 Hour', 'fluent-booking')
1371 ],
1372 [
1373 'value' => '120',
1374 'label' => __('2 Hours', 'fluent-booking')
1375 ],
1376 [
1377 'value' => '180',
1378 'label' => __('3 Hours', 'fluent-booking')
1379 ],
1380 [
1381 'value' => '360',
1382 'label' => __('6 Hours', 'fluent-booking')
1383 ],
1384 [
1385 'value' => '720',
1386 'label' => __('12 Hours', 'fluent-booking')
1387 ],
1388 [
1389 'value' => '1440',
1390 'label' => __('1 Day', 'fluent-booking')
1391 ],
1392 [
1393 'value' => '2880',
1394 'label' => __('2 Days', 'fluent-booking')
1395 ]
1396 ]);
1397 }
1398
1399 public static function getBookingPeriodOptions()
1400 {
1401 return apply_filters('fluent_booking/booking_period_options', [
1402 'upcoming' => __('Upcoming', 'fluent-booking'),
1403 'completed' => __('Completed', 'fluent-booking'),
1404 'pending' => __('Pending', 'fluent-booking'),
1405 'cancelled' => __('Cancelled', 'fluent-booking'),
1406 'all' => __('All', 'fluent-booking'),
1407 ]);
1408 }
1409
1410 public static function getWeekSelectTimes()
1411 {
1412 return apply_filters('fluent_booking/week_select_times_schema', [
1413 'start' => '00:00',
1414 'step' => '00:15',
1415 'end' => '23:45'
1416 ]);
1417 }
1418
1419 public static function getOverrideSelectTimes()
1420 {
1421 return apply_filters('fluent_booking/override_select_times_schema', [
1422 'start' => '00:00',
1423 'step' => '00:15',
1424 'end' => '23:45'
1425 ]);
1426 }
1427
1428 public static function getWeeklyScheduleSchema()
1429 {
1430 return apply_filters('fluent_booking/weekly_schedule_schema', [
1431 'sun' => [
1432 'enabled' => false,
1433 'slots' => []
1434 ],
1435 'mon' => [
1436 'enabled' => true,
1437 'slots' => [
1438 ['start' => '09:00', 'end' => '17:00']
1439 ],
1440 ],
1441 'tue' => [
1442 'enabled' => true,
1443 'slots' => [
1444 ['start' => '09:00', 'end' => '17:00']
1445 ],
1446 ],
1447 'wed' => [
1448 'enabled' => true,
1449 'slots' => [
1450 ['start' => '09:00', 'end' => '17:00']
1451 ],
1452 ],
1453 'thu' => [
1454 'enabled' => true,
1455 'slots' => [
1456 ['start' => '09:00', 'end' => '17:00']
1457 ],
1458 ],
1459 'fri' => [
1460 'enabled' => true,
1461 'slots' => [
1462 ['start' => '09:00', 'end' => '17:00']
1463 ],
1464 ],
1465 'sat' => [
1466 'enabled' => false,
1467 'slots' => []
1468 ],
1469 ]);
1470 }
1471
1472 public static function getCustomFieldTypes()
1473 {
1474 return apply_filters('fluent_booking/custom_fields_types', [
1475 [
1476 'value' => 'email',
1477 'label' => __('Email', 'fluent-booking')
1478 ],
1479 [
1480 'value' => 'text',
1481 'label' => __('Text', 'fluent-booking')
1482 ],
1483 [
1484 'value' => 'textarea',
1485 'label' => __('Textarea', 'fluent-booking')
1486 ],
1487 [
1488 'value' => 'number',
1489 'label' => __('Number', 'fluent-booking')
1490 ],
1491 [
1492 'value' => 'phone',
1493 'label' => __('Phone', 'fluent-booking')
1494 ],
1495 [
1496 'value' => 'radio',
1497 'label' => __('Radio', 'fluent-booking')
1498 ],
1499 [
1500 'value' => 'dropdown',
1501 'label' => __('Select', 'fluent-booking')
1502 ],
1503 [
1504 'value' => 'multi-select',
1505 'label' => __('Multi Select', 'fluent-booking')
1506 ],
1507 [
1508 'value' => 'checkbox',
1509 'label' => __('Checkbox', 'fluent-booking')
1510 ],
1511 [
1512 'value' => 'checkbox-group',
1513 'label' => __('Checkbox Group', 'fluent-booking')
1514 ],
1515 [
1516 'value' => 'date',
1517 'label' => __('Date', 'fluent-booking')
1518 ],
1519 [
1520 'value' => 'file',
1521 'label' => __('File', 'fluent-booking')
1522 ],
1523 [
1524 'value' => 'hidden',
1525 'label' => __('Hidden', 'fluent-booking')
1526 ],
1527 [
1528 'value' => 'terms-and-conditions',
1529 'label' => __('Terms & Conditions', 'fluent-booking')
1530 ]
1531 ]);
1532 }
1533
1534 public static function getDefaultTermsAndConditions()
1535 {
1536 $termsAndConditions = __('I have read and agree to the <a href="#" target="_blank" rel="noopener">Terms and Conditions</a> and <a href="#" target="_blank" rel="noopener">Privacy Policy</a>.', 'fluent-booking');
1537
1538 return apply_filters('fluent_booking/default_terms_and_conditions', $termsAndConditions);
1539 }
1540
1541 public static function getDefaultEmailNotificationSettings()
1542 {
1543 $assetUrl = App::getInstance()['url.assets'];
1544
1545 $checkImage = $assetUrl . 'images/check-mark.png';
1546 $cancelImage = $assetUrl . 'images/cancel-mark.png';
1547 $scheduleImage = $assetUrl . 'images/schedule-mark.png';
1548
1549 return apply_filters('fluent_booking/default_email_notification_settings', [
1550 'booking_conf_attendee' => [
1551 'enabled' => true,
1552 'title' => __('Booking Confirmation Email to Attendee', 'fluent-booking'),
1553 'email' => [
1554 'subject' => 'Booking Confirmation between {{host.name}} & {{guest.full_name}}',
1555 '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)
1556 ],
1557 ],
1558 'booking_conf_host' => [
1559 'enabled' => true,
1560 'is_host' => true,
1561 'title' => __('Booking Confirmation Email to Organizer (You)', 'fluent-booking'),
1562 'email' => [
1563 'additional_recipients' => '',
1564 'subject' => 'New Booking: {{guest.full_name}} @ {{booking.start_date_time_for_host}}',
1565 '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>'
1566 ],
1567 ],
1568 'reminder_to_attendee' => [
1569 'enabled' => false,
1570 'title' => __('Configure Meeting Reminder to Attendee', 'fluent-booking'),
1571 'email' => [
1572 'subject' => 'Meeting Reminder with {{host.name}} @ {{booking.start_date_time_for_attendee}}',
1573 '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>',
1574 'times' => [
1575 [
1576 'unit' => 'minutes',
1577 'value' => 15,
1578 ]
1579 ]
1580 ],
1581 ],
1582 'reminder_to_host' => [
1583 'enabled' => false,
1584 'is_host' => true,
1585 'title' => __('Configure Meeting Reminder to Organizer (You)', 'fluent-booking'),
1586 'email' => [
1587 'additional_recipients' => '',
1588 'subject' => 'Meeting Reminder with {{host.name}} @ {{booking.start_date_time_for_host}}',
1589 '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>',
1590 'times' => [
1591 [
1592 'unit' => 'minutes',
1593 'value' => 15,
1594 ]
1595 ]
1596 ],
1597 ],
1598 'cancelled_by_attendee' => [
1599 'enabled' => true,
1600 'is_host' => true,
1601 'title' => __('Booking Cancelled by Attendee (email to Organizer)', 'fluent-booking'),
1602 'email' => [
1603 'additional_recipients' => '',
1604 'subject' => 'A booking was cancelled with {{guest.full_name}}',
1605 '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>'
1606 ],
1607 ],
1608 'cancelled_by_host' => [
1609 'enabled' => true,
1610 'title' => __('Booking Cancelled by Organizer (email to Attendee)', 'fluent-booking'),
1611 'email' => [
1612 'subject' => 'Your booking was cancelled with {{host.name}}',
1613 '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>'
1614 ],
1615 ],
1616 'rescheduled_by_attendee' => [
1617 'enabled' => true,
1618 'is_host' => true,
1619 'title' => __('Booking Rescheduled by Attendee (email to Organizer)', 'fluent-booking'),
1620 'email' => [
1621 'additional_recipients' => '',
1622 'subject' => 'A booking was rescheduled with {{guest.full_name}}',
1623 '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>'
1624 ],
1625 ],
1626 'rescheduled_by_host' => [
1627 'enabled' => true,
1628 'title' => __('Booking Rescheduled by Organizer (email to Attendee)', 'fluent-booking'),
1629 'email' => [
1630 'subject' => 'Your booking was rescheduled with {{host.name}}',
1631 '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)
1632 ],
1633 ],
1634 'booking_request_host' => [
1635 'enabled' => true,
1636 'is_host' => true,
1637 'title' => __('Booking Approval Request to Host (email to Organizer)', 'fluent-booking'),
1638 'email' => [
1639 'additional_recipients' => '',
1640 'subject' => 'Awaiting Approval: {{guest.full_name}} @ {{booking.start_date_time_for_host}}',
1641 '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>'
1642 ],
1643 ],
1644 'booking_request_attendee' => [
1645 'enabled' => true,
1646 'title' => __('Booking Submission Confirmation (email to Attendee)', 'fluent-booking'),
1647 'email' => [
1648 'subject' => 'Booking Submitted: Meeting between {{host.name}} & {{guest.full_name}}',
1649 '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>'
1650 ],
1651 ],
1652 'declined_by_host' => [
1653 'enabled' => true,
1654 'title' => __('Booking Declined by Organizer (email to Attendee)', 'fluent-booking'),
1655 'email' => [
1656 'subject' => 'Booking Declined: Your booking was declined with {{host.name}}',
1657 '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>'
1658 ],
1659 ],
1660 ]);
1661 }
1662
1663 public static function getAddToCalendarHtml($assetUrl = '')
1664 {
1665 $assetUrl = $assetUrl ?: App::getInstance()['url.assets'];
1666
1667 $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>';
1668
1669 return apply_filters('fluent_booking/add_to_calendar_html', $html);
1670 }
1671
1672 public static function getConfirmAndRejectButton($assetUrl = '')
1673 {
1674 $assetUrl = $assetUrl ?: App::getInstance()['url.assets'];
1675
1676 $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>';
1677
1678 return apply_filters('fluent_booking/confirm_and_reject_button_html', $html);
1679 }
1680
1681 public static function getEditorShortCodes($calendarEvent = null, $isHtmlSupported = false)
1682 {
1683 if (!$isHtmlSupported) {
1684 $groups = [
1685 'guest' => [
1686 'title' => __('Attendee Data', 'fluent-booking'),
1687 'key' => 'guest',
1688 'shortcodes' => [
1689 '{{guest.first_name}}' => __('Guest First Name', 'fluent-booking'),
1690 '{{guest.last_name}}' => __('Guest Last Name', 'fluent-booking'),
1691 '{{guest.full_name}}' => __('Guest Full Name', 'fluent-booking'),
1692 '{{guest.email}}' => __('Guest Email', 'fluent-booking'),
1693 '{{guest.note}}' => __('Guest Note', 'fluent-booking'),
1694 '{{booking.phone}}' => __('Guest Main Phone Number (if provided)', 'fluent-booking'),
1695 '{{guest.timezone}}' => __('Guest Timezone', 'fluent-booking')
1696 ]
1697 ],
1698 'booking' => [
1699 'title' => __('Booking Data', 'fluent-booking'),
1700 'key' => 'booking',
1701 'shortcodes' => [
1702 '{{booking.event_name}}' => __('Event Name', 'fluent-booking'),
1703 '{{booking.description}}' => __('Event Description', 'fluent-booking'),
1704 '{{booking.booking_title}}' => __('Booking Title', 'fluent-booking'),
1705 '{{booking.additional_guests}}' => __('Additional Guests', 'fluent-booking'),
1706 '{{booking.full_start_end_guest_timezone}}' => __('Full Start Date Time (with guest timezone)', 'fluent-booking'),
1707 '{{booking.full_start_end_host_timezone}}' => __('Full Start Date Time (with host timezone)', 'fluent-booking'),
1708 '{{booking.full_start_and_end_guest_timezone}}' => __('Full Start & End Date Time (with guest timezone)', 'fluent-booking'),
1709 '{{booking.full_start_and_end_host_timezone}}' => __('Full Start & End Date Time (with host timezone)', 'fluent-booking'),
1710 '{{booking.start_date_time}}' => __('Event Date Time (UTC)', 'fluent-booking'),
1711 '{{booking.start_date_time_for_attendee}}' => __('Event Date Time (with attendee timezone)', 'fluent-booking'),
1712 '{{booking.start_date_time_for_host}}' => __('Event Date Time (with host timezone)', 'fluent-booking'),
1713 '{{booking.start_date_time_for_attendee.format.Y-m-d}}' => __('Event Date Time (with attendee timezone) (Ex: 2024-05-20)', 'fluent-booking'),
1714 '{{booking.start_date_time_for_host.format.Y-m-d}}' => __('Event Date Time (with host timezone) (Ex: 2024-05-20)', 'fluent-booking'),
1715 '{{booking.location_details_text}}' => __('Event Location Details', 'fluent-booking'),
1716 '{{booking.cancel_reason}}' => __('Event Cancel Reason', 'fluent-booking'),
1717 '{{booking.start_time_human_format}}' => __('Event Start Time (ex: 2 hours from now)', 'fluent-booking'),
1718 '##booking.cancelation_url##' => __('Booking Cancellation URL', 'fluent-booking'),
1719 '##booking.reschedule_url##' => __('Booking Reschedule URL', 'fluent-booking'),
1720 '##booking.admin_booking_url##' => __('Booking Details Admin URL', 'fluent-booking'),
1721 '{{booking.booking_hash}}' => __('Unique Booking Hash', 'fluent-booking'),
1722 '{{booking.reschedule_reason}}' => __('Event Reschedule Reason', 'fluent-booking')
1723 ]
1724 ],
1725 'host' => [
1726 'title' => __('Host Data', 'fluent-booking'),
1727 'key' => 'host',
1728 'shortcodes' => [
1729 '{{host.name}}' => __('Host Name', 'fluent-booking'),
1730 '{{host.email}}' => __('Host Email', 'fluent-booking'),
1731 '{{host.timezone}}' => __('Host Timezone', 'fluent-booking'),
1732 ]
1733 ],
1734 'other' => [
1735 'title' => __('Other', 'fluent-booking'),
1736 'key' => 'other',
1737 'shortcodes' => [
1738 '{{event.id}}' => __('Event ID', 'fluent-booking'),
1739 '{{calendar.id}}' => __('Calendar ID', 'fluent-booking'),
1740 '{{event.title}}' => __('Event Title', 'fluent-booking'),
1741 '{{calendar.title}}' => __('Calendar Title', 'fluent-booking'),
1742 '{{calendar.description}}' => __('Calendar Description', 'fluent-booking'),
1743 '{{add_booking_to_calendar}}' => __('Add Booking to Calendar', 'fluent-booking'),
1744 ]
1745 ]
1746 ];
1747 } else {
1748 $groups = [
1749 'guest' => [
1750 'title' => __('Attendee Data', 'fluent-booking'),
1751 'key' => 'guest',
1752 'shortcodes' => [
1753 '{{guest.first_name}}' => __('Guest First Name', 'fluent-booking'),
1754 '{{guest.last_name}}' => __('Guest Last Name', 'fluent-booking'),
1755 '{{guest.full_name}}' => __('Guest Full Name', 'fluent-booking'),
1756 '{{guest.email}}' => __('Guest Email', 'fluent-booking'),
1757 '{{booking.phone}}' => __('Guest Main Phone Number (if provided)', 'fluent-booking'),
1758 '{{guest.note}}' => __('Guest Note', 'fluent-booking'),
1759 '{{guest.timezone}}' => __('Guest Timezone', 'fluent-booking'),
1760 '{{guest.form_data_html}}' => __('Guest Form Submitted Data (HTML)', 'fluent-booking')
1761 ]
1762 ],
1763 'booking' => [
1764 'title' => __('Booking Data', 'fluent-booking'),
1765 'key' => 'booking',
1766 'shortcodes' => [
1767 '{{booking.event_name}}' => __('Event Name', 'fluent-booking'),
1768 '{{booking.description}}' => __('Event Description', 'fluent-booking'),
1769 '{{booking.booking_title}}' => __('Booking Title', 'fluent-booking'),
1770 '{{booking.additional_guests}}' => __('Additional Guests', 'fluent-booking'),
1771 '{{booking.full_start_end_guest_timezone}}' => __('Full Start Date Time (with guest timezone)', 'fluent-booking'),
1772 '{{booking.full_start_end_host_timezone}}' => __('Full Start Date Time (with host timezone)', 'fluent-booking'),
1773 '{{booking.full_start_and_end_guest_timezone}}' => __('Full Start & End Date Time (with guest timezone)', 'fluent-booking'),
1774 '{{booking.full_start_and_end_host_timezone}}' => __('Full Start & End Date Time (with host timezone)', 'fluent-booking'),
1775 '{{booking.start_date_time}}' => __('Event Date Time (UTC)', 'fluent-booking'),
1776 '{{booking.start_date_time_for_attendee}}' => __('Event Date time (with guest timezone)', 'fluent-booking'),
1777 '{{booking.start_date_time_for_host}}' => __('Event Date time (with host timezone)', 'fluent-booking'),
1778 '{{booking.start_date_time_for_attendee.format.Y-m-d}}' => __('Event Date Time (with attendee timezone) (Ex: 2024-05-20)', 'fluent-booking'),
1779 '{{booking.start_date_time_for_host.format.Y-m-d}}' => __('Event Date Time (with host timezone) (Ex: 2024-05-20)', 'fluent-booking'),
1780 '{{booking.location_details_html}}' => __('Event Location Details (HTML)', 'fluent-booking'),
1781 '{{booking.cancel_reason}}' => __('Event Cancel Reason', 'fluent-booking'),
1782 '{{booking.start_time_human_format}}' => __('Event Start Time (ex: 2 hours from now)', 'fluent-booking'),
1783 '##booking.cancelation_url##' => __('Booking Cancellation URL', 'fluent-booking'),
1784 '##booking.reschedule_url##' => __('Booking Reschedule URL', 'fluent-booking'),
1785 '##booking.admin_booking_url##' => __('Booking Details Admin URL', 'fluent-booking'),
1786 '{{booking.booking_hash}}' => __('Unique Booking Hash', 'fluent-booking'),
1787 '{{booking.reschedule_reason}}' => __('Event Reschedule Reason', 'fluent-booking')
1788 ]
1789 ],
1790 'host' => [
1791 'title' => __('Host Data', 'fluent-booking'),
1792 'key' => 'host',
1793 'shortcodes' => [
1794 '{{host.name}}' => __('Host Name', 'fluent-booking'),
1795 '{{host.email}}' => __('Host Email', 'fluent-booking'),
1796 '{{host.timezone}}' => __('Host Timezone', 'fluent-booking'),
1797 ]
1798 ],
1799 'other' => [
1800 'title' => __('Other', 'fluent-booking'),
1801 'key' => 'other',
1802 'shortcodes' => [
1803 '{{event.id}}' => __('Event ID', 'fluent-booking'),
1804 '{{event.calendar_id}}' => __('Calendar ID', 'fluent-booking'),
1805 '{{event.title}}' => __('Event Title', 'fluent-booking'),
1806 '{{calendar.title}}' => __('Calendar Title', 'fluent-booking'),
1807 '{{calendar.description}}' => __('Calendar Description', 'fluent-booking'),
1808 '{{add_booking_to_calendar}}' => __('Add Booking to Calendar', 'fluent-booking'),
1809 ]
1810 ]
1811 ];
1812 }
1813
1814 if ($calendarEvent) {
1815 $customFields = BookingFieldService::getCustomFields($calendarEvent, true);
1816 foreach ($customFields as $fieldKey => $field) {
1817 $groups['booking']['shortcodes']['{{booking.custom.' . $fieldKey . '}}'] = $field['label'];
1818 if ($field['type'] == 'date') {
1819 $groups['booking']['shortcodes']['{{booking.custom.' . $fieldKey . '.format.Y-m-d}}'] = $field['label'] . ' (Ex: 2024-05-20)';
1820 }
1821 }
1822
1823 if (Helper::isPaymentEnabled($calendarEvent)) {
1824 $groups['payment'] = [
1825 'title' => __('Payment Data', 'fluent-booking'),
1826 'key' => 'payment',
1827 'shortcodes' => [
1828 '{{payment.payment_total}}' => __('Payment Total', 'fluent-booking'),
1829 '{{payment.payment_status}}' => __('Payment Status', 'fluent-booking'),
1830 '{{payment.payment_method}}' => __('Payment Method', 'fluent-booking'),
1831 '{{payment.currency}}' => __('Currency', 'fluent-booking'),
1832 '{{payment.payment_date}}' => __('Payment Date', 'fluent-booking'),
1833 ]
1834 ];
1835
1836 if ($isHtmlSupported) {
1837 $groups['payment']['shortcodes']['{{payment.receipt_html}}'] = __('Payment Receipt (HTML)', 'fluent-booking');
1838 }
1839 }
1840
1841 if ($calendarEvent->isMultiHostsEvent()) {
1842 $totalhost = count($calendarEvent->getHostIds());
1843 for ($i = 1; $i < $totalhost; $i++) {
1844 $groups['host']['shortcodes']['{{team_member.' . $i . '.name}}'] = __('Team Member ', 'fluent-booking') . $i . __(' Name', 'fluent-booking');
1845 $groups['host']['shortcodes']['{{team_member.' . $i . '.email}}'] = __('Team Member ', 'fluent-booking') . $i . __(' Email', 'fluent-booking');
1846 }
1847 }
1848 }
1849
1850 return apply_filters('fluent_booking/editor_shortcodes_groups', $groups, $calendarEvent, $isHtmlSupported);
1851 }
1852
1853 public static function encryptKey($value)
1854 {
1855 if (!$value) {
1856 return $value;
1857 }
1858
1859 if (!extension_loaded('openssl')) {
1860 return $value;
1861 }
1862
1863 $salt = (defined('LOGGED_IN_SALT') && '' !== LOGGED_IN_SALT) ? LOGGED_IN_SALT : 'this-is-a-fallback-salt-but-not-secure';
1864
1865 if (defined('FLUENT_BOOKING_ENCRYPTION_KEY')) {
1866 $key = FLUENT_BOOKING_ENCRYPTION_KEY;
1867 } else {
1868 $key = (defined('LOGGED_IN_KEY') && '' !== LOGGED_IN_KEY) ? LOGGED_IN_KEY : 'this-is-a-fallback-key-but-not-secure';
1869 }
1870
1871 $method = 'aes-256-ctr';
1872 $ivlen = openssl_cipher_iv_length($method);
1873 $iv = openssl_random_pseudo_bytes($ivlen);
1874
1875 $raw_value = openssl_encrypt($value . $salt, $method, $key, 0, $iv);
1876 if (!$raw_value) {
1877 return false;
1878 }
1879
1880 return base64_encode($iv . $raw_value); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
1881 }
1882
1883 public static function decryptKey($raw_value)
1884 {
1885
1886 if (!$raw_value) {
1887 return $raw_value;
1888 }
1889
1890 if (!extension_loaded('openssl')) {
1891 return $raw_value;
1892 }
1893
1894 $raw_value = base64_decode($raw_value, true); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
1895
1896 $method = 'aes-256-ctr';
1897 $ivlen = openssl_cipher_iv_length($method);
1898 $iv = substr($raw_value, 0, $ivlen);
1899
1900 $raw_value = substr($raw_value, $ivlen);
1901
1902 if (defined('FLUENT_BOOKING_ENCRYPTION_KEY')) {
1903 $key = FLUENT_BOOKING_ENCRYPTION_KEY;
1904 } else {
1905 $key = (defined('LOGGED_IN_KEY') && '' !== LOGGED_IN_KEY) ? LOGGED_IN_KEY : 'this-is-a-fallback-key-but-not-secure';
1906 }
1907
1908 $salt = (defined('LOGGED_IN_SALT') && '' !== LOGGED_IN_SALT) ? LOGGED_IN_SALT : 'this-is-a-fallback-salt-but-not-secure';
1909
1910 $value = openssl_decrypt($raw_value, $method, $key, 0, $iv);
1911 if (!$value || substr($value, -strlen($salt)) !== $salt) {
1912 return false;
1913 }
1914
1915 return substr($value, 0, -strlen($salt));
1916 }
1917
1918 public static function debugLog($data)
1919 {
1920 if (defined('FLUENT_BOOKING_DEBUG') && FLUENT_BOOKING_DEBUG) {
1921 error_log(print_r($data, true));
1922 }
1923 }
1924
1925 public static function getGlobalSettings($settingsKey = null)
1926 {
1927 $defaults = [
1928 'payments' => [
1929 'currency' => 'USD',
1930 'is_active' => 'no'
1931 ],
1932 'emailing' => [
1933 'from_name' => '',
1934 'from_email' => '',
1935 'reply_to_name' => '',
1936 'reply_to_email' => '',
1937 'use_host_name' => '',
1938 'use_host_email_on_reply' => '',
1939 'attach_ics_on_confirmation' => '',
1940 'email_footer' => ''
1941 ],
1942 'administration' => [
1943 'admin_email' => '{{wp.admin_email}}',
1944 'summary_notification' => 'no',
1945 'notification_frequency' => 'daily',
1946 'notification_day' => 'mon',
1947 'start_day' => 'sun',
1948 'auto_cancel_timing' => '10',
1949 'auto_complete_timing' => '60',
1950 'default_phone_country' => ''
1951 ],
1952 'time_format' => '12',
1953 'theme' => 'system-default'
1954 ];
1955
1956 $settings = get_option('_fluent_booking_settings', []);
1957
1958 if (empty($settings)) {
1959 $settings = [];
1960 }
1961
1962 $paymentSettings = get_option('fluent_booking_global_payment_settings', []);
1963
1964 if ($paymentSettings) {
1965 $settings['payments'] = $paymentSettings;
1966 }
1967
1968 $settings = wp_parse_args($settings, $defaults);
1969
1970 $emailSettings = $settings['emailing'];
1971
1972 if (empty($settings['administration']['auto_cancel_timing'])) {
1973 $settings['administration']['auto_cancel_timing'] = '10';
1974 }
1975
1976 if (empty($settings['administration']['auto_complete_timing'])) {
1977 $settings['administration']['auto_complete_timing'] = '10';
1978 }
1979
1980 if (empty($emailSettings['from_name']) && defined('FLUENTCRM')) {
1981 $crmSettings = fluentcrmGetGlobalSettings('email_settings', []);
1982 $emailSettings['from_name'] = Arr::get($crmSettings, 'from_name');
1983 if (empty($emailSettings['from_email'])) {
1984 $emailSettings['from_email'] = Arr::get($crmSettings, 'from_email');
1985 }
1986 if (empty($emailSettings['reply_to_name'])) {
1987 $emailSettings['reply_to_name'] = Arr::get($crmSettings, 'reply_to_name');
1988 }
1989 if (empty($emailSettings['reply_to_email'])) {
1990 $emailSettings['reply_to_email'] = Arr::get($crmSettings, 'reply_to_email');
1991 }
1992
1993 $settings['emailing'] = $emailSettings;
1994 }
1995
1996 if ($settingsKey) {
1997 return Arr::get($settings, $settingsKey, []);
1998 }
1999
2000 return $settings;
2001
2002 }
2003
2004 public static function getGlobalAdminSetting($key = null, $default = null)
2005 {
2006 static $settings;
2007 if ($settings) {
2008
2009 if ($key) {
2010 return Arr::get($settings, $key, $default);
2011 }
2012
2013 return $settings;
2014 }
2015
2016 $globalSettings = self::getGlobalSettings();
2017 $settings = Arr::get($globalSettings, 'administration', []);
2018
2019 if ($key) {
2020 return Arr::get($settings, $key, $default);
2021 }
2022
2023 return $settings;
2024 }
2025
2026 public static function getDefaultTimeFormat()
2027 {
2028 static $format;
2029
2030 if ($format) {
2031 return $format;
2032 }
2033
2034 $settings = self::getGlobalSettings();
2035 $format = Arr::get($settings, 'time_format', '24');
2036 return $format;
2037 }
2038
2039 public static function getVerifiedSenders()
2040 {
2041 $verifiedSenders = [];
2042 if (defined('FLUENTMAIL')) {
2043 $smtpSettings = get_option('fluentmail-settings', []);
2044 if ($smtpSettings && count($smtpSettings['mappings'])) {
2045 $verifiedSenders = array_keys($smtpSettings['mappings']);
2046 }
2047 }
2048 /**
2049 * Filter the verified email senders
2050 * @param array $verifiedSenders
2051 */
2052 return apply_filters('fluent_booking/verfied_email_senders', $verifiedSenders);
2053 }
2054
2055 public static function getBookingReceiptLandingBaseUrl()
2056 {
2057 return apply_filters('fluent_booking/booking_receipt_landing_base_url', site_url('/'));
2058 }
2059
2060 public static function getGlobalModuleSettings($cached = true)
2061 {
2062 static $settings = null;
2063
2064 if ($cached && $settings !== null) {
2065 return $settings;
2066 }
2067
2068 $settings = get_option('_fluent_booking_enabled_modules', []);
2069
2070 if (empty($settings) || !\is_array($settings)) {
2071 $settings = [];
2072 }
2073
2074 return $settings;
2075 }
2076
2077 public static function updateGlobalModuleSettings($settings = [])
2078 {
2079 if (!is_array($settings)) {
2080 $settings = [];
2081 }
2082
2083 update_option('_fluent_booking_enabled_modules', $settings);
2084
2085 return self::getGlobalModuleSettings(false);
2086 }
2087
2088 public static function isModuleEnabled($module)
2089 {
2090 $settings = self::getGlobalModuleSettings();
2091
2092 return isset($settings[$module]) && $settings[$module] === 'yes';
2093 }
2094
2095 /**
2096 * @return mixed|void
2097 */
2098 public static function fluentbooking_is_rtl()
2099 {
2100 /**
2101 * If FluentBooking is running on RTL Mode
2102 *
2103 * @param bool $is_rtl
2104 */
2105 return apply_filters('fluent_booking/is_rtl', is_rtl());
2106 }
2107
2108 public static function fluentBookingUserAvatar($id_or_email, $args)
2109 {
2110 if (empty($id_or_email)) {
2111 return '';
2112 }
2113 return apply_filters('fluent_booking/author_photo', get_avatar_url($id_or_email), $args);
2114 }
2115
2116 public static function getPrefSettins($cached = true)
2117 {
2118 static $pref = null;
2119
2120 if ($cached && $pref) {
2121 return $pref;
2122 }
2123
2124 $settings = [
2125 'frontend' => [
2126 'enabled' => 'no',
2127 'slug' => 'my-bookings',
2128 'render_type' => 'standalone',
2129 'page_id' => ''
2130 ]
2131 ];
2132
2133 $storedSettings = get_option('fluent_booking_modules', []);
2134
2135 if ($storedSettings && is_array($storedSettings)) {
2136 $settings = wp_parse_args($storedSettings, $settings);
2137 } else {
2138 update_option('fluent_booking_modules', $settings, 'yes');
2139 }
2140
2141 $pref = $settings;
2142
2143 return $settings;
2144 }
2145
2146 public static function getActiveThemeName()
2147 {
2148 $ins = get_option('_fb_ins_by');
2149
2150 if ($ins) {
2151 return sanitize_text_field($ins);
2152 }
2153
2154 return get_option('template');
2155 }
2156 }
2157