PluginProbe
Booking Calendar / 11.5
Booking Calendar v11.5
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 / assets / template-records / bfb-activate-templates.php

bfb-activate-templates.php in Booking Calendar 11.5, at includes/page-form-builder/assets/template-records/bfb-activate-templates.php

544 lines 17.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Booking Form Builder - Bundled templates activation/update helpers.
4 *
5 * Responsibilities:
6 * - Register bundled BFB templates.
7 * - Seed missing template records into wp_booking_form_structures.
8 * - Track per-template seed versions.
9 * - Optionally update bundled template rows in future releases.
10 *
11 * @package Booking Calendar
12 * @author wpdevelop, oplugins
13 * @web-site https://wpbookingcalendar.com/
14 * @email [email protected]
15 *
16 * @since 11.0.x
17 * @file ../includes/page-form-builder/assets/template-records/bfb-activate-templates.php
18 * @modified 2026-03-09
19 */
20
21 if ( ! defined( 'ABSPATH' ) ) {
22 exit; // Exit if accessed directly.
23 }
24
25 /**
26 * Return option key storing bundled templates seed state.
27 *
28 * Stored value example:
29 * array(
30 * 'service_appointments' => '11.0.0',
31 * 'contact_inquiry' => '11.1.0',
32 * )
33 *
34 * @return string
35 */
36 function wpbc_bfb_activation__get_templates_seed_state_option_key() {
37 return 'wpbc_bfb_templates_seed_state';
38 }
39
40 /**
41 * Get stored bundled templates seed state.
42 *
43 * @return array
44 */
45 function wpbc_bfb_activation__get_templates_seed_state() {
46
47 $state = get_option( wpbc_bfb_activation__get_templates_seed_state_option_key(), array() );
48
49 return ( is_array( $state ) ) ? $state : array();
50 }
51
52 /**
53 * Save bundled templates seed state.
54 *
55 * @param array $state Seed state.
56 *
57 * @return void
58 */
59 function wpbc_bfb_activation__save_templates_seed_state( $state ) {
60
61 if ( ! is_array( $state ) ) {
62 $state = array();
63 }
64
65 update_option( wpbc_bfb_activation__get_templates_seed_state_option_key(), $state );
66 }
67
68 /**
69 * Delete bundled templates seed state.
70 *
71 * @return void
72 */
73 function wpbc_bfb_activation__delete_templates_seed_state() {
74 delete_bk_option( wpbc_bfb_activation__get_templates_seed_state_option_key() );
75 }
76
77 /**
78 * Return absolute path to bundled template records directory.
79 *
80 * @return string
81 */
82 function wpbc_bfb_activation__get_templates_dir_path() {
83
84 // return dirname( __FILE__ ); // . '/../assets/template-records'; //.
85
86 return WPBC_PLUGIN_DIR . '/includes/page-form-builder/assets/template-records';
87 }
88
89 /**
90 * Return bundled template registry.
91 *
92 * Each item must return:
93 * array(
94 * 'template_key' => 'service_appointments',
95 * 'seed_version' => '11.0.0',
96 * 'sync_mode' => 'insert_only', // or 'upsert'
97 * 'record' => array( ... DB columns ... ),
98 * )
99 *
100 * Notes:
101 * - template_key must stay stable across releases.
102 * - seed_version is compared against stored seed state for this template.
103 * - sync_mode:
104 * - insert_only = insert once if missing, never overwrite existing row.
105 * - upsert = insert if missing, update existing row when seed_version increases.
106 *
107 * @return array
108 */
109 function wpbc_bfb_activation__get_templates_registry() {
110
111 $templates = array();
112 $template_files = array(
113
114 // Contact Forms.
115 wpbc_bfb_activation__get_templates_dir_path() . '/contact_form_simple.php',
116 wpbc_bfb_activation__get_templates_dir_path() . '/technical_support_form.php',
117 wpbc_bfb_activation__get_templates_dir_path() . '/inquiry_form_simple.php',
118
119 // Advanced Not Synced Forms.
120 wpbc_bfb_activation__get_templates_dir_path() . '/dates_advanced_2_steps_wizard_with_hints.php',
121 wpbc_bfb_activation__get_templates_dir_path() . '/dates_advanced_form_with_hints.php',
122
123 // Time Slots.
124 wpbc_bfb_activation__get_templates_dir_path() . '/time_slots_start_end_times_1_hour_selection.php',
125 wpbc_bfb_activation__get_templates_dir_path() . '/time_slots_start_duration_times_selection.php',
126 wpbc_bfb_activation__get_templates_dir_path() . '/time_slots_30_min_2_steps_wizard.php',
127 wpbc_bfb_activation__get_templates_dir_path() . '/time_slots_20_min_2_steps_wizard.php',
128
129 // Time - Service Appointments.
130 wpbc_bfb_activation__get_templates_dir_path() . '/time_appointments_3_steps_wizard.php',
131 wpbc_bfb_activation__get_templates_dir_path() . '/time_appointments_2_steps_vertical_layout.php',
132 wpbc_bfb_activation__get_templates_dir_path() . '/time_appointments_2_steps_wizard.php',
133
134 // Full Day - Booking Forms.
135 wpbc_bfb_activation__get_templates_dir_path() . '/dates_form_with_3_columns_layout.php',
136 wpbc_bfb_activation__get_templates_dir_path() . '/dates_form_with_calendar_next_to_form.php',
137 wpbc_bfb_activation__get_templates_dir_path() . '/dates_form_with_vertical_layout.php',
138 wpbc_bfb_activation__get_templates_dir_path() . '/dates_form_wizard_2_steps.php',
139
140 // Hints
141 wpbc_bfb_activation__get_templates_dir_path() . '/time_slots_20_min_3_steps_review_with_hints.php',
142 wpbc_bfb_activation__get_templates_dir_path() . '/time_appointments_3_steps_review_with_hints.php',
143 wpbc_bfb_activation__get_templates_dir_path() . '/dates_advanced_3_steps_review_with_hints.php',
144 wpbc_bfb_activation__get_templates_dir_path() . '/dates_2_columns_sidebar_hints.php',
145
146 // Example future records:
147 // wpbc_bfb_activation__get_templates_dir_path() . '/template-contact-inquiry.php',
148 // wpbc_bfb_activation__get_templates_dir_path() . '/template-event-registration.php',
149 );
150
151 // Keep private live-demo fixtures out of customer template libraries.
152 if ( function_exists( 'wpbc_is_this_demo' ) && wpbc_is_this_demo() ) {
153 $template_files = array_merge(
154 $template_files,
155 array(
156 wpbc_bfb_activation__get_templates_dir_path() . '/demo_personal.php',
157 wpbc_bfb_activation__get_templates_dir_path() . '/demo_business_small.php',
158 wpbc_bfb_activation__get_templates_dir_path() . '/demo_business_medium.php',
159 wpbc_bfb_activation__get_templates_dir_path() . '/demo_business_large.php',
160 wpbc_bfb_activation__get_templates_dir_path() . '/demo_multiuser.php',
161 wpbc_bfb_activation__get_templates_dir_path() . '/demo_multiuser_owner_1.php',
162 wpbc_bfb_activation__get_templates_dir_path() . '/demo_multiuser_owner_2.php',
163 wpbc_bfb_activation__get_templates_dir_path() . '/demo_multiuser_owner_3.php',
164 )
165 );
166 }
167
168 /*
169 * Template cards are listed newest-first, with the row ID as the final
170 * tie-breaker. Seed the preferred Appointment flow after every other bundled
171 * template so it is the first matching card after a clean activation.
172 */
173 $template_files[] = wpbc_bfb_activation__get_templates_dir_path() . '/appointments_services_flow.php';
174
175 foreach ( $template_files as $template_file ) {
176 if ( file_exists( $template_file ) ) {
177 $template_config = require $template_file;
178
179 if ( is_array( $template_config ) ) {
180 $templates[] = $template_config;
181 }
182 }
183 }
184
185 /**
186 * Allow third-party code or future modules to register bundled templates.
187 */
188 $templates = apply_filters( 'wpbc_bfb_activation__templates_registry', $templates );
189
190 return $templates;
191 }
192
193 /**
194 * Add default form appearance settings to bundled template settings_json.
195 *
196 * Individual templates can override any key in their own settings_json; this only fills missing values.
197 *
198 * @param string $settings_json Template settings JSON.
199 *
200 * @return string
201 */
202 function wpbc_bfb_activation__add_default_form_appearance_settings( $settings_json ) {
203
204 $settings = array();
205 if ( is_string( $settings_json ) && '' !== trim( $settings_json ) ) {
206 $decoded = json_decode( (string) $settings_json, true );
207 if ( is_array( $decoded ) ) {
208 $settings = $decoded;
209 }
210 }
211
212 if ( empty( $settings['options'] ) || ! is_array( $settings['options'] ) ) {
213 $settings['options'] = array();
214 }
215
216 if ( function_exists( 'wpbc_bfb_settings__strip_form_style_options_from_form_settings' ) ) {
217 $settings = wpbc_bfb_settings__strip_form_style_options_from_form_settings( $settings );
218 }
219
220 if ( empty( $settings['css_vars'] ) || ! is_array( $settings['css_vars'] ) ) {
221 $settings['css_vars'] = array();
222 }
223
224 if ( empty( $settings['bfb_options'] ) || ! is_array( $settings['bfb_options'] ) ) {
225 $settings['bfb_options'] = array( 'advanced_mode_source' => 'builder' );
226 }
227
228 return function_exists( 'wpbc_form_config__encode_json' )
229 ? wpbc_form_config__encode_json( $settings )
230 : wp_json_encode( $settings );
231 }
232
233 /**
234 * Normalize bundled template config.
235 *
236 * @param array $template_config Raw template config.
237 *
238 * @return array
239 */
240 function wpbc_bfb_activation__normalize_template_config( $template_config ) {
241
242 $template_config = wp_parse_args(
243 $template_config,
244 array(
245 'template_key' => '',
246 'seed_version' => '1.0.0',
247 'sync_mode' => 'insert_only',
248 'record' => array(),
249 )
250 );
251
252 $template_config['template_key'] = sanitize_key( $template_config['template_key'] );
253 $template_config['seed_version'] = (string) $template_config['seed_version'];
254 $template_config['sync_mode'] = ( 'upsert' === $template_config['sync_mode'] ) ? 'upsert' : 'insert_only';
255
256 $template_config['record'] = wp_parse_args(
257 $template_config['record'],
258 array(
259 'form_slug' => '',
260 'status' => 'template',
261 'scope' => 'global',
262 'version' => 1,
263 'booking_resource_id' => null,
264 'owner_user_id' => 0,
265 'engine' => 'bfb',
266 'engine_version' => '1.0',
267 'structure_json' => '',
268 'settings_json' => '',
269 'advanced_form' => '',
270 'content_form' => '',
271 'is_default' => 0,
272 'title' => '',
273 'description' => '',
274 'picture_url' => '',
275 )
276 );
277
278 $template_config['record']['form_slug'] = sanitize_title( $template_config['record']['form_slug'] );
279 $template_config['record']['status'] = sanitize_key( $template_config['record']['status'] );
280 $template_config['record']['scope'] = sanitize_key( $template_config['record']['scope'] );
281 $template_config['record']['version'] = (int) $template_config['record']['version'];
282 $template_config['record']['owner_user_id'] = (int) $template_config['record']['owner_user_id'];
283 $template_config['record']['is_default'] = (int) $template_config['record']['is_default'];
284 $template_config['record']['engine'] = (string) $template_config['record']['engine'];
285 $template_config['record']['engine_version'] = (string) $template_config['record']['engine_version'];
286 $template_config['record']['title'] = (string) $template_config['record']['title'];
287 $template_config['record']['description'] = (string) $template_config['record']['description'];
288 $template_config['record']['picture_url'] = (string) $template_config['record']['picture_url'];
289 $template_config['record']['settings_json'] = wpbc_bfb_activation__add_default_form_appearance_settings( (string) $template_config['record']['settings_json'] );
290
291 if ( null !== $template_config['record']['booking_resource_id'] ) {
292 $template_config['record']['booking_resource_id'] = (int) $template_config['record']['booking_resource_id'];
293 }
294
295 return $template_config;
296 }
297
298 /**
299 * Find existing bundled template row by unique fields.
300 *
301 * @param array $record Template DB record.
302 *
303 * @return int
304 */
305 function wpbc_bfb_activation__find_existing_template_id( $record ) {
306
307 global $wpdb;
308
309 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
310 $existing_id = (int) $wpdb->get_var( $wpdb->prepare(
311 "SELECT booking_form_id
312 FROM {$wpdb->prefix}booking_form_structures
313 WHERE form_slug = %s
314 AND status = %s
315 AND owner_user_id = %d
316 LIMIT 1",
317 $record['form_slug'],
318 $record['status'],
319 (int) $record['owner_user_id']
320 ) );
321
322 return $existing_id;
323 }
324
325 /**
326 * Build DB row for insert/update.
327 *
328 * @param array $record Template DB record.
329 *
330 * @return array
331 */
332 function wpbc_bfb_activation__build_template_db_row( $record ) {
333
334 $now = current_time( 'mysql' );
335
336 return array(
337 'form_slug' => $record['form_slug'],
338 'status' => $record['status'],
339 'scope' => $record['scope'],
340 'version' => (int) $record['version'],
341 'booking_resource_id' => $record['booking_resource_id'],
342 'owner_user_id' => (int) $record['owner_user_id'],
343 'engine' => $record['engine'],
344 'engine_version' => $record['engine_version'],
345 'structure_json' => $record['structure_json'],
346 'settings_json' => $record['settings_json'],
347 'advanced_form' => $record['advanced_form'],
348 'content_form' => $record['content_form'],
349 'is_default' => (int) $record['is_default'],
350 'title' => $record['title'],
351 'description' => $record['description'],
352 'picture_url' => $record['picture_url'],
353 'updated_at' => $now,
354 'updated_by' => 0,
355 );
356 }
357
358 /**
359 * Insert bundled template record.
360 *
361 * @param array $record Template DB record.
362 *
363 * @return bool
364 */
365 function wpbc_bfb_activation__insert_template_record( $record ) {
366
367 global $wpdb;
368
369 $table_name = $wpdb->prefix . 'booking_form_structures';
370 $data = wpbc_bfb_activation__build_template_db_row( $record );
371
372 $data['created_at'] = $data['updated_at'];
373 $data['created_by'] = 0;
374 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
375 $inserted = $wpdb->insert( $table_name, $data );
376
377 return ( false !== $inserted );
378 }
379
380 /**
381 * Update bundled template record by row ID.
382 *
383 * @param int $booking_form_id Existing row ID.
384 * @param array $record Template DB record.
385 *
386 * @return bool
387 */
388 function wpbc_bfb_activation__update_template_record( $booking_form_id, $record ) {
389
390 global $wpdb;
391
392 $table_name = $wpdb->prefix . 'booking_form_structures';
393 $booking_form_id = (int) $booking_form_id;
394 $data = wpbc_bfb_activation__build_template_db_row( $record );
395
396 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
397 $updated = $wpdb->update(
398 $table_name,
399 $data,
400 array(
401 'booking_form_id' => $booking_form_id,
402 )
403 );
404
405 return ( false !== $updated );
406 }
407
408 /**
409 * Sync one bundled template.
410 *
411 * @param array $template_config Template config.
412 * @param array $seed_state Current stored seed state.
413 *
414 * @return array
415 */
416 /**
417 * Sync one bundled template.
418 *
419 * @param array $template_config Template config.
420 * @param array $seed_state Current stored seed state.
421 *
422 * @return array
423 */
424 function wpbc_bfb_activation__sync_one_template( $template_config, $seed_state ) {
425
426 $result = array(
427 'ok' => false,
428 'seed_state' => $seed_state,
429 );
430
431 $template_config = wpbc_bfb_activation__normalize_template_config( $template_config );
432
433 if ( empty( $template_config['template_key'] ) ) {
434 return $result;
435 }
436
437 if ( empty( $template_config['record']['form_slug'] ) ) {
438 return $result;
439 }
440
441 $template_key = $template_config['template_key'];
442 $seed_version = $template_config['seed_version'];
443 $sync_mode = $template_config['sync_mode'];
444 $record = $template_config['record'];
445 $stored_version = isset( $seed_state[ $template_key ] ) ? (string) $seed_state[ $template_key ] : '';
446 $existing_row_id = wpbc_bfb_activation__find_existing_template_id( $record );
447
448 // Already synced for this template version and DB row still exists.
449 if (
450 ( $existing_row_id > 0 ) &&
451 ( ! empty( $stored_version ) ) &&
452 version_compare( $stored_version, $seed_version, '>=' )
453 ) {
454 $result['ok'] = true;
455 return $result;
456 }
457
458 // Insert if missing.
459 if ( $existing_row_id <= 0 ) {
460 $result['ok'] = wpbc_bfb_activation__insert_template_record( $record );
461
462 if ( $result['ok'] ) {
463 $result['seed_state'][ $template_key ] = $seed_version;
464 }
465
466 return $result;
467 }
468
469 // Existing row found.
470 if ( 'upsert' === $sync_mode ) {
471 $result['ok'] = wpbc_bfb_activation__update_template_record( $existing_row_id, $record );
472 } else {
473 // insert_only mode: mark as synced, do not overwrite existing row.
474 $result['ok'] = true;
475 }
476
477 if ( $result['ok'] ) {
478 $result['seed_state'][ $template_key ] = $seed_version;
479 }
480
481 return $result;
482 }
483
484 /**
485 * Seed bundled BFB templates.
486 *
487 * Runs both:
488 * - after table creation,
489 * - when table already exists.
490 *
491 * @return void
492 */
493 /**
494 * Seed bundled BFB templates.
495 *
496 * Runs both:
497 * - after table creation,
498 * - when table already exists.
499 *
500 * @return void
501 */
502 function wpbc_bfb_activation__seed_templates() {
503
504 if ( ! wpbc_is_table_exists( 'booking_form_structures' ) ) {
505 return;
506 }
507
508 $templates = wpbc_bfb_activation__get_templates_registry();
509 if ( empty( $templates ) || ! is_array( $templates ) ) {
510 return;
511 }
512
513 $seed_state = wpbc_bfb_activation__get_templates_seed_state();
514 $is_changed = false;
515
516 foreach ( $templates as $template_config ) {
517
518 $seed_state_before = $seed_state;
519
520 $sync_result = wpbc_bfb_activation__sync_one_template( $template_config, $seed_state );
521 $seed_state = $sync_result['seed_state'];
522
523 if ( $seed_state !== $seed_state_before ) {
524 $is_changed = true;
525 }
526 }
527
528 if ( $is_changed ) {
529 wpbc_bfb_activation__save_templates_seed_state( $seed_state );
530 }
531 }
532 add_action( 'wpbc_bfb_activation__form_structures_table__after_create', 'wpbc_bfb_activation__seed_templates' );
533 add_action( 'wpbc_bfb_activation__form_structures_table__table_already_exists', 'wpbc_bfb_activation__seed_templates' );
534
535 /**
536 * Cleanup bundled templates seed state on deactivation.
537 *
538 * @return void
539 */
540 function wpbc_bfb_activation__cleanup_templates_seed_state_on_deactivation() {
541 wpbc_bfb_activation__delete_templates_seed_state();
542 }
543 add_bk_action( 'wpbc_free_version_deactivation', 'wpbc_bfb_activation__cleanup_templates_seed_state_on_deactivation' );
544