where('id', '!=', $exceptId)->first(); } else { $exist = Calendar::where('slug', $slug)->first(); } if ($exist) { return false; } } if (is_numeric($slug)) { return false; } // check if $slug has any special characters or any space. We will only allow alpha-numeric values return preg_match('/^[a-zA-Z0-9_-]+$/', $slug); } public static function isEventSlugAvailable($slug, $checkDb = true, $calendarId = null, $exceptId = null) { if (in_array($slug, self::$reserved)) { return false; } if (strlen($slug) < 4) { return false; } if ($checkDb) { $eventQuery = CalendarSlot::where('slug', $slug); if ($exceptId) { $eventQuery->where('id', '!=', $exceptId); } if ($calendarId) { $eventQuery->where('calendar_id', $calendarId); } $exist = $eventQuery->first(); if ($exist) { return false; } } if (is_numeric($slug)) { return false; } // check if $slug has any special characters or any space. We will only allow alpha-numeric values return preg_match('/^[a-zA-Z0-9_-]+$/', $slug); } public static function getAppBaseUrl($extension = '') { return apply_filters('fluent_booking/admin_base_url', admin_url('admin.php?page=fluent-booking#/' . $extension), $extension); } public static function getAdminBookingUrl($bookingId) { return self::getAppBaseUrl('scheduled-events?booking_id=' . $bookingId); } public static function getUpgradeUrl() { return 'https://fluentbooking.com/pricing/?utm_source=plugin&utm_medium=wp_install&utm_campaign=fcal_upgrade'; } public static function getNextBookingGroup() { $lastBooking = Booking::orderBy('group_id', 'desc')->first(['group_id']); if ($lastBooking) { return $lastBooking->group_id + 1; } return 1; } public static function getNextIndex() { static $index = 0; $index += 1; return $index; } public static function getGlobalPaymentSettings() { static $settings; if ($settings) { return $settings; } $settings = get_option('fluent_booking_global_payment_settings', []); if (!$settings) { $settings = [ 'currency' => 'USD', 'is_active' => 'no' ]; } return $settings; } public static function isPaymentEnabled($calendarEvent = null) { $settings = self::getGlobalPaymentSettings(); if (Arr::get($settings, 'is_active') == 'yes') { return true; } if ($calendarEvent) { if ($calendarEvent->type != 'paid') { return false; } $exist = Meta::where('object_type', 'calendar_slot') ->where('object_id', $calendarEvent->id) ->where('key', 'payment_settings') ->first(); return $exist && $exist->value && Arr::get($exist->value, 'enabled') == 'yes'; } return false; } public static function isPaymentConfigured($method = 'stripe') { $settings = get_option('fluent_booking_payment_settings_' . $method, []); return Arr::get($settings, 'is_active', 'no') == 'yes'; } /** * Sanitize form inputs recursively. * * @param $input * * @return mixed $input */ public static function fluentbookingSanitizer($input, $attribute = null, $fields = []) { if (is_string($input)) { $element = Arr::get($fields, $attribute . '.element'); if (in_array($element, ['post_content', 'rich_text_input'])) { return wp_kses_post($input); } elseif ('textarea' === $element) { $input = sanitize_textarea_field($input); } elseif ('input_email' === $element) { $input = strtolower(sanitize_text_field($input)); } elseif ('input_url' === $element) { $input = sanitize_url($input); } else { $input = sanitize_text_field($input); } } elseif (is_array($input)) { foreach ($input as $key => &$value) { $attribute = $attribute ? $attribute . '[' . $key . ']' : $key; $value = self::fluentbookingSanitizer($value, $attribute, $fields); $attribute = null; } } return $input; } public static function getMeta($group, $objectId, $key, $withModel = false) { $meta = Meta::where('object_type', $group) ->where('object_id', $objectId) ->where('key', $key) ->first(); if ($meta) { if ($withModel) { return $meta; } return $meta->value; } return null; } public static function updateMeta($group, $objectId, $key, $value) { $meta = self::getMeta($group, $objectId, $key, true); if ($meta) { $meta->value = $value; $meta->save(); return $meta; } return Meta::create([ 'object_type' => $group, 'key' => $key, 'object_id' => $objectId, 'value' => $value ]); } public static function deleteMeta($group, $objectId, $key) { return Meta::where('object_type', $group) ->where('object_id', $objectId) ->where('key', $key) ->delete(); } public static function getBookingMeta($eventId, $metaKey, $withModel = false) { $bookingMeta = BookingMeta::where('booking_id', $eventId) ->where('meta_key', $metaKey) ->first(); if ($bookingMeta) { return $withModel ? $bookingMeta : $bookingMeta->value; } return null; } public static function updateBookingMeta($eventId, $metaKey, $value) { $bookingMeta = self::getBookingMeta($eventId, $metaKey, true); if ($bookingMeta) { $bookingMeta->value = $value; $bookingMeta->save(); return $bookingMeta; } return BookingMeta::create([ 'booking_id' => $eventId, 'meta_key' => $metaKey, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key 'value' => $value ]); } public static function getUserDisplayName($userId = null) { if (!$userId) { $userId = get_current_user_id(); } if (!$userId) { return ''; } $user = get_user_by('ID', $userId); $name = trim($user->first_name . ' ' . $user->last_name); if ($name) { return $name; } return $user->display_name; } public static function getUserEmail($userId = null) { $userId = $userId ?: get_current_user_id(); if (!$userId) { return ''; } $user = get_user_by('ID', $userId); return $user->user_email; } public static function excerpt($text, $max_length = 160) { // Strip HTML tags and convert entities to their corresponding characters $text = html_entity_decode(wp_strip_all_tags($text)); // Remove any line breaks, tabs, or extra whitespace $text = preg_replace('/\s+/', ' ', trim($text)); if (mb_strlen($text) > $max_length) { $text = mb_substr($text, 0, $max_length); $text = preg_replace('/\s+\S+$/', '', $text) . '...'; } return $text; } public static function generateSlotSlug($default, $calendar) { $original = sanitize_title($default, $default, 'display'); $default = $original; $counter = 1; while (CalendarSlot::where('calendar_id', $calendar->id)->where('slug', $default)->first()) { $default = $original . '-' . $counter; $counter += 1; } return apply_filters('fluent_booking/slot_slug', $default, $original); } public static function getIp() { $server = $_SERVER; $clientIp = Arr::get($server, 'HTTP_CLIENT_IP'); $xForwarded = Arr::get($server, 'HTTP_X_FORWARDED_FOR'); if (!empty($clientIp)) { $ip = $clientIp; } elseif (!empty($xForwarded)) { $ip = $clientIp; } else { $ip = $clientIp; } return sanitize_text_field($ip); } public static function fcal_sanitize_html($html) { if (!$html) { return $html; } // Return $html if it's just a plain text if (!preg_match('/<[^>]*>/', $html)) { return $html; } $tags = wp_kses_allowed_html('post'); $tags['style'] = [ 'types' => [], ]; // iframe $tags['iframe'] = [ 'width' => [], 'height' => [], 'src' => [], 'srcdoc' => [], 'title' => [], 'frameborder' => [], 'allow' => [], 'class' => [], 'id' => [], 'allowfullscreen' => [], 'style' => [], ]; //button $tags['button']['onclick'] = []; //svg if (empty($tags['svg'])) { $svg_args = [ 'svg' => [ 'class' => true, 'aria-hidden' => true, 'aria-labelledby' => true, 'role' => true, 'xmlns' => true, 'width' => true, 'height' => true, 'viewbox' => true, ], 'g' => ['fill' => true], 'title' => ['title' => true], 'path' => [ 'd' => true, 'fill' => true, 'transform' => true, ], ]; $tags = array_merge($tags, $svg_args); } $tags = apply_filters('fluent_booking/allowed_html_tags', $tags); return wp_kses($html, $tags); } /** * Sanitize inputs recursively. * * @param array $input * @param array $sanitizeMap * * @return array $input */ public static function fcal_backend_sanitizer($inputs, $sanitizeMap = []) { $originalValues = $inputs; foreach ($inputs as $key => &$value) { if (is_array($value)) { $value = self::fcal_backend_sanitizer($value, $sanitizeMap); } else { $method = Arr::get($sanitizeMap, $key); if (!$method) { continue; } if (is_callable($method)) { $value = call_user_func($method, $value); } elseif (method_exists(self::class, $method)) { $value = call_user_func([self::class, $method], $value); } } } return apply_filters('fluent_booking/backend_sanitized_values', $inputs, $originalValues); } /** * Recursively implode a multi-dimentional array * * @param string $glue * @param array $array * * @return string */ public static function fcalImplodeRecursive($glue, array $array) { $fn = function ($glue, array $array) use (&$fn) { $result = ''; foreach ($array as $item) { if (is_array($item)) { $result .= $fn($glue, $item); } else { $result .= $glue . $item; } } return $result; }; return ltrim($fn($glue, $array), $glue); } public static function getEventColors() { return apply_filters('fluent_booking/event_colors', [ [ 'label' => __('Red-Orange', 'fluent-booking'), 'value' => '#ff4f00' ], [ 'label' => __('Deep Lilac', 'fluent-booking'), 'value' => '#e55cff' ], [ 'label' => __('Purple', 'fluent-booking'), 'value' => '#8247f5' ], [ 'label' => __('Vivid Blue', 'fluent-booking'), 'value' => '#0099ff' ], [ 'label' => __('Cyan', 'fluent-booking'), 'value' => '#0ae8f0' ], [ 'label' => __('Emerald Green', 'fluent-booking'), 'value' => '#17e885' ], [ 'label' => __('Lime Green', 'fluent-booking'), 'value' => '#ccf000' ], [ 'label' => __('Amber', 'fluent-booking'), 'value' => '#ffa600' ] ]); } public static function getMeetingDurations() { return apply_filters('fluent_booking/meeting_durations_schema', [ [ 'value' => '15', 'label' => __('15 Minutes', 'fluent-booking') ], [ 'value' => '30', 'label' => __('30 Minutes', 'fluent-booking') ], [ 'value' => '45', 'label' => __('45 Minutes', 'fluent-booking') ], [ 'value' => '60', 'label' => __('60 Minutes', 'fluent-booking') ], [ 'value' => 'custom', 'label' => __('Custom', 'fluent-booking') ] ]); } public static function getMeetingMultiDurations() { return apply_filters('fluent_booking/meeting_multi_durations_schema', [ [ 'value' => '5', 'label' => __('5 Minutes', 'fluent-booking') ], [ 'value' => '10', 'label' => __('10 Minutes', 'fluent-booking') ], [ 'value' => '15', 'label' => __('15 Minutes', 'fluent-booking') ], [ 'value' => '30', 'label' => __('30 Minutes', 'fluent-booking') ], [ 'value' => '45', 'label' => __('45 Minutes', 'fluent-booking') ], [ 'value' => '50', 'label' => __('50 Minutes', 'fluent-booking') ], [ 'value' => '60', 'label' => __('60 Minutes', 'fluent-booking') ], [ 'value' => '90', 'label' => __('90 Minutes', 'fluent-booking') ], [ 'value' => '120', 'label' => __('120 Minutes', 'fluent-booking') ], [ 'value' => '150', 'label' => __('150 Minutes', 'fluent-booking') ], [ 'value' => '180', 'label' => __('180 Minutes', 'fluent-booking') ], [ 'value' => '240', 'label' => __('240 Minutes', 'fluent-booking') ], [ 'value' => '480', 'label' => __('480 Minutes', 'fluent-booking') ] ]); } public static function getDurationLookup($multiDuration = false) { $durations = $multiDuration ? self::getMeetingMultiDurations() : self::getMeetingDurations(); $durationLookup = []; foreach ($durations as $duration) { $durationLookup[$duration['value']] = $duration['label']; } return $durationLookup; } public static function getBufferTimes() { return apply_filters('fluent_booking/buffer_times_schema', [ [ 'value' => '0', 'label' => __('No buffer time', 'fluent-booking') ], [ 'value' => '5', 'label' => __('5 Minutes', 'fluent-booking') ], [ 'value' => '10', 'label' => __('10 Minutes', 'fluent-booking') ], [ 'value' => '15', 'label' => __('15 Minutes', 'fluent-booking') ], [ 'value' => '20', 'label' => __('20 Minutes', 'fluent-booking') ], [ 'value' => '30', 'label' => __('30 Minutes', 'fluent-booking') ], [ 'value' => '45', 'label' => __('45 Minutes', 'fluent-booking') ], [ 'value' => '60', 'label' => __('60 Minutes', 'fluent-booking') ], [ 'value' => '90', 'label' => __('90 Minutes', 'fluent-booking') ], [ 'value' => '120', 'label' => __('120 Minutes', 'fluent-booking') ] ]); } public static function getSlotIntervals() { return apply_filters('fluent_booking/slot_intervals_schema', [ [ 'value' => '', 'label' => __('Use event length (default)', 'fluent-booking') ], [ 'value' => '5', 'label' => __('5 Minutes', 'fluent-booking') ], [ 'value' => '10', 'label' => __('10 Minutes', 'fluent-booking') ], [ 'value' => '15', 'label' => __('15 Minutes', 'fluent-booking') ], [ 'value' => '20', 'label' => __('20 Minutes', 'fluent-booking') ], [ 'value' => '30', 'label' => __('30 Minutes', 'fluent-booking') ], [ 'value' => '45', 'label' => __('45 Minutes', 'fluent-booking') ], [ 'value' => '60', 'label' => __('60 Minutes', 'fluent-booking') ], [ 'value' => '75', 'label' => __('75 Minutes', 'fluent-booking') ], [ 'value' => '90', 'label' => __('90 Minutes', 'fluent-booking') ], [ 'value' => '105', 'label' => __('105 Minutes', 'fluent-booking') ], [ 'value' => '120', 'label' => __('120 Minutes', 'fluent-booking') ] ]); } public static function getBookingStatusChangingTimes() { return apply_filters('fluent_booking/booking_status_changing_times_schema', [ [ 'value' => '5', 'label' => __('5 Minutes', 'fluent-booking') ], [ 'value' => '10', 'label' => __('10 Minutes', 'fluent-booking') ], [ 'value' => '20', 'label' => __('20 Minutes', 'fluent-booking') ], [ 'value' => '30', 'label' => __('30 Minutes', 'fluent-booking') ], [ 'value' => '40', 'label' => __('40 Minutes', 'fluent-booking') ], [ 'value' => '50', 'label' => __('50 Minutes', 'fluent-booking') ], [ 'value' => '60', 'label' => __('1 Hour', 'fluent-booking') ], [ 'value' => '120', 'label' => __('2 Hours', 'fluent-booking') ], [ 'value' => '180', 'label' => __('3 Hours', 'fluent-booking') ], [ 'value' => '360', 'label' => __('6 Hours', 'fluent-booking') ], [ 'value' => '720', 'label' => __('12 Hours', 'fluent-booking') ], [ 'value' => '1440', 'label' => __('1 Day', 'fluent-booking') ], [ 'value' => '2880', 'label' => __('2 Days', 'fluent-booking') ] ]); } public static function getBookingPeriodOptions() { return apply_filters('fluent_booking/booking_period_options', [ 'upcoming' => __('Upcoming', 'fluent-booking'), 'completed' => __('Completed', 'fluent-booking'), 'pending' => __('Pending', 'fluent-booking'), 'cancelled' => __('Cancelled', 'fluent-booking'), 'all' => __('All', 'fluent-booking'), ]); } public static function getWeekSelectTimes() { return apply_filters('fluent_booking/week_select_times_schema', [ 'start' => '00:00', 'step' => '00:15', 'end' => '23:45' ]); } public static function getOverrideSelectTimes() { return apply_filters('fluent_booking/override_select_times_schema', [ 'start' => '00:00', 'step' => '00:15', 'end' => '23:45' ]); } public static function getWeeklyScheduleSchema() { return apply_filters('fluent_booking/weekly_schedule_schema', [ 'sun' => [ 'enabled' => false, 'slots' => [] ], 'mon' => [ 'enabled' => true, 'slots' => [ ['start' => '09:00', 'end' => '17:00'] ], ], 'tue' => [ 'enabled' => true, 'slots' => [ ['start' => '09:00', 'end' => '17:00'] ], ], 'wed' => [ 'enabled' => true, 'slots' => [ ['start' => '09:00', 'end' => '17:00'] ], ], 'thu' => [ 'enabled' => true, 'slots' => [ ['start' => '09:00', 'end' => '17:00'] ], ], 'fri' => [ 'enabled' => true, 'slots' => [ ['start' => '09:00', 'end' => '17:00'] ], ], 'sat' => [ 'enabled' => false, 'slots' => [] ], ]); } public static function getCustomFieldTypes() { return apply_filters('fluent_booking/custom_fields_types', [ [ 'value' => 'email', 'label' => __('Email', 'fluent-booking') ], [ 'value' => 'text', 'label' => __('Text', 'fluent-booking') ], [ 'value' => 'textarea', 'label' => __('Textarea', 'fluent-booking') ], [ 'value' => 'number', 'label' => __('Number', 'fluent-booking') ], [ 'value' => 'phone', 'label' => __('Phone', 'fluent-booking') ], [ 'value' => 'radio', 'label' => __('Radio', 'fluent-booking') ], [ 'value' => 'dropdown', 'label' => __('Select', 'fluent-booking') ], [ 'value' => 'multi-select', 'label' => __('Multi Select', 'fluent-booking') ], [ 'value' => 'checkbox', 'label' => __('Checkbox', 'fluent-booking') ], [ 'value' => 'checkbox-group', 'label' => __('Checkbox Group', 'fluent-booking') ], [ 'value' => 'date', 'label' => __('Date', 'fluent-booking') ] ]); } public static function getDefaultEmailNotificationSettings() { $assetUrl = App::getInstance()['url.assets']; $checkImage = $assetUrl . 'images/check-mark.png'; $cancelImage = $assetUrl . 'images/cancel-mark.png'; $scheduleImage = $assetUrl . 'images/schedule-mark.png'; return apply_filters('fluent_booking/default_email_notification_settings', [ 'booking_conf_attendee' => [ 'enabled' => true, 'title' => __('Booking Confirmation Email to Attendee', 'fluent-booking'), 'email' => [ 'subject' => 'Booking Confirmation between {{host.name}} & {{guest.full_name}}', 'body' => '

