PluginProbe
Booking Calendar / 11.8.4
Booking Calendar v11.8.4
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 10.11 All 204 releases
booking / includes / booking_modes_v3 / booking_modes-api.php

booking_modes-api.php in Booking Calendar 11.8.4, at includes/booking_modes_v3/booking_modes-api.php

358 lines 11.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Public Booking Modes foundation API.
4 *
5 * @package Booking Calendar
6 * @since 11.8.0
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * Get all registered Booking Calendar administration modes.
15 *
16 * @return array Normalized mode definitions keyed by mode identifier.
17 */
18 function wpbc_booking_modes_get_registered_modes() {
19
20 return WPBC_Booking_Modes_V3_Compatibility_Registry::get_instance()->get_all();
21 }
22
23 /**
24 * Get one registered Booking Calendar administration mode.
25 *
26 * @param string $mode_id Mode identifier.
27 *
28 * @return array|null Mode definition, or null when unknown.
29 */
30 function wpbc_booking_modes_get_mode( $mode_id ) {
31
32 return WPBC_Booking_Modes_V3_Compatibility_Registry::get_instance()->get( $mode_id );
33 }
34
35 /**
36 * Get mode identifiers allowed for the current owner context.
37 *
38 * @return array Allowed mode identifiers.
39 */
40 function wpbc_booking_modes_get_allowed_mode_ids() {
41
42 return WPBC_Booking_Modes_V3_Compatibility_Registry::get_instance()->get_allowed_mode_ids();
43 }
44
45 /**
46 * Get all canonical administration page references.
47 *
48 * @return array Canonical page definitions keyed by stable identifier.
49 */
50 function wpbc_booking_modes_get_canonical_pages() {
51
52 return WPBC_Booking_Modes_V3_Page_Registry::get_instance()->get_all();
53 }
54
55 /**
56 * Get one canonical administration page reference.
57 *
58 * @param string $page_id Canonical page identifier.
59 *
60 * @return array|null Page definition, or null when unknown.
61 */
62 function wpbc_booking_modes_get_canonical_page( $page_id ) {
63
64 return WPBC_Booking_Modes_V3_Page_Registry::get_instance()->get( $page_id );
65 }
66
67 /**
68 * Get an existing canonical administration page URL.
69 *
70 * @param string $page_id Canonical page identifier.
71 *
72 * @return string Administration URL, or an empty string when unknown.
73 */
74 function wpbc_booking_modes_get_canonical_page_url( $page_id ) {
75
76 return WPBC_Booking_Modes_V3_Page_Registry::get_instance()->get_url( $page_id );
77 }
78
79 /**
80 * Get cached request and owner context.
81 *
82 * @return array Normalized context values.
83 */
84 function wpbc_booking_modes_get_context() {
85
86 return WPBC_Booking_Modes_V3_Context::get_instance()->get_context();
87 }
88
89 /**
90 * Get the owner-scoped selected administration mode.
91 *
92 * Missing or invalid configuration resolves to Classic without writing data.
93 *
94 * @param int $owner_user_id Optional owner user ID. Zero uses current context.
95 *
96 * @return string Allowed mode identifier.
97 */
98 function wpbc_booking_modes_get_selected_mode_id( $owner_user_id = 0 ) {
99
100 return WPBC_Booking_Modes_V3_Storage::get_instance()->get_selected_mode_id( $owner_user_id );
101 }
102
103 /**
104 * Save an explicit owner-scoped administration mode selection.
105 *
106 * External handlers must verify nonce and capability before calling this API.
107 *
108 * @param string $mode_id Requested registered mode identifier.
109 * @param int $owner_user_id Optional owner user ID. Zero uses context.
110 *
111 * @return bool|WP_Error True on success, otherwise an error.
112 */
113 function wpbc_booking_modes_set_selected_mode_id( $mode_id, $owner_user_id = 0 ) {
114
115 return WPBC_Booking_Modes_V3_Storage::get_instance()->set_selected_mode_id( $mode_id, $owner_user_id );
116 }
117
118 /**
119 * Check whether the shared navigation consumer boundary is activated.
120 *
121 * The released boundary loads unconditionally. Defining the dedicated constant
122 * as strict false provides an emergency presentation-only
123 * rollback without disabling the mode registry and stored preference.
124 *
125 * @return bool True when the internal navigation getter should use the resolver.
126 */
127 function wpbc_booking_modes_is_navigation_boundary_enabled() {
128
129 return ! defined( 'WPBC_ENABLE_BOOKING_MODES_NAVIGATION' ) || false !== WPBC_ENABLE_BOOKING_MODES_NAVIGATION;
130 }
131
132 /**
133 * Resolve the legacy administration navigation for mode presentation.
134 *
135 * The result is built once per request. Existing page controllers continue to
136 * use their original routes, capabilities, rendering, and save behavior.
137 *
138 * @param array $legacy_navigation Complete legacy page, tab, and subtab tree.
139 *
140 * @return array Cached presentation navigation tree.
141 */
142 function wpbc_booking_modes_resolve_navigation( $legacy_navigation ) {
143 if ( ! function_exists( 'wpbc_booking_modes_v3_compile_sidebar_navigation' ) ) {
144 return is_array( $legacy_navigation ) ? $legacy_navigation : array();
145 }
146
147 WPBC_Booking_Modes_V3_Source_Index::get_instance()->capture( $legacy_navigation );
148
149 return wpbc_booking_modes_v3_compile_sidebar_navigation( $legacy_navigation );
150 }
151
152 /**
153 * Get canonical page identifiers present in the resolved legacy tree.
154 *
155 * @return array Available canonical page identifiers, or an empty array before resolution.
156 */
157 function wpbc_booking_modes_get_available_page_ids() {
158 if ( ! function_exists( 'wpbc_booking_modes_v3_get_available_canonical_page_ids' ) ) {
159 return array();
160 }
161
162 return wpbc_booking_modes_v3_get_available_canonical_page_ids();
163 }
164
165 /**
166 * Resolve a request route to its stable canonical page identifier.
167 *
168 * @param string $page_tag Existing WordPress admin page slug.
169 * @param string $tab_tag Existing Booking Calendar tab slug.
170 * @param string $subtab_tag Existing Booking Calendar subtab slug.
171 *
172 * @return string Canonical page identifier, or an empty string when unknown.
173 */
174 function wpbc_booking_modes_get_canonical_page_id_for_route( $page_tag, $tab_tag = '', $subtab_tag = '' ) {
175
176 $page_tag = sanitize_key( (string) $page_tag );
177 $tab_tag = sanitize_key( (string) $tab_tag );
178 $subtab_tag = sanitize_key( (string) $subtab_tag );
179
180 foreach ( wpbc_booking_modes_get_canonical_pages() as $page_id => $canonical_page ) {
181 if ( $page_tag === $canonical_page['page'] && $tab_tag === $canonical_page['tab'] && $subtab_tag === $canonical_page['subtab'] ) {
182 return $page_id;
183 }
184 }
185
186 return '';
187 }
188
189 /**
190 * Resolve the stable identifier for the current Booking Calendar admin route.
191 *
192 * @return string Canonical page identifier, or an empty string when unknown.
193 */
194 function wpbc_booking_modes_get_current_canonical_page_id() {
195
196 $context = wpbc_booking_modes_get_context();
197
198 return wpbc_booking_modes_get_canonical_page_id_for_route( $context['page'], $context['tab'], $context['subtab'] );
199 }
200
201 /**
202 * Resolve a canonical page identifier from a validated same-site URL.
203 *
204 * This is used by the AJAX switch handler so redirect selection is based on
205 * the server-observed referer rather than a browser-submitted route value.
206 *
207 * @param string $admin_url Candidate Booking Calendar administration URL.
208 *
209 * @return string Canonical page identifier, or an empty string when invalid.
210 */
211 function wpbc_booking_modes_get_canonical_page_id_from_url( $admin_url ) {
212
213 $admin_url = is_scalar( $admin_url ) ? wp_validate_redirect( (string) $admin_url, '' ) : '';
214
215 if ( '' === $admin_url ) {
216 return '';
217 }
218
219 $query_string = wp_parse_url( $admin_url, PHP_URL_QUERY );
220 $query_args = array();
221
222 if ( ! is_string( $query_string ) ) {
223 return '';
224 }
225
226 wp_parse_str( $query_string, $query_args );
227
228 $page_tag = isset( $query_args['page'] ) && is_scalar( $query_args['page'] ) ? $query_args['page'] : '';
229 $tab_tag = isset( $query_args['tab'] ) && is_scalar( $query_args['tab'] ) ? $query_args['tab'] : '';
230 $subtab_tag = isset( $query_args['subtab'] ) && is_scalar( $query_args['subtab'] ) ? $query_args['subtab'] : '';
231
232 return wpbc_booking_modes_get_canonical_page_id_for_route( $page_tag, $tab_tag, $subtab_tag );
233 }
234
235 /**
236 * Get the capability required to switch administration presentation modes.
237 *
238 * The default mirrors the configured capability for the main Booking Calendar
239 * menu so every user who can reach that screen can retain a personal mode.
240 *
241 * @return string WordPress capability name.
242 */
243 function wpbc_booking_modes_get_switch_capability() {
244
245 $role_capabilities = array(
246 'administrator' => 'activate_plugins',
247 'editor' => 'publish_pages',
248 'author' => 'publish_posts',
249 'contributor' => 'edit_posts',
250 'subscriber' => 'read',
251 );
252 $configured_role_option = get_bk_option( 'booking_user_role_booking' );
253 $configured_role = is_scalar( $configured_role_option ) ? sanitize_key( (string) $configured_role_option ) : 'subscriber';
254 $capability = isset( $role_capabilities[ $configured_role ] ) ? $role_capabilities[ $configured_role ] : 'read';
255
256 /**
257 * Filter the capability required to switch Booking Calendar modes.
258 *
259 * @param string $capability WordPress capability name.
260 */
261 $capability = apply_filters( 'wpbc_booking_modes_switch_capability', $capability );
262
263 return is_scalar( $capability ) ? sanitize_key( (string) $capability ) : 'read';
264 }
265
266 /**
267 * Check whether the current active Booking Calendar user may switch modes.
268 *
269 * @return bool True for an active signed-in owner with menu access.
270 */
271 function wpbc_booking_modes_current_user_can_switch() {
272
273 $context = wpbc_booking_modes_get_context();
274
275 return $context['owner_user_id'] > 0
276 && current_user_can( wpbc_booking_modes_get_switch_capability() )
277 && (bool) apply_bk_filter( 'multiuser_is_current_user_active', true );
278 }
279
280 /**
281 * Validate a mode-switch request without writing the owner preference.
282 *
283 * @param string $mode_id Requested mode identifier.
284 * @param string $nonce Request nonce.
285 *
286 * @return true|WP_Error True when valid, otherwise a request error.
287 */
288 function wpbc_booking_modes_validate_switch_request( $mode_id, $nonce ) {
289
290 if ( ! wp_verify_nonce( $nonce, 'wpbc_booking_modes_switch_nonce' ) ) {
291 return new WP_Error( 'wpbc_booking_modes_invalid_nonce', __( 'The mode change request expired. Reload the page and try again.', 'booking' ) );
292 }
293
294 if ( ! wpbc_booking_modes_current_user_can_switch() ) {
295 return new WP_Error( 'wpbc_booking_modes_forbidden', __( 'You are not allowed to change the Booking Calendar administration mode.', 'booking' ) );
296 }
297
298 $mode_id = sanitize_key( (string) $mode_id );
299
300 if ( ! in_array( $mode_id, wpbc_booking_modes_get_allowed_mode_ids(), true ) ) {
301 return new WP_Error( 'wpbc_booking_modes_invalid_mode', __( 'The selected Booking Calendar administration mode is not available.', 'booking' ) );
302 }
303
304 return true;
305 }
306
307 /**
308 * Build the safe server-selected redirect after a mode switch.
309 *
310 * The current route is retained only when the target mode presents it. A route
311 * hidden by that mode falls back to its registered default, then to Bookings.
312 *
313 * @param string $mode_id Target mode identifier.
314 * @param string $current_page_id Current canonical page identifier.
315 *
316 * @return string Valid same-site administration URL.
317 */
318 function wpbc_booking_modes_get_switch_redirect_url( $mode_id, $current_page_id = '' ) {
319
320 $mode = wpbc_booking_modes_get_mode( $mode_id );
321 $current_page_id = sanitize_key( (string) $current_page_id );
322 $redirect_page_id = '';
323
324 if ( is_array( $mode ) && '' !== $current_page_id ) {
325 $current_placement = isset( $mode['pages'][ $current_page_id ] ) && is_array( $mode['pages'][ $current_page_id ] )
326 ? $mode['pages'][ $current_page_id ]
327 : null;
328
329 if (
330 ( null === $current_placement && ! empty( $mode['preserve_unmapped_pages'] ) )
331 || ( null !== $current_placement && ( ! isset( $current_placement['visible'] ) || false !== (bool) $current_placement['visible'] ) )
332 ) {
333 $redirect_page_id = $current_page_id;
334 }
335 }
336
337 if ( '' === $redirect_page_id && is_array( $mode ) ) {
338 $redirect_page_id = $mode['default_page'];
339 }
340
341 $redirect_url = wpbc_booking_modes_get_canonical_page_url( $redirect_page_id );
342
343 if ( '' === $redirect_url ) {
344 $redirect_url = admin_url( 'admin.php?page=wpbc' );
345 }
346
347 /**
348 * Filter the server-selected URL used after a successful mode switch.
349 *
350 * @param string $redirect_url Proposed administration URL.
351 * @param string $mode_id Target mode identifier.
352 * @param string $current_page_id Current canonical page identifier.
353 */
354 $redirect_url = apply_filters( 'wpbc_booking_modes_switch_redirect_url', $redirect_url, $mode_id, $current_page_id );
355
356 return wp_validate_redirect( $redirect_url, admin_url( 'admin.php?page=wpbc' ) );
357 }
358