PluginProbe
Booking Calendar / 11.5
Booking Calendar v11.5
11.9 11.8.4 11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 All 205 releases
booking / includes / page-appointment-services / appointment_services__ui.php

appointment_services__ui.php in Booking Calendar 11.5, at includes/page-appointment-services/appointment_services__ui.php

564 lines 26.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /** Appointment Services presentation helpers. @package Booking Calendar */
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit;
5 }
6
7 /**
8 * Build capability-aware semantic administration links for Providers.
9 *
10 * Providers remain Booking Resources. These routes expose familiar
11 * Appointment terminology while preserving the existing availability and
12 * Service assignment controllers as the single source of truth.
13 *
14 * @param int $resource_id Optional Provider booking resource ID.
15 * @param bool $include_service_assignments Whether to include the Services-catalog shortcut.
16 *
17 * @return array<int,array<string,string>> Link title, URL, and icon values.
18 */
19 function wpbc_appointment_services_get_provider_admin_links( $resource_id = 0, $include_service_assignments = true ) {
20 $resource_id = absint( $resource_id );
21 $links = array();
22
23 if ( wpbc_appointment_services_can_manage_availability() ) {
24 $working_hours_url = function_exists( 'wpbc_get_general_availability_url' )
25 ? wpbc_get_general_availability_url()
26 : admin_url( 'admin.php?page=wpbc-availability&tab=general_availability' );
27 $days_off_url = function_exists( 'wpbc_get_availability_url' )
28 ? wpbc_get_availability_url()
29 : admin_url( 'admin.php?page=wpbc-availability' );
30 $working_hours_url = add_query_arg( 'wpbc_ag_open', 'working_time', $working_hours_url );
31 if ( $resource_id ) {
32 $working_hours_url = add_query_arg( 'resource_id', $resource_id, $working_hours_url );
33 $days_off_url = add_query_arg( 'resource_id', $resource_id, $days_off_url );
34 }
35 $links[] = array(
36 'title' => __( 'Working Hours', 'booking' ),
37 'url' => $working_hours_url,
38 'icon' => 'wpbc-bi-clock',
39 );
40 $links[] = array(
41 'title' => __( 'Days Off', 'booking' ),
42 'url' => $days_off_url,
43 'icon' => 'wpbc-bi-calendar-x',
44 );
45 }
46
47 if ( $include_service_assignments && current_user_can( wpbc_appointment_services_get_manage_capability() ) ) {
48 $service_assignments_url = admin_url( 'admin.php?page=wpbc-services' );
49 $services_link_title = __( 'Manage Services', 'booking' );
50 if ( $resource_id ) {
51 $service_assignments_url = add_query_arg( 'provider_id', $resource_id, $service_assignments_url );
52 $services_link_title = __( 'Assigned Services', 'booking' );
53 }
54 $links[] = array(
55 'title' => $services_link_title,
56 'url' => $service_assignments_url,
57 'icon' => 'wpbc-bi-grid',
58 );
59 }
60
61 return (array) apply_filters( 'wpbc_appointment_provider_admin_links', $links, $resource_id, $include_service_assignments );
62 }
63
64 /**
65 * Render semantic Provider administration links using standard WP buttons.
66 *
67 * @param int $resource_id Optional Provider booking resource ID.
68 * @param string $css_class Optional additional wrapper class.
69 * @param bool $include_service_assignments Whether to include the Services-catalog shortcut.
70 *
71 * @return void
72 */
73 function wpbc_appointment_services_render_provider_admin_links( $resource_id = 0, $css_class = '', $include_service_assignments = true ) {
74 $links = wpbc_appointment_services_get_provider_admin_links( $resource_id, $include_service_assignments );
75 if ( empty( $links ) ) {
76 return;
77 }
78 ?>
79 <div class="wpbc_appointment_provider_links wpbc_ui_el__buttons_group <?php echo esc_attr( sanitize_html_class( $css_class ) ); ?>">
80 <?php foreach ( $links as $link ) : ?>
81 <a class="button button-secondary" href="<?php echo esc_url( $link['url'] ); ?>">
82 <i class="menu_icon icon-1x <?php echo esc_attr( $link['icon'] ); ?>" aria-hidden="true"></i>
83 <?php echo esc_html( $link['title'] ); ?>
84 </a>
85 <?php endforeach; ?>
86 </div>
87 <?php
88 }
89
90 /**
91 * Add a mode-aware setup guide above the existing Resources table.
92 *
93 * Appointment mode retains Provider and Service terminology. Rental and
94 * Classic modes use their native resource terminology and omit the
95 * Appointment-only Services action.
96 *
97 * @param string $settings_section Existing Resources page section identifier.
98 *
99 * @return void
100 */
101 function wpbc_appointment_services_render_provider_tools( $settings_section ) {
102 if (
103 'resources' !== $settings_section
104 || ! function_exists( 'wpbc_is_resources_page' )
105 || ! wpbc_is_resources_page()
106 || ! function_exists( 'wpbc_is_11_5_features_enabled' )
107 || ! wpbc_is_11_5_features_enabled()
108 ) {
109 return;
110 }
111
112 $selected_mode_id = function_exists( 'wpbc_booking_modes_get_selected_mode_id' )
113 ? wpbc_booking_modes_get_selected_mode_id()
114 : 'classic';
115 $guide_title = __( 'Booking Resources and availability', 'booking' );
116 $guide_description = __( 'Configure available weekdays and dates for each Booking Resource, then use the Publish buttons below to add its booking form to a page.', 'booking' );
117 $guide_links = array();
118
119 if ( 'appointment' === $selected_mode_id ) {
120 $guide_title = __( 'Provider schedules and Services', 'booking' );
121 $guide_description = __( 'Providers use Booking Resources to manage availability. Configure their working hours and days off, then assign them to Services.', 'booking' );
122 $guide_links = wpbc_appointment_services_get_provider_admin_links( 0, true );
123 } else {
124 if ( 'rental' === $selected_mode_id ) {
125 $guide_title = __( 'Property availability and publishing', 'booking' );
126 $guide_description = __( 'Properties use Booking Resources to manage availability. Configure available weekdays and dates, then publish each property\'s booking form below.', 'booking' );
127 }
128
129 if ( wpbc_appointment_services_can_manage_availability() ) {
130 $weekdays_availability_url = function_exists( 'wpbc_get_general_availability_url' )
131 ? wpbc_get_general_availability_url()
132 : admin_url( 'admin.php?page=wpbc-availability&tab=general_availability' );
133 $days_availability_url = function_exists( 'wpbc_get_availability_url' )
134 ? wpbc_get_availability_url()
135 : admin_url( 'admin.php?page=wpbc-availability' );
136
137 $guide_links[] = array(
138 'title' => ( 'rental' === $selected_mode_id ) ? __( 'Weekdays Availability', 'booking' ) : __( 'General Availability', 'booking' ),
139 'url' => $weekdays_availability_url,
140 'icon' => 'wpbc-bi-calendar-week',
141 );
142 $guide_links[] = array(
143 'title' => __( 'Days Availability', 'booking' ),
144 'url' => $days_availability_url,
145 'icon' => 'wpbc-bi-calendar-check',
146 );
147 }
148 }
149
150 ?>
151 <div class="wpbc_appointment_provider_tools">
152 <div class="wpbc_appointment_provider_tools__copy">
153 <strong><?php echo esc_html( $guide_title ); ?></strong>
154 <span><?php echo esc_html( $guide_description ); ?></span>
155 </div>
156 <?php if ( ! empty( $guide_links ) ) : ?>
157 <div class="wpbc_appointment_provider_links wpbc_ui_el__buttons_group wpbc_appointment_provider_tools__actions">
158 <?php foreach ( $guide_links as $guide_link ) : ?>
159 <a class="button button-secondary" href="<?php echo esc_url( $guide_link['url'] ); ?>">
160 <i class="menu_icon icon-1x <?php echo esc_attr( $guide_link['icon'] ); ?>" aria-hidden="true"></i>
161 <?php echo esc_html( $guide_link['title'] ); ?>
162 </a>
163 <?php endforeach; ?>
164 </div>
165 <?php endif; ?>
166 </div>
167 <?php
168 }
169 add_action( 'wpbc_hook_settings_page_before_content_table', 'wpbc_appointment_services_render_provider_tools', 15, 1 );
170
171 /**
172 * Render one disabled Service inspector field for client-side editing.
173 *
174 * @param string $field_id Stable field and DOM identifier.
175 * @param string $label User-facing field label.
176 * @param string $type Input type, textarea, or status.
177 * @param array<string,mixed> $args Optional min, step, placeholder, help, and slider values.
178 *
179 * @return void
180 */
181 function wpbc_appointment_services_render_field( $field_id, $label, $type = 'text', $args = array() ) {
182 $args = wp_parse_args(
183 $args,
184 array(
185 'min' => '',
186 'step' => '',
187 'placeholder' => '',
188 'help' => '',
189 'slider' => false,
190 'slider_min' => 0,
191 'slider_max' => 100,
192 'slider_step' => 1,
193 )
194 );
195 $slider_aria_label = '';
196 if ( $args['slider'] ) {
197 /* translators: %s: Service numeric field label. */
198 $slider_aria_label = sprintf( __( 'Adjust %s', 'booking' ), $label );
199 }
200 ?>
201 <div class="inspector__row">
202 <?php if ( 'status' === $type ) : ?>
203 <span id="<?php echo esc_attr( $field_id ); ?>_label" class="inspector__label"><?php echo esc_html( $label ); ?></span>
204 <?php else : ?>
205 <label for="<?php echo esc_attr( $field_id ); ?>" class="inspector__label"><?php echo esc_html( $label ); ?></label>
206 <?php endif; ?>
207 <div class="inspector__control">
208 <?php if ( 'textarea' === $type ) : ?>
209 <textarea id="<?php echo esc_attr( $field_id ); ?>" class="inspector__input" data-service-field="<?php echo esc_attr( $field_id ); ?>" rows="4" disabled></textarea>
210 <?php elseif ( 'status' === $type ) : ?>
211 <input type="hidden" id="<?php echo esc_attr( $field_id ); ?>" data-service-field="<?php echo esc_attr( $field_id ); ?>" value="active" disabled />
212 <div class="wpbc_appointment_services__status_options" role="radiogroup" aria-labelledby="<?php echo esc_attr( $field_id ); ?>_label">
213 <label for="<?php echo esc_attr( $field_id ); ?>_active">
214 <input type="radio" id="<?php echo esc_attr( $field_id ); ?>_active" name="wpbc_appointment_service_status" value="active" data-service-status-choice checked disabled />
215 <span><?php esc_html_e( 'Active', 'booking' ); ?></span>
216 </label>
217 <label for="<?php echo esc_attr( $field_id ); ?>_inactive">
218 <input type="radio" id="<?php echo esc_attr( $field_id ); ?>_inactive" name="wpbc_appointment_service_status" value="inactive" data-service-status-choice disabled />
219 <span><?php esc_html_e( 'Inactive', 'booking' ); ?></span>
220 </label>
221 <label for="<?php echo esc_attr( $field_id ); ?>_archived">
222 <input type="radio" id="<?php echo esc_attr( $field_id ); ?>_archived" name="wpbc_appointment_service_status" value="archived" data-service-status-choice disabled />
223 <span><?php esc_html_e( 'Archived', 'booking' ); ?></span>
224 </label>
225 </div>
226 <?php else : ?>
227 <div class="<?php echo $args['slider'] ? 'wpbc_appointment_services__number_control' : ''; ?>">
228 <input type="<?php echo esc_attr( $type ); ?>" id="<?php echo esc_attr( $field_id ); ?>" class="inspector__input" data-service-field="<?php echo esc_attr( $field_id ); ?>" <?php echo '' !== $args['min'] ? 'min="' . esc_attr( $args['min'] ) . '"' : ''; ?> <?php echo '' !== $args['step'] ? 'step="' . esc_attr( $args['step'] ) . '"' : ''; ?> placeholder="<?php echo esc_attr( $args['placeholder'] ); ?>" disabled />
229 <?php if ( $args['slider'] ) : ?>
230 <input type="range"
231 class="wpbc_appointment_services__number_slider"
232 data-service-range-field="<?php echo esc_attr( $field_id ); ?>"
233 data-service-range-default-min="<?php echo esc_attr( $args['slider_min'] ); ?>"
234 data-service-range-default-max="<?php echo esc_attr( $args['slider_max'] ); ?>"
235 min="<?php echo esc_attr( $args['slider_min'] ); ?>"
236 max="<?php echo esc_attr( $args['slider_max'] ); ?>"
237 step="<?php echo esc_attr( $args['slider_step'] ); ?>"
238 value="<?php echo esc_attr( $args['slider_min'] ); ?>"
239 aria-label="<?php echo esc_attr( $slider_aria_label ); ?>"
240 disabled />
241 <?php endif; ?>
242 </div>
243 <?php endif; ?>
244 <?php if ( $args['help'] ) : ?>
245 <p class="description wpbc_bfb__help"><?php echo esc_html( $args['help'] ); ?></p>
246 <?php endif; ?>
247 </div>
248 </div>
249 <?php
250 }
251
252 /**
253 * Render the Service image selector using the shared WordPress media library.
254 *
255 * The URL is stored with the Service payload while the media attachment remains
256 * managed by WordPress. A readonly URL field keeps the AJAX editor contract
257 * transparent and allows the common media-uploader helper to populate it.
258 *
259 * @return void
260 */
261 function wpbc_appointment_services_render_picture_field() {
262 ?>
263 <div class="inspector__row wpbc_appointment_services__picture_row">
264 <label for="picture_url" class="inspector__label"><?php esc_html_e( 'Picture', 'booking' ); ?></label>
265 <div class="inspector__control">
266 <div class="wpbc_appointment_services__media">
267 <button type="button" class="wpbc_appointment_services__media_preview wpbc_media_upload_button" data-modal_title="<?php esc_attr_e( 'Select Service Image', 'booking' ); ?>" data-btn_title="<?php esc_attr_e( 'Use this image', 'booking' ); ?>" data-url_field="picture_url" aria-label="<?php esc_attr_e( 'Select Service image', 'booking' ); ?>" disabled>
268 <img alt="" class="wpbc_appointment_services__media_image" hidden />
269 <i class="wpbc_appointment_services__media_placeholder menu_icon icon-1x wpbc-bi-image-fill" aria-hidden="true"></i>
270 </button>
271 <div class="wpbc_appointment_services__media_actions wpbc_ui_el__buttons_group">
272 <button type="button" class="button wpbc_media_upload_button wpbc_appointment_services__select_image" data-modal_title="<?php esc_attr_e( 'Select Service Image', 'booking' ); ?>" data-btn_title="<?php esc_attr_e( 'Use this image', 'booking' ); ?>" data-url_field="picture_url" disabled><?php esc_html_e( 'Select image', 'booking' ); ?></button>
273 <button type="button" class="button wpbc_appointment_services__remove_image" disabled><?php esc_html_e( 'Remove', 'booking' ); ?></button>
274 </div>
275 </div>
276 <input type="text" id="picture_url" class="inspector__input" data-service-field="picture_url" value="" placeholder="<?php esc_attr_e( 'Select image...', 'booking' ); ?>" readonly disabled />
277 <p class="description wpbc_bfb__help"><?php esc_html_e( 'Used in the Services catalog and Appointment selection.', 'booking' ); ?></p>
278 </div>
279 </div>
280 <?php
281 }
282
283 /**
284 * Render the general Service fields for the inspector callback.
285 *
286 * @return void
287 */
288 function wpbc_appointment_services_render_general_fields() {
289 wpbc_appointment_services_render_field( 'title', __( 'Service title', 'booking' ), 'text', array( 'placeholder' => __( 'Example: Initial Consultation', 'booking' ) ) );
290 wpbc_appointment_services_render_field( 'description', __( 'Description', 'booking' ), 'textarea' );
291 wpbc_appointment_services_render_picture_field();
292 wpbc_appointment_services_render_field( 'status', __( 'Status', 'booking' ), 'status' );
293 }
294
295 /**
296 * Render duration and buffer fields for the inspector.
297 *
298 * @return void
299 */
300 function wpbc_appointment_services_render_scheduling_fields() {
301
302 wpbc_appointment_services_render_field(
303 'duration_minutes',
304 __( 'Duration (minutes)', 'booking' ),
305 'number',
306 array(
307 'min' => 1,
308 'step' => 1,
309 'slider' => true,
310 'slider_min' => 1,
311 'slider_max' => 480,
312 'slider_step' => 5,
313 )
314 );
315 wpbc_appointment_services_render_field(
316 'buffer_before_minutes',
317 __( 'Buffer before (minutes)', 'booking' ),
318 'number',
319 array(
320 'min' => 0,
321 'step' => 1,
322 'slider' => true,
323 'slider_min' => 0,
324 'slider_max' => 180,
325 'slider_step' => 5,
326 )
327 );
328 wpbc_appointment_services_render_field(
329 'buffer_after_minutes',
330 __( 'Buffer after (minutes)', 'booking' ),
331 'number',
332 array(
333 'min' => 0,
334 'step' => 1,
335 'slider' => true,
336 'slider_min' => 0,
337 'slider_max' => 180,
338 'slider_step' => 5,
339 )
340 );
341 }
342
343 /**
344 * Render Service pricing fields for the inspector.
345 *
346 * @return void
347 */
348 function wpbc_appointment_services_render_pricing_fields() {
349 if ( ! wpbc_appointment_services_is_pricing_available() ) {
350 ?>
351 <div class="inspector__row wpbc_appointment_services__pricing_upgrade">
352 <div class="inspector__control">
353 <div class="inspector__label">
354 <?php esc_html_e( 'Service price', 'booking' ); ?>
355 <a class="wpbc_pro_label" href="<?php echo esc_url( 'https://wpbookingcalendar.com/features/' ); ?>" target="_blank" rel="noopener noreferrer">BS+</a>
356 </div>
357 <p class="description wpbc_bfb__help"><?php esc_html_e( 'Service pricing and online payments are available in Booking Calendar Business Small or higher. Service scheduling remains fully available in this edition.', 'booking' ); ?></p>
358 </div>
359 </div>
360 <?php
361 return;
362 }
363
364 wpbc_appointment_services_render_field( 'base_cost', __( 'Base price', 'booking' ), 'number', array(
365 'min' => 0,
366 'step' => '0.01',
367 'slider' => true,
368 'slider_min' => 0,
369 'slider_max' => 100000,
370 'slider_step' => 1, //'0.01',
371 ) );
372 }
373
374 /**
375 * Render the existing booking-resource choices as assigned Providers.
376 *
377 * @return void
378 */
379 function wpbc_appointment_services_render_provider_fields() {
380 ?>
381 <div class="inspector__row">
382 <label for="resource_ids" class="inspector__label"><?php esc_html_e( 'Assigned Providers', 'booking' ); ?></label>
383 <div class="inspector__control">
384 <select id="resource_ids" class="inspector__input" data-service-field="resource_ids" multiple size="6" disabled>
385 <?php foreach ( wpbc_appointment_services_get_provider_options() as $resource_id => $title ) : ?>
386 <option value="<?php echo absint( $resource_id ); ?>"><?php echo esc_html( $title ); ?></option>
387 <?php endforeach; ?>
388 </select>
389 <p class="description wpbc_bfb__help"><?php esc_html_e( 'Select every Provider who can perform this Service. Providers use the availability of their Booking Calendar resource.', 'booking' ); ?></p>
390 <?php wpbc_appointment_services_render_provider_admin_links( 0, 'wpbc_appointment_provider_links--inspector', false ); ?>
391 </div>
392 </div>
393 <?php
394 }
395
396 /**
397 * Render the Booking Form assignment field for the inspector.
398 *
399 * @return void
400 */
401 function wpbc_appointment_services_render_form_fields() {
402 ?>
403 <div class="inspector__row">
404 <label for="booking_form_id" class="inspector__label"><?php esc_html_e( 'Booking Form', 'booking' ); ?></label>
405 <div class="inspector__control">
406 <select id="booking_form_id" class="inspector__input" data-service-field="booking_form_id" disabled>
407 <?php foreach ( wpbc_appointment_services_get_form_options() as $form_id => $title ) : ?>
408 <option value="<?php echo absint( $form_id ); ?>"><?php echo esc_html( $title ); ?></option>
409 <?php endforeach; ?>
410 </select>
411 </div>
412 </div>
413 <?php
414 }
415
416 /**
417 * Render duplicate and archive actions for the inspector.
418 *
419 * @return void
420 */
421 function wpbc_appointment_services_render_advanced_fields() {
422 ?>
423 <button type="button" class="button wpbc_appointment_services__duplicate" disabled><?php
424 esc_html_e( 'Duplicate Service', 'booking' ); ?></button>
425 <button type="button" class="button button-link-delete wpbc_appointment_services__archive" disabled><?php
426 esc_html_e( 'Archive Service', 'booking' ); ?></button><?php
427 }
428
429 /**
430 * Render the complete Service Settings inspector panel.
431 *
432 * @return void
433 */
434 function wpbc_appointment_services_render_settings_panel() {
435 WPBC_UI_Sidebar_Panels::render_inspector_header( __( 'Service Settings', 'booking' ), __( 'Select a Service or create a new one.', 'booking' ) );
436 WPBC_UI_Sidebar_Panels::render_collapsible_group( array(
437 'id' => 'wpbc_service_general',
438 'group' => 'service-general',
439 'title' => __( 'General', 'booking' ),
440 'open' => true,
441 ), 'wpbc_appointment_services_render_general_fields' );
442 WPBC_UI_Sidebar_Panels::render_collapsible_group( array(
443 'id' => 'wpbc_service_scheduling',
444 'group' => 'service-scheduling',
445 'title' => __( 'Scheduling', 'booking' ),
446 'open' => true,
447 ), 'wpbc_appointment_services_render_scheduling_fields' );
448 WPBC_UI_Sidebar_Panels::render_collapsible_group( array(
449 'id' => 'wpbc_service_pricing',
450 'group' => 'service-pricing',
451 'title' => __( 'Pricing', 'booking' ),
452 ), 'wpbc_appointment_services_render_pricing_fields' );
453 WPBC_UI_Sidebar_Panels::render_collapsible_group( array(
454 'id' => 'wpbc_service_providers',
455 'group' => 'service-providers',
456 'title' => __( 'Providers', 'booking' ),
457 ), 'wpbc_appointment_services_render_provider_fields' );
458 WPBC_UI_Sidebar_Panels::render_collapsible_group( array(
459 'id' => 'wpbc_service_form',
460 'group' => 'service-form',
461 'title' => __( 'Booking Form', 'booking' ),
462 ), 'wpbc_appointment_services_render_form_fields' );
463 WPBC_UI_Sidebar_Panels::render_collapsible_group( array(
464 'id' => 'wpbc_service_advanced',
465 'group' => 'service-advanced',
466 'title' => __( 'Advanced', 'booking' ),
467 ), 'wpbc_appointment_services_render_advanced_fields' );
468 }
469
470 /**
471 * Render the Service editor action in the native right-sidebar footer.
472 *
473 * The footer is outside the SimpleBar scrolling element so Save Service is
474 * immediately visible and remains available while inspector widgets scroll.
475 * JavaScript reveals it only while the Settings panel has an open editor.
476 *
477 * @param array $active_page_arr Active page, tab, and subtab identifiers.
478 *
479 * @return void
480 */
481 function wpbc_appointment_services_render_right_sidebar_footer( $active_page_arr ) {
482 if (
483 empty( $active_page_arr['active_page'] )
484 || 'wpbc-services' !== $active_page_arr['active_page']
485 || ! wpbc_appointment_services__is_page()
486 || ! current_user_can( wpbc_appointment_services_get_manage_capability() )
487 ) {
488 return;
489 }
490 ?>
491 <div class="wpbc_ui_el__vert_right_bar__footer_section wpbc_appointment_services__right_sidebar_footer" hidden>
492 <div class="wpbc_appointment_services__top_actions wpbc_appointment_services__footer_actions wpbc_ui_el__buttons_group" hidden>
493 <button type="button" class="button button-primary wpbc_appointment_services__save" hidden disabled>
494 <?php esc_html_e( 'Save Service', 'booking' ); ?>
495 </button>
496 </div>
497 </div>
498 <?php
499 }
500 add_action( 'wpbc_ui__right_vertical_sidebar_footer', 'wpbc_appointment_services_render_right_sidebar_footer', 10, 1 );
501
502 /**
503 * Render contextual help for the Service and Provider data model.
504 *
505 * @return void
506 */
507 function wpbc_appointment_services_render_help_panel() {
508 WPBC_UI_Sidebar_Panels::render_inspector_header( __( 'About Services', 'booking' ), __( 'How Services work with the existing Booking Calendar architecture.', 'booking' ) );
509 ?>
510 <div class="wpbc_appointment_services__help"><p><?php
511 if ( wpbc_appointment_services_is_pricing_available() ) {
512 esc_html_e( 'A Service describes what a customer can book. Its settings define the appointment duration, preparation and recovery buffers, price, and Booking Form.', 'booking' );
513 } else {
514 esc_html_e( 'A Service describes what a customer can book. Its settings define the appointment duration, preparation and recovery buffers, Providers, and Booking Form.', 'booking' );
515 }
516 ?></p>
517 <h4><?php
518 esc_html_e( 'Providers and availability', 'booking' ); ?></h4>
519 <p><?php
520 esc_html_e( 'Providers remain Booking Calendar resources because every Provider needs an independent availability calendar.', 'booking' ); ?></p>
521 <ul>
522 <li><?php
523 esc_html_e( 'The weekday dots are a recurring weekly summary. A weekday is available when General Availability allows it and, when Working Time is enabled, the Provider has at least one working interval that day.', 'booking' ); ?></li>
524 <li><?php
525 esc_html_e( 'The summary does not check Seasons, date-specific days off, existing bookings, time-slot rules, Service duration, or buffers. The customer booking calendar performs those complete checks for the selected date and time.', 'booking' ); ?></li>
526 <li><?php
527 esc_html_e( 'When several Providers are assigned, a green dot means at least one of them is normally available that weekday. Point to the dot to see which Providers are included.', 'booking' ); ?></li>
528 <li><?php
529 esc_html_e( 'Use the Provider initials below the dots to open that Provider\'s Working Time settings directly.', 'booking' ); ?></li>
530 </ul>
531 <h4><?php
532 esc_html_e( 'Getting started', 'booking' ); ?></h4>
533 <ol>
534 <li><?php
535 esc_html_e( 'Add a Service and enter its duration.', 'booking' ); ?></li>
536 <li><?php
537 esc_html_e( 'Assign at least one Provider.', 'booking' ); ?></li>
538 <li><?php
539 esc_html_e( 'Select a Booking Form and save the Service.', 'booking' ); ?></li>
540 <li><?php
541 esc_html_e( 'Add the [booking_appointment] shortcode to the page where customers should make Appointments.', 'booking' ); ?></li>
542 </ol>
543 <h4><?php esc_html_e( 'Appointment shortcode', 'booking' ); ?></h4>
544 <p><code>[booking_appointment]</code></p>
545 <p><?php esc_html_e( 'Optional parameters:', 'booking' ); ?></p>
546 <ul>
547 <li><code>service_id</code>, <code>provider_id</code> &mdash; <?php esc_html_e( 'restrict the flow to one Service or Provider.', 'booking' ); ?></li>
548 <li><code>services</code>, <code>providers</code> &mdash; <?php esc_html_e( 'comma-separated lists of allowed Service or Provider IDs; Services follow the supplied order.', 'booking' ); ?></li>
549 <li><code>form_type</code> &mdash; <?php esc_html_e( 'override the Booking Form selected in the Service.', 'booking' ); ?></li>
550 <li><code>nummonths</code>, <code>startmonth</code> &mdash; <?php esc_html_e( 'set the calendar count and initial month.', 'booking' ); ?></li>
551 <li><code>calendar_dates_start</code>, <code>calendar_dates_end</code> &mdash; <?php esc_html_e( 'limit the calendar to an inclusive date range in YYYY-MM-DD format.', 'booking' ); ?></li>
552 <li><code>options</code> &mdash; <?php esc_html_e( 'pass supported native Booking Calendar options.', 'booking' ); ?></li>
553 <li><code>auto_select_provider</code> &mdash; <?php esc_html_e( 'use "on" to skip the Provider step when only one compatible Provider exists; disabled by default.', 'booking' ); ?></li>
554 <li><code>show_progress</code> &mdash; <?php esc_html_e( 'use "off" to hide the numbered Appointment progress line.', 'booking' ); ?></li>
555 <li><code>progress_item_1_title</code> through <code>progress_item_3_title</code> &mdash; <?php esc_html_e( 'replace the three titles shown below the progress numbers; use an empty value to hide a title.', 'booking' ); ?></li>
556 <li><code>progress_item_1_number</code> through <code>progress_item_3_number</code> &mdash; <?php esc_html_e( 'replace the displayed progress numbers; use an empty value to hide a number.', 'booking' ); ?></li>
557 <li><code>screen_1_title</code>, <code>screen_1_description</code>, <code>screen_2_title</code>, <code>screen_2_description</code> &mdash; <?php esc_html_e( 'replace the Service and Provider screen headings; use an empty value to hide an element.', 'booking' ); ?></li>
558 <li><code>allow_past</code> &mdash; <?php esc_html_e( 'use "on" to allow administrators or controlled workflows to select past dates.', 'booking' ); ?></li>
559 </ul>
560 <p><code>[booking_appointment service_id=&quot;12&quot; provider_id=&quot;5&quot;]</code></p>
561 <p><code>[booking_appointment progress_item_1_title=&quot;&quot; progress_item_1_number=&quot;01/03&quot; progress_item_2_title=&quot;Specialist&quot; progress_item_3_title=&quot;Schedule &amp; Details&quot;]</code></p>
562 </div><?php
563 }
564