PluginProbe ʕ •ᴥ•ʔ
Appointment Booking Plugin – LatePoint | Calendar & Scheduling for WordPress / 5.1.4
Appointment Booking Plugin – LatePoint | Calendar & Scheduling for WordPress v5.1.4
5.6.8 5.6.7 5.6.6 5.6.5 5.6.4 5.6.3 5.6.2 5.6.1 5.6.0 5.5.2 5.5.1 5.5.0 5.4.2 trunk 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.1.91 5.1.92 5.1.93 5.1.94 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1
latepoint / lib / helpers / calendar_helper.php
latepoint / lib / helpers Last commit date
activities_helper.php 1 year ago agent_helper.php 1 year ago auth_helper.php 1 year ago blocks_helper.php 1 year ago booking_helper.php 1 year ago bricks_helper.php 1 year ago bundles_helper.php 1 year ago calendar_helper.php 1 year ago carts_helper.php 1 year ago connector_helper.php 1 year ago csv_helper.php 1 year ago customer_helper.php 1 year ago database_helper.php 1 year ago debug_helper.php 1 year ago defaults_helper.php 1 year ago elementor_helper.php 1 year ago email_helper.php 1 year ago encrypt_helper.php 1 year ago events_helper.php 1 year ago form_helper.php 1 year ago icalendar_helper.php 1 year ago image_helper.php 1 year ago invoices_helper.php 1 year ago license_helper.php 1 year ago location_helper.php 1 year ago marketing_systems_helper.php 1 year ago meeting_systems_helper.php 1 year ago menu_helper.php 1 year ago meta_helper.php 1 year ago migrations_helper.php 1 year ago money_helper.php 1 year ago notifications_helper.php 1 year ago order_intent_helper.php 1 year ago orders_helper.php 1 year ago pages_helper.php 1 year ago params_helper.php 1 year ago payments_helper.php 1 year ago price_breakdown_helper.php 1 year ago process_jobs_helper.php 1 year ago processes_helper.php 1 year ago replacer_helper.php 1 year ago resource_helper.php 1 year ago roles_helper.php 1 year ago router_helper.php 1 year ago service_helper.php 1 year ago sessions_helper.php 1 year ago settings_helper.php 1 year ago shortcodes_helper.php 1 year ago sms_helper.php 1 year ago steps_helper.php 1 year ago stripe_connect_helper.php 1 year ago styles_helper.php 1 year ago support_topics_helper.php 1 year ago time_helper.php 1 year ago timeline_helper.php 1 year ago transaction_intent_helper.php 1 year ago util_helper.php 1 year ago version_specific_updates_helper.php 1 year ago whatsapp_helper.php 1 year ago work_periods_helper.php 1 year ago wp_datetime.php 1 year ago wp_user_helper.php 1 year ago
calendar_helper.php
500 lines
1 <?php
2 /*
3 * Copyright (c) 2022 LatePoint LLC. All rights reserved.
4 */
5
6
7 class OsCalendarHelper {
8
9 /**
10 * Get list of statuses which should not appear on calendar
11 *
12 * @return array
13 */
14 public static function get_booking_statuses_hidden_from_calendar(): array {
15 $statuses = explode( ',', OsSettingsHelper::get_settings_value( 'calendar_hidden_statuses', '' ) );
16
17 /**
18 * Get list of statuses which bookings should not appear on calendar
19 *
20 * @param {array} $statuses array of status codes that will be hidden from calendar
21 * @returns {array} The filtered array of status codes
22 *
23 * @since 4.7.0
24 * @hook latepoint_get_booking_statuses_hidden_from_calendar
25 *
26 */
27 return apply_filters( 'latepoint_get_booking_statuses_hidden_from_calendar', $statuses );
28 }
29
30
31 /**
32 * Returns an array of booking status codes to be displayed on calendar
33 *
34 * @return {array} The array of statuses
35 */
36 public static function get_booking_statuses_to_display_on_calendar(): array {
37 $hidden_statuses = self::get_booking_statuses_hidden_from_calendar();
38 $all_statuses = OsBookingHelper::get_statuses_list();
39 $eligible_statuses = [];
40 foreach ( $all_statuses as $status_code => $status_label ) {
41 if ( ! in_array( $status_code, $hidden_statuses ) ) {
42 $eligible_statuses[] = $status_code;
43 }
44 }
45
46 /**
47 * Returns an array of booking status codes to be displayed on calendar
48 *
49 * @param {array} array of statuses
50 *
51 * @returns {array} The array of statuses
52 *
53 * @since 4.7.0
54 * @hook latepoint_get_booking_statuses_to_display_on_calendar
55 *
56 */
57 return apply_filters( 'latepoint_get_booking_statuses_to_display_on_calendar', $eligible_statuses );
58 }
59
60 public static function is_external_calendar_enabled( string $external_calendar_code ): bool {
61 return OsSettingsHelper::is_on( 'enable_' . $external_calendar_code );
62 }
63
64 public static function get_list_of_external_calendars( $enabled_only = false ) {
65 $external_calendars = [];
66
67 /**
68 * Returns an array of external calendars
69 *
70 * @param {array} array of calendars
71 * @param {bool} filter to return only calendars that are enabled
72 *
73 * @returns {array} The array of external calendars
74 *
75 * @since 4.7.0
76 * @hook latepoint_list_of_external_calendars
77 *
78 */
79 return apply_filters( 'latepoint_list_of_external_calendars', $external_calendars, $enabled_only );
80 }
81
82
83 /**
84 * @param \LatePoint\Misc\BookingRequest $booking_request
85 * @param DateTime $target_date
86 * @param array $settings
87 *
88 * @return void
89 */
90 public static function generate_calendar_for_datepicker_step( \LatePoint\Misc\BookingRequest $booking_request, DateTime $target_date, array $settings = [] ) {
91 $defaults = [
92 'exclude_booking_ids' => [],
93 'number_of_months_to_preload' => 1,
94 'timezone_name' => false,
95 'layout' => 'classic',
96 'highlight_target_date' => false,
97 'consider_cart_items' => false,
98 ];
99
100 $settings = OsUtilHelper::merge_default_atts( $defaults, $settings );
101
102 $weekdays = OsBookingHelper::get_weekdays_arr();
103 $today_date = new OsWpDateTime( 'today' );
104
105
106 ?>
107 <div class="os-current-month-label-w calendar-mobile-controls">
108 <div class="os-current-month-label">
109 <div class="current-month">
110 <?php if ( $settings['highlight_target_date'] ) {
111 echo esc_html( OsTimeHelper::get_nice_date_with_optional_year( $target_date->format( 'Y-m-d' ), false ) );
112 } else {
113 echo esc_html( OsUtilHelper::get_month_name_by_number( $target_date->format( 'n' ) ) );
114 } ?>
115 </div>
116 <div class="current-year"><?php echo esc_html( $target_date->format( 'Y' ) ); ?></div>
117 </div>
118 <div class="os-month-control-buttons-w">
119 <button type="button" class="os-month-prev-btn disabled" data-route="<?php echo esc_attr( OsRouterHelper::build_route_name( 'steps', 'load_datepicker_month' ) ); ?>">
120 <i class="latepoint-icon latepoint-icon-arrow-left"></i></button>
121 <?php if ( $settings['layout'] == 'horizontal' ) {
122 echo '<button class="latepoint-btn latepoint-btn-outline os-month-today-btn" data-year="' . esc_attr( $today_date->format( 'Y' ) ) . '" data-month="' . esc_attr( $today_date->format( 'n' ) ) . '" data-date="' . esc_attr( $today_date->format( 'Y-m-d' ) ) . '">' . esc_html__( 'Today', 'latepoint' ) . '</button>';
123 } ?>
124 <button type="button" class="os-month-next-btn" data-route="<?php echo esc_attr( OsRouterHelper::build_route_name( 'steps', 'load_datepicker_month' ) ); ?>">
125 <i class="latepoint-icon latepoint-icon-arrow-right"></i></button>
126 </div>
127 </div>
128 <?php if ( $settings['layout'] == 'classic' ) { ?>
129 <div class="os-weekdays">
130 <?php
131 $start_of_week = OsSettingsHelper::get_start_of_week();
132
133 // Output the divs for each weekday
134 for ( $i = $start_of_week - 1; $i < $start_of_week - 1 + 7; $i ++ ) {
135 // Calculate the index within the range of 0-6
136 $index = $i % 7;
137
138 // Output the div for the current weekday
139 echo '<div class="weekday weekday-' . esc_attr( $index + 1 ) . '">' . esc_html( $weekdays[ $index ] ) . '</div>';
140 }
141 ?>
142 </div>
143 <?php } ?>
144 <div class="os-months">
145 <?php
146 $month_settings = [
147 'active' => true,
148 'timezone_name' => $settings['timezone_name'],
149 'highlight_target_date' => $settings['highlight_target_date'],
150 'exclude_booking_ids' => $settings['exclude_booking_ids'],
151 'consider_cart_items' => $settings['consider_cart_items']
152 ];
153
154
155 // if it's not from admin - blackout dates that are not available to select due to date restrictions in settings
156 $month_settings['earliest_possible_booking'] = OsSettingsHelper::get_settings_value( 'earliest_possible_booking', false );
157 $month_settings['latest_possible_booking'] = OsSettingsHelper::get_settings_value( 'latest_possible_booking', false );
158
159 OsCalendarHelper::generate_single_month( $booking_request, $target_date, $month_settings );
160 for ( $i = 1; $i <= $settings['number_of_months_to_preload']; $i ++ ) {
161 $next_month_target_date = clone $target_date;
162 $next_month_target_date->modify( 'first day of next month' );
163 $month_settings['active'] = false;
164 $month_settings['highlight_target_date'] = false;
165 OsCalendarHelper::generate_single_month( $booking_request, $next_month_target_date, $month_settings );
166 }
167 ?>
168 </div><?php
169 }
170
171 public static function generate_single_month( \LatePoint\Misc\BookingRequest $booking_request, DateTime $target_date, array $settings = [] ) {
172 $defaults = [
173 'accessed_from_backend' => false,
174 'active' => false,
175 'layout' => 'classic',
176 'highlight_target_date' => false,
177 'timezone_name' => false,
178 'earliest_possible_booking' => false,
179 'latest_possible_booking' => false,
180 'exclude_booking_ids' => [],
181 'consider_cart_items' => false,
182 'hide_slot_availability_count' => OsStepsHelper::hide_slot_availability_count()
183 ];
184 $settings = OsUtilHelper::merge_default_atts( $defaults, $settings );
185
186 if ( $settings['timezone_name'] && $settings['timezone_name'] != OsTimeHelper::get_wp_timezone_name() ) {
187 $timeshift_minutes = OsTimeHelper::get_timezone_shift_in_minutes( $settings['timezone_name'] );
188 } else {
189 $timeshift_minutes = 0;
190 }
191
192 // set service to the first available if not set
193 // IMPORTANT, we have to have service in the booking request, otherwise we can't know duration and intervals
194 $service = new OsServiceModel();
195 $service = $service->where( [ 'id' => $booking_request->service_id ] )->set_limit( 1 )->get_results_as_models();
196 if ( $service ) {
197 if ( ! $booking_request->duration ) {
198 $booking_request->duration = $service->duration;
199 }
200 $selectable_time_interval = $service->get_timeblock_interval();
201 } else {
202 echo '<div class="latepoint-message latepoint-message-error">' . esc_html__( 'In order to generate the calendar, a service must be selected.', 'latepoint' ) . '</div>';
203
204 return;
205 }
206
207
208 # Get bounds for a month of a targetted day
209 $calendar_start = clone $target_date;
210 $calendar_start->modify( 'first day of this month' );
211 $calendar_end = clone $target_date;
212 $calendar_end->modify( 'last day of this month' );
213
214
215 // if it's a classic layout - it means we need to load some days from previous and next month, to fill in blank spaces on the grid
216 if ( $settings['layout'] == 'classic' ) {
217 $weekday_for_first_day_of_month = intval( $calendar_start->format( 'N' ) );
218 $weekday_for_last_day_of_month = intval( $calendar_end->format( 'N' ) );
219
220 $week_starts_on = OsSettingsHelper::get_start_of_week();
221 $week_ends_on = $week_starts_on > 1 ? $week_starts_on - 1 : 7;
222
223 if ( $weekday_for_first_day_of_month != $week_starts_on ) {
224 $days_to_subtract = ( $weekday_for_first_day_of_month - $week_starts_on + 7 ) % 7;
225 $calendar_start->modify( '-' . $days_to_subtract . ' days' );
226 }
227
228 if ( $weekday_for_last_day_of_month != $week_ends_on ) {
229 $days_to_add = ( $weekday_for_last_day_of_month > $week_ends_on ) ? abs( 7 - $weekday_for_last_day_of_month + $week_ends_on ) : ( $week_ends_on - $weekday_for_last_day_of_month );
230 $calendar_end->modify( '+' . $days_to_add . ' days' );
231 }
232 }
233
234 // apply timeshift if needed
235 $now_datetime = OsTimeHelper::now_datetime_object();
236
237 // figure out when the earliest and latest bookings can be placed
238 $earliest_possible_booking = ( $settings['earliest_possible_booking'] ) ? new OsWpDateTime( $settings['earliest_possible_booking'] ) : clone $now_datetime;
239 $latest_possible_booking = ( $settings['latest_possible_booking'] ) ? new OsWpDateTime( $settings['latest_possible_booking'] ) : clone $calendar_end;
240 // make sure they are set correctly
241 if ( ! $earliest_possible_booking ) {
242 $earliest_possible_booking = clone $now_datetime;
243 }
244 if ( ! $latest_possible_booking ) {
245 $latest_possible_booking = clone $calendar_end;
246 }
247
248 $date_range_start = ( $calendar_start->format( 'Y-m-d' ) > $earliest_possible_booking->format( 'Y-m-d' ) ) ? $calendar_start : $earliest_possible_booking;
249 $date_range_end = ( $calendar_end->format( 'Y-m-d' ) < $latest_possible_booking->format( 'Y-m-d' ) ) ? $calendar_end : $latest_possible_booking;
250
251 // make sure date range is within the requested calendar range
252 if ( ( $date_range_start->format( 'Y-m-d' ) >= $calendar_start->format( 'Y-m-d' ) )
253 && ( $date_range_end->format( 'Y-m-d' ) <= $calendar_end->format( 'Y-m-d' ) )
254 && ( $date_range_start->format( 'Y-m-d' ) <= $date_range_end->format( 'Y-m-d' ) ) ) {
255 $daily_resources = OsResourceHelper::get_resources_grouped_by_day( $booking_request, $date_range_start, $date_range_end, [
256 'timeshift_minutes' => $timeshift_minutes,
257 'accessed_from_backend' => $settings['accessed_from_backend'],
258 'exclude_booking_ids' => $settings['exclude_booking_ids'],
259 'consider_cart_items' => $settings['consider_cart_items']
260 ] );
261 } else {
262 $daily_resources = [];
263 }
264
265 $active_class = $settings['active'] ? 'active' : '';
266 $hide_single_slot_class = OsStepsHelper::hide_timepicker_when_one_slot_available() ? 'hide-if-single-slot' : '';
267 echo '<div class="os-monthly-calendar-days-w ' . esc_attr( $hide_single_slot_class . ' ' . $active_class ) . '" data-calendar-layout="' . esc_attr( $settings['layout'] ) . '" data-calendar-year="' . esc_attr( $target_date->format( 'Y' ) ) . '" data-calendar-month="' . esc_attr( $target_date->format( 'n' ) ) . '" data-calendar-month-label="' . esc_attr( OsUtilHelper::get_month_name_by_number( $target_date->format( 'n' ) ) ) . '"><div class="os-monthly-calendar-days">';
268 // DAYS LOOP START
269 for ( $day_date = clone $calendar_start; $day_date <= $calendar_end; $day_date->modify( '+1 day' ) ) {
270 if ( ! isset( $daily_resources[ $day_date->format( 'Y-m-d' ) ] ) ) {
271 $daily_resources[ $day_date->format( 'Y-m-d' ) ] = [];
272 }
273
274 $is_today = ( $day_date->format( 'Y-m-d' ) == $now_datetime->format( 'Y-m-d' ) );
275 $is_day_in_past = ( $day_date->format( 'Y-m-d' ) < $now_datetime->format( 'Y-m-d' ) );
276 $is_target_month = ( $day_date->format( 'm' ) == $target_date->format( 'm' ) );
277 $is_next_month = ( $day_date->format( 'm' ) > $target_date->format( 'm' ) );
278 $is_prev_month = ( $day_date->format( 'm' ) < $target_date->format( 'm' ) );
279 $not_in_allowed_period = false;
280
281 if ( $day_date->format( 'Y-m-d' ) < $earliest_possible_booking->format( 'Y-m-d' ) ) {
282 $not_in_allowed_period = true;
283 }
284 if ( $day_date->format( 'Y-m-d' ) > $latest_possible_booking->format( 'Y-m-d' ) ) {
285 $not_in_allowed_period = true;
286 }
287
288 $work_minutes = [];
289
290 foreach ( $daily_resources[ $day_date->format( 'Y-m-d' ) ] as $resource ) {
291 if ( $is_day_in_past && $not_in_allowed_period ) {
292 continue;
293 }
294 $work_minutes = array_merge( $work_minutes, $resource->work_minutes );
295 }
296 $work_minutes = array_unique( $work_minutes, SORT_NUMERIC );
297 sort( $work_minutes, SORT_NUMERIC );
298
299
300 $work_boundaries = OsResourceHelper::get_work_boundaries_for_resources( $daily_resources[ $day_date->format( 'Y-m-d' ) ] );
301 $total_work_minutes = $work_boundaries->end_time - $work_boundaries->start_time;
302
303 $booking_slots = OsResourceHelper::get_ordered_booking_slots_from_resources( $daily_resources[ $day_date->format( 'Y-m-d' ) ] );
304
305 $bookable_minutes = [];
306 foreach ( $booking_slots as $booking_slot ) {
307 if ( $booking_slot->can_accomodate( $booking_request->total_attendees ) ) {
308 $bookable_minutes[ $booking_slot->start_time ] = isset( $bookable_minutes[ $booking_slot->start_time ] ) ? max( $booking_slot->available_capacity(), $bookable_minutes[ $booking_slot->start_time ] ) : $booking_slot->available_capacity();
309 }
310 }
311 ksort( $bookable_minutes );
312 $bookable_minutes_with_capacity_data = '';
313 // this is a group service
314 if ( $service->is_group_service() && ! $settings['hide_slot_availability_count'] ) {
315 foreach ( $bookable_minutes as $minute => $available_capacity ) {
316 $bookable_minutes_with_capacity_data .= $minute . ':' . $available_capacity . ',';
317 }
318 } else {
319 foreach ( $bookable_minutes as $minute => $available_capacity ) {
320 $bookable_minutes_with_capacity_data .= $minute . ',';
321 }
322 }
323 $bookable_minutes_with_capacity_data = rtrim( $bookable_minutes_with_capacity_data, ',' );
324
325
326 $bookable_slots_count = count( $bookable_minutes );
327 // TODO use work minutes instead to calculate minimum gap
328 $minimum_slot_gap = \LatePoint\Misc\BookingSlot::find_minimum_gap_between_slots( $booking_slots );
329 $day_class = 'os-day os-day-current week-day-' . strtolower( $day_date->format( 'N' ) );
330 $tabbable = true;
331 if ( empty( $bookable_minutes ) ) {
332 $day_class .= ' os-not-available';
333 $tabbable = false;
334 }
335 if ( $is_today ) {
336 $day_class .= ' os-today';
337 }
338 if ( $is_day_in_past ) {
339 $day_class .= ' os-day-passed';
340 $tabbable = false;
341 }
342 if ( $is_target_month ) {
343 $day_class .= ' os-month-current';
344 }
345 if ( $is_next_month ) {
346 $day_class .= ' os-month-next';
347 }
348 if ( $is_prev_month ) {
349 $day_class .= ' os-month-prev';
350 }
351 if ( $not_in_allowed_period ) {
352 $day_class .= ' os-not-in-allowed-period';
353 $tabbable = false;
354 }
355 if ( count( $bookable_minutes ) == 1 && OsStepsHelper::hide_timepicker_when_one_slot_available() ) {
356 $day_class .= ' os-one-slot-only';
357 }
358 if ( ( $day_date->format( 'Y-m-d' ) == $target_date->format( 'Y-m-d' ) ) && $settings['highlight_target_date'] ) {
359 $day_class .= ' selected';
360 }
361 ?>
362
363 <div <?php if($tabbable) echo 'tabindex="0"'; ?> role="button" class="<?php echo esc_attr( $day_class ); ?>"
364 data-date="<?php echo esc_attr( $day_date->format( 'Y-m-d' ) ); ?>"
365 data-nice-date="<?php echo esc_attr( OsTimeHelper::get_nice_date_with_optional_year( $day_date->format( 'Y-m-d' ), false ) ); ?>"
366 data-service-duration="<?php echo esc_attr( $booking_request->duration ); ?>"
367 data-total-work-minutes="<?php echo esc_attr( $total_work_minutes ); ?>"
368 data-work-start-time="<?php echo esc_attr( $work_boundaries->start_time ); ?>"
369 data-work-end-time="<?php echo esc_attr( $work_boundaries->end_time ); ?>"
370 data-bookable-minutes="<?php echo esc_attr( $bookable_minutes_with_capacity_data ); ?>"
371 data-work-minutes="<?php echo esc_attr( implode( ',', $work_minutes ) ); ?>"
372 data-interval="<?php echo esc_attr( $selectable_time_interval ); ?>">
373 <?php if ( $settings['layout'] == 'horizontal' ) { ?>
374 <div
375 class="os-day-weekday"><?php echo esc_html( OsBookingHelper::get_weekday_name_by_number( $day_date->format( 'N' ) ) ); ?></div><?php } ?>
376 <div class="os-day-box">
377 <?php
378 if ( $bookable_slots_count && ! $settings['hide_slot_availability_count'] ) {
379 // translators: %d is the number of slots available
380 echo '<div class="os-available-slots-tooltip">' . esc_html( sprintf( __( '%d Available', 'latepoint' ), $bookable_slots_count ) ) . '</div>';
381 } ?>
382 <div class="os-day-number"><?php echo esc_html( $day_date->format( 'j' ) ); ?></div>
383 <?php if ( ! $is_day_in_past && ! $not_in_allowed_period ) { ?>
384 <div class="os-day-status">
385 <?php
386 if ( $total_work_minutes > 0 && $bookable_slots_count ) {
387 $available_blocks_count = 0;
388 $not_available_started_count = 0;
389 $duration = $booking_request->duration;
390 $end_time = $work_boundaries->end_time - $duration;
391 $processed_count = 0;
392 $last_available_slot_time = false;
393 $bookable_ranges = [];
394 $loop_availability_status = false;
395 for ( $i = 0; $i < count( $booking_slots ); $i ++ ) {
396 if ( $booking_slots[ $i ]->can_accomodate( $booking_request->total_attendees ) ) {
397 // AVAILABLE SLOT
398 if ( $loop_availability_status && $i > 0 && ( ( $booking_slots[ $i ]->start_time - $booking_slots[ $i - 1 ]->start_time ) > $minimum_slot_gap ) ) {
399 // big gap between previous slot and this slot
400 $bookable_ranges[] = $booking_slots[ $i - 1 ]->start_time + $minimum_slot_gap;
401 $bookable_ranges[] = $booking_slots[ $i ]->start_time;
402 }
403 if ( ! $loop_availability_status ) {
404 $bookable_ranges[] = $booking_slots[ $i ]->start_time;
405 }
406 $last_available_slot_time = $booking_slots[ $i ]->start_time;
407 $loop_availability_status = true;
408 } else {
409 // NOT AVAILABLE
410 // a different resource but with the same start time, so that if its available (checked in next loop iteration) - we don't block this slot
411 if ( isset( $booking_slots[ $i + 1 ] ) && $booking_slots[ $i + 1 ]->start_time == $booking_slots[ $i ]->start_time ) {
412 continue;
413 }
414 // check if last available slot had the same start time as current one, if so - we don't block this slot and move to the next one
415 if ( $last_available_slot_time == $booking_slots[ $i ]->start_time && isset( $booking_slots[ $i - 1 ] ) && $booking_slots[ $i - 1 ]->start_time == $booking_slots[ $i ]->start_time ) {
416 continue;
417 }
418 // if last available slot exists and previous slot was also available
419 if ( $last_available_slot_time && $loop_availability_status ) {
420 $bookable_ranges[] = $last_available_slot_time + $minimum_slot_gap;
421 }
422 $loop_availability_status = false;
423 }
424 }
425 if ( $bookable_ranges ) {
426 for ( $i = 0; $i < count( $bookable_ranges ); $i += 2 ) {
427 $left = ( $bookable_ranges[ $i ] - $work_boundaries->start_time ) / $total_work_minutes * 100;
428 $width = isset( $bookable_ranges[ $i + 1 ] ) ? ( ( $bookable_ranges[ $i + 1 ] - $bookable_ranges[ $i ] ) / $total_work_minutes * 100 ) : ( ( $work_boundaries->end_time - $bookable_ranges[ $i ] ) / $total_work_minutes * 100 );
429 echo '<div class="day-available" style="left:' . esc_attr( $left ) . '%;width:' . esc_attr( $width ) . '%;"></div>';
430 }
431 }
432 }
433 ?>
434 </div>
435 <?php } ?>
436 </div>
437 </div>
438
439 <?php
440
441 // DAYS LOOP END
442 }
443 echo '</div></div>';
444 }
445
446 // Used on holiday/custom schedule generator lightbox
447 public static function generate_monthly_calendar_days_only( $target_date_string = 'today', $highlight_target_date = false ) {
448 $target_date = new OsWpDateTime( $target_date_string );
449 $calendar_start = clone $target_date;
450 $calendar_start->modify( 'first day of this month' );
451 $calendar_end = clone $target_date;
452 $calendar_end->modify( 'last day of this month' );
453
454 $weekday_for_first_day_of_month = $calendar_start->format( 'N' ) - 1;
455 $weekday_for_last_day_of_month = $calendar_end->format( 'N' ) - 1;
456
457
458 if ( $weekday_for_first_day_of_month > 0 ) {
459 $calendar_start->modify( '-' . $weekday_for_first_day_of_month . ' days' );
460 }
461
462 if ( $weekday_for_last_day_of_month < 6 ) {
463 $days_to_add = 6 - $weekday_for_last_day_of_month;
464 $calendar_end->modify( '+' . $days_to_add . ' days' );
465 }
466
467 echo '<div class="os-monthly-calendar-days-w" data-calendar-year="' . esc_attr( $target_date->format( 'Y' ) ) . '" data-calendar-month="' . esc_attr( $target_date->format( 'n' ) ) . '" data-calendar-month-label="' . esc_attr( OsUtilHelper::get_month_name_by_number( $target_date->format( 'n' ) ) ) . '">
468 <div class="os-monthly-calendar-days">';
469 for ( $day_date = clone $calendar_start; $day_date <= $calendar_end; $day_date->modify( '+1 day' ) ) {
470 $is_today = ( $day_date->format( 'Y-m-d' ) == OsTimeHelper::today_date() ) ? true : false;
471 $is_day_in_past = ( $day_date->format( 'Y-m-d' ) < OsTimeHelper::today_date() ) ? true : false;
472 $day_class = 'os-day os-day-current week-day-' . strtolower( $day_date->format( 'N' ) );
473
474 if ( $day_date->format( 'm' ) > $target_date->format( 'm' ) ) {
475 $day_class .= ' os-month-next';
476 }
477 if ( $day_date->format( 'm' ) < $target_date->format( 'm' ) ) {
478 $day_class .= ' os-month-prev';
479 }
480
481 if ( $is_today ) {
482 $day_class .= ' os-today';
483 }
484 if ( $highlight_target_date && ( $day_date->format( 'Y-m-d' ) == $target_date->format( 'Y-m-d' ) ) ) {
485 $day_class .= ' selected';
486 }
487 if ( $is_day_in_past ) {
488 $day_class .= ' os-day-passed';
489 } ?>
490 <div class="<?php echo esc_attr( $day_class ); ?>" data-date="<?php echo esc_attr( $day_date->format( 'Y-m-d' ) ); ?>">
491 <div class="os-day-box">
492 <div class="os-day-number"><?php echo esc_html( $day_date->format( 'j' ) ); ?></div>
493 </div>
494 </div><?php
495 }
496 echo '</div></div>';
497 }
498
499
500 }