| 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> — <?php esc_html_e( 'restrict the flow to one Service or Provider.', 'booking' ); ?></li> |
| 548 |
<li><code>services</code>, <code>providers</code> — <?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> — <?php esc_html_e( 'override the Booking Form selected in the Service.', 'booking' ); ?></li> |
| 550 |
<li><code>nummonths</code>, <code>startmonth</code> — <?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> — <?php esc_html_e( 'limit the calendar to an inclusive date range in YYYY-MM-DD format.', 'booking' ); ?></li> |
| 552 |
<li><code>options</code> — <?php esc_html_e( 'pass supported native Booking Calendar options.', 'booking' ); ?></li> |
| 553 |
<li><code>auto_select_provider</code> — <?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> — <?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> — <?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> — <?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> — <?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> — <?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="12" provider_id="5"]</code></p> |
| 561 |
<p><code>[booking_appointment progress_item_1_title="" progress_item_1_number="01/03" progress_item_2_title="Specialist" progress_item_3_title="Schedule & Details"]</code></p> |
| 562 |
</div><?php |
| 563 |
} |
| 564 |
|