Your event has been scheduled


Event Name

{{booking.event_name}} with {{host.name}}

When

{{booking.full_start_end_guest_timezone}}

Who

Where

{{booking.location_details_html}}

Additional notes

{{guest.note}}


' . __('Need to make a change?', 'fluent-booking') . ' ' . __('Reschedule', 'fluent-booking') . ' or ' . __('Cancel', 'fluent-booking') . '


' . self::getAddToCalendarHtml($assetUrl) ], ], 'booking_conf_host' => [ 'enabled' => true, 'is_host' => true, 'title' => __('Booking Confirmation Email to Organizer (You)', 'fluent-booking'), 'email' => [ 'additional_recipients' => '', 'subject' => 'New Booking: {{guest.full_name}} @ {{booking.start_date_time_for_host}}', 'body' => '

A new event has been scheduled


Event Name

{{booking.event_name}} with {{guest.full_name}}

When

{{booking.full_start_end_host_timezone}}

Who

Where

{{booking.location_details_html}}

Note

{{guest.note}}

Additional Data

{{guest.form_data_html}}


View on the Website

' ], ], 'reminder_to_attendee' => [ 'enabled' => false, 'title' => __('Configure Meeting Reminder to Attendee', 'fluent-booking'), 'email' => [ 'subject' => 'Meeting Reminder with {{host.name}} @ {{booking.start_date_time_for_attendee}}', 'body' => '

