PluginProbe
Booking Calendar / 11.9
Booking Calendar v11.9
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
← All changes | includes/ui_settings/parts/ui__nav_top.php +204 -27 11.6 → 11.9 View file →
@@ -1,4 +1,4 @@
1 1 <?php
2 2 /**
3 3 * Admin Panel UI - Parts
4 4 *
@@ -68,9 +68,51 @@
68 68 echo '</div>';
69 69 }
70 70
71 71
72 +/**
73 + * Order validated starter pages for the Booking Calendar top dropdown.
74 + *
75 + * The publishing module remains responsible for discovering valid pages. This
76 + * helper controls presentation only and appends unknown future page purposes in
77 + * their original order so new integrations are not hidden.
78 + *
79 + * @param array $wpbc_starter_pages Validated starter pages keyed by purpose.
80 + *
81 + * @return array Starter pages in top-dropdown display order.
82 + */
83 +function wpbc_ui__top_nav__order_starter_pages( $wpbc_starter_pages ) {
72 84
85 + if ( empty( $wpbc_starter_pages ) || ! is_array( $wpbc_starter_pages ) ) {
86 + return array();
87 + }
88 +
89 + $preferred_page_order = array(
90 + 'full_day_booking',
91 + 'appointment_booking',
92 + 'time_slots_booking',
93 + 'resource_selector_booking',
94 + 'contact_form',
95 + );
96 + $ordered_starter_pages = array();
97 +
98 + foreach ( $preferred_page_order as $page_key ) {
99 + if ( array_key_exists( $page_key, $wpbc_starter_pages ) ) {
100 + $ordered_starter_pages[ $page_key ] = $wpbc_starter_pages[ $page_key ];
101 + }
102 + }
103 +
104 + foreach ( $wpbc_starter_pages as $page_key => $wpbc_starter_page ) {
105 + if ( ! array_key_exists( $page_key, $ordered_starter_pages ) ) {
106 + $ordered_starter_pages[ $page_key ] = $wpbc_starter_page;
107 + }
108 + }
109 +
110 + return $ordered_starter_pages;
111 +}
112 +
113 +
114 +
73 115 /**
74 116 * Show element - "WPBC - Main Dropdown"
75 117 *
76 118 * @return void
@@ -81,17 +123,11 @@
81 123 $svg_icon_style = 'margin:5px 5px 0 0;'; // 'background-position: 0 0;background-size: ' . $svg_size . ' ' . $svg_size . ';width: ' . $svg_size . ';height: ' . $svg_size . ';'; //.
82 124 $svg_icon = wpbc_get_svg_logo_for_background( '#555', '#e5e5e5', '1.0' );
83 125
84 126 $wpbc_starter_pages = function_exists( 'wpbc_get_published_activation_booking_pages' ) ? wpbc_get_published_activation_booking_pages() : array();
127 + $wpbc_starter_pages = wpbc_ui__top_nav__order_starter_pages( $wpbc_starter_pages );
85 128 $wp_post_booking_absolute = false;
86 129
87 - if (
88 - empty( $wpbc_starter_pages ) &&
89 - function_exists( 'wpbc_stp_wiz__is_exist_published_page_with_booking_form' )
90 - ) {
91 - $wp_post_booking_absolute = wpbc_stp_wiz__is_exist_published_page_with_booking_form();
92 - }
93 -
94 130 $el_arr = array(
95 131 // 'title' => 'Booking Calendar',
96 132 // 'font_icon' => 'wpbc-bi-calendar2-range',
97 133 'title_html' => '<span class="nav-tab-text" style="margin: -3px 0 0 5px;font-size: 16px;padding: 0;"><span style="position: absolute;font-size: 7px;margin-top: 13px;margin-left: 1px;">WP</span>Booking Calendar</span>',
@@ -108,13 +144,8 @@
108 144 $el_arr['items'][] = array(
109 145 'type' => 'header',
110 146 'title' => __( 'Visit Booking Pages', 'booking' ),
111 147 );
112 - $el_arr['items'][] = array(
113 - 'type' => 'link',
114 - 'title' => __( 'Visit Home Page', 'booking' ),
115 - 'url' => esc_url( home_url( '/' ) ),
116 - );
117 148
118 149 foreach ( $wpbc_starter_pages as $wpbc_starter_page ) {
119 150 if ( empty( $wpbc_starter_page['url'] ) ) {
120 151 continue;
@@ -132,8 +163,14 @@
132 163 'title' => $wpbc_starter_page_title,
133 164 'url' => esc_url( $wpbc_starter_page['url'] ),
134 165 );
135 166 }
167 +
168 + $el_arr['items'][] = array(
169 + 'type' => 'link',
170 + 'title' => __( 'Visit Home Page', 'booking' ),
171 + 'url' => esc_url( home_url( '/' ) ),
172 + );
136 173 } elseif ( ! empty( $wp_post_booking_absolute ) ) {
137 174 $el_arr['items'][] = array(
138 175 'type' => 'header',
139 176 'title' => __( 'Visit Booking Page', 'booking' ),
@@ -139,15 +176,15 @@
139 176 'title' => __( 'Visit Booking Page', 'booking' ),
140 177 );
141 178 $el_arr['items'][] = array(
142 179 'type' => 'link',
143 - 'title' => __( 'Visit Home Page', 'booking' ),
144 - 'url' => esc_url( home_url( '/' ) ),
180 + 'title' => __( 'Go to page with booking form', 'booking' ),
181 + 'url' => esc_url( $wp_post_booking_absolute ),
145 182 );
146 183 $el_arr['items'][] = array(
147 184 'type' => 'link',
148 - 'title' => __( 'Go to page with booking form', 'booking' ),
149 - 'url' => esc_url( $wp_post_booking_absolute ),
185 + 'title' => __( 'Visit Home Page', 'booking' ),
186 + 'url' => esc_url( home_url( '/' ) ),
150 187 );
151 188 }
152 189 $el_arr['items'][] = array(
153 190 'type' => 'header',
@@ -309,32 +346,172 @@
309 346 }
310 347
311 348
312 349 /**
313 - * Get Full Screen mode from the immediate browser cookie, falling back to saved user meta value.
350 + * Build a short-lived browser value for an immediately changed fullscreen preference.
314 351 *
315 - * @param string $saved_value Saved user-meta value.
352 + * The timestamp distinguishes a pending navigation safeguard from legacy
353 + * year-long cookies, which must not override a successfully stored user value.
316 354 *
317 - * @return string 'On', 'Off', or empty string.
355 + * @param string $mode Fullscreen mode, either `On` or `Off`.
356 + * @param int|null $issued_timestamp Optional Unix timestamp for deterministic tests.
357 + *
358 + * @return string Pending cookie value, or an empty string for an invalid mode.
318 359 */
319 -function wpbc_ui__get_full_screen_mode_from_cookie( $saved_value = '' ) {
360 +function wpbc_ui__create_full_screen_mode_cookie_value( $mode, $issued_timestamp = null ) {
320 361
362 + if ( ! in_array( $mode, array( 'On', 'Off' ), true ) ) {
363 + return '';
364 + }
365 +
366 + $issued_timestamp = null === $issued_timestamp ? time() : absint( $issued_timestamp );
367 +
368 + return $mode . '|' . $issued_timestamp;
369 +}
370 +
371 +/**
372 + * Return every server-side cookie path used by Booking Calendar administration.
373 + *
374 + * Multiple paths are updated together to replace legacy cookies created by
375 + * root, subdirectory, or WordPress administration requests.
376 + *
377 + * @return string[] Unique absolute cookie paths.
378 + */
379 +function wpbc_ui__get_full_screen_mode_cookie_paths() {
380 +
381 + $cookie_paths = array( '/' );
382 +
383 + if ( defined( 'COOKIEPATH' ) && COOKIEPATH ) {
384 + $cookie_paths[] = COOKIEPATH;
385 + }
386 +
387 + if ( defined( 'ADMIN_COOKIE_PATH' ) && ADMIN_COOKIE_PATH ) {
388 + $cookie_paths[] = ADMIN_COOKIE_PATH;
389 + }
390 +
391 + return array_values( array_unique( array_filter( $cookie_paths ) ) );
392 +}
393 +
394 +/**
395 + * Set the pending fullscreen cookie on every applicable administration path.
396 + *
397 + * User metadata remains authoritative. This short-lived cookie only bridges
398 + * immediate navigation and replaces stale same-name cookies on narrower paths.
399 + *
400 + * @param string $mode Fullscreen mode, either `On` or `Off`.
401 + *
402 + * @return bool True when the mode was valid; otherwise false.
403 + */
404 +function wpbc_ui__set_full_screen_mode_cookie( $mode ) {
405 +
406 + $cookie_value = wpbc_ui__create_full_screen_mode_cookie_value( $mode );
407 + if ( '' === $cookie_value ) {
408 + return false;
409 + }
410 +
411 + if ( ! headers_sent() ) {
412 + $cookie_domain = defined( 'COOKIE_DOMAIN' ) ? COOKIE_DOMAIN : '';
413 +
414 + foreach ( wpbc_ui__get_full_screen_mode_cookie_paths() as $cookie_path ) {
415 + setcookie(
416 + 'wpbc_admin_full_screen',
417 + $cookie_value,
418 + time() + ( 5 * 60 ),
419 + $cookie_path,
420 + $cookie_domain,
421 + is_ssl(),
422 + false
423 + );
424 + }
425 + }
426 +
427 + $_COOKIE['wpbc_admin_full_screen'] = $cookie_value;
428 +
429 + return true;
430 +}
431 +
432 +/**
433 + * Resolve fullscreen mode from saved user data and an optional pending cookie.
434 + *
435 + * A fresh timestamped cookie temporarily wins so immediate navigation remains
436 + * deterministic if the asynchronous AJAX request is interrupted. A legacy
437 + * plain `On` or `Off` cookie is accepted only when no valid user preference
438 + * exists, preventing stale or duplicate-path cookies from overriding storage.
439 + *
440 + * @param string $saved_value Saved user-meta value.
441 + * @param string $cookie_value Browser cookie value.
442 + * @param int|null $current_timestamp Optional Unix timestamp for deterministic tests.
443 + *
444 + * @return string `On`, `Off`, or an empty string.
445 + */
446 +function wpbc_ui__resolve_full_screen_mode( $saved_value = '', $cookie_value = '', $current_timestamp = null ) {
447 +
321 448 $saved_value = in_array( $saved_value, array( 'On', 'Off' ), true ) ? $saved_value : '';
449 + $cookie_value = is_scalar( $cookie_value ) ? (string) $cookie_value : '';
322 450
323 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
324 - if ( ! isset( $_COOKIE['wpbc_admin_full_screen'] ) ) {
451 + if ( in_array( $cookie_value, array( 'On', 'Off' ), true ) ) {
452 + return '' === $saved_value ? $cookie_value : $saved_value;
453 + }
454 +
455 + if ( ! preg_match( '/^(On|Off)\|([0-9]{10,})$/', $cookie_value, $cookie_parts ) ) {
325 456 return $saved_value;
326 457 }
327 458
328 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
329 - $cookie_value = sanitize_text_field( $_COOKIE['wpbc_admin_full_screen'] );
459 + $current_timestamp = null === $current_timestamp ? time() : absint( $current_timestamp );
460 + $issued_timestamp = absint( $cookie_parts[2] );
461 + $pending_cookie_lifetime = 5 * 60;
462 + $allowed_clock_skew = 60;
330 463
331 - if ( in_array( $cookie_value, array( 'On', 'Off' ), true ) ) {
332 - return $cookie_value;
464 + if (
465 + $issued_timestamp > ( $current_timestamp + $allowed_clock_skew )
466 + || $issued_timestamp < ( $current_timestamp - $pending_cookie_lifetime )
467 + ) {
468 + return $saved_value;
333 469 }
334 470
335 - return $saved_value;
471 + return $cookie_parts[1];
336 472 }
473 +
474 +/**
475 + * Get fullscreen mode from the immediate browser cookie and saved user metadata.
476 + *
477 + * @param string $saved_value Saved user-meta value.
478 + *
479 + * @return string `On`, `Off`, or an empty string.
480 + */
481 +function wpbc_ui__get_full_screen_mode_from_cookie( $saved_value = '' ) {
482 +
483 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Optional same-origin UI preference.
484 + $cookie_value = isset( $_COOKIE['wpbc_admin_full_screen'] ) && is_scalar( $_COOKIE['wpbc_admin_full_screen'] )
485 + ? sanitize_text_field( wp_unslash( $_COOKIE['wpbc_admin_full_screen'] ) )
486 + : '';
487 +
488 + return wpbc_ui__resolve_full_screen_mode( $saved_value, $cookie_value );
489 +}
490 +
491 +/**
492 + * Synchronize the fullscreen navigation cookie after verified user-meta storage.
493 + *
494 + * @param int $user_id User whose preference was saved.
495 + * @param string $data_name Saved Booking Calendar preference name.
496 + * @param array $sanitized_data Sanitized value stored in user metadata.
497 + *
498 + * @return void
499 + */
500 +function wpbc_ui__sync_full_screen_cookie_after_user_data_save( $user_id, $data_name, $sanitized_data ) {
501 +
502 + if (
503 + 'is_full_screen' !== $data_name
504 + || wpbc_get_current_user_id() !== absint( $user_id )
505 + || ! isset( $sanitized_data['value'] )
506 + || ! is_scalar( $sanitized_data['value'] )
507 + ) {
508 + return;
509 + }
510 +
511 + wpbc_ui__set_full_screen_mode_cookie( (string) $sanitized_data['value'] );
512 +}
513 +add_action( 'wpbc_user_custom_data_saved', 'wpbc_ui__sync_full_screen_cookie_after_user_data_save', 10, 3 );
337 514
338 515
339 516 /**
340 517 * Set the admin full screen class