PluginProbe
Booking Calendar / 11.0
Booking Calendar v11.0
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 10.11.2 All 203 releases
booking / includes / page-form-builder / save-load / bfb-form-loader.php

bfb-form-loader.php in Booking Calendar 11.0, at includes/page-form-builder/save-load/bfb-form-loader.php

525 lines 16.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Booking Form Loader (Builder + Legacy fallback).
4 *
5 * This helper:
6 * - Accepts a logical form identifier (form_slug) + status (and optional form_id).
7 * - Asks the Booking Form Builder (BFB) for exported form/content.
8 * - If Builder returns nothing, falls back to legacy:
9 * * booking_form / booking_form_show options.
10 * * booking_forms_extended (custom forms).
11 * * simple visual form export (booking_form_visual).
12 *
13 * It only returns the **source strings** (shortcodes):
14 * - "booking form" (form) – the main form shortcodes.
15 * - "Content of booking fields data" (content) – email/content template.
16 *
17 * Rendering/parsing of shortcodes stays in:
18 * - WPBC_BFB _FormShortcodeEngine (new engine), or
19 * - the legacy HTML generators (simple form free).
20 *
21 * @package Booking Calendar
22 * @subpackage Form Builder
23 * @file includes/page-form-builder/save-load/bfb-form-loader.php
24 *
25 * @since 11.0.0
26 */
27
28 if ( ! defined( 'ABSPATH' ) ) {
29 exit;
30 }
31
32 /**
33 * Basically it is wrapper to call this function: wpbc_bfb__load_from_bfb_table() for loading data from DB
34 */
35
36 /**
37 * Central helper for resolving which booking form configuration
38 * should be used on the front-end (Builder vs legacy).
39 */
40 class WPBC_BFB_Form_Loader {
41
42 /**
43 * Singleton instance.
44 *
45 * @var WPBC_BFB_Form_Loader|null
46 */
47 protected static $instance = null;
48
49 /**
50 * Protect direct construction – use get_instance().
51 */
52 protected function __construct() {}
53
54 /**
55 * Prevent cloning.
56 */
57 protected function __clone() {}
58
59 /**
60 * Prevent unserializing.
61 */
62 public function __wakeup() { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
63 _doing_it_wrong( __METHOD__, 'Unserializing WPBC_BFB_Form_Loader is not allowed.', '11.0.0' );
64 }
65
66 /**
67 * Get singleton instance.
68 *
69 * @return WPBC_BFB_Form_Loader
70 */
71 public static function get_instance() {
72
73 if ( null === self::$instance ) {
74 self::$instance = new self();
75 }
76
77 return self::$instance;
78 }
79
80 /**
81 * Get booking form (shortcodes string) by form slug / ID.
82 *
83 * This returns the main "Booking form" configuration in shortcodes format.
84 * It does NOT parse shortcodes, only returns the source string.
85 *
86 * @param array $args {
87 * Optional. Arguments for resolving the form.
88 *
89 * @type string $form_slug Logical form identifier. Examples:
90 * 'standard', 'appointments-services-1'.
91 * Empty string or 'auto' means: resolve using
92 * legacy default custom form for $resource_id.
93 * @type int $form_id Optional. Numeric ID of the Builder form
94 * (booking_form_id in booking_form_structures).
95 * If provided, Builder may prefer it over form_slug.
96 * @type string $status Desired Builder status. Examples:
97 * 'published', 'preview', 'draft', 'archived'.
98 * Legacy fallback ignores it.
99 * @type string $bfb_form_status Optional alias for $status used in shortcodes,
100 * e.g. bfb_form_status="preview".
101 * @type int $resource_id Booking resource ID. Used when resolving the
102 * default custom form in legacy code.
103 * @type int $user_id Optional user ID. Mostly for MultiUser; legacy
104 * get_bk_option() already respects the current user.
105 * }
106 *
107 * @return string Booking form in shortcodes format.
108 */
109 public static function get_form( $args = array() ) {
110
111 return self::get_instance()->get_value_internal( 'form', $args );
112 }
113
114 /**
115 * Get "Content of booking fields data" template (shortcodes string)
116 * by form slug / ID.
117 *
118 * @param array $args See WPBC_BFB_Form_Loader::get_form().
119 *
120 * @return string Content template in shortcodes format.
121 */
122 public static function get_content( $args = array() ) {
123
124 return self::get_instance()->get_value_internal( 'content', $args );
125 }
126
127 /**
128 * Get both booking form and content template at once.
129 *
130 * @param array $args See WPBC_BFB_Form_Loader::get_form().
131 *
132 * @return array {
133 * @type string $form Booking form in shortcodes format.
134 * @type string $content "Content of booking fields data" in shortcodes format.
135 * @type string $source 'builder' or 'legacy'.
136 * @type string $form_slug Resolved form slug that was actually used.
137 * }
138 */
139 public static function get_pair( $args = array() ) {
140
141 return self::get_instance()->get_pair_internal( $args );
142 }
143
144 /**
145 * Internal router for single value.
146 *
147 * @param string $what 'form' or 'content'.
148 * @param array $args Arguments.
149 *
150 * @return string
151 */
152 protected function get_value_internal( $what, $args ) {
153
154 $pair = $this->get_pair_internal( $args );
155
156 if ( 'content' === $what ) {
157 return isset( $pair['content'] ) ? $pair['content'] : '';
158 }
159
160 return isset( $pair['form'] ) ? $pair['form'] : '';
161 }
162
163 /**
164 * Internal logic for resolving Builder vs legacy form.
165 *
166 * @param array $args Arguments.
167 *
168 * @return array See self::get_pair().
169 */
170 protected function get_pair_internal( $args ) {
171
172 $defaults = array(
173 'form_slug' => '',
174 'form_id' => 0,
175 'status' => 'published',
176 'bfb_form_status' => '',
177 'resource_id' => 0,
178 'user_id' => 0,
179 );
180
181 $args = wp_parse_args( $args, $defaults );
182
183 // Normalize types.
184 $args['form_id'] = isset( $args['form_id'] ) ? intval( $args['form_id'] ) : 0;
185 $args['resource_id'] = isset( $args['resource_id'] ) ? intval( $args['resource_id'] ) : 0;
186 $args['user_id'] = isset( $args['user_id'] ) ? intval( $args['user_id'] ) : 0;
187
188 // Map BFB alias into status if provided (e.g. bfb_form_status="preview").
189 if ( ! empty( $args['bfb_form_status'] ) ) {
190 $args['status'] = $args['bfb_form_status'];
191 }
192 unset( $args['bfb_form_status'] );
193
194 // Normalize status to a known set where possible (DB uses e.g. active/preview).
195 $args['status'] = $this->normalize_status( $args['status'] );
196
197 /**
198 * Filter the raw arguments before any resolution.
199 *
200 * Can be used to:
201 * - Map resource_id -> default form_slug.
202 * - Inject MultiUser scopes.
203 *
204 * @param array $args Arguments passed to the loader.
205 */
206 $args = apply_filters( 'wpbc_bfb_form_loader_args', $args );
207
208 // Resolve empty / "auto" slug into concrete value using existing legacy logic.
209 $resolved_slug = $this->resolve_form_slug( $args );
210 $args['form_slug'] = $resolved_slug;
211
212 // ---------------------------------------------------------------------
213 // 1. Try to load from Builder table via filter.
214 // ---------------------------------------------------------------------
215 $builder_pair = $this->maybe_load_from_builder( $args );
216
217 if ( is_array( $builder_pair ) ) {
218 $builder_form = isset( $builder_pair['form'] ) ? $builder_pair['form'] : '';
219 $builder_content = isset( $builder_pair['content'] ) ? $builder_pair['content'] : '';
220 $builder_settings_json = isset( $builder_pair['settings_json'] ) ? (string) $builder_pair['settings_json'] : '';
221
222 if ( ( '' !== trim( $builder_form ) ) || ( '' !== trim( $builder_content ) ) ) {
223 return array(
224 'form' => $builder_form,
225 'content' => $builder_content,
226 'settings_json' => $builder_settings_json,
227 'source' => 'builder',
228 'form_slug' => $resolved_slug,
229 );
230 }
231 }
232
233
234 // ---------------------------------------------------------------------
235 // 2. Fallback to legacy storage (options / usermeta).
236 // ---------------------------------------------------------------------
237 $legacy_pair = $this->load_from_legacy( $args );
238
239 return array(
240 'form' => isset( $legacy_pair['form'] ) ? $legacy_pair['form'] : '',
241 'content' => isset( $legacy_pair['content'] ) ? $legacy_pair['content'] : '',
242 'settings_json' => '', // legacy has no per-form settings_json yet.
243 'source' => 'legacy',
244 'form_slug' => $resolved_slug,
245 );
246 }
247
248 /**
249 * Normalize loader status to match DB semantics.
250 *
251 * Maps generic or legacy-like values (e.g. 'publish') to actual statuses
252 * used in booking_form_structures ('published', 'preview', 'draft', 'archived').
253 *
254 * @param string $status Raw status.
255 *
256 * @return string Normalized status.
257 */
258 protected function normalize_status( $status ) {
259
260 $status = strtolower( trim( (string) $status ) );
261
262 if ( '' === $status ) {
263 $status = 'published';
264 }
265
266 // Map some common aliases.
267 if ( in_array( $status, array( 'publish', 'published' ), true ) ) {
268 $status = 'published';
269 }
270
271 return $status;
272 }
273
274 /**
275 * Resolve empty or special slugs into real legacy form names.
276 *
277 * Examples:
278 * - '' or 'auto' => current default custom form for $resource_id (or 'standard').
279 * - 'standard' => keep as is.
280 *
281 * @param array $args Loader arguments.
282 *
283 * @return string Resolved form slug.
284 */
285 protected function resolve_form_slug( $args ) {
286
287 $slug = isset( $args['form_slug'] ) ? trim( (string) $args['form_slug'] ) : '';
288
289 if ( '' !== $slug && 'auto' !== $slug ) {
290 return $slug;
291 }
292
293 $resource_id = isset( $args['resource_id'] ) ? intval( $args['resource_id'] ) : 0;
294
295 // Existing logic for resolving default custom form for specific resource.
296 if ( $resource_id > 0 ) {
297 $default_slug = apply_bk_filter( 'wpbc_get_default_custom_form', 'standard', $resource_id );
298 } else {
299 $default_slug = 'standard';
300 }
301
302 if ( empty( $default_slug ) ) {
303 $default_slug = 'standard';
304 }
305
306 return $default_slug;
307 }
308
309 /**
310 * Try to get form + content from the new Builder storage.
311 *
312 * The actual lookup is delegated to a filter so that this class
313 * does not depend on any concrete BFB DB schema.
314 *
315 * If Builder is disabled, the table is missing or the requested slug/ID
316 * does not exist, the filter should return the $empty value.
317 *
318 * @param array $args Loader arguments.
319 *
320 * @return array {
321 * @type string $form Optional. Booking form in shortcodes format.
322 * @type string $content Optional. Content of booking fields data in shortcodes format.
323 * }
324 */
325 protected function maybe_load_from_builder( $args ) {
326
327 $empty = array(
328 'form' => '',
329 'content' => '',
330 'settings_json' => '',
331 );
332
333 /**
334 * Allows the Booking Form Builder module to provide form/content strings.
335 *
336 * Typical implementation in BFB (pseudo-code):
337 *
338 * function my_bfb_loader( $empty, $args ) {
339 * // 1) Verify Builder is active and table exists.
340 * // 2) If $args['form_id'] > 0:
341 * // SELECT row FROM {$wpdb->prefix}booking_form_structures
342 * // WHERE booking_form_id = $args['form_id']
343 * // AND status = $args['status'];
344 * // else:
345 * // SELECT row FROM {$wpdb->prefix}booking_form_structures
346 * // WHERE form_slug = $args['form_slug']
347 * // AND status = $args['status'];
348 * // 3) If found, return array(
349 * // 'form' => $row->advanced_form,
350 * // 'content' => $row->content_form,
351 * // );
352 * // 4) On any error or no row found, return $empty.
353 * }
354 *
355 * @param array $empty Default empty value.
356 * @param array $args Loader arguments (form_slug, form_id, status, resource_id, user_id).
357 */
358 $pair = apply_filters( 'wpbc_bfb_form_loader_from_builder', $empty, $args );
359
360 if ( ! is_array( $pair ) ) {
361 return $empty;
362 }
363
364 // Normalize to have both keys.
365 $pair = wp_parse_args(
366 $pair,
367 array(
368 'form' => '',
369 'content' => '',
370 'settings_json' => '',
371 )
372 );
373
374 return $pair;
375 }
376
377 /**
378 * Fallback loader that reads forms from legacy options (and MultiUser usermeta).
379 *
380 * It reuses the same mechanisms as your current code:
381 * - Default form:
382 * * booking_form / booking_form_show options.
383 * - Custom forms:
384 * * booking_forms_extended via:
385 * - apply_bk_filter( 'wpdev_get_booking_form', ... )
386 * - wpbc_get_custom_booking_form() for content.
387 * - Simple mode:
388 * * wpbc_simple_form__get_booking_form__as_shortcodes().
389 * * wpbc_simple_form__get_form_show__as_shortcodes().
390 *
391 * @param array $args Loader arguments.
392 *
393 * @return array {
394 * @type string $form Booking form (shortcodes).
395 * @type string $content Content of booking fields data (shortcodes).
396 * }
397 */
398 protected function load_from_legacy( $args ) {
399
400 $form_slug = isset( $args['form_slug'] ) ? (string) $args['form_slug'] : 'standard';
401
402 // -----------------------------------------------------------------
403 // 1. Advanced booking form (shortcodes).
404 // -----------------------------------------------------------------
405 $default_form = get_bk_option( 'booking_form' );
406 $form = '';
407
408 if ( 'standard' === $form_slug || '' === $form_slug ) {
409
410 // Default standard form.
411 $form = $default_form;
412
413 } else {
414
415 // Custom form via existing filter that reads booking_forms_extended.
416 $form = apply_bk_filter( 'wpdev_get_booking_form', $default_form, $form_slug );
417 }
418
419 // If still empty, build advanced form from Simple mode visual structure.
420 if ( ( '' === trim( $form ) ) && function_exists( 'wpbc_simple_form__get_booking_form__as_shortcodes' ) ) {
421 $form = wpbc_simple_form__get_booking_form__as_shortcodes();
422 }
423
424 // -----------------------------------------------------------------
425 // 2. "Content of booking fields data" (shortcodes).
426 // -----------------------------------------------------------------
427 $default_content = get_bk_option( 'booking_form_show' );
428 $content = '';
429
430 if ( 'standard' === $form_slug || '' === $form_slug ) {
431
432 // Default standard content.
433 $content = $default_content;
434
435 } else {
436
437 // Custom content via helper that reads booking_forms_extended[name]['content'].
438 if ( function_exists( 'wpbc_get_custom_booking_form' ) ) {
439 $content = wpbc_get_custom_booking_form(
440 $default_content,
441 $form_slug,
442 false, // Let helper call get_bk_option( 'booking_forms_extended' ) internally.
443 'content',
444 true // Replace simple HTML shortcodes <r>, <c>, <f>, <l>, <item>.
445 );
446 }
447 }
448
449 // If still empty, build content from Simple mode visual structure.
450 if ( ( '' === trim( $content ) ) && function_exists( 'wpbc_simple_form__get_form_show__as_shortcodes' ) ) {
451 $content = wpbc_simple_form__get_form_show__as_shortcodes();
452 }
453
454 /**
455 * Final filter over legacy values before returning.
456 *
457 * @param array $pair {
458 * @type string $form Booking form (shortcodes).
459 * @type string $content Content of booking fields data (shortcodes).
460 * }
461 * @param array $args Loader arguments.
462 */
463 $pair = apply_filters(
464 'wpbc_bfb_form_loader_legacy',
465 array(
466 'form' => $form,
467 'content' => $content,
468 ),
469 $args
470 );
471
472 // Ensure expected shape.
473 $pair = wp_parse_args(
474 $pair,
475 array(
476 'form' => '',
477 'content' => '',
478 )
479 );
480
481 return $pair;
482 }
483 }
484
485
486
487
488 /**
489 * Wrapper: get booking form (shortcodes) by slug/status.
490 *
491 * This is a convenience function for use in templates or older code.
492 *
493 * @param array $args See WPBC_BFB_Form_Loader::get_form().
494 *
495 * @return string
496 */
497 function wpbc_bfb_get_booking_form_source( $args = array() ) {
498
499 return WPBC_BFB_Form_Loader::get_form( $args );
500 }
501
502 /**
503 * Wrapper: get "Content of booking fields data" (shortcodes) by slug/status.
504 *
505 * @param array $args See WPBC_BFB_Form_Loader::get_form().
506 *
507 * @return string
508 */
509 function wpbc_bfb_get_booking_content_source( $args = array() ) {
510
511 return WPBC_BFB_Form_Loader::get_content( $args );
512 }
513
514 /**
515 * Wrapper: get both booking form and content template at once.
516 *
517 * @param array $args See WPBC_BFB_Form_Loader::get_form().
518 *
519 * @return array See WPBC_BFB_Form_Loader::get_pair().
520 */
521 function wpbc_bfb_get_booking_form_pair( $args = array() ) {
522
523 return WPBC_BFB_Form_Loader::get_pair( $args );
524 }
525