Reminder: Your meeting will start in {{booking.start_time_human_format}}


Event Name

{{booking.event_name}} with {{host.name}}

When

{{booking.full_start_end_guest_timezone}}

Who

Where

{{booking.location_details_html}}

Additional notes

{{guest.note}}


' . __('Need to make a change?', 'fluent-booking') . ' ' . __('Reschedule', 'fluent-booking') . ' or ' . __('Cancel', 'fluent-booking') . '

', 'times' => [ [ 'unit' => 'minutes', 'value' => 15, ] ] ], ], 'reminder_to_host' => [ 'enabled' => false, 'is_host' => true, 'title' => __('Configure Meeting Reminder to Organizer (You)', 'fluent-booking'), 'email' => [ 'additional_recipients' => '', 'subject' => 'Meeting Reminder with {{host.name}} @ {{booking.start_date_time_for_host}}', 'body' => '

Reminder: Your meeting will start in {{booking.start_time_human_format}}


Event Name

{{booking.event_name}} with {{guest.full_name}}

When

{{booking.full_start_end_host_timezone}}

Who

Where

{{booking.location_details_html}}

Note

{{guest.note}}

Additional Data

{{guest.form_data_html}}


View on the Website

', 'times' => [ [ 'unit' => 'minutes', 'value' => 15, ] ] ], ], 'cancelled_by_attendee' => [ 'enabled' => true, 'is_host' => true, 'title' => __('Booking Cancelled by Attendee (email to Organizer)', 'fluent-booking'), 'email' => [ 'additional_recipients' => '', 'subject' => 'A booking was cancelled with {{guest.full_name}}', 'body' => '

