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
booking / includes / page-catalog-booking-resources / class-wpbc-catalog-booking-resource-availability.php

class-wpbc-catalog-booking-resource-availability.php in Booking Calendar 11.9, at includes/page-catalog-booking-resources/class-wpbc-catalog-booking-resource-availability.php

525 lines 22.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Independent availability adapter for the template-driven Resources catalog.
4 *
5 * @package Booking Calendar
6 * @since 11.6.0
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * Read, validate, and save availability fields without legacy catalog services.
15 *
16 * The adapter owns only the two settings that are safe to edit in the Resource
17 * inspector. It preserves season filters and every unrelated Search
18 * Availability option when updating their canonical storage records.
19 */
20 final class WPBC_Catalog_Booking_Resource_Availability {
21
22 /**
23 * Return presentation definitions for the Availability and search group.
24 *
25 * @param array<string,mixed> $resource Authorized Resource record.
26 *
27 * @return array<int,array<string,mixed>> Inspector field definitions.
28 */
29 public function get_field_definitions( $resource ) {
30 $resource_id = isset( $resource['id'] ) ? absint( $resource['id'] ) : 0;
31 $owner_user_id = isset( $resource['owner_user_id'] ) ? absint( $resource['owner_user_id'] ) : 0;
32 $resource_type = isset( $resource['resource_type'] ) ? sanitize_key( (string) $resource['resource_type'] ) : 'single';
33 $can_manage_days = current_user_can( wpbc_catalog_booking_resources_get_role_capability( 'booking_user_role_availability' ) );
34 $can_manage_search = current_user_can( wpbc_catalog_booking_resources_get_manage_capability() );
35 $previous_active_user = $this->set_owner_environment( $resource_id );
36 $availability = $this->get_season_availability( $resource_id );
37 $fields = array();
38
39 if ( class_exists( 'wpdev_bk_biz_l' ) && function_exists( 'wpbc_searchable_resources__get_all_options' ) ) {
40 $is_child = 'child' === $resource_type;
41 $searchable = $this->get_searchable_status( $resource_id, $is_child );
42 $search_url = $this->get_searchable_resources_url( $resource_id );
43 $fields[] = array(
44 'key' => 'searchable_status',
45 'label' => __( 'Search Availability results', 'booking' ),
46 'type' => $is_child || ! $can_manage_search ? 'readonly' : 'select',
47 'value' => $searchable,
48 'display_value' => 'on' === $searchable ? __( 'Searchable', 'booking' ) : __( 'Hidden from search results', 'booking' ),
49 'editable' => ! $is_child && $can_manage_search,
50 'options' => array(
51 array( 'value' => 'on', 'label' => __( 'Searchable', 'booking' ) ),
52 array( 'value' => 'off', 'label' => __( 'Hidden from search results', 'booking' ) ),
53 ),
54 'help' => $is_child
55 ? __( 'Child resources stay hidden because Search Availability returns their top-level parent resource.', 'booking' )
56 : __( 'Choose whether this Booking Resource can appear in Search Availability results.', 'booking' ),
57 'link_url' => $search_url,
58 'link_label' => $search_url ? __( 'Manage search presentation and filters', 'booking' ) : '',
59 );
60 } else {
61 $fields[] = array(
62 'key' => 'searchable_status',
63 'label' => __( 'Search Availability results', 'booking' ),
64 'type' => 'readonly',
65 'value' => '',
66 'display_value' => __( 'Not available in this version', 'booking' ),
67 'editable' => false,
68 'help' => __( 'Control whether this Booking Resource appears in Search Availability results.', 'booking' ),
69 );
70 }
71
72 if ( class_exists( 'wpdev_bk_biz_m' ) && function_exists( 'wpbc_get_resource_meta' ) && function_exists( 'wpbc_save_resource_meta' ) ) {
73 $availability_mode = 'Off' === $availability['general'] ? 'unavailable' : 'available';
74 $season_url = $can_manage_days ? $this->get_season_availability_url( $resource_id ) : '';
75 $active_rules = $this->count_active_season_rules( $availability );
76 $fields[] = array(
77 'key' => 'availability_mode',
78 'label' => __( 'Default day availability', 'booking' ),
79 'type' => $can_manage_days ? 'select' : 'readonly',
80 'value' => $availability_mode,
81 'display_value' => 'available' === $availability_mode ? __( 'Available', 'booking' ) : __( 'Unavailable', 'booking' ),
82 'editable' => $can_manage_days,
83 'options' => array(
84 array( 'value' => 'available', 'label' => __( 'Available', 'booking' ) ),
85 array( 'value' => 'unavailable', 'label' => __( 'Unavailable', 'booking' ) ),
86 ),
87 'help' => __( 'Active season rules invert this default only on the dates matched by those rules.', 'booking' ),
88 'link_url' => $season_url,
89 'link_label' => $season_url ? __( 'Manage season availability', 'booking' ) : '',
90 );
91 $fields[] = array(
92 'key' => 'active_season_rules',
93 'label' => __( 'Active season rules', 'booking' ),
94 'type' => 'readonly',
95 'value' => (string) $active_rules,
96 /* translators: %s: Number of active season availability rules. */
97 'display_value' => sprintf( _n( '%s rule', '%s rules', $active_rules, 'booking' ), number_format_i18n( $active_rules ) ),
98 'editable' => false,
99 'link_url' => $season_url,
100 'link_label' => $season_url ? __( 'Review season rules', 'booking' ) : '',
101 );
102 } else {
103 $fields[] = array(
104 'key' => 'availability_mode',
105 'label' => __( 'Season availability', 'booking' ),
106 'type' => 'readonly',
107 'value' => '',
108 'display_value' => __( 'Not available in this version', 'booking' ),
109 'editable' => false,
110 'help' => __( 'Set a default availability state and apply seasonal availability rules.', 'booking' ),
111 );
112 }
113
114 $manual_url = $can_manage_days ? $this->get_manual_availability_url( $resource_id ) : '';
115 $fields[] = array(
116 'key' => 'manual_date_availability',
117 'label' => __( 'Manual date availability', 'booking' ),
118 'type' => 'readonly',
119 'value' => __( 'Per-date overrides', 'booking' ),
120 'display_value' => __( 'Per-date overrides', 'booking' ),
121 'editable' => false,
122 'help' => __( 'Use the availability calendar to mark individual dates available or unavailable.', 'booking' ),
123 'link_url' => $manual_url,
124 'link_label' => $manual_url ? __( 'Manage dates', 'booking' ) : '',
125 );
126
127 $global_url = $can_manage_days && $this->can_edit_owner_settings( $owner_user_id ) && function_exists( 'wpbc_get_general_availability_url' )
128 ? esc_url_raw( wpbc_get_general_availability_url( true, false ) )
129 : '';
130 $fields[] = array(
131 'key' => 'booking_window_start',
132 'label' => __( 'Earliest bookable day', 'booking' ),
133 'type' => 'readonly',
134 'value' => sanitize_text_field( (string) get_bk_option( 'booking_unavailable_days_num_from_today' ) ),
135 'display_value' => $this->format_booking_window_start(),
136 'editable' => false,
137 'help' => __( 'This is a global Booking Calendar rule shared by every Booking Resource.', 'booking' ),
138 'link_url' => $global_url,
139 'link_label' => $global_url ? __( 'Change global booking window', 'booking' ) : '',
140 );
141 $fields[] = array(
142 'key' => 'booking_window_horizon',
143 'label' => __( 'Booking horizon', 'booking' ),
144 'type' => 'readonly',
145 'value' => class_exists( 'wpdev_bk_biz_m' ) ? (string) get_bk_option( 'booking_available_days_num_from_today' ) : '',
146 'display_value' => class_exists( 'wpdev_bk_biz_m' ) ? $this->format_booking_window_horizon() : __( 'Not available in this version', 'booking' ),
147 'editable' => false,
148 'help' => __( 'This is a global Booking Calendar rule shared by every Booking Resource.', 'booking' ),
149 'link_url' => class_exists( 'wpdev_bk_biz_m' ) ? $global_url : '',
150 'link_label' => class_exists( 'wpdev_bk_biz_m' ) && $global_url ? __( 'Change global booking window', 'booking' ) : '',
151 );
152
153 $this->restore_owner_environment( $previous_active_user, $resource_id );
154
155 return $fields;
156 }
157
158 /**
159 * Validate submitted availability values supported by the current edition.
160 *
161 * @param array<string,mixed> $resource Authorized Resource record.
162 * @param array<string,mixed> $submitted_fields Untrusted inspector values.
163 *
164 * @return array<string,string>|WP_Error Validated changes or safe error.
165 */
166 public function validate_fields( $resource, $submitted_fields ) {
167 $validated = array();
168 if ( array_key_exists( 'availability_mode', $submitted_fields ) && is_scalar( $submitted_fields['availability_mode'] ) ) {
169 if ( ! class_exists( 'wpdev_bk_biz_m' ) || ! current_user_can( wpbc_catalog_booking_resources_get_role_capability( 'booking_user_role_availability' ) ) ) {
170 return new WP_Error( 'wpbc_catalog_resource_availability_forbidden', __( 'You cannot change availability for this Booking Resource.', 'booking' ) );
171 }
172 $availability_mode = sanitize_key( (string) $submitted_fields['availability_mode'] );
173 if ( ! in_array( $availability_mode, array( 'available', 'unavailable' ), true ) ) {
174 return new WP_Error( 'wpbc_catalog_resource_availability_invalid', __( 'Select a valid default availability state.', 'booking' ) );
175 }
176 $validated['availability_mode'] = $availability_mode;
177 }
178
179 if ( array_key_exists( 'searchable_status', $submitted_fields ) && is_scalar( $submitted_fields['searchable_status'] ) ) {
180 $is_child = isset( $resource['resource_type'] ) && 'child' === (string) $resource['resource_type'];
181 if ( ! class_exists( 'wpdev_bk_biz_l' ) || $is_child || ! current_user_can( wpbc_catalog_booking_resources_get_manage_capability() ) ) {
182 return new WP_Error( 'wpbc_catalog_resource_searchability_forbidden', __( 'You cannot change Search Availability visibility for this Booking Resource.', 'booking' ) );
183 }
184 $searchable_status = sanitize_key( (string) $submitted_fields['searchable_status'] );
185 if ( ! in_array( $searchable_status, array( 'on', 'off' ), true ) ) {
186 return new WP_Error( 'wpbc_catalog_resource_searchability_invalid', __( 'Select a valid Search Availability visibility.', 'booking' ) );
187 }
188 $validated['searchable_status'] = $searchable_status;
189 }
190
191 return $validated;
192 }
193
194 /**
195 * Save validated availability fields and return an exact rollback snapshot.
196 *
197 * @param array<string,mixed> $resource Authorized Resource record.
198 * @param array<string,string> $validated_fields Validated availability values.
199 *
200 * @return array<string,mixed>|WP_Error Rollback snapshot or safe error.
201 */
202 public function save_fields( $resource, $validated_fields ) {
203 $resource_id = isset( $resource['id'] ) ? absint( $resource['id'] ) : 0;
204 if ( ! $resource_id || empty( $validated_fields ) ) {
205 return array();
206 }
207
208 $previous_active_user = $this->set_owner_environment( $resource_id );
209 $rollback = array();
210 if ( array_key_exists( 'availability_mode', $validated_fields ) ) {
211 $rollback['availability'] = $this->get_season_availability( $resource_id );
212 $availability = $rollback['availability'];
213 $availability['general'] = 'available' === $validated_fields['availability_mode'] ? 'On' : 'Off';
214 if ( ! function_exists( 'wpbc_save_resource_meta' ) || ! wpbc_save_resource_meta( $resource_id, 'availability', $availability ) ) {
215 $this->restore_owner_environment( $previous_active_user, $resource_id );
216
217 return new WP_Error( 'wpbc_catalog_resource_availability_not_saved', __( 'The Booking Resource availability could not be saved.', 'booking' ) );
218 }
219 }
220
221 if ( array_key_exists( 'searchable_status', $validated_fields ) ) {
222 $current_search_options = function_exists( 'wpbc_catalog_searchable_resources_option_writer' )
223 ? wpbc_catalog_searchable_resources_option_writer()->get_all()
224 : new WP_Error( 'wpbc_catalog_resource_searchability_unavailable', __( 'Search Availability settings are unavailable.', 'booking' ) );
225 if ( is_wp_error( $current_search_options ) ) {
226 $this->restore_fields_in_owner_context( $resource_id, $rollback );
227 $this->restore_owner_environment( $previous_active_user, $resource_id );
228
229 return $current_search_options;
230 }
231 $saved = $this->save_searchable_status( $resource_id, $validated_fields['searchable_status'], $current_search_options );
232 if ( is_wp_error( $saved ) ) {
233 $this->restore_fields_in_owner_context( $resource_id, $rollback );
234 $this->restore_owner_environment( $previous_active_user, $resource_id );
235
236 return $saved;
237 }
238 $rollback['search_options_write'] = $saved;
239 }
240
241 $this->restore_owner_environment( $previous_active_user, $resource_id );
242 if ( array_key_exists( 'availability_mode', $validated_fields ) && function_exists( 'make_bk_action' ) ) {
243 make_bk_action( 'wpbc_reinit_seasonfilters_cache' );
244 }
245 do_action( 'wpbc_catalog_booking_resource_availability_saved', $resource_id, $validated_fields );
246
247 return $rollback;
248 }
249
250 /**
251 * Restore a snapshot after a later catalog mutation fails.
252 *
253 * @param int $resource_id Booking Resource ID.
254 * @param array<string,mixed> $rollback Snapshot returned by save_fields().
255 *
256 * @return true|WP_Error True after restoration or a Searchable Resources recovery error.
257 */
258 public function restore_fields( $resource_id, $rollback ) {
259 if ( ! $resource_id || empty( $rollback ) ) {
260 return true;
261 }
262 $previous_active_user = $this->set_owner_environment( $resource_id );
263 $restored = $this->restore_fields_in_owner_context( $resource_id, $rollback );
264 $this->restore_owner_environment( $previous_active_user, $resource_id );
265 if ( isset( $rollback['availability'] ) && function_exists( 'make_bk_action' ) ) {
266 make_bk_action( 'wpbc_reinit_seasonfilters_cache' );
267 }
268
269 return $restored;
270 }
271
272 /**
273 * Restore canonical values while the correct owner context is active.
274 *
275 * @param int $resource_id Booking Resource ID.
276 * @param array<string,mixed> $rollback Rollback snapshot.
277 *
278 * @return true|WP_Error True after restoration or a Searchable Resources recovery error.
279 */
280 private function restore_fields_in_owner_context( $resource_id, $rollback ) {
281 if ( isset( $rollback['availability'] ) && function_exists( 'wpbc_save_resource_meta' ) ) {
282 wpbc_save_resource_meta( $resource_id, 'availability', $rollback['availability'] );
283 }
284 if ( isset( $rollback['search_options_write'] ) && function_exists( 'wpbc_catalog_searchable_resources_option_writer' ) ) {
285 $search_restored = wpbc_catalog_searchable_resources_option_writer()->compensate( $rollback['search_options_write'] );
286 if ( is_wp_error( $search_restored ) ) {
287 return $search_restored;
288 }
289 }
290
291 return true;
292 }
293
294 /**
295 * Read canonical season availability while preserving every filter entry.
296 *
297 * @param int $resource_id Booking Resource ID.
298 *
299 * @return array{general:string,filter:array} Normalized availability record.
300 */
301 private function get_season_availability( $resource_id ) {
302 $availability = array( 'general' => 'On', 'filter' => array() );
303 if ( ! $resource_id || ! function_exists( 'wpbc_get_resource_meta' ) ) {
304 return $availability;
305 }
306 $records = wpbc_get_resource_meta( $resource_id, 'availability' );
307 if ( empty( $records[0]->value ) ) {
308 return $availability;
309 }
310 $stored = maybe_unserialize( $records[0]->value );
311 if ( is_array( $stored ) ) {
312 $availability['general'] = isset( $stored['general'] ) && 'Off' === $stored['general'] ? 'Off' : 'On';
313 $availability['filter'] = isset( $stored['filter'] ) && is_array( $stored['filter'] ) ? $stored['filter'] : array();
314 }
315
316 return $availability;
317 }
318
319 /**
320 * Count enabled season rules.
321 *
322 * @param array<string,mixed> $availability Normalized availability record.
323 *
324 * @return int Enabled rule count.
325 */
326 private function count_active_season_rules( $availability ) {
327 $rule_count = 0;
328 foreach ( isset( $availability['filter'] ) ? (array) $availability['filter'] : array() as $filter_state ) {
329 if ( 'On' === $filter_state ) {
330 ++$rule_count;
331 }
332 }
333
334 return $rule_count;
335 }
336
337 /**
338 * Return whether one top-level Resource appears in Search Availability.
339 *
340 * @param int $resource_id Booking Resource ID.
341 * @param bool $is_child Whether hierarchy forces the Resource hidden.
342 *
343 * @return string `on` or `off`.
344 */
345 private function get_searchable_status( $resource_id, $is_child = false ) {
346 if ( $is_child || ! function_exists( 'wpbc_searchable_resources__get_all_options' ) ) {
347 return 'off';
348 }
349 $all_options = (array) wpbc_searchable_resources__get_all_options();
350
351 return isset( $all_options[ $resource_id ]['is_searchable'] ) && 'On' === $all_options[ $resource_id ]['is_searchable'] ? 'on' : 'off';
352 }
353
354 /**
355 * Save only one Resource's Search Availability visibility.
356 *
357 * @param int $resource_id Booking Resource ID.
358 * @param string $searchable_status Canonical `on` or `off` value.
359 * @param array<mixed> $before_options Exact reviewed Search option snapshot.
360 *
361 * @return array<string,mixed>|WP_Error Verified write record or safe error.
362 */
363 private function save_searchable_status( $resource_id, $searchable_status, $before_options ) {
364 if ( ! function_exists( 'wpbc_catalog_searchable_resources_option_writer' ) ) {
365 return new WP_Error( 'wpbc_catalog_resource_searchability_unavailable', __( 'Search Availability settings are unavailable.', 'booking' ) );
366 }
367 if ( ! is_array( $before_options ) ) {
368 return new WP_Error( 'wpbc_catalog_resource_searchability_unavailable', __( 'Search Availability settings are unavailable.', 'booking' ) );
369 }
370 $write_result = wpbc_catalog_searchable_resources_option_writer()->write_resource_visibility(
371 $before_options,
372 absint( $resource_id ),
373 'on' === $searchable_status,
374 'booking_resources_control'
375 );
376 if ( is_wp_error( $write_result ) ) {
377 return $write_result;
378 }
379
380 if ( $searchable_status !== $this->get_searchable_status( $resource_id ) ) {
381 $compensated = wpbc_catalog_searchable_resources_option_writer()->compensate( $write_result );
382
383 return is_wp_error( $compensated )
384 ? new WP_Error( 'wpbc_catalog_resource_searchability_recovery_required', __( 'Search Availability visibility could not be verified. Reload and inspect this Booking Resource before making another change.', 'booking' ) )
385 : new WP_Error( 'wpbc_catalog_resource_searchability_not_saved', __( 'Search Availability visibility could not be saved.', 'booking' ) );
386 }
387
388 return $write_result;
389 }
390
391 /**
392 * Build a direct manual-date availability URL.
393 *
394 * @param int $resource_id Booking Resource ID.
395 *
396 * @return string Authorized URL or an empty string.
397 */
398 private function get_manual_availability_url( $resource_id ) {
399 return function_exists( 'wpbc_get_availability_url' )
400 ? esc_url_raw( add_query_arg( 'resource_id', absint( $resource_id ), wpbc_get_availability_url( true, false ) ) )
401 : '';
402 }
403
404 /**
405 * Build a direct season-availability URL.
406 *
407 * @param int $resource_id Booking Resource ID.
408 *
409 * @return string Authorized URL or an empty string.
410 */
411 private function get_season_availability_url( $resource_id ) {
412 return function_exists( 'wpbc_get_availability_url' )
413 ? esc_url_raw( add_query_arg( array( 'tab' => 'season_availability', 'edit_resource_id' => absint( $resource_id ) ), wpbc_get_availability_url( true, false ) ) )
414 : '';
415 }
416
417 /**
418 * Build a direct Searchable Resources URL.
419 *
420 * @param int $resource_id Booking Resource ID.
421 *
422 * @return string Authorized URL or an empty string.
423 */
424 private function get_searchable_resources_url( $resource_id ) {
425 return function_exists( 'wpbc_get_resources_url' )
426 ? esc_url_raw( add_query_arg( array( 'tab' => 'searchable_resources', 'wh_resource_id' => absint( $resource_id ) ), wpbc_get_resources_url( true, false ) ) )
427 : '';
428 }
429
430 /**
431 * Format the earliest globally bookable day.
432 *
433 * @return string Human-readable booking-window start.
434 */
435 private function format_booking_window_start() {
436 $stored_start = sanitize_text_field( (string) get_bk_option( 'booking_unavailable_days_num_from_today' ) );
437 if ( '' === $stored_start || '0' === $stored_start ) {
438 return __( 'Today', 'booking' );
439 }
440 if ( function_exists( 'wpbc_availability_general__get_unavailable_from_today_options' ) ) {
441 $options = wpbc_availability_general__get_unavailable_from_today_options();
442 if ( isset( $options[ $stored_start ] ) ) {
443 return wp_strip_all_tags( (string) $options[ $stored_start ] ) . ' ' . __( 'from now', 'booking' );
444 }
445 }
446 if ( preg_match( '/^(\d+)m$/', $stored_start, $matches ) ) {
447 $minutes = absint( $matches[1] );
448
449 return sprintf( _n( '%s minute from now', '%s minutes from now', $minutes, 'booking' ), number_format_i18n( $minutes ) );
450 }
451 $days = absint( $stored_start );
452
453 return sprintf( _n( '%s day from today', '%s days from today', $days, 'booking' ), number_format_i18n( $days ) );
454 }
455
456 /**
457 * Format the globally configured booking horizon.
458 *
459 * @return string Human-readable booking horizon.
460 */
461 private function format_booking_window_horizon() {
462 $stored_horizon = get_bk_option( 'booking_available_days_num_from_today' );
463 if ( '' === (string) $stored_horizon || 0 === absint( $stored_horizon ) ) {
464 return __( 'No day limit', 'booking' );
465 }
466 $days = absint( $stored_horizon );
467
468 return sprintf( _n( '%s day from today', '%s days from today', $days, 'booking' ), number_format_i18n( $days ) );
469 }
470
471 /**
472 * Determine whether the current account can edit an owner's global settings.
473 *
474 * @param int $owner_user_id Resource owner user ID.
475 *
476 * @return bool True when the exact settings context is accessible.
477 */
478 private function can_edit_owner_settings( $owner_user_id ) {
479 if ( ! current_user_can( wpbc_catalog_booking_resources_get_role_capability( 'booking_user_role_settings' ) ) ) {
480 return false;
481 }
482 if ( ! class_exists( 'wpdev_bk_multiuser' ) ) {
483 return true;
484 }
485 $owner_user_id = absint( $owner_user_id );
486 if ( $owner_user_id && (bool) apply_bk_filter( 'is_user_super_admin', $owner_user_id ) ) {
487 $owner_user_id = 0;
488 }
489 $current_user = function_exists( 'wpbc_mu__wp_get_current_user' ) ? wpbc_mu__wp_get_current_user() : wp_get_current_user();
490 $current_user_id = is_object( $current_user ) && isset( $current_user->ID ) ? absint( $current_user->ID ) : 0;
491 if ( $current_user_id && (bool) apply_bk_filter( 'is_user_super_admin', $current_user_id ) ) {
492 $current_user_id = 0;
493 }
494
495 return $owner_user_id === $current_user_id;
496 }
497
498 /**
499 * Activate the owning MultiUser option context.
500 *
501 * @param int $resource_id Booking Resource ID.
502 *
503 * @return mixed Previous active-user token.
504 */
505 private function set_owner_environment( $resource_id ) {
506 return function_exists( 'apply_bk_filter' )
507 ? apply_bk_filter( 'wpbc_mu_set_environment_for_owner_of_resource', -1, absint( $resource_id ) )
508 : -1;
509 }
510
511 /**
512 * Restore the prior MultiUser option context.
513 *
514 * @param mixed $previous_active_user Previous active-user token.
515 * @param int $resource_id Resource ID used for the switch.
516 *
517 * @return void
518 */
519 private function restore_owner_environment( $previous_active_user, $resource_id ) {
520 if ( $resource_id && function_exists( 'make_bk_action' ) ) {
521 make_bk_action( 'wpbc_mu_set_environment_for_user', $previous_active_user );
522 }
523 }
524 }
525