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
← All changes | includes/_front_end/class-fe-booking-context.php +57 -12 11.811.8.4 View file →
@@ -82,8 +82,50 @@
82 82 return '' === $custom_form ? 'standard' : $custom_form;
83 83 }
84 84
85 85 /**
86 + * Normalize additional aggregate Booking Resource IDs for signed contexts.
87 + *
88 + * The legacy shortcode renderer represents an aggregate form as the primary
89 + * Resource followed by its additional Resources. Calendar runtime state
90 + * intentionally stores only the additional Resources because the primary is
91 + * already carried separately as resource_id. Removing that separately bound
92 + * primary gives both established shapes one canonical representation while
93 + * preserving an exact-set security comparison for every additional Resource.
94 + *
95 + * @param array|string|int $aggregate_resource_ids Candidate Resource IDs.
96 + * @param mixed $primary_resource_id Separately bound primary Resource ID.
97 + *
98 + * @return int[] Sorted unique positive IDs excluding the primary Resource.
99 + */
100 +function wpbc_classic_booking_context_normalize_aggregate_resource_ids( $aggregate_resource_ids, $primary_resource_id = 0 ) {
101 + $aggregate_resource_ids = is_array( $aggregate_resource_ids ) ? $aggregate_resource_ids : array( $aggregate_resource_ids );
102 + $primary_resource_id = absint( $primary_resource_id );
103 + $normalized_resource_ids = array();
104 +
105 + foreach ( $aggregate_resource_ids as $aggregate_resource_id ) {
106 + if ( ! is_int( $aggregate_resource_id ) && ! is_float( $aggregate_resource_id ) && ! is_string( $aggregate_resource_id ) ) {
107 + continue;
108 + }
109 +
110 + $resource_id_parts = preg_split( '/[;,\s]+/', (string) $aggregate_resource_id, -1, PREG_SPLIT_NO_EMPTY );
111 + foreach ( (array) $resource_id_parts as $resource_id_part ) {
112 + $resource_id = absint( $resource_id_part );
113 + if ( ! $resource_id || $resource_id === $primary_resource_id ) {
114 + continue;
115 + }
116 +
117 + $normalized_resource_ids[ $resource_id ] = $resource_id;
118 + }
119 + }
120 +
121 + $normalized_resource_ids = array_values( $normalized_resource_ids );
122 + sort( $normalized_resource_ids, SORT_NUMERIC );
123 +
124 + return $normalized_resource_ids;
125 +}
126 +
127 +/**
86 128 * Normalize the native Booking Form context before it is signed or consumed.
87 129 *
88 130 * @param mixed $context Raw context values.
89 131 *
@@ -103,13 +145,12 @@
103 145 'aggregate_resource_ids' => array(),
104 146 'allow_past' => false,
105 147 )
106 148 );
107 - $calendar_dates_start = wpbc_classic_booking_context_normalize_date( $context['calendar_dates_start'] );
108 -
109 - $aggregate_resource_ids = array_values( array_unique( array_filter( array_map( 'absint', (array) $context['aggregate_resource_ids'] ) ) ) );
110 - sort( $aggregate_resource_ids, SORT_NUMERIC );
111 - $booking_workflow = sanitize_key( (string) $context['booking_workflow'] );
149 + $calendar_dates_start = wpbc_classic_booking_context_normalize_date( $context['calendar_dates_start'] );
150 + $resource_id = absint( $context['resource_id'] );
151 + $aggregate_resource_ids = wpbc_classic_booking_context_normalize_aggregate_resource_ids( $context['aggregate_resource_ids'], $resource_id );
152 + $booking_workflow = sanitize_key( (string) $context['booking_workflow'] );
112 153 if ( ! in_array( $booking_workflow, array( 'classic', 'appointment', 'resource_selector' ), true ) ) {
113 154 $booking_workflow = 'classic';
114 155 }
115 156
@@ -116,9 +157,9 @@
116 157 // Derive permission from the site-authored date boundary; never trust a caller-supplied allow_past flag.
117 158 return array(
118 159 'context_version' => absint( $context['context_version'] ),
119 160 'booking_workflow' => $booking_workflow,
120 - 'resource_id' => absint( $context['resource_id'] ),
161 + 'resource_id' => $resource_id,
121 162 'calendar_dates_start' => $calendar_dates_start,
122 163 'calendar_dates_end' => wpbc_classic_booking_context_normalize_date( $context['calendar_dates_end'] ),
123 164 'custom_form' => wpbc_classic_booking_context_normalize_form( $context['custom_form'] ),
124 165 'aggregate_resource_ids' => $aggregate_resource_ids,
@@ -254,15 +295,19 @@
254 295 if ( $custom_form !== $context['custom_form'] ) {
255 296 return new WP_Error( 'classic_booking_context_form_mismatch', __( 'The selected Booking Form does not match this calendar. Please reload the page and try again.', 'booking' ) );
256 297 }
257 298
258 - if ( is_string( $aggregate_resource_ids ) ) {
259 - $aggregate_resource_ids = preg_split( '/[;,\s]+/', $aggregate_resource_ids, -1, PREG_SPLIT_NO_EMPTY );
260 - }
261 - $aggregate_resource_ids = array_values( array_unique( array_filter( array_map( 'absint', (array) $aggregate_resource_ids ) ) ) );
262 - sort( $aggregate_resource_ids, SORT_NUMERIC );
299 + $aggregate_resource_ids = wpbc_classic_booking_context_normalize_aggregate_resource_ids( $aggregate_resource_ids, $context['resource_id'] );
263 300 if ( $aggregate_resource_ids !== $context['aggregate_resource_ids'] ) {
264 - return new WP_Error( 'classic_booking_context_aggregate_mismatch', __( 'The booking resources do not match this calendar. Please reload the page and try again.', 'booking' ) );
301 + $troubleshooting_url = 'https://wpbookingcalendar.com/faq/troubleshooting-the-booking-resources-do-not-match-this-calendar/';
302 + $aggregate_mismatch_message = esc_html__( 'The booking resources do not match this calendar. Please reload the page and try again.', 'booking' );
303 + $aggregate_mismatch_message .= sprintf(
304 + '<br><a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a>',
305 + esc_url( $troubleshooting_url ),
306 + esc_html__( 'Open the troubleshooting guide.', 'booking' )
307 + );
308 +
309 + return new WP_Error( 'classic_booking_context_aggregate_mismatch', $aggregate_mismatch_message );
265 310 }
266 311
267 312 if ( is_string( $submitted_dates ) ) {
268 313 $submitted_dates = preg_split( '/\s*,\s*/', $submitted_dates, -1, PREG_SPLIT_NO_EMPTY );