Booking Cancellation


A scheduled meeting has been canceled. Here are the details:

Event Name

{{booking.event_name}} with {{guest.full_name}}

When

{{booking.full_start_end_host_timezone}} (cancelled)

Cancellation Reason

{{booking.cancel_reason}}

Who

Where

{{booking.location_details_html}}

Note

{{guest.note}}

Additional Data

{{guest.form_data_html}}


View on the Website

' ], ], 'cancelled_by_host' => [ 'enabled' => true, 'title' => __('Booking Cancelled by Organizer (email to Attendee)', 'fluent-booking'), 'email' => [ 'subject' => 'Your booking was cancelled with {{host.name}}', 'body' => '

Booking Cancellation


Your scheduled meeting has been canceled. Here are the details:

Event Name

{{booking.event_name}} with {{guest.full_name}}

When

{{booking.full_start_end_host_timezone}} (cancelled)

Cancellation Reason

{{booking.cancel_reason}}

' ], ], 'rescheduled_by_attendee' => [ 'enabled' => true, 'is_host' => true, 'title' => __('Booking Rescheduled by Attendee (email to Organizer)', 'fluent-booking'), 'email' => [ 'additional_recipients' => '', 'subject' => 'A booking was rescheduled with {{guest.full_name}}', 'body' => '

