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

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

600 lines 22.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 exit; // Exit if accessed directly.
4 }
5
6 /**
7 * Helper functions for saving / loading between different versions of booking forms.
8 *
9 * This file manages Booking Form Builder form configuration stored in
10 * booking_form_structures. Legacy option readers live in the import-only
11 * module: includes/page-form-builder/legacy-import/.
12 *
13 * It introduces a normalized FormConfig array:
14 *
15 * [
16 * 'id' => booking_form_id,
17 * 'form_name' => 'standard' or custom key (maps to form_slug),
18 * 'engine' => 'bfb' | 'advanced_mode',
19 * 'engine_version' => '1.0',
20 * 'title' => string,
21 * 'description' => string,
22 * 'scope' => string,
23 * 'status' => string,
24 * 'is_default' => int (0|1),
25 * 'booking_resource_id' => int|null,
26 * 'owner_user_id' => int,
27 * 'structure_json' => string, // BFB structure or legacy stub/simple_form.
28 * 'settings' => array, // Decoded settings_json.
29 * 'advanced_form' => string, // Booking form shortcode configuration.
30 * 'content_form' => string, // Fields content template.
31 * 'picture_url' => string,
32 * 'created_at' => string,
33 * 'updated_at' => string,
34 * ]
35 *
36 * What we do:
37 * - Use booking_form_structures as canonical FormConfig storage.
38 * Each row carries form_slug, owner_user_id, engine, structure_json,
39 * settings_json, advanced_form and content_form.
40 *
41 * Main public API:
42 * - wpbc_form_config_load():
43 * Loads only from booking_form_structures.
44 *
45 * - wpbc_form_config_save():
46 * Writes only to booking_form_structures via
47 * WPBC_BFB_Form_Storage::save_form().
48 *
49 * @package Booking Calendar.
50 * @author wpdevelop, oplugins
51 * @web-site https://wpbookingcalendar.com/
52 * @email info@wpbookingcalendar.com
53 *
54 * @modified 2025-12-07
55 * @version 1.1
56 * @file ../includes/page-form-builder/save-load/bfb-form-manager.php
57 */
58
59 // == 1. Small JSON helper ==
60
61 /**
62 * Safely JSON-encode arbitrary data for storage.
63 *
64 * Wrapper around wp_json_encode() that guarantees a string return value.
65 * If encoding fails, an empty string is returned.
66 *
67 * @param mixed $data Arbitrary data to be encoded.
68 *
69 * @return string JSON string, or empty string on failure.
70 */
71 function wpbc_form_config__encode_json( $data ) {
72 $json = wp_json_encode( $data );
73
74 return ( false === $json ) ? '' : $json;
75 }
76
77 // == 2. Build FormConfig from DB row ==
78
79 /**
80 * Normalize raw DB row from booking_form_structures into a FormConfig array.
81 *
82 * This is the single place where columns from booking_form_structures are
83 * mapped into the canonical FormConfig keys used in the new Form Manager.
84 *
85 * @param object $row Database row object. Typically returned by
86 * WPBC_BFB_Form_Storage::get_current_form_by_key().
87 *
88 * @return array|null Normalized FormConfig array or null if the row is empty.
89 */
90 function wpbc_form_config__from_row( $row ) {
91
92 if ( ! $row ) {
93 return null;
94 }
95
96 $settings = array();
97 if ( ! empty( $row->settings_json ) ) {
98 $decoded = json_decode( $row->settings_json, true );
99 if ( is_array( $decoded ) ) {
100 $settings = $decoded;
101 }
102 }
103
104 return array(
105 'id' => (int) $row->booking_form_id,
106 'owner_user_id' => isset( $row->owner_user_id ) ? (int) $row->owner_user_id : 0,
107 // External API uses "form_name" (key used in Builder / shortcodes); in DB it is stored as form_slug.
108 'form_name' => isset( $row->form_slug ) ? (string) $row->form_slug : '',
109 'engine' => ! empty( $row->engine ) ? (string) $row->engine : 'bfb',
110 'engine_version' => ! empty( $row->engine_version ) ? (string) $row->engine_version : '1.0',
111 'title' => isset( $row->title ) ? (string) $row->title : '',
112 'description' => isset( $row->description ) ? (string) $row->description : '',
113 'scope' => isset( $row->scope ) ? (string) $row->scope : 'global',
114 'status' => isset( $row->status ) ? (string) $row->status : 'published',
115 'is_default' => isset( $row->is_default ) ? (int) $row->is_default : 0,
116 'booking_resource_id' => isset( $row->booking_resource_id ) ? (int) $row->booking_resource_id : null,
117 'structure_json' => isset( $row->structure_json ) ? (string) $row->structure_json : '',
118 'settings' => $settings,
119 'advanced_form' => isset( $row->advanced_form ) ? (string) $row->advanced_form : '',
120 'content_form' => isset( $row->content_form ) ? (string) $row->content_form : '',
121 'picture_url' => isset( $row->picture_url ) ? (string) $row->picture_url : '',
122 'created_at' => isset( $row->created_at ) ? (string) $row->created_at : '',
123 'updated_at' => isset( $row->updated_at ) ? (string) $row->updated_at : '',
124 );
125 }
126
127 // == 3. Detect if a form already exists in storage ==
128
129 /**
130 * Check if a FormConfig row already exists in storage.
131 *
132 * Currently this lookup is global per site (form_slug only, status 'published')
133 * and does not yet filter by owner_user_id. The user_id parameter is reserved
134 * for future MultiUser-aware lookups.
135 *
136 * @param string $form_key Unique form key/slug (e.g. 'standard').
137 * @param int $user_id Optional. Owner user ID. Default 0 (global, not used yet).
138 *
139 * @return bool True if a row exists, false otherwise.
140 */
141 function wpbc_form_config_exists_in_storage( $form_key, $user_id = 0 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
142
143 $form_key = (string) $form_key;
144 if ( '' === $form_key ) {
145 return false;
146 }
147
148 // Do not filter by owner_user_id for now – global per site, status = 'published'.
149 $row = WPBC_BFB_Form_Storage::get_current_form_by_key( $form_key, $user_id, 'published' );
150
151 return ( $row && ! empty( $row->booking_form_id ) );
152 }
153
154
155 // == 4. Public loader: DB only ==
156
157 /**
158 * Load unified FormConfig for a given form_key and optional owner.
159 *
160 * This is the main read API for booking form configuration:
161 * Loads only from the booking_form_structures table.
162 *
163 * @param string $form_key Form key. 'standard' or custom key. Default 'standard'.
164 * @param int $user_id Owner user ID for MultiUser environment. Default 0.
165 *
166 * @return array|null Normalized FormConfig array or null if nothing found.
167 */
168 function wpbc_form_config_load( $form_key = 'standard', $user_id = 0, $status = 'published', $is_fallback_to_legacy = false ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
169
170 $form_key = (string) $form_key;
171 if ( '' === $form_key ) {
172 $form_key = 'standard';
173
174 }
175
176 $row = WPBC_BFB_Form_Storage::get_current_form_by_key( $form_key, $user_id, $status );
177 if ( $row ) {
178 return wpbc_form_config__from_row( $row );
179 }
180
181 // Not found.
182 return null;
183 }
184
185 // == 5. Public saver: BFB (and later other engines) -> DB ==
186
187 /**
188 * Save BFB Form into DB - Main Save Function!
189 *
190 * Save unified FormConfig into booking_form_structures.
191 *
192 * Expected minimal keys in $form_config:
193 * - form_name
194 * - engine
195 * - structure_json (for BFB this is full Builder structure JSON)
196 * - advanced_form (booking form shortcode configuration)
197 * - content_form (fields data/content configuration)
198 *
199 * Behaviour:
200 * - Always writes to booking_form_structures via WPBC_BFB_Form_Storage::save_form().
201 * - Uses form_slug = form_name.
202 * - Uses status from $form_config['status'] or 'published' by default.
203 *
204 * @param array $form_config Normalized FormConfig array.
205 * @param array $args {
206 * Optional. Additional saving arguments.
207 *
208 * @type bool $sync_legacy Deprecated. Ignored. BFB does not sync legacy options.
209 * }
210 *
211 * @return int|false booking_form_id on success, or false on failure.
212 */
213 function wpbc_form_config_save( array $form_config, array $args = array() ) {
214
215 $args = wp_parse_args(
216 $args,
217 array(
218 'sync_legacy' => false,
219 )
220 );
221
222 $form_name = isset( $form_config['form_name'] ) ? (string) $form_config['form_name'] : '';
223 if ( '' === $form_name ) {
224 $form_name = 'standard';
225 }
226
227 $engine = isset( $form_config['engine'] ) ? (string) $form_config['engine'] : 'bfb';
228 $engine_version = isset( $form_config['engine_version'] ) ? (string) $form_config['engine_version'] : '1.0';
229
230 $structure_json = isset( $form_config['structure_json'] ) ? (string) $form_config['structure_json'] : '';
231 $settings = isset( $form_config['settings'] ) ? $form_config['settings'] : array();
232 if ( function_exists( 'wpbc_bfb_settings__strip_form_style_options_from_form_settings' ) ) {
233 $settings = wpbc_bfb_settings__strip_form_style_options_from_form_settings( $settings );
234 }
235 $settings_json = wpbc_form_config__encode_json( $settings ); // Returns '' on error/empty.
236
237 $advanced_form = isset( $form_config['advanced_form'] ) ? (string) $form_config['advanced_form'] : '';
238 $content_form = isset( $form_config['content_form'] ) ? (string) $form_config['content_form'] : '';
239
240 if ( '' === $structure_json && 'bfb' === $engine ) {
241 // For BFB we expect real structure JSON.
242 return false;
243 }
244
245 $owner_user_id = isset( $form_config['owner_user_id'] ) ? (int) $form_config['owner_user_id'] : 0;
246
247 $storage_data = array(
248 // New schema uses form_slug; we map form_name -> form_slug.
249 'form_slug' => $form_name,
250
251 'title' => isset( $form_config['title'] ) ? (string) $form_config['title'] : $form_name,
252 'description' => isset( $form_config['description'] ) ? (string) $form_config['description'] : '',
253 'scope' => isset( $form_config['scope'] ) ? (string) $form_config['scope'] : 'global',
254
255 'booking_resource_id' => isset( $form_config['booking_resource_id'] ) ? (int) $form_config['booking_resource_id'] : null,
256 'owner_user_id' => ! empty( $owner_user_id ) ? $owner_user_id : 0,
257 'is_default' => ! empty( $form_config['is_default'] ) ? 1 : 0,
258 'status' => isset( $form_config['status'] ) ? (string) $form_config['status'] : 'published',
259
260 'engine' => $engine,
261 'engine_version' => $engine_version,
262 'structure_json' => $structure_json,
263 'settings_json' => $settings_json,
264 'advanced_form' => $advanced_form,
265 'content_form' => $content_form,
266
267 // Optional picture/preview image URL.
268 'picture_url' => isset( $form_config['picture_url'] ) ? (string) $form_config['picture_url'] : null,
269 );
270
271 $booking_form_id = WPBC_BFB_Form_Storage::save_form( $storage_data );
272
273 return $booking_form_id;
274 }
275
276 /**
277 * Save the Standard booking form as a BFB canonical form record.
278 *
279 * This is used by activation/setup paths that previously wrote directly into
280 * legacy options such as booking_form and booking_form_show.
281 *
282 * @param string $advanced_form Advanced booking form shortcodes.
283 * @param string $content_form Content of booking fields data shortcodes.
284 * @param int $owner_user_id Optional MultiUser owner ID.
285 * @param array $args Optional args: visual_form_structure, form_name, title.
286 *
287 * @return int|false booking_form_id on success, or false on failure.
288 */
289 function wpbc_bfb_save_standard_form_from_advanced_mode( $advanced_form, $content_form, $owner_user_id = 0, $args = array() ) {
290
291 $args = wp_parse_args(
292 $args,
293 array(
294 'visual_form_structure' => false,
295 'form_name' => 'standard',
296 'title' => __( 'Standard', 'booking' ),
297 )
298 );
299
300 $structure_arr = array();
301 $engine = 'advanced_mode';
302
303 if ( is_array( $args['visual_form_structure'] ) && function_exists( 'wpbc_simple_form__export_to_bfb_structure' ) ) {
304 $structure_arr = wpbc_simple_form__export_to_bfb_structure( $args['visual_form_structure'] );
305 if ( is_array( $structure_arr ) && ! empty( $structure_arr ) ) {
306 $engine = 'bfb';
307 }
308 }
309
310 $form_config = array(
311 'form_name' => (string) $args['form_name'],
312 'engine' => $engine,
313 'engine_version' => '1.0',
314 'structure_json' => wpbc_form_config__encode_json( $structure_arr ),
315 'settings' => array(),
316 'advanced_form' => (string) $advanced_form,
317 'content_form' => (string) $content_form,
318 'owner_user_id' => max( 0, (int) $owner_user_id ),
319 'title' => (string) $args['title'],
320 'description' => '',
321 'scope' => 'global',
322 'status' => 'published',
323 'is_default' => 1,
324 'booking_resource_id' => null,
325 );
326
327 return wpbc_form_config_save( $form_config, array( 'sync_legacy' => false ) );
328 }
329
330
331 /**
332 * Delete all BFB forms owned by one regular MultiUser account.
333 *
334 * This belongs to the full owner-settings deletion lifecycle. Merely switching
335 * an owner Off must not call it, so the user's Builder forms remain available
336 * after reactivation.
337 *
338 * @param int $owner_user_id Owner user ID.
339 *
340 * @return bool
341 */
342 function wpbc_bfb_delete_forms_for_owner( $owner_user_id ) {
343
344 $owner_user_id = absint( $owner_user_id );
345 if ( $owner_user_id <= 0 ) {
346 return false;
347 }
348 if ( function_exists( 'wpbc_is_table_exists' ) && ! wpbc_is_table_exists( 'booking_form_structures' ) ) {
349 return true;
350 }
351
352 global $wpdb;
353
354 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
355 $deleted = $wpdb->delete(
356 $wpdb->prefix . 'booking_form_structures',
357 array( 'owner_user_id' => $owner_user_id ),
358 array( '%d' )
359 );
360
361 return ( false !== $deleted );
362 }
363
364
365 // == Default Load Form !) ==
366
367 /**
368 * Get default form key used by the Form Builder.
369 *
370 * Centralizes the default key for the main booking form, currently 'standard'.
371 *
372 * @return string Default form key.
373 */
374 function wpbc_bfb_get_default_form_key() {
375
376 if ( isset( $_GET['form_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
377 $form_name = sanitize_text_field( wp_unslash( $_GET['form_name'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
378 if ( '' !== $form_name ) {
379 return $form_name;
380 }
381 }
382
383 return 'standard';
384 }
385
386 /**
387 * Output AJAX boot configuration for the Form Builder.
388 *
389 * Prints a small inline script that exposes WPBC_BFB_Ajax on window. This
390 * configuration is consumed by the JS Builder to perform save / load
391 * requests via admin-ajax.php.
392 *
393 * Should be called only on the Form Builder admin page.
394 *
395 * @return void
396 */
397 function wpbc_bfb_output_ajax_boot_config() {
398
399 $form_key = wpbc_bfb_get_default_form_key(); // 'standard' – or detect from current screen / URL / selection.
400
401 $ajax_config = array(
402 'url' => admin_url( 'admin-ajax.php' ),
403 'nonce_save' => wp_create_nonce( 'wpbc_bfb_form_save' ),
404 'nonce_load' => wp_create_nonce( 'wpbc_bfb_form_load' ),
405 'nonce_create' => wp_create_nonce( 'wpbc_bfb_form_create' ),
406 'nonce_list' => wp_create_nonce( 'wpbc_bfb_form_list' ),
407 'form_name' => $form_key, // info: INIT_FORM_LOAD.
408 'engine' => 'bfb',
409 'engine_version' => '1.0',
410 // Initial load behavior.
411 'initial_load' => 'ajax', // 'ajax' / 'example' / 'blank'.
412 'initial_load_fallback' => 'example', // 'example' / 'blank'.
413 'load_action' => 'WPBC_AJX_BFB_LOAD_FORM_CONFIG',
414 );
415 ?>
416 <script type="text/javascript"> window.WPBC_BFB_Ajax = <?php echo wp_json_encode( $ajax_config ); ?>; </script>
417 <?php
418 }
419
420 /**
421 * Get the "advanced" booking form configuration for a given form key.
422 *
423 * This is a thin convenience wrapper around wpbc_form_config_load() that
424 * returns only the advanced_form string.
425 *
426 * @param string $form_key Form key. Default 'standard'.
427 *
428 * @return string Advanced form configuration or empty string if not found.
429 */
430 function wpbc_get_form_advanced( $form_key = 'standard' ) {
431 $cfg = wpbc_form_config_load( $form_key );
432
433 return ( ! empty( $cfg['advanced_form'] ) ? $cfg['advanced_form'] : '' );
434 }
435
436 /**
437 * Get the "content" (fields data) configuration for a given form key.
438 *
439 * This is a thin convenience wrapper around wpbc_form_config_load() that
440 * returns only the content_form string.
441 *
442 * @param string $form_key Form key. Default 'standard'.
443 *
444 * @return string Content form configuration or empty string if not found.
445 */
446 function wpbc_get_form_content( $form_key = 'standard' ) {
447 $cfg = wpbc_form_config_load( $form_key );
448
449 return ( ! empty( $cfg['content_form'] ) ? $cfg['content_form'] : '' );
450 }
451
452
453
454 /**
455 * Bridge: implement wpbc_bfb_form_loader_from_builder filter using
456 * booking_form_structures table.
457 *
458 * This function is responsible ONLY for pulling already exported
459 * shortcodes/markup from the BFB storage:
460 * - advanced_form -> "booking form" shortcodes.
461 * - content_form -> "Content of booking fields data" shortcodes.
462 *
463 * It does NOT try to interpret structure_json; that is the Builder's job.
464 *
465 * @since 11.0.0
466 */
467
468
469 /**
470 * Load form/content from booking_form_structures for the Form Loader.
471 *
472 * Expected $args keys (normalized by WPBC_BFB_Form_Loader):
473 * - form_slug : string Logical form key (e.g. 'standard').
474 * - form_id : int booking_form_id (optional, takes precedence).
475 * - status : string 'published', 'preview', 'draft', ...
476 * - resource_id : int Booking resource ID (currently informational).
477 * - user_id : int Current user ID (reserved for future MultiUser).
478 *
479 * @param array $empty Default empty pair: ['form' => '', 'content' => ''].
480 * @param array $args Loader arguments.
481 *
482 * @return array Pair ['form' => string, 'content' => string].
483 */
484 function wpbc_bfb__load_from_bfb_table( $empty, $args ) {
485
486 global $wpdb;
487
488 // Ensure we have a consistent empty array.
489 if ( ! is_array( $empty ) ) {
490 $empty = array(
491 'form' => '',
492 'content' => '',
493 );
494 }
495
496 // Normalized args (defensive).
497 $form_id = isset( $args['form_id'] ) ? intval( $args['form_id'] ) : 0;
498 $form_slug = isset( $args['form_slug'] ) ? (string) $args['form_slug'] : '';
499 $status = isset( $args['status'] ) ? strtolower( trim( (string) $args['status'] ) ) : 'published';
500
501 // FixIn: 2026-03-08.
502 $has_user_key = array_key_exists( 'user_id', $args );
503 $owner_user_id = $has_user_key ? max( 0, (int) $args['user_id'] ) : 0;
504
505 $has_owner_key = array_key_exists( 'owner_user_id', $args );
506 $owner_user_id = $has_owner_key ? max( $owner_user_id, (int) $args['owner_user_id'] ) : $owner_user_id;
507
508 $has_owner_key = $has_user_key || $has_owner_key;
509
510 // -----------------------------------------------------------------
511 // Normalize status to match DB semantics.
512 // booking_form_structures uses values like: active, preview, draft, archived.
513 // -----------------------------------------------------------------
514 if ( '' === $status ) {
515 $status = 'published';
516 } elseif ( in_array( $status, array( 'publish', 'published' ), true ) ) {
517 $status = 'published';
518 }
519
520
521 // Nothing to do if we have neither an ID nor a slug.
522 if ( $form_id <= 0 && '' === $form_slug ) {
523 return $empty;
524 }
525
526 // Optional: if helper exists, ensure table really exists.
527 if ( function_exists( 'wpbc_is_table_exists' ) && ! wpbc_is_table_exists( 'booking_form_structures' ) ) {
528 return $empty;
529 }
530
531 // -----------------------------------------------------------------
532 // Build SELECT depending on whether form_id is available.
533 // -----------------------------------------------------------------
534 if ( $form_id > 0 ) {
535 // Prefer direct lookup by primary key + status.
536 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
537 $row = $wpdb->get_row( $wpdb->prepare( "SELECT advanced_form, content_form, settings_json
538 FROM {$wpdb->prefix}booking_form_structures
539 WHERE booking_form_id = %d
540 AND status = %s
541 LIMIT 1", $form_id, $status ) );
542 } else {
543
544 if ( $has_owner_key && $owner_user_id > 0 ) {
545
546 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
547 $row = $wpdb->get_row( $wpdb->prepare( "SELECT advanced_form, content_form, settings_json
548 FROM {$wpdb->prefix}booking_form_structures
549 WHERE form_slug = %s
550 AND status = %s
551 AND owner_user_id = %d
552 ORDER BY version DESC, updated_at DESC, booking_form_id DESC
553 LIMIT 1", $form_slug, $status, $owner_user_id ) );
554
555 } elseif ( $has_owner_key ) {
556
557 // global: 0 or NULL
558 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
559 $row = $wpdb->get_row( $wpdb->prepare( "SELECT advanced_form, content_form, settings_json
560 FROM {$wpdb->prefix}booking_form_structures
561 WHERE form_slug = %s
562 AND status = %s
563 AND ( owner_user_id = 0 OR owner_user_id IS NULL )
564 ORDER BY version DESC, updated_at DESC, booking_form_id DESC
565 LIMIT 1", $form_slug, $status ) );
566
567 } else {
568
569 // Legacy behavior: no owner filter at all.
570 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
571 $row = $wpdb->get_row( $wpdb->prepare( "SELECT advanced_form, content_form, settings_json
572 FROM {$wpdb->prefix}booking_form_structures
573 WHERE form_slug = %s
574 AND status = %s
575 LIMIT 1", $form_slug, $status ) );
576 }
577 }
578
579
580 if ( ! $row ) {
581 return $empty;
582 }
583
584 // Ensure we always return both keys, even if one is empty.
585 $form = isset( $row->advanced_form ) ? (string) $row->advanced_form : '';
586 $content = isset( $row->content_form ) ? (string) $row->content_form : '';
587 $settings_json = isset( $row->settings_json ) ? (string) $row->settings_json : '';
588
589 return array(
590 'form' => $form,
591 'content' => $content,
592 'settings_json' => $settings_json,
593 );
594 }
595
596 /**
597 * Attach loader to wpbc_bfb_form_loader_from_builder.
598 */
599 add_filter( 'wpbc_bfb_form_loader_from_builder', 'wpbc_bfb__load_from_bfb_table', 10, 2 );
600