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-add-appointment / add_appointment__page.php

add_appointment__page.php in Booking Calendar 11.5, at includes/page-add-appointment/add_appointment__page.php

500 lines 20.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Dedicated Add Appointment administrator page.
4 *
5 * @package Booking Calendar
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 /**
13 * Check whether the Add Appointment tab is the current Booking Calendar page.
14 *
15 * @return bool True on the Add Appointment tab.
16 */
17 function wpbc_add_appointment_page_is_active() {
18 if ( ! is_admin() || ! wpbc_is_11_5_features_enabled() ) {
19 return false;
20 }
21
22 $page = isset( $_GET['page'] ) && ! is_array( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
23 $tab = isset( $_GET['tab'] ) && ! is_array( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
24
25 return 'wpbc' === $page && 'add-appointment' === $tab;
26 }
27
28 /**
29 * Return the canonical administrator URL for the Add Appointment workflow.
30 *
31 * @return string Absolute WordPress administrator URL.
32 */
33 function wpbc_add_appointment_page_get_url() {
34 return add_query_arg(
35 array(
36 'page' => 'wpbc',
37 'tab' => 'add-appointment',
38 ),
39 admin_url( 'admin.php' )
40 );
41 }
42
43 /**
44 * Read the page-level Appointment options from the current administrator URL.
45 *
46 * These values configure only the dedicated Add Appointment screen. Service
47 * duration, buffers, price, and Booking Form remain owned by the Service.
48 *
49 * @return array{calendar_months:int,auto_select_provider:bool,allow_past:bool} Normalized page options.
50 */
51 function wpbc_add_appointment_page_get_settings() {
52 $months = isset( $_GET['appointment_months'] ) && ! is_array( $_GET['appointment_months'] )
53 ? absint( wp_unslash( $_GET['appointment_months'] ) ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
54 : 1;
55 $months = min( 12, max( 1, $months ) );
56
57 return array(
58 'calendar_months' => $months,
59 'auto_select_provider' => isset( $_GET['appointment_auto_select_provider'] ) && ! is_array( $_GET['appointment_auto_select_provider'] ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended
60 'allow_past' => isset( $_GET['allow_past'] ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended
61 );
62 }
63
64 /**
65 * Print the legacy booking context required by calendar and submit scripts.
66 *
67 * Reusing the Add Booking minimum-date calculation keeps past-date behavior
68 * identical in both administrator workflows.
69 *
70 * @param bool $allow_past Whether past dates may be selected and submitted.
71 *
72 * @return void
73 */
74 function wpbc_add_appointment_page_print_booking_context( $allow_past ) {
75 $allow_past_date_arr = WPBC_Add_Booking_Component::get_allow_past_min_date_arr(
76 array(
77 'allow_past' => $allow_past ? 1 : 0,
78 'booking_hash' => '',
79 )
80 );
81 ?>
82 <script type="text/javascript">
83 if ( 'undefined' !== typeof _wpbc ) {
84 _wpbc.set_other_param( 'this_page_booking_hash', '' );
85 _wpbc.set_other_param( 'this_page_allow_past', <?php echo wp_json_encode( $allow_past ? 1 : 0 ); ?> );
86 _wpbc.set_other_param( 'this_page_allow_past_arr', <?php echo wp_json_encode( $allow_past_date_arr ); ?> );
87 }
88 </script>
89 <?php
90 }
91
92 /**
93 * Enqueue the existing Appointment controller and the page-only admin styles.
94 *
95 * @param string $where_to_load Booking Calendar asset context.
96 *
97 * @return void
98 */
99 function wpbc_add_appointment_page_enqueue_css( $where_to_load ) {
100 if ( ! in_array( $where_to_load, array( 'admin', 'both' ), true ) || ! wpbc_add_appointment_page_is_active() ) {
101 return;
102 }
103
104 wp_enqueue_style(
105 'wpbc-add-appointment-page',
106 trailingslashit( plugins_url( '', __FILE__ ) ) . '_out/add_appointment_page.css',
107 array( 'wpbc-all-admin', 'wpbc-booking-appointment' ),
108 WP_BK_VERSION_NUM
109 );
110 }
111 add_action( 'wpbc_enqueue_css_files', 'wpbc_add_appointment_page_enqueue_css', 73 );
112
113 /**
114 * Enqueue the existing AJAX Appointment controller and page inspector client.
115 *
116 * @param string $where_to_load Booking Calendar asset context.
117 *
118 * @return void
119 */
120 function wpbc_add_appointment_page_enqueue_js( $where_to_load ) {
121 if ( ! in_array( $where_to_load, array( 'admin', 'both' ), true ) || ! wpbc_add_appointment_page_is_active() ) {
122 return;
123 }
124
125 wp_enqueue_script(
126 'wpbc-add-appointment-page',
127 trailingslashit( plugins_url( '', __FILE__ ) ) . '_out/add_appointment_page.js',
128 array( 'jquery', 'wpbc-booking-appointment', 'wpbc_all' ),
129 WP_BK_VERSION_NUM,
130 array( 'in_footer' => WPBC_JS_IN_FOOTER )
131 );
132 $settings = wpbc_add_appointment_page_get_settings();
133 $allow_past_date_arr = WPBC_Add_Booking_Component::get_allow_past_min_date_arr(
134 array(
135 'allow_past' => $settings['allow_past'] ? 1 : 0,
136 'booking_hash' => '',
137 )
138 );
139
140 wp_localize_script(
141 'wpbc-add-appointment-page',
142 'wpbc_add_appointment_page_config',
143 array(
144 'emptyLabel' => __( 'Not selected', 'booking' ),
145 'enabledLabel' => __( 'Enabled', 'booking' ),
146 'disabledLabel' => __( 'Disabled', 'booking' ),
147 'minutesLabel' => __( 'min', 'booking' ),
148 'allowPast' => $settings['allow_past'] ? 1 : 0,
149 'allowPastDateArr' => $allow_past_date_arr,
150 )
151 );
152 }
153 add_action( 'wpbc_enqueue_js_files', 'wpbc_add_appointment_page_enqueue_js', 73 );
154
155 /**
156 * Add Appointment page integrated into the shared Booking Calendar page shell.
157 */
158 class WPBC_Page_Add_Appointment extends WPBC_Page_Structure {
159
160 /**
161 * Place the page beside Booking Listing, Timeline, and Add Booking.
162 *
163 * @return string Parent page slug.
164 */
165 public function in_page() {
166 if ( ! WPBC_Add_Booking_Component::current_user_can_add_booking() ) {
167 return (string) wp_rand( 100000, 1000000 );
168 }
169
170 return 'wpbc';
171 }
172
173 /**
174 * Register the feature-gated Appointment tab and shared inspector layout.
175 *
176 * @return array<string,array<string,mixed>> Tab definition.
177 */
178 public function tabs() {
179 return array(
180 'add-appointment' => array(
181 'is_show_top_path' => true,
182 'is_show_top_navigation' => true,
183 'left_navigation__default_view_mode' => 'min',
184 'right_vertical_sidebar__is_show' => true,
185 'right_vertical_sidebar__default_view_mode' => '',
186 'right_vertical_sidebar_compact__is_show' => true,
187 'page_title' => __( 'Add New Appointment', 'booking' ),
188 'page_description' => __( 'Select a Service and Provider, then create the Appointment with the existing Booking Calendar form.', 'booking' ),
189 'title' => __( 'Add Appointment', 'booking' ),
190 'hint' => __( 'Add Appointment', 'booking' ),
191 'font_icon' => 'wpbc-bi-plus-circle-dotted wpbc_icn_rotate_180',
192 'default' => false,
193 'disabled' => false,
194 'hided' => false,
195 'subtabs' => array(),
196 ),
197 );
198 }
199
200 /**
201 * Render compact controls for the Appointment inspector.
202 *
203 * @return void
204 */
205 public function right_sidebar_compact_content() {
206 WPBC_UI_Sidebar_Panels::render_rightbar_tabs(
207 array(
208 array(
209 'id' => 'wpbc_tab_add_appointment_overview',
210 'panel_id' => 'wpbc_add_appointment__inspector_overview',
211 'title' => __( 'Settings', 'booking' ),
212 'icon' => 'wpbc_icn_tune',
213 'selected' => true,
214 ),
215 array(
216 'id' => 'wpbc_tab_add_appointment_help',
217 'panel_id' => 'wpbc_add_appointment__inspector_help',
218 'title' => __( 'Help', 'booking' ),
219 'icon' => 'wpbc-bi-info-circle',
220 ),
221 ),
222 array(
223 'aria_label' => __( 'Add Appointment Panels', 'booking' ),
224 'context' => 'add_appointment',
225 'class' => 'wpbc_add_appointment__rightbar_tabs',
226 )
227 );
228 }
229
230 /**
231 * Render the standard Builder-style Appointment inspector panels.
232 *
233 * @return void
234 */
235 public function right_sidebar_content() {
236 ?>
237 <div class="wpbc_bfb__panel--library wpbc_rightbar_palette wpbc_add_appointment__rightbar">
238 <?php
239 WPBC_UI_Sidebar_Panels::render_panel(
240 array(
241 'id' => 'wpbc_add_appointment__inspector_overview',
242 'labelledby' => 'wpbc_tab_add_appointment_overview',
243 'class' => 'wpbc_add_appointment__inspector_overview',
244 ),
245 array( $this, 'render_overview_panel' )
246 );
247 WPBC_UI_Sidebar_Panels::render_panel(
248 array(
249 'id' => 'wpbc_add_appointment__inspector_help',
250 'labelledby' => 'wpbc_tab_add_appointment_help',
251 'class' => 'wpbc_add_appointment__inspector_help',
252 'hidden' => true,
253 ),
254 array( $this, 'render_help_panel' )
255 );
256 ?>
257 </div>
258 <?php
259 }
260
261 /**
262 * Render the contextual workflow panel.
263 *
264 * @return void
265 */
266 public function render_overview_panel() {
267 $settings = wpbc_add_appointment_page_get_settings();
268 WPBC_UI_Sidebar_Panels::render_inspector_header( __( 'Appointment Settings', 'booking' ), __( 'Page-level options for this administrator booking.', 'booking' ) );
269 ?>
270 <div class="wpbc_bfb__inspector__body wpbc_add_appointment__inspector_body">
271 <?php
272 WPBC_UI_Sidebar_Panels::render_collapsible_group(
273 array(
274 'id' => 'wpbc_add_appointment_summary_group',
275 'group' => 'add-appointment-summary',
276 'title' => __( 'Appointment Summary', 'booking' ),
277 'open' => true,
278 ),
279 array( $this, 'render_summary_content' )
280 );
281 WPBC_UI_Sidebar_Panels::render_collapsible_group(
282 array(
283 'id' => 'wpbc_add_appointment_booking_tools_group',
284 'group' => 'add-appointment-booking-tools',
285 'title' => __( 'Booking tools', 'booking' ),
286 'open' => false,
287 ),
288 function () {
289 $send_emails = get_bk_option( 'booking_send_emails_off_addbooking' ) !== 'On';
290 ?>
291 <div class="wpbc_add_appointment__setting_row wpbc_add_appointment__setting_row--toggle">
292 <?php
293 wpbc_flex_toggle(
294 array(
295 'id' => 'is_send_email_for_pending',
296 'name' => 'is_send_email_for_pending',
297 'label' => array( 'title' => __( 'Emails sending', 'booking' ) ),
298 'value' => 'On',
299 'selected' => $send_emails,
300 'legend' => __( 'Send email notifications for this Appointment', 'booking' ),
301 )
302 );
303 ?>
304 <p><?php esc_html_e( 'Send the normal Booking Calendar notifications when this Appointment is created.', 'booking' ); ?></p>
305 </div>
306 <div class="wpbc_add_appointment__panel_actions wpbc_add_appointment__tool_actions">
307 <button type="button" class="button wpbc_add_appointment__autofill" data-wpbc-add-appointment-autofill disabled><?php esc_html_e( 'Auto-fill form', 'booking' ); ?></button>
308 <button type="button" class="button wpbc_add_appointment__start_over" data-wpbc-add-appointment-start-over hidden><?php esc_html_e( 'Start over', 'booking' ); ?></button>
309 </div>
310 <p class="wpbc_add_appointment__tool_help"><?php esc_html_e( 'Auto-fill becomes available after the Booking Form loads. It fills sample contact details but never submits the Appointment.', 'booking' ); ?></p>
311 <?php
312 }
313 );
314 WPBC_UI_Sidebar_Panels::render_collapsible_group(
315 array(
316 'id' => 'wpbc_add_appointment_booking_options_group',
317 'group' => 'add-appointment-booking-options',
318 'title' => __( 'Booking options', 'booking' ),
319 'open' => false,
320 ),
321 function () use ( $settings ) {
322 ?>
323 <form class="wpbc_add_appointment__settings_form" method="get" action="<?php echo esc_url( admin_url( 'admin.php' ) ); ?>">
324 <input type="hidden" name="page" value="wpbc">
325 <input type="hidden" name="tab" value="add-appointment">
326 <div class="wpbc_add_appointment__setting_row">
327 <label for="wpbc_add_appointment__months"><strong><?php esc_html_e( 'Calendar months', 'booking' ); ?></strong></label>
328 <select id="wpbc_add_appointment__months" name="appointment_months">
329 <?php foreach ( array( 1, 2, 3, 4, 6, 12 ) as $months ) : ?>
330 <option value="<?php echo absint( $months ); ?>" <?php selected( $settings['calendar_months'], $months ); ?>><?php echo absint( $months ); ?></option>
331 <?php endforeach; ?>
332 </select>
333 <p><?php esc_html_e( 'Number of months shown in the Provider calendar.', 'booking' ); ?></p>
334 </div>
335 <div class="wpbc_add_appointment__setting_row wpbc_add_appointment__setting_row--toggle">
336 <?php
337 wpbc_flex_toggle(
338 array(
339 'id' => 'wpbc_add_appointment__auto_provider',
340 'name' => 'appointment_auto_select_provider',
341 'label' => array( 'title' => __( 'Auto-select the only Provider', 'booking' ) ),
342 'value' => '1',
343 'selected' => $settings['auto_select_provider'],
344 'legend' => __( 'Auto-select the only compatible Provider', 'booking' ),
345 )
346 );
347 ?>
348 <p><?php esc_html_e( 'Skip Provider selection when only one compatible Provider exists.', 'booking' ); ?></p>
349 </div>
350 <div class="wpbc_add_appointment__setting_row wpbc_add_appointment__setting_row--toggle">
351 <?php
352 wpbc_flex_toggle(
353 array(
354 'id' => 'wpbc_add_appointment__allow_past',
355 'name' => 'allow_past',
356 'label' => array( 'title' => __( 'Allow booking in the past', 'booking' ) ),
357 'value' => '1',
358 'selected' => $settings['allow_past'],
359 'legend' => __( 'Allow booking in the past', 'booking' ),
360 )
361 );
362 ?>
363 <p><?php esc_html_e( 'Use only for historical or manually entered Appointments.', 'booking' ); ?></p>
364 </div>
365 <button type="submit" class="button button-primary wpbc_add_appointment__apply_settings"><?php esc_html_e( 'Apply settings', 'booking' ); ?></button>
366 <p class="wpbc_add_appointment__settings_notice"><?php esc_html_e( 'Applying settings restarts the current selection.', 'booking' ); ?></p>
367 </form>
368 <?php
369 }
370 );
371 WPBC_UI_Sidebar_Panels::render_collapsible_group(
372 array(
373 'id' => 'wpbc_add_appointment_manage_setup_group',
374 'group' => 'add-appointment-manage-setup',
375 'title' => __( 'Manage setup', 'booking' ),
376 'open' => false,
377 ),
378 function () {
379 ?>
380 <p><?php
381 if ( wpbc_appointment_services_is_pricing_available() ) {
382 esc_html_e( 'Services define duration, buffers, price, and Booking Form. Providers retain their existing calendars and availability.', 'booking' );
383 } else {
384 esc_html_e( 'Services define duration, buffers, and Booking Form. Providers retain their existing calendars and availability.', 'booking' );
385 }
386 ?></p>
387 <div class="wpbc_add_appointment__panel_actions">
388 <a class="button" href="<?php echo esc_url( admin_url( 'admin.php?page=wpbc-services' ) ); ?>"><?php esc_html_e( 'Manage Services', 'booking' ); ?></a>
389 <a class="button" href="<?php echo esc_url( admin_url( 'admin.php?page=wpbc-resources' ) ); ?>"><?php esc_html_e( 'Manage Providers', 'booking' ); ?></a>
390 </div>
391 <?php
392 }
393 );
394 do_action( 'wpbc_admin_add_appointment_overview_panel' );
395 ?>
396 </div>
397 <?php
398 }
399
400 /**
401 * Render a live, read-only summary of the current Appointment stage.
402 *
403 * @return void
404 */
405 public function render_summary_content() {
406 ?>
407 <dl class="wpbc_add_appointment__summary" aria-live="polite">
408 <div class="wpbc_add_appointment__summary_status"><dt><?php esc_html_e( 'Current step', 'booking' ); ?></dt><dd data-wpbc-add-appointment-summary="step"><?php esc_html_e( 'Service', 'booking' ); ?></dd></div>
409 <div><dt><?php esc_html_e( 'Service', 'booking' ); ?></dt><dd data-wpbc-add-appointment-summary="service">&mdash;</dd></div>
410 <div><dt><?php esc_html_e( 'Provider', 'booking' ); ?></dt><dd data-wpbc-add-appointment-summary="provider">&mdash;</dd></div>
411 <div><dt><?php esc_html_e( 'Duration', 'booking' ); ?></dt><dd data-wpbc-add-appointment-summary="duration">&mdash;</dd></div>
412 <div><dt><?php esc_html_e( 'Buffers (before / after)', 'booking' ); ?></dt><dd data-wpbc-add-appointment-summary="buffers">&mdash;</dd></div>
413 <?php if ( wpbc_appointment_services_is_pricing_available() ) : ?>
414 <div><dt><?php esc_html_e( 'Service price', 'booking' ); ?></dt><dd data-wpbc-add-appointment-summary="price">&mdash;</dd></div>
415 <?php endif; ?>
416 <div><dt><?php esc_html_e( 'Date', 'booking' ); ?></dt><dd data-wpbc-add-appointment-summary="date">&mdash;</dd></div>
417 <div><dt><?php esc_html_e( 'Start time', 'booking' ); ?></dt><dd data-wpbc-add-appointment-summary="time">&mdash;</dd></div>
418 <div><dt><?php esc_html_e( 'Customer', 'booking' ); ?></dt><dd data-wpbc-add-appointment-summary="customer">&mdash;</dd></div>
419 <div><dt><?php esc_html_e( 'Booking Form', 'booking' ); ?></dt><dd data-wpbc-add-appointment-summary="form">&mdash;</dd></div>
420 <div>
421 <dt><?php esc_html_e( 'Email notifications', 'booking' ); ?></dt>
422 <dd>
423 <a href="#wpbc_add_appointment_booking_tools_group"
424 class="wpbc_add_appointment__summary_link"
425 data-wpbc-add-appointment-open-group="add-appointment-booking-tools"
426 data-wpbc-add-appointment-focus="#is_send_email_for_pending"
427 data-wpbc-add-appointment-summary="emails"
428 aria-label="<?php esc_attr_e( 'Change email notification setting', 'booking' ); ?>">&mdash;</a>
429 </dd>
430 </div>
431 </dl>
432 <?php do_action( 'wpbc_admin_add_appointment_summary_panel' ); ?>
433 <?php
434 }
435
436 /**
437 * Render contextual help without duplicating Booking Calendar settings.
438 *
439 * @return void
440 */
441 public function render_help_panel() {
442 WPBC_UI_Sidebar_Panels::render_inspector_header( __( 'Appointment Help', 'booking' ), __( 'This page creates a normal Booking with an attached Service snapshot.', 'booking' ) );
443 ?>
444 <div class="wpbc_bfb__inspector__body wpbc_bfb__inspector__body--content wpbc_add_appointment__help_body">
445 <div class="wpbc_add_appointment__hint"><span class="wpbc_icn_info_outline" aria-hidden="true"></span><p><?php esc_html_e( 'Availability belongs to the selected Provider booking resource. Service duration and buffers are validated before submission.', 'booking' ); ?></p></div>
446 <div class="wpbc_add_appointment__help_section">
447 <h4><?php esc_html_e( 'Appointment Flow', 'booking' ); ?></h4>
448 <ol class="wpbc_add_appointment__steps">
449 <li><span>1</span><?php esc_html_e( 'Choose a Service', 'booking' ); ?></li>
450 <li><span>2</span><?php esc_html_e( 'Choose a Provider', 'booking' ); ?></li>
451 <li><span>3</span><?php esc_html_e( 'Select date, time, and details', 'booking' ); ?></li>
452 </ol>
453 </div>
454 <div class="wpbc_add_appointment__help_section">
455 <h4><?php esc_html_e( 'When to use this page', 'booking' ); ?></h4>
456 <p><?php esc_html_e( 'Use Add Appointment for the guided Service-first workflow. Use Add Booking for unrestricted resource-first administration.', 'booking' ); ?></p>
457 </div>
458 <a class="button wpbc_add_appointment__help_action" href="<?php echo esc_url( wpbc_get_new_booking_url() ); ?>"><?php esc_html_e( 'Open Add Booking', 'booking' ); ?></a>
459 <?php do_action( 'wpbc_admin_add_appointment_help_panel' ); ?>
460 </div>
461 <?php
462 }
463
464 /**
465 * Render the existing AJAX Appointment component inside the admin canvas.
466 *
467 * @return void|false False when the current user cannot add bookings.
468 */
469 public function content() {
470 do_action( 'wpbc_hook_add_booking_page_header', 'add_appointment' );
471
472 if ( ! wpbc_is_mu_user_can_be_here( 'activated_user' ) || ! WPBC_Add_Booking_Component::current_user_can_add_booking() ) {
473 return false;
474 }
475
476 if ( function_exists( 'wpbc_js_for_bookings_page' ) ) {
477 wpbc_js_for_bookings_page();
478 }
479
480 $settings = wpbc_add_appointment_page_get_settings();
481 $config = array(
482 'cal_count' => $settings['calendar_months'],
483 'auto_select_provider' => $settings['auto_select_provider'],
484 'allow_past' => $settings['allow_past'],
485 );
486 $config = (array) apply_filters( 'wpbc_admin_add_appointment_config', $config, $settings );
487 wpbc_add_appointment_page_print_booking_context( $settings['allow_past'] );
488 ?>
489 <div class="wpbc_add_appointment_page wpdevelop" data-wpbc-add-appointment-page="1">
490 <div class="wpbc_add_appointment__canvas">
491 <?php echo wpbc_booking_appointment_shortcode( $config ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
492 </div>
493 </div>
494 <?php
495
496 do_action( 'wpbc_hook_add_booking_page_footer', 'add_appointment' );
497 }
498 }
499 add_action( 'wpbc_menu_created', array( new WPBC_Page_Add_Appointment(), '__construct' ) );
500