Booking Rescheduled


A scheduled meeting has been rescheduled. Here are the details:

Event Name

{{booking.event_name}} with {{guest.full_name}}

When

New Time: {{booking.full_start_end_host_timezone}} (new)

Previous Time: {{booking.previous_meeting_time}}

Rescheduling Reason

{{booking.reschedule_reason}}

Who

Where

{{booking.location_details_html}}

Note

{{guest.note}}

Additional Data

{{guest.form_data_html}}


View on the Website

' ], ], 'rescheduled_by_host' => [ 'enabled' => true, 'title' => __('Booking Rescheduled by Organizer (email to Attendee)', 'fluent-booking'), 'email' => [ 'subject' => 'Your booking was rescheduled with {{host.name}}', 'body' => '

Booking Rescheduled


Your scheduled meeting has been rescheduled. Here are the details:

Event Name

{{booking.event_name}} with {{guest.full_name}}

When

New Time: {{booking.full_start_end_host_timezone}} (new)

Previous Time: {{booking.previous_meeting_time}}

Rescheduling Reason

{{booking.reschedule_reason}}


' . __('Need to make a change?', 'fluent-booking') . ' ' . __('Reschedule', 'fluent-booking') . ' or ' . __('Cancel', 'fluent-booking') . '


' . self::getAddToCalendarHtml($assetUrl) ], ], 'booking_request_host' => [ 'enabled' => true, 'is_host' => true, 'title' => __('Booking Approval Request to Host (email to Organizer)', 'fluent-booking'), 'email' => [ 'additional_recipients' => '', 'subject' => 'Awaiting Approval: {{guest.full_name}} @ {{booking.start_date_time_for_host}}', 'body' => '

A booking is still waiting for your approval


Someone has requested to schedule an event on your calendar. Here are the details:

Event Name

{{booking.event_name}} with {{guest.full_name}}

When

{{booking.full_start_end_host_timezone}}

Who

Where

{{booking.location_details_html}}

Note

{{guest.note}}

Additional Data

{{guest.form_data_html}}


' . self::getConfirmAndRejectButton($assetUrl) . '

View on the Website

' ], ], 'booking_request_attendee' => [ 'enabled' => true, 'title' => __('Booking Submission Confirmation (email to Attendee)', 'fluent-booking'), 'email' => [ 'subject' => 'Booking Submitted: Meeting between {{host.name}} & {{guest.full_name}}', 'body' => '

Your booking has been submitted


Please wait for the host to confirm your booking.

Event Name

{{booking.event_name}} with {{host.name}}

When

{{booking.full_start_end_guest_timezone}}

Who

Where

{{booking.location_details_html}}

Additional notes

{{guest.note}}


' . __('Need to make a change?', 'fluent-booking') . ' ' . __('Reschedule', 'fluent-booking') . ' or ' . __('Cancel', 'fluent-booking') . '

' ], ], 'declined_by_host' => [ 'enabled' => true, 'title' => __('Booking Declined by Organizer (email to Attendee)', 'fluent-booking'), 'email' => [ 'subject' => 'Booking Declined: Your booking was declined with {{host.name}}', 'body' => '

Booking Declined


Your booking request has been declined. Here are the details:

Event Name

{{booking.event_name}} with {{guest.full_name}}

When

{{booking.full_start_end_host_timezone}} (declined)

Reason

{{booking.reject_reason}}

' ], ], ]); } public static function getAddToCalendarHtml($assetUrl = '') { $assetUrl = $assetUrl ?: App::getInstance()['url.assets']; $html = '
' . __('Add to calendar', 'fluent-booking') . 'Google CalendarOutlookMicrosoft OfficeOther Calendar
'; return apply_filters('fluent_booking/add_to_calendar_html', $html); } public static function getConfirmAndRejectButton($assetUrl = '') { $assetUrl = $assetUrl ?: App::getInstance()['url.assets']; $html = '

' . __('Confirm', 'fluent-booking') . '

 

' . __('Reject', 'fluent-booking') . '

