PluginProbe
Booking Calendar / 11.4
Booking Calendar v11.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 / page-form-builder / legacy-import / bfb-import-legacy-forms.php

bfb-import-legacy-forms.php in Booking Calendar 11.4, at includes/page-form-builder/legacy-import/bfb-import-legacy-forms.php

630 lines 18.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Booking Calendar - Legacy Forms Importer -> booking_form_structures.
4 *
5 * Purpose:
6 * - Import legacy booking forms from:
7 * - global options
8 * - booking_forms_extended
9 * - MultiUser regular user user_meta
10 * - Materialize them into booking_form_structures as canonical FormConfig rows.
11 *
12 * Supported cases:
13 * - Standard form from:
14 * - booking_form_visual
15 * - booking_form
16 * - booking_form_show
17 * - Custom forms from:
18 * - booking_forms_extended
19 *
20 * Strategy:
21 * - If legacy form has Simple Form structure -> import as engine = 'bfb'
22 * - If legacy form has only Advanced Form -> import as engine = 'advanced_mode'
23 * with EMPTY Builder structure.
24 *
25 * Notes:
26 * - Free version:
27 * - Simple Form is converted into real BFB structure.
28 * - Paid versions:
29 * - Advanced Form is imported without BFB structure yet.
30 * - Only advanced_form + content_form are imported.
31 *
32 * @package Booking Calendar
33 * @subpackage Form Builder
34 *
35 * @since 11.0.0
36 * @file ../includes/page-form-builder/save-load/bfb-import-legacy-forms.php
37 */
38
39 if ( ! defined( 'ABSPATH' ) ) {
40 exit;
41 }
42
43 /**
44 * Get legacy option value for global or user owner context.
45 *
46 * @param string $option_name
47 * @param int $owner_user_id
48 *
49 * @return mixed
50 */
51 function wpbc_bfb_get_legacy_option_value( $option_name, $owner_user_id = 0 ) {
52
53 $option_name = (string) $option_name;
54 $owner_user_id = absint( $owner_user_id );
55
56 if ( $owner_user_id > 0 ) {
57 return get_user_option( $option_name, $owner_user_id );
58 }
59
60 return get_bk_option( $option_name );
61 }
62
63 /**
64 * Check whether legacy form data is effectively empty.
65 *
66 * @param array $legacy_form
67 *
68 * @return bool
69 */
70 function wpbc_bfb_is_empty_legacy_form( $legacy_form ) {
71
72 $visual = isset( $legacy_form['visual'] ) ? $legacy_form['visual'] : array();
73 $advanced_form = isset( $legacy_form['advanced_form'] ) ? (string) $legacy_form['advanced_form'] : '';
74 $content_form = isset( $legacy_form['content_form'] ) ? (string) $legacy_form['content_form'] : '';
75
76 $has_visual = ( is_array( $visual ) && ! empty( $visual ) );
77 $has_adv = ( '' !== trim( $advanced_form ) );
78 $has_cnt = ( '' !== trim( $content_form ) );
79
80 return ( ! $has_visual && ! $has_adv && ! $has_cnt );
81 }
82
83 /**
84 * Get normalized legacy standard form for specific owner.
85 *
86 * @param int $owner_user_id
87 *
88 * @return array|null
89 */
90 function wpbc_bfb_get_legacy_standard_form_for_owner( $owner_user_id = 0 ) {
91
92 $owner_user_id = absint( $owner_user_id );
93
94 $advanced_form = wpbc_bfb_get_legacy_option_value( 'booking_form', $owner_user_id );
95 $content_form = wpbc_bfb_get_legacy_option_value( 'booking_form_show', $owner_user_id );
96 $visual = wpbc_bfb_get_legacy_option_value( 'booking_form_visual', $owner_user_id );
97
98 $visual = maybe_unserialize( $visual );
99 if ( ! is_array( $visual ) ) {
100 $visual = array();
101 }
102
103 $legacy_engine = 'legacy_advanced';
104 if ( ! empty( $visual ) ) {
105 $legacy_engine = 'legacy_simple';
106 }
107
108 $legacy_form = array(
109 'form_name' => 'standard',
110 'title' => __( 'Standard', 'booking' ),
111 'description' => '',
112 'picture_url' => '',
113 'owner_user_id' => $owner_user_id,
114 'is_default' => 1,
115 'booking_resource_id' => null,
116 'legacy_engine' => $legacy_engine,
117 'visual' => $visual,
118 'advanced_form' => (string) $advanced_form,
119 'content_form' => (string) $content_form,
120 );
121
122 if ( wpbc_bfb_is_empty_legacy_form( $legacy_form ) ) {
123 return null;
124 }
125
126 return $legacy_form;
127 }
128
129 /**
130 * Get normalized legacy custom forms for specific owner.
131 *
132 * @param int $owner_user_id
133 *
134 * @return array
135 */
136 function wpbc_bfb_get_legacy_custom_forms_for_owner( $owner_user_id = 0 ) {
137
138 $owner_user_id = absint( $owner_user_id );
139
140 $extended = wpbc_bfb_get_legacy_option_value( 'booking_forms_extended', $owner_user_id );
141 $extended = maybe_unserialize( $extended );
142
143 if ( ! is_array( $extended ) || empty( $extended ) ) {
144 return array();
145 }
146
147 $forms = array();
148
149 foreach ( $extended as $one ) {
150
151 if ( ! is_array( $one ) ) {
152 continue;
153 }
154
155 $form_name = isset( $one['name'] ) ? sanitize_text_field( (string) $one['name'] ) : '';
156 if ( '' === $form_name || 'standard' === $form_name ) {
157 continue;
158 }
159
160 $visual = isset( $one['simple_form'] ) ? $one['simple_form'] : array();
161 $visual = maybe_unserialize( $visual );
162 if ( ! is_array( $visual ) ) {
163 $visual = array();
164 }
165
166 $legacy_engine = 'legacy_advanced';
167 if ( ! empty( $visual ) ) {
168 $legacy_engine = 'legacy_simple';
169 }
170
171 $legacy_form = array(
172 'form_name' => $form_name,
173 'title' => isset( $one['title'] ) ? sanitize_text_field( (string) $one['title'] ) : $form_name,
174 'description' => isset( $one['description'] ) ? sanitize_textarea_field( (string) $one['description'] ) : '',
175 'picture_url' => '',
176 'owner_user_id' => $owner_user_id,
177 'is_default' => ! empty( $one['is_default'] ) ? 1 : 0,
178 'booking_resource_id' => isset( $one['booking_resource_id'] ) ? absint( $one['booking_resource_id'] ) : null,
179 'legacy_engine' => $legacy_engine,
180 'visual' => $visual,
181 'advanced_form' => isset( $one['form'] ) ? (string) $one['form'] : '',
182 'content_form' => isset( $one['content'] ) ? (string) $one['content'] : '',
183 );
184
185 if ( wpbc_bfb_is_empty_legacy_form( $legacy_form ) ) {
186 continue;
187 }
188
189 $forms[] = $legacy_form;
190 }
191
192 return $forms;
193 }
194
195 /**
196 * Get all legacy forms for specific owner.
197 *
198 * @param int $owner_user_id
199 * @param bool $import_standard
200 * @param bool $import_custom
201 *
202 * @return array
203 */
204 function wpbc_bfb_get_legacy_forms_for_owner( $owner_user_id = 0, $import_standard = true, $import_custom = true ) {
205
206 $forms = array();
207
208 if ( $import_standard ) {
209 $standard_form = wpbc_bfb_get_legacy_standard_form_for_owner( $owner_user_id );
210 if ( ! empty( $standard_form ) ) {
211 $forms[] = $standard_form;
212 }
213 }
214
215 if ( $import_custom ) {
216 $custom_forms = wpbc_bfb_get_legacy_custom_forms_for_owner( $owner_user_id );
217 if ( ! empty( $custom_forms ) ) {
218 $forms = array_merge( $forms, $custom_forms );
219 }
220 }
221
222 return $forms;
223 }
224
225 /**
226 * Build normalized settings for imported legacy form.
227 *
228 * @param string $legacy_engine
229 *
230 * @return array
231 */
232 function wpbc_bfb_get_imported_settings_for_legacy_engine( $legacy_engine ) {
233
234 $advanced_mode_source = ( 'legacy_simple' === $legacy_engine ) ? 'auto' : 'advanced';
235
236 return wpbc_bfb__normalize_settings_array(
237 array(
238 'options' => array(),
239 'css_vars' => array(),
240 'bfb_options' => array(
241 'advanced_mode_source' => $advanced_mode_source,
242 ),
243 )
244 );
245 }
246
247 /**
248 * Build FormConfig array from normalized legacy form.
249 *
250 * Important:
251 * - legacy_simple -> create real BFB structure and store as engine = 'bfb'
252 * - legacy_advanced -> store as BFB Advanced Mode row with advanced/content source
253 *
254 * @param array $legacy_form
255 *
256 * @return array
257 */
258 function wpbc_bfb_build_form_config_from_legacy_form( $legacy_form, $args ) {
259
260 $args = wp_parse_args(
261 $args,
262 array(
263 'skip_if_exists' => true,
264 'set_bfb_form_not_defined' => true,
265 )
266 );
267
268 $legacy_engine = isset( $legacy_form['legacy_engine'] ) ? (string) $legacy_form['legacy_engine'] : 'legacy_advanced';
269 $visual = isset( $legacy_form['visual'] ) ? $legacy_form['visual'] : array();
270
271 $engine = 'advanced_mode';
272 $engine_version = '1.0';
273 $structure_json = wpbc_form_config__encode_json( array() );
274
275 if ( 'legacy_simple' === $legacy_engine ) {
276
277 $engine = 'bfb';
278 $structure_arr = wpbc_simple_form__export_to_bfb_structure( $visual );
279
280 if ( empty( $structure_arr ) || ! is_array( $structure_arr ) ) {
281 $structure_arr = wpbc_bfb__get_blank_structure_seed();
282 }
283
284 $structure_json = wpbc_form_config__encode_json( $structure_arr );
285 }
286
287 return array(
288 'form_name' => isset( $legacy_form['form_name'] ) ? (string) $legacy_form['form_name'] : 'standard',
289 'engine' => $engine,
290 'engine_version' => $engine_version,
291 'structure_json' => $structure_json,
292 'settings' => wpbc_bfb_get_imported_settings_for_legacy_engine( $legacy_engine ),
293 'advanced_form' => isset( $legacy_form['advanced_form'] ) ? (string) $legacy_form['advanced_form'] : '',
294 'content_form' => isset( $legacy_form['content_form'] ) ? (string) $legacy_form['content_form'] : '',
295 'owner_user_id' => isset( $legacy_form['owner_user_id'] ) ? absint( $legacy_form['owner_user_id'] ) : 0,
296 'title' => isset( $legacy_form['title'] ) ? (string) $legacy_form['title'] : '',
297 'description' => isset( $legacy_form['description'] ) ? (string) $legacy_form['description'] : '',
298 'picture_url' => isset( $legacy_form['picture_url'] ) ? (string) $legacy_form['picture_url'] : '',
299 'scope' => 'global',
300 'status' => 'published',
301 'is_default' => ! empty( $legacy_form['is_default'] ) ? 1 : 0,
302 'booking_resource_id' => isset( $legacy_form['booking_resource_id'] ) ? $legacy_form['booking_resource_id'] : null,
303 );
304 }
305
306 /**
307 * Import one normalized legacy form into booking_form_structures.
308 *
309 * @param array $legacy_form
310 * @param array $args
311 *
312 * @return array
313 */
314 function wpbc_bfb_import_one_legacy_form( $legacy_form, $args = array() ) {
315
316 $args = wp_parse_args(
317 $args,
318 array(
319 'skip_if_exists' => true,
320 'set_bfb_form_not_defined' => true,
321 )
322 );
323
324 $form_name = isset( $legacy_form['form_name'] ) ? (string) $legacy_form['form_name'] : '';
325 $owner_user_id = isset( $legacy_form['owner_user_id'] ) ? absint( $legacy_form['owner_user_id'] ) : 0;
326
327 if ( '' === $form_name ) {
328 return array(
329 'status' => 'error',
330 'message' => __( 'Missing form name.', 'booking' ),
331 );
332 }
333
334 $is_fallback_to_legacy = false;
335 $existing = wpbc_form_config_load( $form_name, $owner_user_id, 'published', $is_fallback_to_legacy );
336
337 if ( ! empty( $existing ) && ! empty( $args['skip_if_exists'] ) ) {
338 return array(
339 'status' => 'skipped',
340 'form_name' => $form_name,
341 'owner_user_id' => $owner_user_id,
342 'booking_form_id' => isset( $existing['id'] ) ? absint( $existing['id'] ) : 0,
343 'imported_engine' => isset( $existing['engine'] ) ? (string) $existing['engine'] : '',
344 'legacy_engine' => isset( $legacy_form['legacy_engine'] ) ? (string) $legacy_form['legacy_engine'] : '',
345 );
346 }
347
348 $form_config = wpbc_bfb_build_form_config_from_legacy_form( $legacy_form, $args );
349 $sync_legacy = false;
350
351 $booking_form_id = wpbc_form_config_save(
352 $form_config,
353 array(
354 'sync_legacy' => (bool) $sync_legacy,
355 )
356 );
357
358 if ( ! $booking_form_id ) {
359 return array(
360 'status' => 'error',
361 'form_name' => $form_name,
362 'owner_user_id' => $owner_user_id,
363 'legacy_engine' => isset( $legacy_form['legacy_engine'] ) ? (string) $legacy_form['legacy_engine'] : '',
364 'message' => __( 'Error saving imported legacy form.', 'booking' ),
365 );
366 }
367
368 return array(
369 'status' => 'imported',
370 'form_name' => $form_name,
371 'owner_user_id' => $owner_user_id,
372 'booking_form_id' => absint( $booking_form_id ),
373 'imported_engine' => isset( $form_config['engine'] ) ? (string) $form_config['engine'] : '',
374 'legacy_engine' => isset( $legacy_form['legacy_engine'] ) ? (string) $legacy_form['legacy_engine'] : '',
375 );
376 }
377
378 /**
379 * Import legacy forms for one owner.
380 *
381 * @param int $owner_user_id
382 * @param array $args
383 *
384 * @return array
385 */
386 function wpbc_bfb_import_legacy_forms_for_owner( $owner_user_id = 0, $args = array() ) {
387
388 $args = wp_parse_args(
389 $args,
390 array(
391 'import_standard' => true,
392 'import_custom' => true,
393 'skip_if_exists' => true,
394 'set_bfb_form_not_defined' => true,
395 )
396 );
397
398 $owner_user_id = absint( $owner_user_id );
399 $legacy_forms = wpbc_bfb_get_legacy_forms_for_owner( $owner_user_id, $args['import_standard'], $args['import_custom'] );
400
401 $result = array(
402 'owner_user_id' => $owner_user_id,
403 'imported' => 0,
404 'skipped' => 0,
405 'errors' => 0,
406 'items' => array(),
407 );
408
409 foreach ( $legacy_forms as $legacy_form ) {
410
411 $item_result = wpbc_bfb_import_one_legacy_form( $legacy_form, $args );
412 $result['items'][] = $item_result;
413
414 switch ( $item_result['status'] ) {
415 case 'imported':
416 ++$result['imported'];
417 break;
418 case 'skipped':
419 ++$result['skipped'];
420 break;
421 default:
422 ++$result['errors'];
423 break;
424 }
425 }
426
427 return $result;
428 }
429
430 /**
431 * Get activated regular user IDs in MultiUser.
432 *
433 * @return array
434 */
435 function wpbc_bfb_get_mu_activated_regular_user_ids() {
436
437 $user_ids = array();
438
439 if ( ! class_exists( 'wpdev_bk_multiuser' ) ) {
440 return $user_ids;
441 }
442
443 global $wpdb;
444 $prefix = $wpdb->get_blog_prefix();
445
446 $users = get_users(
447 array(
448 'fields' => 'ids',
449 'meta_key' => "{$prefix}booking_is_active", // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
450 'meta_value' => 'On', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
451 'number' => 9999,
452 )
453 );
454
455 if ( empty( $users ) ) {
456 return $user_ids;
457 }
458
459 foreach ( $users as $user_id ) {
460
461 $user_id = absint( $user_id );
462 if ( $user_id <= 0 ) {
463 continue;
464 }
465
466 $is_super_admin = apply_bk_filter( 'is_user_super_admin', $user_id );
467 if ( $is_super_admin ) {
468 continue;
469 }
470
471 $user_ids[] = $user_id;
472 }
473
474 return array_values( array_unique( $user_ids ) );
475 }
476
477 /**
478 * Import legacy forms depending on requested mode.
479 *
480 * Modes:
481 * - current_context : import current owner context only
482 * - all_global : import global forms only
483 * - all_users : import global + all activated MU regular users
484 *
485 * @param array $args
486 *
487 * @return array
488 */
489 function wpbc_bfb_import_legacy_forms( $args = array() ) {
490
491 $args = wp_parse_args(
492 $args,
493 array(
494 'mode' => 'current_context',
495 'import_standard' => true,
496 'import_custom' => true,
497 'skip_if_exists' => true,
498 'set_bfb_form_not_defined' => true,
499 )
500 );
501
502 $mode = sanitize_key( (string) $args['mode'] );
503 if ( ! in_array( $mode, array( 'current_context', 'all_global', 'all_users' ), true ) ) {
504 $mode = 'current_context';
505 }
506
507 $current_owner_user_id = 0;
508 if ( class_exists( 'WPBC_FE_Custom_Form_Helper' ) ) {
509 $current_owner_user_id = WPBC_FE_Custom_Form_Helper::wpbc_mu__get_current__owner_user_id();
510 }
511
512 $summary = array(
513 'mode' => $mode,
514 'imported' => 0,
515 'skipped' => 0,
516 'errors' => 0,
517 'owners' => array(),
518 'message' => '',
519 );
520
521 if ( 'current_context' === $mode ) {
522 // Import booking forms only for the == Current User == (usually - "Regular User").
523 $owner_result = wpbc_bfb_import_legacy_forms_for_owner( $current_owner_user_id, $args );
524 $summary['owners'][] = $owner_result;
525
526 } elseif ( 'all_global' === $mode ) {
527 // Import booking forms for == Super Booking Admin == user ( user_id = 0 ).
528 $owner_result = wpbc_bfb_import_legacy_forms_for_owner( 0, $args );
529 $summary['owners'][] = $owner_result;
530
531 } elseif ( 'all_users' === $mode ) {
532 // Import booking forms for == All Users ==.
533
534 // Always import global first.
535 $summary['owners'][] = wpbc_bfb_import_legacy_forms_for_owner( 0, $args );
536
537 $user_ids = wpbc_bfb_get_mu_activated_regular_user_ids();
538
539 foreach ( $user_ids as $user_id ) {
540 $summary['owners'][] = wpbc_bfb_import_legacy_forms_for_owner( $user_id, $args );
541 }
542 }
543
544 foreach ( $summary['owners'] as $owner_result ) {
545 $summary['imported'] += isset( $owner_result['imported'] ) ? absint( $owner_result['imported'] ) : 0;
546 $summary['skipped'] += isset( $owner_result['skipped'] ) ? absint( $owner_result['skipped'] ) : 0;
547 $summary['errors'] += isset( $owner_result['errors'] ) ? absint( $owner_result['errors'] ) : 0;
548 }
549
550 $summary['message'] = sprintf(
551 /* translators: 1: imported count, 2: skipped count, 3: error count */
552 __( 'Legacy forms import finished. Imported: %1$d. Skipped: %2$d. Errors: %3$d.', 'booking' ),
553 $summary['imported'],
554 $summary['skipped'],
555 $summary['errors']
556 );
557
558 return $summary;
559 }
560
561 /**
562 * AJAX: import legacy forms into booking_form_structures.
563 *
564 * Modes:
565 * - current_context
566 * - all_global
567 * - all_users
568 *
569 * @return void
570 */
571 function wpbc_bfb_ajax_import_legacy_forms() {
572
573 if ( ! check_ajax_referer( 'wpbc_bfb_import_legacy_forms', 'nonce', false ) ) {
574 wp_send_json_error(
575 array(
576 'code' => 'invalid_nonce',
577 'message' => __( 'Security check failed.', 'booking' ),
578 )
579 );
580 }
581
582 if ( ! current_user_can( wpbc_bfb_get_manage_cap() ) ) {
583 wp_send_json_error(
584 array(
585 'code' => 'forbidden',
586 'message' => __( 'You are not allowed to import booking forms.', 'booking' ),
587 )
588 );
589 }
590
591 $mode = isset( $_POST['mode'] ) ? sanitize_key( wp_unslash( $_POST['mode'] ) ) : 'current_context';
592 if ( ! in_array( $mode, array( 'current_context', 'all_global', 'all_users' ), true ) ) {
593 $mode = 'current_context';
594 }
595
596 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
597 $skip_if_exists = isset( $_POST['skip_if_exists'] ) ? ( 'skip' === wp_unslash( $_POST['skip_if_exists'] ) ) : true;
598 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
599 $set_bfb_form_not_defined = isset( $_POST['set_bfb_form_not_defined'] ) ? ( 'not_defined' === wp_unslash( $_POST['set_bfb_form_not_defined'] ) ) : true;
600
601 // Security: importing all MU users is allowed only for super admin context.
602 if ( 'all_users' === $mode ) {
603 $current_user_id = wpbc_get_current_user_id();
604 $is_user_super_admin = apply_bk_filter( 'is_user_super_admin', $current_user_id );
605
606 if ( ! $is_user_super_admin ) {
607 wp_send_json_error(
608 array(
609 'code' => 'forbidden_all_users',
610 'message' => __( 'Only super admin can import forms for all users.', 'booking' ),
611 )
612 );
613 }
614 }
615
616 $summary = wpbc_bfb_import_legacy_forms(
617 array(
618 'mode' => $mode,
619 'import_standard' => true,
620 'import_custom' => true,
621 'skip_if_exists' => $skip_if_exists,
622 'set_bfb_form_not_defined' => $set_bfb_form_not_defined,
623 )
624 );
625
626 wp_send_json_success( $summary );
627 }
628 add_action( 'wp_ajax_' . 'WPBC_AJX_BFB_IMPORT_LEGACY_FORMS', 'wpbc_bfb_ajax_import_legacy_forms' );
629
630