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
← All changes | includes/page-form-builder/ajax/bfb-ajax.php +157 -62 11.8.4 → 11.9 View file →
@@ -140,8 +140,23 @@
140 140 '--wpbc-bfb-col-ai',
141 141 '--wpbc-bfb-col-gap',
142 142 '--wpbc-bfb-col-ac',
143 143 '--wpbc-bfb-col-aself',
144 + '--wpbc-bfb-col-padding',
145 + '--wpbc-bfb-col-margin',
146 + '--wpbc-bfb-col-padding-top',
147 + '--wpbc-bfb-col-padding-right',
148 + '--wpbc-bfb-col-padding-bottom',
149 + '--wpbc-bfb-col-padding-left',
150 + '--wpbc-bfb-col-margin-top',
151 + '--wpbc-bfb-col-margin-right',
152 + '--wpbc-bfb-col-margin-bottom',
153 + '--wpbc-bfb-col-margin-left',
154 + '--wpbc-bfb-col-max-width',
155 + '--wpbc-bfb-col-max-height',
156 + '--wpbc-bfb-col-overflow',
157 + '--wpbc-bfb-col-overflow-x',
158 + '--wpbc-bfb-col-overflow-y',
144 159 '--wpbc-bfb-form-background',
145 160 '--wpbc-bfb-form-border-color',
146 161 '--wpbc-bfb-form-border-width',
147 162 '--wpbc-bfb-form-border-radius',
@@ -722,21 +737,26 @@
722 737 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
723 738 $preview_form_style_raw = isset( $_POST['preview_form_style'] ) ? wp_unslash( $_POST['preview_form_style'] ) : '';
724 739
725 740 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
726 - $content_form_raw = isset( $_POST['content_form'] ) ? wp_unslash( $_POST['content_form'] ) : '';
727 - $content_form = wpbc_bfb_sanitize_form_text( $content_form_raw );
741 + $content_form_raw = isset( $_POST['content_form'] ) && is_scalar( $_POST['content_form'] )
742 + ? wp_unslash( $_POST['content_form'] )
743 + : '';
744 + $content_form = wpbc_bfb_sanitize_form_text( $content_form_raw );
745 +
746 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
747 + $advanced_form_raw = isset( $_POST['advanced_form'] ) && is_scalar( $_POST['advanced_form'] )
748 + ? wp_unslash( $_POST['advanced_form'] )
749 + : '';
750 + $advanced_form = wpbc_bfb_sanitize_form_text( $advanced_form_raw );
728 751
729 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
730 - $advanced_form_raw = isset( $_POST['advanced_form'] ) ? wp_unslash( $_POST['advanced_form'] ) : '';
731 - $advanced_form = wpbc_bfb_sanitize_form_text( $advanced_form_raw );
732 752
733 -
734 753 // Validate structure JSON.
735 754 $structure_arr = json_decode( $structure_raw, true );
736 755 if ( ! is_array( $structure_arr ) ) {
737 756 wp_send_json_error( array( 'code' => 'invalid_structure', 'message' => __( 'Form structure is not a valid JSON object.', 'booking' ) ) );
738 757 }
758 + $preview_structure_arr = $structure_arr;
739 759
740 760 /**
741 761 * Filter and sanitize a decoded Form Builder structure before persistence.
742 762 *
@@ -890,9 +910,17 @@
890 910 if ( $return_preview_url && 'preview' === $status && class_exists( 'WPBC_BFB_Preview_Service' ) ) {
891 911
892 912 $preview_service = WPBC_BFB_Preview_Service::get_instance();
893 913
894 - $res = $preview_service->create_preview_session( $preview_form_id, wpbc_get_current_user_id(), $structure_arr, $form_name, $advanced_form, $content_form, $preview_form_style );
914 + $res = $preview_service->create_preview_session(
915 + $preview_form_id,
916 + get_current_user_id(),
917 + $preview_structure_arr,
918 + $form_name,
919 + $advanced_form_raw,
920 + $content_form_raw,
921 + $preview_form_style
922 + );
895 923
896 924 if ( is_array( $res ) && ! empty( $res['preview_url'] ) ) {
897 925 $preview_url = (string) $res['preview_url'];
898 926 $preview_token = ! empty( $res['token'] ) ? (string) $res['token'] : '';
@@ -898,27 +926,9 @@
898 926 $preview_token = ! empty( $res['token'] ) ? (string) $res['token'] : '';
899 927 }
900 928 }
901 929
902 - $setup_step_saved = false;
903 - $setup_step = isset( $_POST['wpbc_setup_step'] ) ? sanitize_key( wp_unslash( $_POST['wpbc_setup_step'] ) ) : '';
904 - if ( ! empty( $setup_step ) && class_exists( 'WPBC_SETUP_WIZARD_STEPS' ) ) {
905 - $setup_steps = new WPBC_SETUP_WIZARD_STEPS();
906 - $steps_arr = $setup_steps->get_steps_arr();
907 - if ( function_exists( 'wpbc_setup_wizard__detect_step_from_admin_url' ) ) {
908 - $referer_step = wpbc_setup_wizard__detect_step_from_admin_url( wp_get_referer() );
909 - if ( ! empty( $referer_step ) && isset( $steps_arr[ $referer_step ] ) ) {
910 - $setup_step = $referer_step;
911 - }
912 - }
913 - if ( isset( $steps_arr[ $setup_step ] ) ) {
914 - $setup_steps->db__set_step_as_saved( $setup_step, true );
915 - $setup_steps->db__save_current_step_name( $setup_step );
916 - $setup_step_saved = true;
917 - }
918 - }
919 -
920 - wp_send_json_success(
930 + wp_send_json_success(
921 931 array(
922 932 'booking_form_id' => $booking_form_id,
923 933 'form_name' => $form_name,
924 934 'engine' => $engine,
@@ -927,10 +937,9 @@
927 937 'token' => $preview_token,
928 938 'title' => isset( $form_config['title'] ) ? (string) $form_config['title'] : '',
929 939 'description' => isset( $form_config['description'] ) ? (string) $form_config['description'] : '',
930 940 'picture_url' => isset( $form_config['picture_url'] ) ? (string) $form_config['picture_url'] : '',
931 - 'setup_step_saved' => $setup_step_saved,
932 - )
941 + )
933 942 );
934 943
935 944 }
936 945 add_action( 'wp_ajax_' . 'WPBC_AJX_BFB_SAVE_FORM_CONFIG', 'wpbc_bfb_ajax_save_form_config' );
@@ -1299,32 +1308,101 @@
1299 1308 }
1300 1309 add_action( 'wp_ajax_' . 'WPBC_AJX_BFB_CREATE_FORM_CONFIG', 'wpbc_bfb_ajax_create_form_config' );
1301 1310
1302 1311
1303 -/**
1304 - * Handle AJAX request: list booking forms for current user (and optionally global ones).
1305 - *
1306 - * Security:
1307 - * - Verifies wpbc_bfb_form_list nonce (sent as 'nonce').
1308 - * - Requires current_user_can( wpbc_bfb_get_manage_cap() ).
1309 - *
1310 - * Expects POST:
1311 - * - nonce : string Nonce for 'wpbc_bfb_form_list'.
1312 - * - include_global : 0|1 If 1, include global forms (owner_user_id=0/NULL) in addition to user-owned.
1313 - * - status : string Default 'published'. Allowed: published|preview|draft|archived|template
1314 - * - search : string Optional filter by title/slug/description
1315 - * - limit : int Optional max rows (default 20, max 500)
1316 - * - page : int Optional page number, starts from 1
1317 - *
1318 - * Response (JSON):
1319 - * - success: true|false
1320 - * - data: { forms: [ ... ] }
1321 - *
1322 - * @since 11.0.0
1323 - *
1324 - * @return void
1325 - */
1326 -function wpbc_bfb_ajax_list_forms() {
1312 +/**
1313 + * Build optional adjacency-aware ordering for the template library.
1314 + *
1315 + * Domains may register stable before/after slug pairs through
1316 + * `wpbc_bfb_template_library_adjacencies`. The list endpoint keeps every pair
1317 + * together at the existing target template's chronological position without
1318 + * placing domain slugs or other business knowledge in the shared controller.
1319 + *
1320 + * @param string $table_name Trusted Booking Form structures table name.
1321 + *
1322 + * @return array SQL fragments and ordered prepare arguments.
1323 + */
1324 +function wpbc_bfb_get_template_library_order_clauses( $table_name ) {
1325 +
1326 + $adjacencies = apply_filters( 'wpbc_bfb_template_library_adjacencies', array() );
1327 +
1328 + if ( ! is_array( $adjacencies ) ) {
1329 + $adjacencies = array();
1330 + }
1331 +
1332 + $effective_updated_at_cases = array();
1333 + $adjacency_rank_cases = array();
1334 + $effective_updated_at_args = array();
1335 + $adjacency_rank_args = array();
1336 +
1337 + foreach ( $adjacencies as $adjacency ) {
1338 + if ( ! is_array( $adjacency ) ) {
1339 + continue;
1340 + }
1341 +
1342 + $before_slug = isset( $adjacency['before'] ) ? sanitize_title( (string) $adjacency['before'] ) : '';
1343 + $after_slug = isset( $adjacency['after'] ) ? sanitize_title( (string) $adjacency['after'] ) : '';
1344 +
1345 + if ( '' === $before_slug || '' === $after_slug || $before_slug === $after_slug ) {
1346 + continue;
1347 + }
1348 +
1349 + $effective_updated_at_cases[] = "WHEN form_slug = %s THEN COALESCE(
1350 + ( SELECT MAX( wpbc_adjacent_target.updated_at )
1351 + FROM {$table_name} AS wpbc_adjacent_target
1352 + WHERE wpbc_adjacent_target.form_slug = %s
1353 + AND wpbc_adjacent_target.status = 'template'
1354 + AND ( wpbc_adjacent_target.owner_user_id = 0 OR wpbc_adjacent_target.owner_user_id IS NULL ) ),
1355 + updated_at
1356 + )";
1357 + $effective_updated_at_args[] = $before_slug;
1358 + $effective_updated_at_args[] = $after_slug;
1359 +
1360 + $adjacency_rank_cases[] = 'WHEN form_slug = %s THEN 2 WHEN form_slug = %s THEN 1';
1361 + $adjacency_rank_args[] = $before_slug;
1362 + $adjacency_rank_args[] = $after_slug;
1363 + }
1364 +
1365 + if ( empty( $effective_updated_at_cases ) ) {
1366 + return array(
1367 + 'effective_updated_at_sql' => 'updated_at',
1368 + 'adjacency_rank_sql' => '',
1369 + 'args' => array(),
1370 + );
1371 + }
1372 +
1373 + return array(
1374 + 'effective_updated_at_sql' => 'CASE ' . implode( ' ', $effective_updated_at_cases ) . ' ELSE updated_at END',
1375 + 'adjacency_rank_sql' => 'CASE ' . implode( ' ', $adjacency_rank_cases ) . ' ELSE 0 END',
1376 + 'args' => array_merge( $effective_updated_at_args, $adjacency_rank_args ),
1377 + );
1378 +}
1379 +
1380 +/**
1381 + * Handle AJAX request: list booking forms for current user (and optionally global ones).
1382 + *
1383 + * Security:
1384 + * - Verifies wpbc_bfb_form_list nonce (sent as 'nonce').
1385 + * - Requires current_user_can( wpbc_bfb_get_manage_cap() ).
1386 + *
1387 + * Expects POST:
1388 + * - nonce : string Nonce for 'wpbc_bfb_form_list'.
1389 + * - include_global : 0|1 If 1, include global forms (owner_user_id=0/NULL) in addition to user-owned.
1390 + * - status : string Default 'published'. Allowed: published|preview|draft|archived|template
1391 + * - search : string Optional filter by title/slug/description
1392 + * - limit : int Optional max rows (default 20, max 500)
1393 + * - page : int Optional page number, starts from 1
1394 + *
1395 + * Response (JSON):
1396 + * - success: true|false
1397 + * - data: { forms: [ ... ] }
1398 + *
1399 + * @since 11.0.0
1400 + *
1401 + * @return void
1402 + */
1403 +
1404 +function wpbc_bfb_ajax_list_forms() {
1327 1405
1328 1406 global $wpdb;
1329 1407
1330 1408 if ( ! check_ajax_referer( 'wpbc_bfb_form_list', 'nonce', false ) ) {
@@ -1438,18 +1516,35 @@
1438 1516 $where_sql .= " AND ( " . implode( ' OR ', $or_groups ) . " ) ";
1439 1517 }
1440 1518 }
1441 1519
1442 - // Order:
1443 - // - prefer user-owned rows first (when include_global + owner_user_id > 0)
1444 - // - default forms first
1445 - // - newest first
1446 - $order_sql = " ORDER BY is_default DESC, updated_at DESC, version DESC, booking_form_id DESC ";
1520 + // Order:
1521 + // - prefer user-owned rows first (when include_global + owner_user_id > 0)
1522 + // - default forms first
1523 + // - preserve registered template adjacency at the target template's position
1524 + // - newest first
1525 + $template_order_clauses = array(
1526 + 'effective_updated_at_sql' => 'updated_at',
1527 + 'adjacency_rank_sql' => '',
1528 + 'args' => array(),
1529 + );
1530 +
1531 + if ( 'template' === $status ) {
1532 + $template_order_clauses = wpbc_bfb_get_template_library_order_clauses( $table );
1533 + }
1534 +
1535 + $effective_updated_at_sql = $template_order_clauses['effective_updated_at_sql'];
1536 + $adjacency_rank_order_sql = '' !== $template_order_clauses['adjacency_rank_sql']
1537 + ? ', ' . $template_order_clauses['adjacency_rank_sql'] . ' DESC'
1538 + : '';
1539 + $order_sql = " ORDER BY is_default DESC, {$effective_updated_at_sql} DESC{$adjacency_rank_order_sql}, version DESC, booking_form_id DESC ";
1540 +
1541 + if ( $owner_user_id > 0 && $include_global ) {
1542 + $order_sql = " ORDER BY ( owner_user_id = " . intval( $owner_user_id ) . " ) DESC, is_default DESC, {$effective_updated_at_sql} DESC{$adjacency_rank_order_sql}, version DESC, booking_form_id DESC ";
1543 + }
1544 +
1545 + $query_args = array_merge( $where_args, $template_order_clauses['args'] );
1447 1546
1448 - if ( $owner_user_id > 0 && $include_global ) {
1449 - $order_sql = " ORDER BY ( owner_user_id = " . intval( $owner_user_id ) . " ) DESC, is_default DESC, updated_at DESC, version DESC, booking_form_id DESC ";
1450 - }
1451 -
1452 1547 $limit_plus_one = $limit + 1;
1453 1548
1454 1549 $sql = "SELECT booking_form_id, form_slug, title, description, picture_url, updated_at, owner_user_id, status, scope, is_default, version
1455 1550 FROM {$table}
@@ -1457,9 +1552,9 @@
1457 1552 {$order_sql}
1458 1553 LIMIT " . intval( $limit_plus_one ) . ' OFFSET ' . intval( $offset );
1459 1554
1460 1555 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
1461 - $rows = $wpdb->get_results( $wpdb->prepare( $sql, $where_args ) );
1556 + $rows = $wpdb->get_results( $wpdb->prepare( $sql, $query_args ) );
1462 1557
1463 1558 $has_more = ( count( (array) $rows ) > $limit );
1464 1559 if ( $has_more ) {
1465 1560 $rows = array_slice( (array) $rows, 0, $limit );