'; return apply_filters('fluent_booking/confirm_and_reject_button_html', $html); } public static function getEditorShortCodes($calendarEvent = null, $isHtmlSupported = false) { if (!$isHtmlSupported) { $groups = [ 'guest' => [ 'title' => __('Attendee Data', 'fluent-booking'), 'key' => 'guest', 'shortcodes' => [ '{{guest.first_name}}' => __('Guest First Name', 'fluent-booking'), '{{guest.last_name}}' => __('Guest Last Name', 'fluent-booking'), '{{guest.full_name}}' => __('Guest Full Name', 'fluent-booking'), '{{guest.email}}' => __('Guest Email', 'fluent-booking'), '{{guest.note}}' => __('Guest Note', 'fluent-booking'), '{{booking.phone}}' => __('Guest Main Phone Number (if provided)', 'fluent-booking'), '{{guest.timezone}}' => __('Guest Timezone', 'fluent-booking') ] ], 'booking' => [ 'title' => __('Booking Data', 'fluent-booking'), 'key' => 'booking', 'shortcodes' => [ '{{booking.event_name}}' => __('Event Name', 'fluent-booking'), '{{booking.description}}' => __('Event Description', 'fluent-booking'), '{{booking.booking_title}}' => __('Booking Title', 'fluent-booking'), '{{booking.additional_guests}}' => __('Additional Guests', 'fluent-booking'), '{{booking.full_start_end_guest_timezone}}' => __('Full Start Date Time (with guest timezone)', 'fluent-booking'), '{{booking.full_start_end_host_timezone}}' => __('Full Start Date Time (with host timezone)', 'fluent-booking'), '{{booking.full_start_and_end_guest_timezone}}' => __('Full Start & End Date Time (with guest timezone)', 'fluent-booking'), '{{booking.full_start_and_end_host_timezone}}' => __('Full Start & End Date Time (with host timezone)', 'fluent-booking'), '{{booking.start_date_time}}' => __('Event Date Time (UTC)', 'fluent-booking'), '{{booking.start_date_time_for_attendee}}' => __('Event Date Time (with attendee timezone)', 'fluent-booking'), '{{booking.start_date_time_for_host}}' => __('Event Date Time (with host timezone)', 'fluent-booking'), '{{booking.location_details_text}}' => __('Event Location Details', 'fluent-booking'), '{{booking.cancel_reason}}' => __('Event Cancel Reason', 'fluent-booking'), '{{booking.start_time_human_format}}' => __('Event Start Time (ex: 2 hours from now)', 'fluent-booking'), '##booking.cancelation_url##' => __('Booking Cancellation URL', 'fluent-booking'), '##booking.reschedule_url##' => __('Booking Reschedule URL', 'fluent-booking'), '##booking.admin_booking_url##' => __('Booking Details Admin URL', 'fluent-booking'), '{{booking.booking_hash}}' => __('Unique Booking Hash', 'fluent-booking'), '{{booking.reschedule_reason}}' => __('Event Reschedule Reason', 'fluent-booking') ] ], 'host' => [ 'title' => __('Host Data', 'fluent-booking'), 'key' => 'host', 'shortcodes' => [ '{{host.name}}' => __('Host Name', 'fluent-booking'), '{{host.email}}' => __('Host Email', 'fluent-booking'), '{{host.timezone}}' => __('Host Timezone', 'fluent-booking'), ] ], 'other' => [ 'title' => __('Other', 'fluent-booking'), 'key' => 'other', 'shortcodes' => [ '{{event.id}}' => __('Event ID', 'fluent-booking'), '{{calendar.id}}' => __('Calendar ID', 'fluent-booking'), '{{event.title}}' => __('Event Title', 'fluent-booking'), '{{calendar.title}}' => __('Calendar Title', 'fluent-booking'), '{{calendar.description}}' => __('Calendar Description', 'fluent-booking'), '{{add_booking_to_calendar}}' => __('Add Booking to Calendar', 'fluent-booking'), ] ] ]; } else { $groups = [ 'guest' => [ 'title' => __('Attendee Data', 'fluent-booking'), 'key' => 'guest', 'shortcodes' => [ '{{guest.first_name}}' => __('Guest First Name', 'fluent-booking'), '{{guest.last_name}}' => __('Guest Last Name', 'fluent-booking'), '{{guest.full_name}}' => __('Guest Full Name', 'fluent-booking'), '{{guest.email}}' => __('Guest Email', 'fluent-booking'), '{{booking.phone}}' => __('Guest Main Phone Number (if provided)', 'fluent-booking'), '{{guest.note}}' => __('Guest Note', 'fluent-booking'), '{{guest.timezone}}' => __('Guest Timezone', 'fluent-booking'), '{{guest.form_data_html}}' => __('Guest Form Submitted Data (HTML)', 'fluent-booking') ] ], 'booking' => [ 'title' => __('Booking Data', 'fluent-booking'), 'key' => 'booking', 'shortcodes' => [ '{{booking.event_name}}' => __('Event Name', 'fluent-booking'), '{{booking.description}}' => __('Event Description', 'fluent-booking'), '{{booking.booking_title}}' => __('Booking Title', 'fluent-booking'), '{{booking.additional_guests}}' => __('Additional Guests', 'fluent-booking'), '{{booking.full_start_end_guest_timezone}}' => __('Full Start Date Time (with guest timezone)', 'fluent-booking'), '{{booking.full_start_end_host_timezone}}' => __('Full Start Date Time (with host timezone)', 'fluent-booking'), '{{booking.full_start_and_end_guest_timezone}}' => __('Full Start & End Date Time (with guest timezone)', 'fluent-booking'), '{{booking.full_start_and_end_host_timezone}}' => __('Full Start & End Date Time (with host timezone)', 'fluent-booking'), '{{booking.start_date_time}}' => __('Event Date Time (UTC)', 'fluent-booking'), '{{booking.start_date_time_for_attendee}}' => __('Event Date time (with guest timezone)', 'fluent-booking'), '{{booking.start_date_time_for_host}}' => __('Event Date time (with host timezone)', 'fluent-booking'), '{{booking.location_details_html}}' => __('Event Location Details (HTML)', 'fluent-booking'), '{{booking.cancel_reason}}' => __('Event Cancel Reason', 'fluent-booking'), '{{booking.start_time_human_format}}' => __('Event Start Time (ex: 2 hours from now)', 'fluent-booking'), '##booking.cancelation_url##' => __('Booking Cancellation URL', 'fluent-booking'), '##booking.reschedule_url##' => __('Booking Reschedule URL', 'fluent-booking'), '##booking.admin_booking_url##' => __('Booking Details Admin URL', 'fluent-booking'), '{{booking.booking_hash}}' => __('Unique Booking Hash', 'fluent-booking'), '{{booking.reschedule_reason}}' => __('Event Reschedule Reason', 'fluent-booking') ] ], 'host' => [ 'title' => __('Host Data', 'fluent-booking'), 'key' => 'host', 'shortcodes' => [ '{{host.name}}' => __('Host Name', 'fluent-booking'), '{{host.email}}' => __('Host Email', 'fluent-booking'), '{{host.timezone}}' => __('Host Timezone', 'fluent-booking'), ] ], 'other' => [ 'title' => __('Other', 'fluent-booking'), 'key' => 'other', 'shortcodes' => [ '{{event.id}}' => __('Event ID', 'fluent-booking'), '{{event.calendar_id}}' => __('Calendar ID', 'fluent-booking'), '{{event.title}}' => __('Event Title', 'fluent-booking'), '{{calendar.title}}' => __('Calendar Title', 'fluent-booking'), '{{calendar.description}}' => __('Calendar Description', 'fluent-booking'), '{{add_booking_to_calendar}}' => __('Add Booking to Calendar', 'fluent-booking'), ] ] ]; } if ($calendarEvent) { $customFields = BookingFieldService::getCustomFields($calendarEvent, true); foreach ($customFields as $fieldKey => $field) { $groups['booking']['shortcodes']['{{booking.custom.' . $fieldKey . '}}'] = $field['label']; if ($field['type'] == 'date') { $groups['booking']['shortcodes']['{{booking.custom.' . $fieldKey . '.format.Y-m-d}}'] = $field['label'] . ' (Ex: 2024-05-20)'; } } if (Helper::isPaymentEnabled($calendarEvent)) { $groups['payment'] = [ 'title' => __('Payment Data', 'fluent-booking'), 'key' => 'payment', 'shortcodes' => [ '{{payment.payment_total}}' => __('Payment Total', 'fluent-booking'), '{{payment.payment_status}}' => __('Payment Status', 'fluent-booking'), '{{payment.payment_method}}' => __('Payment Method', 'fluent-booking'), '{{payment.currency}}' => __('Currency', 'fluent-booking'), '{{payment.payment_date}}' => __('Payment Date', 'fluent-booking'), ] ]; if ($isHtmlSupported) { $groups['payment']['shortcodes']['{{payment.receipt_html}}'] = __('Payment Receipt (HTML)', 'fluent-booking'); } } if ($calendarEvent->isMultiHostsEvent()) { $totalhost = count($calendarEvent->getHostIds()); for ($i = 1; $i < $totalhost; $i++) { $groups['host']['shortcodes']['{{team_member.' . $i . '.name}}'] = __('Team Member ', 'fluent-booking') . $i . __(' Name', 'fluent-booking'); $groups['host']['shortcodes']['{{team_member.' . $i . '.email}}'] = __('Team Member ', 'fluent-booking') . $i . __(' Email', 'fluent-booking'); } } } return apply_filters('fluent_booking/editor_shortcodes_groups', $groups, $calendarEvent, $isHtmlSupported); } public static function encryptKey($value) { if (!$value) { return $value; } if (!extension_loaded('openssl')) { return $value; } $salt = (defined('LOGGED_IN_SALT') && '' !== LOGGED_IN_SALT) ? LOGGED_IN_SALT : 'this-is-a-fallback-salt-but-not-secure'; if (defined('FLUENT_BOOKING_ENCRYPTION_KEY')) { $key = FLUENT_BOOKING_ENCRYPTION_KEY; } else { $key = (defined('LOGGED_IN_KEY') && '' !== LOGGED_IN_KEY) ? LOGGED_IN_KEY : 'this-is-a-fallback-key-but-not-secure'; } $method = 'aes-256-ctr'; $ivlen = openssl_cipher_iv_length($method); $iv = openssl_random_pseudo_bytes($ivlen); $raw_value = openssl_encrypt($value . $salt, $method, $key, 0, $iv); if (!$raw_value) { return false; } return base64_encode($iv . $raw_value); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode } public static function decryptKey($raw_value) { if (!$raw_value) { return $raw_value; } if (!extension_loaded('openssl')) { return $raw_value; } $raw_value = base64_decode($raw_value, true); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode $method = 'aes-256-ctr'; $ivlen = openssl_cipher_iv_length($method); $iv = substr($raw_value, 0, $ivlen); $raw_value = substr($raw_value, $ivlen); if (defined('FLUENT_BOOKING_ENCRYPTION_KEY')) { $key = FLUENT_BOOKING_ENCRYPTION_KEY; } else { $key = (defined('LOGGED_IN_KEY') && '' !== LOGGED_IN_KEY) ? LOGGED_IN_KEY : 'this-is-a-fallback-key-but-not-secure'; } $salt = (defined('LOGGED_IN_SALT') && '' !== LOGGED_IN_SALT) ? LOGGED_IN_SALT : 'this-is-a-fallback-salt-but-not-secure'; $value = openssl_decrypt($raw_value, $method, $key, 0, $iv); if (!$value || substr($value, -strlen($salt)) !== $salt) { return false; } return substr($value, 0, -strlen($salt)); } public static function debugLog($data) { if (defined('FLUENT_BOOKING_DEBUG') && FLUENT_BOOKING_DEBUG) { error_log(print_r($data, true)); } } public static function getGlobalSettings($settingsKey = null) { $defaults = [ 'payments' => [ 'currency' => 'USD', 'is_active' => 'no' ], 'emailing' => [ 'from_name' => '', 'from_email' => '', 'reply_to_name' => '', 'reply_to_email' => '', 'use_host_name' => '', 'use_host_email_on_reply' => '', 'attach_ics_on_confirmation' => '', 'email_footer' => '' ], 'administration' => [ 'admin_email' => '{{wp.admin_email}}', 'summary_notification' => 'no', 'notification_frequency' => 'daily', 'notification_day' => 'mon', 'start_day' => 'sun', 'auto_cancel_timing' => '10', 'auto_complete_timing' => '60', 'default_phone_country' => '' ], 'time_format' => '12', 'theme' => 'system-default' ]; $settings = get_option('_fluent_booking_settings', []); if (empty($settings)) { $settings = []; } $paymentSettings = get_option('fluent_booking_global_payment_settings', []); if ($paymentSettings) { $settings['payments'] = $paymentSettings; } $settings = wp_parse_args($settings, $defaults); $emailSettings = $settings['emailing']; if (empty($settings['administration']['auto_cancel_timing'])) { $settings['administration']['auto_cancel_timing'] = '10'; } if (empty($settings['administration']['auto_complete_timing'])) { $settings['administration']['auto_complete_timing'] = '10'; } if (empty($emailSettings['from_name']) && defined('FLUENTCRM')) { $crmSettings = fluentcrmGetGlobalSettings('email_settings', []); $emailSettings['from_name'] = Arr::get($crmSettings, 'from_name'); if (empty($emailSettings['from_email'])) { $emailSettings['from_email'] = Arr::get($crmSettings, 'from_email'); } if (empty($emailSettings['reply_to_name'])) { $emailSettings['reply_to_name'] = Arr::get($crmSettings, 'reply_to_name'); } if (empty($emailSettings['reply_to_email'])) { $emailSettings['reply_to_email'] = Arr::get($crmSettings, 'reply_to_email'); } $settings['emailing'] = $emailSettings; } if ($settingsKey) { return Arr::get($settings, $settingsKey, []); } return $settings; } public static function getGlobalAdminSetting($key = null, $default = null) { static $settings; if ($settings) { if ($key) { return Arr::get($settings, $key, $default); } return $settings; } $globalSettings = self::getGlobalSettings(); $settings = Arr::get($globalSettings, 'administration', []); if ($key) { return Arr::get($settings, $key, $default); } return $settings; } public static function getDefaultTimeFormat() { static $format; if ($format) { return $format; } $settings = self::getGlobalSettings(); $format = Arr::get($settings, 'time_format', '24'); return $format; } public static function getVerifiedSenders() { $verifiedSenders = []; if (defined('FLUENTMAIL')) { $smtpSettings = get_option('fluentmail-settings', []); if ($smtpSettings && count($smtpSettings['mappings'])) { $verifiedSenders = array_keys($smtpSettings['mappings']); } } /** * Filter the verified email senders * @param array $verifiedSenders */ return apply_filters('fluent_booking/verfied_email_senders', $verifiedSenders); } public static function getBookingReceiptLandingBaseUrl() { return apply_filters('fluent_booking/booking_receipt_landing_base_url', site_url('/')); } public static function getGlobalModuleSettings($cached = true) { static $settings = null; if ($cached && $settings !== null) { return $settings; } $settings = get_option('_fluent_booking_enabled_modules', []); if (empty($settings) || !\is_array($settings)) { $settings = []; } return $settings; } public static function updateGlobalModuleSettings($settings = []) { if (!is_array($settings)) { $settings = []; } update_option('_fluent_booking_enabled_modules', $settings); return self::getGlobalModuleSettings(false); } public static function isModuleEnabled($module) { $settings = self::getGlobalModuleSettings(); return isset($settings[$module]) && $settings[$module] === 'yes'; } /** * @return mixed|void */ public static function fluentbooking_is_rtl() { /** * If FluentBooking is running on RTL Mode * * @param bool $is_rtl */ return apply_filters('fluent_booking/is_rtl', is_rtl()); } public static function fluentBookingUserAvatar($id_or_email, $args) { if (empty($id_or_email)) { return ''; } return apply_filters('fluent_booking/author_photo', get_avatar_url($id_or_email), $args); } public static function getPrefSettins($cached = true) { static $pref = null; if ($cached && $pref) { return $pref; } $settings = [ 'frontend' => [ 'enabled' => 'no', 'slug' => 'my-bookings', 'render_type' => 'standalone', 'page_id' => '' ] ]; $storedSettings = get_option('fluent_booking_modules', []); if ($storedSettings && is_array($storedSettings)) { $settings = wp_parse_args($storedSettings, $settings); } else { update_option('fluent_booking_modules', $settings, 'yes'); } $pref = $settings; return $settings; } }