PluginProbe
Booking Calendar / 11.7
Booking Calendar v11.7
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-catalog-booking-resources / booking-resources-catalog-page.php

booking-resources-catalog-page.php in Booking Calendar 11.7, at includes/page-catalog-booking-resources/booking-resources-catalog-page.php

628 lines 26.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Template-driven Booking Resources catalog page shell.
4 *
5 * @package Booking Calendar
6 * @since 11.6.0
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * Determine whether the current request targets the independent catalog page.
15 *
16 * @return bool True only for the gated catalog administration route.
17 */
18 function wpbc_catalog_booking_resources_is_page() {
19 return 'new' === wpbc_booking_resources_catalog_get_request_renderer();
20 }
21
22 /**
23 * Map the established Booking Calendar minimum role to a capability.
24 *
25 * @param string $role_option Booking Calendar option containing a minimum role.
26 *
27 * @return string WordPress capability name.
28 */
29 function wpbc_catalog_booking_resources_get_role_capability( $role_option ) {
30 $minimum_role = get_bk_option( sanitize_key( $role_option ) );
31 $capabilities = array(
32 'administrator' => 'activate_plugins',
33 'editor' => 'publish_pages',
34 'author' => 'publish_posts',
35 'contributor' => 'edit_posts',
36 'subscriber' => 'read',
37 );
38
39 return isset( $capabilities[ $minimum_role ] ) ? $capabilities[ $minimum_role ] : 'manage_options';
40 }
41
42 /**
43 * Return the capability required by the canonical Resources role setting.
44 *
45 * Free installations use the Settings role because they do not expose the
46 * multi-resource role option. Paid editions use the Resources role so the
47 * parallel page remains aligned with the established administration boundary.
48 *
49 * @return string WordPress capability name.
50 */
51 function wpbc_catalog_booking_resources_get_manage_capability() {
52 $role_option = class_exists( 'wpdev_bk_personal' ) ? 'booking_user_role_resources' : 'booking_user_role_settings';
53 $capability = wpbc_catalog_booking_resources_get_role_capability( $role_option );
54
55 /**
56 * Filter the capability required to view the independent Resources catalog.
57 *
58 * @param string $capability WordPress capability name.
59 */
60 return (string) apply_filters( 'wpbc_catalog_booking_resources_manage_capability', $capability );
61 }
62
63 /**
64 * Return allow-listed shared request overrides from the initial page URL.
65 *
66 * These values remain untrusted and are normalized by WPBC_UI_Catalog_Request.
67 * Subsequent browser requests do not reuse this URL layer.
68 *
69 * @return array<string,mixed> Untrusted initial shared request overrides.
70 */
71 function wpbc_catalog_booking_resources_get_initial_url_overrides() {
72 $url_overrides = array();
73 $url_parameters = array(
74 'page_number' => array( 'page_number', 'catalog_page' ),
75 'items_per_page' => array( 'items_per_page', 'catalog_per_page' ),
76 'sort_by' => array( 'sort_by', 'catalog_sort' ),
77 'sort_order' => array( 'sort_order', 'catalog_order' ),
78 'search' => array( 'search', 'catalog_search' ),
79 'visible_columns' => array( 'visible_columns', 'catalog_columns' ),
80 'column_order' => array( 'column_order', 'catalog_column_order' ),
81 'template_pack' => array( 'template_pack' ),
82 );
83
84 foreach ( $url_parameters as $request_key => $parameter_names ) {
85 foreach ( $parameter_names as $parameter_name ) {
86 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only initial catalog display overrides.
87 if ( ! array_key_exists( $parameter_name, $_GET ) ) {
88 continue;
89 }
90 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Validated by the shared request normalizer.
91 $request_value = wp_unslash( $_GET[ $parameter_name ] );
92 if ( in_array( $request_key, array( 'visible_columns', 'column_order' ), true ) && is_scalar( $request_value ) ) {
93 $request_value = '' === trim( (string) $request_value ) ? array() : explode( ',', (string) $request_value );
94 }
95 $url_overrides[ $request_key ] = $request_value;
96 break;
97 }
98 }
99
100 return $url_overrides;
101 }
102
103 /**
104 * Build the normalized browser configuration for the initial catalog mount.
105 *
106 * Phase 4 localizes the read endpoint and enables shared automatic loading.
107 * The browser renders the returned DTOs through registered Resource templates.
108 *
109 * @return array<string,mixed> Browser-safe catalog configuration.
110 */
111 function wpbc_catalog_booking_resources_get_client_config() {
112 $catalog_id = 'catalog_booking_resources';
113 $configuration = WPBC_UI_Catalog_Registry::get_instance()->get_configuration( $catalog_id );
114
115 if ( empty( $configuration ) ) {
116 return array();
117 }
118
119 $stored_preferences = WPBC_UI_Catalog_Preferences::load( $catalog_id );
120 $request = WPBC_UI_Catalog_Request::create(
121 $configuration,
122 array( 'request_id' => 1 ),
123 $stored_preferences,
124 wpbc_catalog_booking_resources_get_initial_url_overrides(),
125 true
126 );
127 $stored_resource_request = WPBC_Catalog_Booking_Resources_Request::create(
128 array_intersect_key( $stored_preferences, array( 'resource_type' => true, 'hierarchy_state' => true ) )
129 );
130 if ( is_wp_error( $stored_resource_request ) ) {
131 $stored_resource_request = WPBC_Catalog_Booking_Resources_Request::create();
132 }
133 $resource_request = $stored_resource_request;
134 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only initial filter override validated below.
135 if ( ! empty( $configuration['features']['resource_type_filter'] ) && isset( $_GET['resource_type'] ) ) {
136 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Validated by the Resource request object.
137 $resource_request = WPBC_Catalog_Booking_Resources_Request::create(
138 array(
139 'resource_type' => wp_unslash( $_GET['resource_type'] ),
140 'hierarchy_state' => $stored_resource_request->get( 'hierarchy_state', array() ),
141 )
142 );
143 }
144 $auto_load = ! is_wp_error( $request ) && ! is_wp_error( $resource_request );
145
146 if ( is_wp_error( $request ) || is_wp_error( $resource_request ) ) {
147 $fallback_request = WPBC_UI_Catalog_Request::create( $configuration, array( 'request_id' => 1 ) );
148 if ( is_wp_error( $fallback_request ) ) {
149 return array();
150 }
151
152 $initial_request = $fallback_request->to_array();
153 $initial_request['resource_type'] = 'all';
154 $initial_request['hierarchy_state'] = WPBC_Catalog_Booking_Resources_Request::create()->get_hierarchy_state_json();
155 $initial_error = is_wp_error( $request ) ? $request : $resource_request;
156 $initial_response = WPBC_UI_Catalog_Response::from_wp_error( $catalog_id, 1, $initial_error );
157 } else {
158 $initial_request = $request->to_array();
159 $initial_request['resource_type'] = $resource_request->get( 'resource_type', 'all' );
160 $initial_request['hierarchy_state'] = $resource_request->get_hierarchy_state_json();
161 $empty_response = WPBC_UI_Catalog_Response::create_empty( $catalog_id, $request );
162 if ( is_wp_error( $empty_response ) ) {
163 $initial_response = WPBC_UI_Catalog_Response::from_wp_error( $catalog_id, 1, $empty_response );
164 } else {
165 $initial_response = $empty_response->to_array();
166 }
167 }
168
169 $client_configuration = WPBC_UI_Catalog::get_client_configuration(
170 $catalog_id,
171 'wpbc_catalog_booking_resources',
172 $initial_request,
173 $initial_response
174 );
175 $client_configuration['ajax_url'] = admin_url( 'admin-ajax.php' );
176 $client_configuration['auto_load'] = $auto_load;
177 $client_configuration['is_demo'] = function_exists( 'wpbc_is_this_demo' ) && wpbc_is_this_demo();
178 $client_configuration['nonce'] = wp_create_nonce( $configuration['nonce_name'] );
179 $client_configuration['details_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCE_DETAILS';
180 $client_configuration['inspector_create_schema_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCE_CREATE_SCHEMA';
181 $client_configuration['inspector_edit_schema_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCE_EDIT_SCHEMA';
182 $client_configuration['inspector_create_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCE_CREATE';
183 $client_configuration['inspector_update_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCE_UPDATE';
184 $client_configuration['bulk_schema_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCES_BULK_SCHEMA';
185 $client_configuration['bulk_preview_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCES_BULK_PREVIEW';
186 $client_configuration['bulk_apply_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCES_BULK_APPLY';
187 $client_configuration['inline_schema_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCES_INLINE_SCHEMA';
188 $client_configuration['inline_preview_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCES_INLINE_PREVIEW';
189 $client_configuration['inline_apply_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCES_INLINE_APPLY';
190 $client_configuration['delete_preview_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCES_DELETE_PREVIEW';
191 $client_configuration['delete_apply_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCES_DELETE_APPLY';
192 $client_configuration['capacity_context_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCE_CAPACITY_CONTEXT';
193 $client_configuration['capacity_preview_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCE_CAPACITY_PREVIEW';
194 $client_configuration['capacity_apply_action'] = 'WPBC_AJX_CATALOG_BOOKING_RESOURCE_CAPACITY_APPLY';
195 $default_request = WPBC_UI_Catalog_Request::create( $configuration );
196 $client_configuration['default_request'] = is_wp_error( $default_request ) ? array() : $default_request->to_array();
197 $client_configuration['default_request']['resource_type'] = 'all';
198 $client_configuration['default_request']['hierarchy_state'] = WPBC_Catalog_Booking_Resources_Request::create()->get_hierarchy_state_json();
199 $client_configuration['url_parameters'] = array(
200 'page_number' => 'catalog_page',
201 'items_per_page' => 'catalog_per_page',
202 'sort_by' => 'catalog_sort',
203 'sort_order' => 'catalog_order',
204 'search' => 'catalog_search',
205 'visible_columns' => 'catalog_columns',
206 'column_order' => 'catalog_column_order',
207 'template_pack' => 'template_pack',
208 );
209 if ( ! empty( $configuration['features']['resource_type_filter'] ) ) {
210 $client_configuration['url_parameters']['resource_type'] = 'resource_type';
211 }
212
213 return $client_configuration;
214 }
215
216 /**
217 * Enqueue catalog styles only on the independent Resources page.
218 *
219 * @param string $where_to_load Booking Calendar asset context.
220 *
221 * @return void
222 */
223 function wpbc_catalog_booking_resources_enqueue_css( $where_to_load ) {
224 if ( ! in_array( $where_to_load, array( 'admin', 'both' ), true ) || ! wpbc_catalog_booking_resources_is_page() ) {
225 return;
226 }
227
228 $asset_path = __DIR__ . '/_out/booking_resources_catalog.css';
229 $asset_modified = is_readable( $asset_path ) ? filemtime( $asset_path ) : false;
230 $asset_version = false !== $asset_modified ? WP_BK_VERSION_NUM . '.' . $asset_modified : WP_BK_VERSION_NUM;
231
232 WPBC_UI_Catalog::enqueue_styles();
233 wp_enqueue_style(
234 'wpbc-catalog-booking-resources',
235 trailingslashit( plugins_url( '', __FILE__ ) ) . '_out/booking_resources_catalog.css',
236 array( 'wpbc-ui-catalog' ),
237 $asset_version
238 );
239 }
240 add_action( 'wpbc_enqueue_css_files', 'wpbc_catalog_booking_resources_enqueue_css', 68 );
241
242 /**
243 * Enqueue and configure catalog scripts only on the independent Resources page.
244 *
245 * @param string $where_to_load Booking Calendar asset context.
246 *
247 * @return void
248 */
249 function wpbc_catalog_booking_resources_enqueue_js( $where_to_load ) {
250 if ( ! in_array( $where_to_load, array( 'admin', 'both' ), true ) || ! wpbc_catalog_booking_resources_is_page() ) {
251 return;
252 }
253
254 $asset_path = __DIR__ . '/_out/booking_resources_catalog.js';
255 $asset_modified = is_readable( $asset_path ) ? filemtime( $asset_path ) : false;
256 $asset_version = false !== $asset_modified ? WP_BK_VERSION_NUM . '.' . $asset_modified : WP_BK_VERSION_NUM;
257
258 WPBC_UI_Catalog::enqueue_scripts();
259 if ( function_exists( 'wpbc_load_js__required_for_media_upload' ) ) {
260 wpbc_load_js__required_for_media_upload();
261 }
262 if ( function_exists( 'wpbc_load_js__required_for_modals' ) ) {
263 wpbc_load_js__required_for_modals();
264 }
265 wp_enqueue_script(
266 'wpbc-catalog-booking-resources',
267 trailingslashit( plugins_url( '', __FILE__ ) ) . '_out/booking_resources_catalog.js',
268 array( 'wpbc-ui-catalog', 'wpbc-ui-catalog-hierarchy', 'wpbc-ui-catalog-selection', 'wpbc-ui-catalog-actions', 'wpbc-admin-support' ),
269 $asset_version,
270 array( 'in_footer' => WPBC_JS_IN_FOOTER )
271 );
272 wp_localize_script(
273 'wpbc-catalog-booking-resources',
274 'wpbc_catalog_booking_resources_config',
275 wpbc_catalog_booking_resources_get_client_config()
276 );
277 }
278 add_action( 'wpbc_enqueue_js_files', 'wpbc_catalog_booking_resources_enqueue_js', 68 );
279
280 /**
281 * Print registered WP templates only for the independent catalog page.
282 *
283 * Templates are static presentation files. They perform no authorization,
284 * queries, mutations, or domain decisions.
285 *
286 * @return void
287 */
288 function wpbc_catalog_booking_resources_print_templates() {
289 static $templates_printed = false;
290
291 if ( $templates_printed || ! wpbc_catalog_booking_resources_is_page() ) {
292 return;
293 }
294
295 $templates_printed = true;
296 WPBC_UI_Catalog::print_templates( 'catalog_booking_resources' );
297 }
298 add_action( 'admin_footer', 'wpbc_catalog_booking_resources_print_templates', 40 );
299
300 /**
301 * Render the shared Free-edition Booking Resource upgrade button.
302 *
303 * Both the top toolbar and catalog footer open the same informational modal.
304 * The toolbar keeps its compact label on one line, while the footer preserves
305 * the established superscript Pro marker used by in-page upgrade controls.
306 *
307 * @param bool $use_superscript Whether to render the Pro marker in a sup element.
308 *
309 * @return void
310 */
311 function wpbc_catalog_booking_resources_render_upgrade_button( $use_superscript = false ) {
312 ?>
313 <button
314 type="button"
315 class="button button-primary tooltip_bottom wpbc_catalog_booking_resources__upgrade_button"
316 data-wpbc-catalog-booking-resource-upgrade
317 data-wpbc-catalog-booking-resource-upgrade-url="<?php echo esc_url( 'https://wpbookingcalendar.com/features/' ); ?>"
318 aria-haspopup="dialog"
319 aria-controls="wpbc_catalog_booking_resources__upgrade_modal"
320 data-original-title="<?php esc_attr_e( 'Adding more Booking Resources is available in paid versions.', 'booking' ); ?>"
321 title="<?php esc_attr_e( 'Adding more Booking Resources is available in paid versions.', 'booking' ); ?>"
322 >
323 <span class="wpbc-bi-plus-lg" aria-hidden="true"></span>
324 <?php if ( $use_superscript ) : ?>
325 <?php esc_html_e( 'Add Booking Resource', 'booking' ); ?>
326 <sup><?php esc_html_e( '(Pro)', 'booking' ); ?></sup>
327 <?php else : ?>
328 <?php esc_html_e( 'Add Booking Resource (Pro)', 'booking' ); ?>
329 <?php endif; ?>
330 </button>
331 <?php
332 }
333
334 /**
335 * Render the old-compatible Add Resource control in the native top toolbar.
336 *
337 * @param string $page_tag Current Booking Calendar page tag.
338 * @param string $active_page_tab Current active tab.
339 * @param string $active_page_subtab Current active subtab.
340 *
341 * @return void
342 */
343 function wpbc_catalog_booking_resources_render_top_toolbar( $page_tag, $active_page_tab, $active_page_subtab ) {
344 unset( $page_tag, $active_page_tab, $active_page_subtab );
345
346 if ( ! wpbc_catalog_booking_resources_is_page() || ! current_user_can( wpbc_catalog_booking_resources_get_manage_capability() ) ) {
347 return;
348 }
349 $maximum_quantity = ( new WPBC_Catalog_Booking_Resource_Inspector_Schema() )->get_maximum_quantity();
350 ?>
351 <div class="wpbc_ui_el__buttons_group wpbc_catalog_booking_resources__top_toolbar">
352 <?php if ( class_exists( 'wpdev_bk_personal' ) && 0 < $maximum_quantity ) : ?>
353 <button type="button" class="button button-primary" data-wpbc-catalog-booking-resource-create data-wpbc-right-sidebar-keep-open="1">
354 <span class="wpbc-bi-plus-lg" aria-hidden="true"></span>
355 <?php esc_html_e( 'Add Booking Resource', 'booking' ); ?>
356 </button>
357 <?php elseif ( class_exists( 'wpdev_bk_personal' ) ) : ?>
358 <span class="wpbc_catalog_booking_resources__free_limit_top"><span class="wpbc-bi-info-circle" aria-hidden="true"></span><?php esc_html_e( 'The Booking Resource limit for this account has been reached.', 'booking' ); ?></span>
359 <?php else : ?>
360 <?php wpbc_catalog_booking_resources_render_upgrade_button(); ?>
361 <?php endif; ?>
362 </div>
363 <?php
364 }
365 add_action( 'wpbc_ui_el__top_nav__content_end', 'wpbc_catalog_booking_resources_render_top_toolbar', 20, 3 );
366
367 /**
368 * Render the Free-edition explanation shown by the Pro-only add control.
369 *
370 * The modal is informational only. It never calls a mutation endpoint in the
371 * Free edition and keeps the existing single default Resource available.
372 *
373 * @return void
374 */
375 function wpbc_catalog_booking_resources_render_free_upgrade_modal() {
376 if ( class_exists( 'wpdev_bk_personal' ) ) {
377 return;
378 }
379 ?>
380 <div class="wpdevelop">
381 <div
382 id="wpbc_catalog_booking_resources__upgrade_modal"
383 class="modal wpbc_popup_modal wpbc_catalog_booking_resources__upgrade_modal"
384 tabindex="-1"
385 role="dialog"
386 aria-hidden="true"
387 aria-labelledby="wpbc_catalog_booking_resources__upgrade_modal_title"
388 aria-describedby="wpbc_catalog_booking_resources__upgrade_modal_description"
389 >
390 <div class="modal-dialog">
391 <div class="modal-content">
392 <div class="modal-header">
393 <button type="button" class="close" data-dismiss="modal" aria-label="<?php esc_attr_e( 'Close', 'booking' ); ?>"><span aria-hidden="true">&times;</span></button>
394 <h4 id="wpbc_catalog_booking_resources__upgrade_modal_title" class="modal-title"><?php esc_html_e( 'Add more Booking Resources with Pro', 'booking' ); ?></h4>
395 </div>
396 <div class="modal-body">
397 <p id="wpbc_catalog_booking_resources__upgrade_modal_description"><?php esc_html_e( 'Creating additional Booking Resources is available in paid versions of Booking Calendar. Each Resource can have its own calendar and availability.', 'booking' ); ?></p>
398 <p><?php esc_html_e( 'Your default Resource remains ready to customize in the Free version.', 'booking' ); ?></p>
399 </div>
400 <div class="modal-footer">
401 <button type="button" class="button button-secondary" data-dismiss="modal"><?php esc_html_e( 'Close', 'booking' ); ?></button>
402 <a class="button button-primary" href="<?php echo esc_url( 'https://wpbookingcalendar.com/features/' ); ?>" target="_blank" rel="noopener noreferrer">
403 <?php esc_html_e( 'Compare Pro versions', 'booking' ); ?>
404 <span class="screen-reader-text"> <?php esc_html_e( '(opens in a new tab)', 'booking' ); ?></span>
405 </a>
406 </div>
407 </div>
408 </div>
409 </div>
410 </div>
411 <?php
412 }
413
414 /**
415 * Render the reusable informational dialog for catalog warnings and messages.
416 *
417 * The browser runtime supplies escaped text through textContent before opening
418 * the established Booking Calendar modal. Keeping one dialog in the page avoids
419 * browser alerts while preserving a safe fallback when modal assets fail.
420 *
421 * @return void
422 */
423 function wpbc_catalog_booking_resources_render_message_modal() {
424 ?>
425 <div class="wpdevelop">
426 <div
427 id="wpbc_catalog_booking_resources__message_modal"
428 class="modal wpbc_popup_modal wpbc_catalog_booking_resources__upgrade_modal wpbc_catalog_booking_resources__message_modal"
429 tabindex="-1"
430 role="dialog"
431 aria-hidden="true"
432 aria-labelledby="wpbc_catalog_booking_resources__message_modal_title"
433 aria-describedby="wpbc_catalog_booking_resources__message_modal_description"
434 >
435 <div class="modal-dialog">
436 <div class="modal-content">
437 <div class="modal-header">
438 <button type="button" class="close" data-dismiss="modal" aria-label="<?php esc_attr_e( 'Close', 'booking' ); ?>"><span aria-hidden="true">&times;</span></button>
439 <h4 id="wpbc_catalog_booking_resources__message_modal_title" class="modal-title" data-wpbc-default-title="<?php esc_attr_e( 'Booking Resources', 'booking' ); ?>"><?php esc_html_e( 'Booking Resources', 'booking' ); ?></h4>
440 </div>
441 <div class="modal-body">
442 <p id="wpbc_catalog_booking_resources__message_modal_description"></p>
443 </div>
444 <div class="modal-footer">
445 <button type="button" class="button button-primary" data-dismiss="modal"><?php esc_html_e( 'Close', 'booking' ); ?></button>
446 </div>
447 </div>
448 </div>
449 </div>
450 </div>
451 <?php
452 }
453
454 /**
455 * Render sticky inspector actions in the native right-sidebar footer.
456 *
457 * @param array $active_page Current page identifiers.
458 *
459 * @return void
460 */
461 function wpbc_catalog_booking_resources_render_right_sidebar_footer( $active_page ) {
462 if (
463 empty( $active_page['active_page'] )
464 || 'wpbc-resources' !== $active_page['active_page']
465 || ! wpbc_catalog_booking_resources_is_page()
466 || ! current_user_can( wpbc_catalog_booking_resources_get_manage_capability() )
467 ) {
468 return;
469 }
470 ?>
471 <div class="wpbc_ui_el__vert_right_bar__footer_section wpbc_catalog_booking_resources__right_sidebar_footer" data-wpbc-ui-catalog-inspector-footer hidden>
472 <div class="wpbc_catalog_booking_resources__footer_actions wpbc_ui_el__buttons_group">
473 <button type="button" class="button" data-wpbc-ui-catalog-inspector-cancel><?php esc_html_e( 'Cancel', 'booking' ); ?></button>
474 <button type="submit" class="button button-primary" form="wpbc_catalog_booking_resource_inspector_form" data-wpbc-ui-catalog-inspector-save disabled><?php esc_html_e( 'Save changes', 'booking' ); ?></button>
475 </div>
476 </div>
477 <?php
478 }
479 add_action( 'wpbc_ui__right_vertical_sidebar_footer', 'wpbc_catalog_booking_resources_render_right_sidebar_footer', 10, 1 );
480
481 /**
482 * Register the independent catalog shell with the shared admin page controller.
483 */
484 class WPBC_Page_Catalog_Booking_Resources extends WPBC_Page_Structure {
485
486 /**
487 * Return the catalog page slug for authorized users.
488 *
489 * @return string Page slug or a non-matching value when unauthorized.
490 */
491 public function in_page() {
492 if ( ! wpbc_booking_resources_catalog_should_use_new_renderer() || ! current_user_can( wpbc_catalog_booking_resources_get_manage_capability() ) ) {
493 return 'wpbc-catalog-booking-resources-unauthorized';
494 }
495
496 return 'wpbc-resources';
497 }
498
499 /**
500 * Define the initial template-driven catalog page tab.
501 *
502 * @return array<string,array<string,mixed>> Page tab definition.
503 */
504 public function tabs() {
505 return array(
506 'resources' => array(
507 'is_show_top_path' => true,
508 'is_show_top_navigation' => false,
509 'left_navigation__default_view_mode' => 'compact',
510 'right_vertical_sidebar__is_show' => true,
511 'right_vertical_sidebar__default_view_mode' => 'none',
512 'right_vertical_sidebar__content_click_collapse_mode' => 'none',
513 'right_vertical_sidebar_compact__is_show' => true,
514 'top_path' => array( 'root_title' => false ),
515 'top_path_title' => __( 'Booking Resources', 'booking' ),
516 'title' => __( 'Booking Resources', 'booking' ),
517 'page_title' => __( 'Booking Resources', 'booking' ),
518 'hint' => __( 'A new, unified listing for the properties, people, places, and assets customers can book.', 'booking' ),
519 'font_icon' => 'wpbc-bi-collection',
520 'default' => true,
521 'disabled' => false,
522 'hided' => false,
523 'subtabs' => array(),
524 ),
525 );
526 }
527
528 /**
529 * Render the compact Settings tab for the native right sidebar.
530 *
531 * @return void
532 */
533 public function right_sidebar_compact_content() {
534 WPBC_UI_Sidebar_Panels::render_rightbar_tabs(
535 array(
536 array(
537 'id' => 'wpbc_tab_catalog_booking_resources_selection',
538 'panel_id' => 'wpbc_catalog_booking_resources__inspector_selection',
539 'title' => __( 'Settings', 'booking' ),
540 'icon' => 'wpbc_icn_tune',
541 'selected' => true,
542 ),
543 ),
544 array(
545 'aria_label' => __( 'Booking resource panels', 'booking' ),
546 'context' => 'catalog_booking_resources',
547 'class' => 'wpbc_catalog_booking_resources__rightbar_tabs',
548 )
549 );
550 }
551
552 /**
553 * Render the template target inside the native old-compatible palette.
554 *
555 * @return void
556 */
557 public function right_sidebar_content() {
558 ?>
559 <div class="wpbc_bfb__panel--library wpbc_rightbar_palette wpbc_catalog_booking_resources__rightbar">
560 <?php
561 WPBC_UI_Sidebar_Panels::render_panel(
562 array(
563 'id' => 'wpbc_catalog_booking_resources__inspector_selection',
564 'labelledby' => 'wpbc_tab_catalog_booking_resources_selection',
565 'class' => 'wpbc_catalog_booking_resources__inspector_panel',
566 ),
567 static function () {
568 ?><div data-wpbc-catalog-booking-resources-inspector-host></div><?php
569 }
570 );
571 ?>
572 </div>
573 <?php
574 }
575
576 /**
577 * Render the Phase 4 catalog mount without querying Booking Resource data in PHP.
578 *
579 * @return void|false False when the current user is unauthorized.
580 */
581 public function content() {
582 if ( 'new' !== wpbc_booking_resources_catalog_get_request_renderer() || ! current_user_can( wpbc_catalog_booking_resources_get_manage_capability() ) ) {
583 return false;
584 }
585 ?>
586 <div class="wpbc_catalog_booking_resources_page">
587 <div id="wpbc_catalog_booking_resources" class="wpbc_catalog_booking_resources__mount" data-wpbc-catalog-mount="catalog_booking_resources" aria-live="polite">
588 <div class="wpbc_spins_loading_container wpbc_ui_catalog__loading" role="status">
589 <div class="wpbc_booking_form_spin_loader" aria-hidden="true">
590 <div class="wpbc_spins_loader_wrapper">
591 <div class="wpbc_one_spin_loader_mini2"></div>
592 </div>
593 </div>
594 <span><?php esc_html_e( 'Loading', 'booking' ); ?>...</span>
595 </div>
596 </div>
597 <noscript>
598 <div class="notice notice-error inline">
599 <p><?php esc_html_e( 'JavaScript is required to display the Booking Resources catalog.', 'booking' ); ?></p>
600 </div>
601 </noscript>
602 </div>
603 <?php if ( ! class_exists( 'wpdev_bk_personal' ) ) : ?>
604 <div class="wpbc_catalog_booking_resources__footer_upgrade">
605 <?php wpbc_catalog_booking_resources_render_upgrade_button( true ); ?>
606 </div>
607 <?php endif; ?>
608 <div class="wpbc_page_publish_notice_section wpbc_catalog_booking_resources__footer_notice">
609 <?php
610 // Render only the provider guidance formerly attached to the broad legacy Resources hook.
611 if ( function_exists( 'wpbc_appointment_services_render_provider_tools' ) ) {
612 wpbc_appointment_services_render_provider_tools( 'resources' );
613 }
614 ?>
615 </div>
616 <?php
617 wpbc_catalog_booking_resources_render_free_upgrade_modal();
618 wpbc_catalog_booking_resources_render_message_modal();
619 if ( class_exists( 'WPBC_Booking_Form_Publish_Modal' ) ) {
620 WPBC_Booking_Form_Publish_Modal::render();
621 }
622 }
623 }
624
625 if ( wpbc_booking_resources_catalog_should_use_new_renderer() ) {
626 add_action( 'wpbc_menu_created', array( new WPBC_Page_Catalog_Booking_Resources(), '__construct' ) );
627 }
628