PluginProbe
Booking Calendar / 11.8.4
Booking Calendar v11.8.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
← All changes | includes/page-bookings/bookings__sql.php +698 -115 10.1011.8.4 View file →
@@ -1,4 +1,4 @@
1 1 <?php /**
2 2 * @version 1.0
3 3 * @description Bookings Listing SQL
4 4 * @category Booking Listing
@@ -7,8 +7,9 @@
7 7 * @web-site http://oplugins.com/
8 8 * @email info@oplugins.com
9 9 *
10 10 * @modified 2022-04-07
11 + * @file ../includes/page-bookings/bookings__sql.php
11 12 */
12 13
13 14 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
14 15
@@ -29,9 +30,9 @@
29 30 */
30 31 function wpbc_ajx_get__request_params__names_default( $structure_type = 'validate_and_default' ){
31 32
32 33 // Clean specific $_REQUEST params, if param is NOT set then return "default"
33 - $params_for_cleaning = array(
34 + $params_for_cleaning = array(
34 35 // 'wh_booking_id' => array( 'validate' => 'digit_or_date', 'default' => '' ),
35 36
36 37 // 'digit_or_csd' can check about 'digit_or_csd' in arrays, as well
37 38 'wh_booking_type' => array( 'validate' => 'digit_or_csd', 'default' => array( '0' ) ) // if ['0'] - All booking resources, ['-1'] - lost bookings in deleted resources
@@ -89,12 +90,23 @@
89 90 , 'scroll_start_date' => array( 'validate' => 'digit_or_date', 'default' => '' ) // number | date 2016-07-20
90 91 , 'scroll_day' => array( 'validate' => 'd', 'default' => 0 ) // '1' | ''
91 92 , 'scroll_month' => array( 'validate' => 'd', 'default' => 0 ) // '1' | ''
92 93 , 'limit_hours' => array( 'validate' => 'digit_or_csd', 'default' => '' ) //
93 - , 'only_booked_resources' => array( 'validate' => 'd', 'default' => 0 ) // '1' | ''
94 + , 'only_booked_resources' => array( 'validate' => 'd', 'default' => 0 ) // '1' | ''
95 +
96 + );
97 +
98 + /**
99 + * Filter the Booking Listing request schema before values are sanitized.
100 + *
101 + * Extensions may add narrowly scoped listing filters without duplicating the
102 + * saved-user-request or AJAX sanitization pipeline.
103 + *
104 + * @param array<string,array<string,mixed>> $params_for_cleaning Request validation and default definitions.
105 + * @param string $structure_type Requested schema representation.
106 + */
107 + $params_for_cleaning = apply_filters( 'wpbc_booking_listing_request_params_schema', $params_for_cleaning, $structure_type );
94 108
95 - );
96 -
97 109 if ( 'validate_and_default' == $structure_type ) {
98 110 return $params_for_cleaning;
99 111 }
100 112
@@ -378,9 +390,9 @@
378 390 */
379 391
380 392
381 393 // 4. Include dates into bookings (Wide and Short dates view)
382 - $bookings_with_dates = wpbc_ajx_include_bookingdates_in_bookings( $bookings_obj, $booking_dates_obj );
394 + $bookings_with_dates = wpbc_ajx_include_bookingdates_in_the_bookings( $bookings_obj, $booking_dates_obj );
383 395 /**
384 396 Array ( [182] => stdClass Object (
385 397
386 398 [booking_db] => stdClass Object (
@@ -589,9 +601,9 @@
589 601 . $sql['where']
590 602 . $sql['order'];
591 603 // , $sql['sql_args']
592 604 // );
593 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
605 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
594 606 $resources = $wpdb->get_results( $sql_prepared );
595 607
596 608 $resources_arr = array();
597 609
@@ -918,12 +930,36 @@
918 930 $sql['where'] = apply_bk_filter('update_where_sql_for_getting_bookings_in_multiuser', $sql['where'] ); // Add 'AND bk.booking_type IN ( $user_resources )' to the end of Where
919 931 }
920 932 }
921 933
922 - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
923 -
924 -
925 - switch ( $params['wh_sort'] ) {
934 + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
935 +
936 + /**
937 + * Filter the prepared Booking Listing WHERE fragment and its placeholders.
938 + *
939 + * The base query has already applied dates, resources, MultiUser ownership,
940 + * status, cost, and keyword rules. Additions must return the same two keys.
941 + *
942 + * @param array{where:string,args:array<int,mixed>} $query_parts WHERE SQL and prepare arguments.
943 + * @param array<string,mixed> $request_params Sanitized listing request.
944 + * @param array<string,mixed> $params Request merged with defaults.
945 + */
946 + $query_parts = apply_filters(
947 + 'wpbc_booking_listing_sql_query_parts',
948 + array(
949 + 'where' => $sql['where'],
950 + 'args' => $sql_args,
951 + ),
952 + $request_params,
953 + $params
954 + );
955 + if ( is_array( $query_parts ) && isset( $query_parts['where'], $query_parts['args'] ) && is_string( $query_parts['where'] ) && is_array( $query_parts['args'] ) ) {
956 + $sql['where'] = $query_parts['where'];
957 + $sql_args = $query_parts['args'];
958 + }
959 +
960 +
961 + switch ( $params['wh_sort'] ) {
926 962 case 'booking_id__asc':
927 963 $order_by = 'booking_id ASC ';
928 964 break;
929 965 case 'booking_id__desc':
@@ -977,9 +1013,9 @@
977 1013 // SELECT at this specific PAGE /////////////////////////////////////////////////////////////////
978 1014 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
979 1015 /* phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare */
980 1016 $sql_prepared = $wpdb->prepare( $sql['start_select'] . $sql['from'] . $sql['where'] . $sql['order'] . $sql['limit'], $sql_args );
981 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
1017 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
982 1018 $bookings_sql_obj = $wpdb->get_results( $sql_prepared );
983 1019
984 1020
985 1021 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -996,9 +1032,9 @@
996 1032 } else {
997 1033 /* phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare */
998 1034 $sql_prepared = $wpdb->prepare( $sql_for_listing_count, $sql_args_count );
999 1035 }
1000 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
1036 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
1001 1037 $bookings_count = $wpdb->get_results( $sql_prepared );
1002 1038 $bookings_count = ( ( count( $bookings_count ) > 0 ) ? $bookings_count[0]->count : 0 );
1003 1039
1004 1040 return array(
@@ -1027,44 +1063,44 @@
1027 1063 else { $and_pre = ''; $and_suf = ' AND '; }
1028 1064
1029 1065 // Actual
1030 1066 if ( ( ( $wh_booking_date === '' ) && ( $wh_booking_date2 === '' ) ) || ($wh_booking_date === '0') ) {
1031 - $sql_where = $and_pre."( ".$pref."booking_date >= ( CURDATE() - INTERVAL '00:00:01' HOUR_SECOND ) ) ".$and_suf ; // FixIn: 8.5.2.14.
1067 + $sql_where = $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL '00:00:01' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ; // FixIn: 8.5.2.14.
1032 1068
1033 1069 } else if ($wh_booking_date === '1') { // Today // FixIn: 7.1.2.8.
1034 - $sql_where = $and_pre."( ".$pref."booking_date <= ( CURDATE() + INTERVAL '23:59:59' HOUR_SECOND ) ) ".$and_suf ;
1035 - $sql_where .= $and_pre."( ".$pref."booking_date >= ( CURDATE() - INTERVAL '00:00:01' HOUR_SECOND ) ) ".$and_suf ; // FixIn: 8.4.7.21.
1070 + $sql_where = $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL '23:59:59' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ;
1071 + $sql_where .= $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL '00:00:01' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ; // FixIn: 8.4.7.21.
1036 1072
1037 1073
1038 1074 } else if ($wh_booking_date === '2') { // Previous
1039 - $sql_where = $and_pre."( ".$pref."booking_date <= ( CURDATE() - INTERVAL '00:00:01' HOUR_SECOND ) ) ".$and_suf ; // FixIn: 8.5.2.16.
1075 + $sql_where = $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL '00:00:01' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ; // FixIn: 8.5.2.16.
1040 1076
1041 1077 } else if ($wh_booking_date === '3') { // All
1042 1078 $sql_where = '';
1043 1079
1044 1080 } else if ($wh_booking_date === '4') { // Next
1045 - $sql_where = $and_pre."( ".$pref."booking_date <= ( CURDATE() + INTERVAL ". $wh_booking_date2 . " DAY ) ) ".$and_suf ;
1046 - // $sql_where .= $and_pre."( ".$pref."booking_date >= ( CURDATE() - INTERVAL 1 DAY ) ) ".$and_suf ;
1047 - $sql_where .= $and_pre."( ".$pref."booking_date > ( CURDATE() ) ) ".$and_suf ; // FixIn: 8.0.1.1.
1081 + $wh_booking_date2 = intval( $wh_booking_date2 ); // FixIn: 10.14.16.1.
1082 + $sql_where = $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL ". $wh_booking_date2 . " DAY", 'curdate' ) . ") ) ".$and_suf ;
1083 + // $sql_where .= $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ;
1084 + $sql_where .= $and_pre."( ".$pref."booking_date > ( " . wpbc_sql_date_math_expr_explicit('', 'curdate') . " ) ) ".$and_suf ; // FixIn: 8.0.1.1.
1048 1085
1049 1086 } else if ($wh_booking_date === '5') { // Prior
1050 1087 $wh_booking_date2 = str_replace('-', '', $wh_booking_date2);
1051 - $sql_where = $and_pre."( ".$pref."booking_date >= ( CURDATE() - INTERVAL ". $wh_booking_date2 . " DAY ) ) ".$and_suf ;
1052 - $sql_where .= $and_pre."( ".$pref."booking_date <= ( CURDATE() + INTERVAL 1 DAY ) ) ".$and_suf ;
1088 + $wh_booking_date2 = intval( $wh_booking_date2 ); // FixIn: 10.14.16.1.
1089 + $sql_where = $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL ". $wh_booking_date2 . " DAY", 'curdate' ) . ") ) ".$and_suf ;
1090 + $sql_where .= $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ;
1053 1091
1054 1092 } else if ($wh_booking_date === '7') { // Check In date - Today/Tomorrow
1055 - // $sql_where = $and_pre."( ".$pref."booking_date <= ( CURDATE() + INTERVAL '23:59:59' HOUR_SECOND ) ) ".$and_suf ;
1056 - // $sql_where .= $and_pre."( ".$pref."booking_date >= ( CURDATE() ) ) ".$and_suf ;
1057 - $sql_where = $and_pre."( ".$pref."booking_date <= ( CURDATE() + INTERVAL '1 23:59:59' DAY_SECOND ) ) ".$and_suf ;
1058 - $sql_where .= $and_pre."( ".$pref."booking_date >= ( CURDATE() + INTERVAL 1 DAY ) ) ".$and_suf ;
1093 + $sql_where = $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL '47:59:59' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ;
1094 + $sql_where .= $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ;
1059 1095
1060 1096 } else if ($wh_booking_date === '8') { // Check Out date - Tomorrow
1061 - $sql_where = $and_pre."( ".$pref."booking_date <= ( CURDATE() + INTERVAL '1 23:59:59' DAY_SECOND ) ) ".$and_suf ;
1062 - $sql_where .= $and_pre."( ".$pref."booking_date >= ( CURDATE() + INTERVAL 1 DAY ) ) ".$and_suf ;
1097 + $sql_where = $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL '47:59:59' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ;
1098 + $sql_where .= $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ;
1063 1099
1064 1100 } else if ( ( $wh_booking_date === '9' ) || ( $wh_booking_date === '10' ) || ( $wh_booking_date === '11' ) ) { // Today check in/out
1065 - $sql_where = $and_pre."( ".$pref."booking_date <= ( CURDATE() + INTERVAL 1 DAY ) ) ".$and_suf ;
1066 - $sql_where .= $and_pre."( ".$pref."booking_date >= ( CURDATE() - INTERVAL 1 DAY ) ) ".$and_suf ;
1101 + $sql_where = $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ;
1102 + $sql_where .= $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ;
1067 1103
1068 1104 } else { // Fixed
1069 1105
1070 1106 $wh_booking_date = wpbc_sanitize_date( $wh_booking_date );
@@ -1117,10 +1153,10 @@
1117 1153 if ($pref == 'bk.') { $and_pre = ' AND '; $and_suf = ''; }
1118 1154 else { $and_pre = ''; $and_suf = ' AND '; }
1119 1155
1120 1156 if ($wh_modification_date === '1') { // Today
1121 - $sql_where = $and_pre."( ".$pref."modification_date <= ( CURDATE() + INTERVAL '23:59:59' HOUR_SECOND ) ) ".$and_suf ; // FixIn: 8.4.7.22.
1122 - $sql_where .= $and_pre."( ".$pref."modification_date >= ( CURDATE() - INTERVAL '00:00:01' HOUR_SECOND ) ) ".$and_suf ; // FixIn: 8.4.7.22.
1157 + $sql_where = $and_pre."( ".$pref."modification_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL '23:59:59' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ; // FixIn: 8.4.7.22.
1158 + $sql_where .= $and_pre."( ".$pref."modification_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL '00:00:01' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ; // FixIn: 8.4.7.22.
1123 1159
1124 1160 } else if ($wh_modification_date === '3') { // All
1125 1161 $sql_where = '';
1126 1162
@@ -1125,10 +1161,11 @@
1125 1161 $sql_where = '';
1126 1162
1127 1163 } else if ($wh_modification_date === '5') { // Prior
1128 1164 $wh_modification_date2 = str_replace('-', '', $wh_modification_date2);
1129 - $sql_where = $and_pre."( ".$pref."modification_date >= ( CURDATE() - INTERVAL ". $wh_modification_date2 . " DAY ) ) ".$and_suf ;
1130 - $sql_where .= $and_pre."( ".$pref."modification_date <= ( CURDATE() + INTERVAL 1 DAY ) ) ".$and_suf ;
1165 + $wh_modification_date2 = intval( $wh_modification_date2 ); // FixIn: 10.14.16.1.
1166 + $sql_where = $and_pre."( ".$pref."modification_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL ". $wh_modification_date2 . " DAY", 'curdate' ) . ") ) ".$and_suf ;
1167 + $sql_where .= $and_pre."( ".$pref."modification_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ;
1131 1168
1132 1169 } else { // Fixed
1133 1170
1134 1171 $wh_modification_date = wpbc_sanitize_date( $wh_modification_date ); // FixIn: 9.4.4.1.
@@ -1257,9 +1294,9 @@
1257 1294 )
1258 1295 ) " ;
1259 1296
1260 1297 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
1261 - if ( ( isset($_REQUEST['view_mode']) ) && ( $_REQUEST['view_mode']== 'vm_calendar' ) ) {
1298 + if ( ( isset($_REQUEST['tab']) ) && ( $_REQUEST['tab']== 'vm_calendar' ) ) {
1262 1299
1263 1300 // Skip the bookings from the children resources, if we are in the Calendar view mode at the admin panel
1264 1301
1265 1302 } else {
@@ -1414,9 +1451,9 @@
1414 1451 $sql .= " ORDER BY booking_id, type_id, booking_date ";
1415 1452 } else {
1416 1453 $sql .= " ORDER BY booking_id, booking_date ";
1417 1454 }
1418 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
1455 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
1419 1456 $booking_dates_sql_obj = $wpdb->get_results( $sql );
1420 1457 } else {
1421 1458 $booking_dates_sql_obj = array();
1422 1459 }
@@ -1601,9 +1638,9 @@
1601 1638 * )
1602 1639 * [181] => stdClass Object (
1603 1640 * ....
1604 1641 */
1605 - function wpbc_ajx_include_bookingdates_in_bookings( $bookings_obj, $booking_dates_obj ){
1642 + function wpbc_ajx_include_bookingdates_in_the_bookings( $bookings_obj, $booking_dates_obj ){
1606 1643
1607 1644 $bookings_arr = array();
1608 1645 foreach ( $bookings_obj as $booking ) {
1609 1646
@@ -1707,14 +1744,376 @@
1707 1744 }
1708 1745
1709 1746 } // bookings loop: $booking_id => $booking
1710 1747
1711 - return $bookings_arr;
1712 - }
1748 + return $bookings_arr;
1749 + }
1750 +
1751 +
1752 + /**
1753 + * Build an empty Booking Listing Resource-allocation DTO.
1754 + *
1755 + * A stable empty shape keeps the browser template data-only and avoids
1756 + * edition-specific checks in the presentation layer.
1757 + *
1758 + * @return array<string,mixed> Empty Resource-allocation DTO.
1759 + */
1760 + function wpbc_booking_listing_get_empty_resource_allocation() {
1761 +
1762 + return array(
1763 + 'is_multiple_resources' => false,
1764 + 'resource_count' => 0,
1765 + 'resource_count_label' => '',
1766 + 'date_summary_label' => '',
1767 + 'segment_count' => 0,
1768 + 'segments' => array(),
1769 + );
1770 + }
1771 +
1772 +
1773 + /**
1774 + * Return a localized time label for one allocation day.
1775 + *
1776 + * Duplicate timestamps are expected when a quantity booking reserves
1777 + * several Resources. Midnight represents a full day and is omitted. When
1778 + * two or more non-midnight values exist, the first and last values describe
1779 + * the booked time interval without repeating it for every Resource.
1780 + *
1781 + * @param array<string,mixed> $allocation_day Normalized day record.
1782 + *
1783 + * @return string Localized time or time-range label. Empty for full days.
1784 + */
1785 + function wpbc_booking_listing_get_allocation_day_time_label( $allocation_day ) {
1786 +
1787 + if ( empty( $allocation_day['times'] ) || ! is_array( $allocation_day['times'] ) ) {
1788 + return '';
1789 + }
1790 +
1791 + $sql_times = array_values( array_unique( array_filter( array_map( 'strval', $allocation_day['times'] ) ) ) );
1792 + sort( $sql_times, SORT_STRING );
1793 +
1794 + $formatted_times = array();
1795 + foreach ( $sql_times as $sql_time ) {
1796 + if ( '00:00:00' === $sql_time ) {
1797 + continue;
1798 + }
1799 +
1800 + list( , $formatted_time ) = wpbc_get_date_in_correct_format( $allocation_day['date'] . ' ' . $sql_time );
1801 + $formatted_time = trim( $formatted_time );
1802 + if ( '' !== $formatted_time ) {
1803 + $formatted_times[] = $formatted_time;
1804 + }
1805 + }
1806 +
1807 + $formatted_times = array_values( array_unique( $formatted_times ) );
1808 + if ( empty( $formatted_times ) ) {
1809 + return '';
1810 + }
1811 +
1812 + if ( 1 === count( $formatted_times ) ) {
1813 + return $formatted_times[0];
1814 + }
1815 +
1816 + return $formatted_times[0] . ' – ' . $formatted_times[ count( $formatted_times ) - 1 ];
1817 + }
1818 +
1819 +
1820 + /**
1821 + * Format one chronological Resource-allocation period.
1822 + *
1823 + * Common recurrent times are shown once after the date range. Check-in and
1824 + * check-out times that differ between the first and final day stay attached
1825 + * to their respective dates. Full-day periods contain dates only.
1826 + *
1827 + * @param string $start_date First date in Y-m-d format.
1828 + * @param string $end_date Final date in Y-m-d format.
1829 + * @param array<string,array> $allocation_days Normalized days keyed by Y-m-d.
1830 + *
1831 + * @return string Localized period label.
1832 + */
1833 + function wpbc_booking_listing_format_allocation_period_label( $start_date, $end_date, $allocation_days ) {
1834 +
1835 + list( $start_date_label ) = wpbc_get_date_in_correct_format( $start_date . ' 00:00:00' );
1836 + list( $end_date_label ) = wpbc_get_date_in_correct_format( $end_date . ' 00:00:00' );
1837 +
1838 + $period_days = array();
1839 + foreach ( $allocation_days as $date_key => $allocation_day ) {
1840 + if ( $date_key >= $start_date && $date_key <= $end_date ) {
1841 + $period_days[ $date_key ] = $allocation_day;
1842 + }
1843 + }
1844 +
1845 + $day_time_labels = array();
1846 + foreach ( $period_days as $date_key => $allocation_day ) {
1847 + $day_time_labels[ $date_key ] = wpbc_booking_listing_get_allocation_day_time_label( $allocation_day );
1848 + }
1849 +
1850 + if ( $start_date === $end_date ) {
1851 + $time_label = isset( $day_time_labels[ $start_date ] ) ? $day_time_labels[ $start_date ] : '';
1852 +
1853 + return '' !== $time_label ? $start_date_label . ', ' . $time_label : $start_date_label;
1854 + }
1855 +
1856 + $non_empty_time_labels = array_values( array_filter( $day_time_labels ) );
1857 + $unique_time_labels = array_values( array_unique( $non_empty_time_labels ) );
1858 + if ( count( $non_empty_time_labels ) === count( $period_days ) && 1 === count( $unique_time_labels ) ) {
1859 + return $start_date_label . ' – ' . $end_date_label . ', ' . $unique_time_labels[0];
1860 + }
1861 +
1862 + $start_time_label = isset( $day_time_labels[ $start_date ] ) ? $day_time_labels[ $start_date ] : '';
1863 + $end_time_label = isset( $day_time_labels[ $end_date ] ) ? $day_time_labels[ $end_date ] : '';
1864 + if ( '' !== $start_time_label ) {
1865 + $start_date_label .= ', ' . $start_time_label;
1866 + }
1867 + if ( '' !== $end_time_label ) {
1868 + $end_date_label .= ', ' . $end_time_label;
1869 + }
1870 +
1871 + return $start_date_label . ' – ' . $end_date_label;
1872 + }
1873 +
1874 +
1875 + /**
1876 + * Resolve authorized Resource presentation records for an allocation set.
1877 + *
1878 + * Only titles already present in the owner-filtered Booking Listing Resource
1879 + * collection are exposed. Missing or deleted Resources receive the existing
1880 + * neutral fallback instead of leaking an unavailable title.
1881 + *
1882 + * @param array<int> $resource_ids Resource IDs in display order.
1883 + * @param array<int,array> $booking_resources_arr Owner-filtered Resource records.
1884 + *
1885 + * @return array<int,array<string,mixed>> JSON-safe Resource presentation records.
1886 + */
1887 + function wpbc_booking_listing_get_allocation_resource_records( $resource_ids, $booking_resources_arr ) {
1888 +
1889 + $resource_records = array();
1890 + foreach ( $resource_ids as $resource_id ) {
1891 + $resource_id = absint( $resource_id );
1892 + $resource_title = isset( $booking_resources_arr[ $resource_id ]['title'] )
1893 + ? wp_strip_all_tags( wpbc_lang( $booking_resources_arr[ $resource_id ]['title'] ) )
1894 + : __( 'Resource not exist', 'booking' );
1895 +
1896 + $resource_records[] = array(
1897 + 'resource_id' => $resource_id,
1898 + 'resource_title' => $resource_title,
1899 + 'is_missing' => ! isset( $booking_resources_arr[ $resource_id ] ),
1900 + );
1901 + }
1902 +
1903 + return $resource_records;
1904 + }
1905 +
1906 +
1907 + /**
1908 + * Group normalized allocation days into chronological Resource-set segments.
1909 + *
1910 + * Consecutive dates are merged only while their complete Resource set stays
1911 + * identical. This represents both a booking that moves between Resources and
1912 + * a quantity booking that reserves several Resources for the same period.
1913 + *
1914 + * @param array<string,array> $allocation_days Normalized days keyed by Y-m-d.
1915 + * @param array<int,array> $booking_resources_arr Owner-filtered Resource records.
1916 + *
1917 + * @return array<int,array<string,mixed>> Ordered allocation segments.
1918 + */
1919 + function wpbc_booking_listing_group_allocation_days( $allocation_days, $booking_resources_arr ) {
1920 +
1921 + $segments = array();
1922 + $current_segment = array();
1923 +
1924 + foreach ( $allocation_days as $date_key => $allocation_day ) {
1925 + $resource_ids = array_values( array_unique( array_map( 'absint', array_keys( $allocation_day['resources'] ) ) ) );
1926 + sort( $resource_ids, SORT_NUMERIC );
1927 + $resource_signature = implode( ',', $resource_ids );
1928 +
1929 + $is_same_segment = ! empty( $current_segment )
1930 + && $resource_signature === $current_segment['resource_signature']
1931 + && wpbc_is_next_day( $date_key, $current_segment['end_date'] );
1932 +
1933 + if ( ! $is_same_segment ) {
1934 + if ( ! empty( $current_segment ) ) {
1935 + $current_segment['period_label'] = wpbc_booking_listing_format_allocation_period_label(
1936 + $current_segment['start_date'],
1937 + $current_segment['end_date'],
1938 + $allocation_days
1939 + );
1940 + $current_segment['resources'] = wpbc_booking_listing_get_allocation_resource_records( $current_segment['resource_ids'], $booking_resources_arr );
1941 + unset( $current_segment['resource_signature'], $current_segment['resource_ids'] );
1942 + $segments[] = $current_segment;
1943 + }
1944 +
1945 + $current_segment = array(
1946 + 'start_date' => $date_key,
1947 + 'end_date' => $date_key,
1948 + 'day_count' => 1,
1949 + 'resource_signature' => $resource_signature,
1950 + 'resource_ids' => $resource_ids,
1951 + );
1952 + continue;
1953 + }
1954 +
1955 + $current_segment['end_date'] = $date_key;
1956 + ++$current_segment['day_count'];
1957 + }
1958 +
1959 + if ( ! empty( $current_segment ) ) {
1960 + $current_segment['period_label'] = wpbc_booking_listing_format_allocation_period_label(
1961 + $current_segment['start_date'],
1962 + $current_segment['end_date'],
1963 + $allocation_days
1964 + );
1965 + $current_segment['resources'] = wpbc_booking_listing_get_allocation_resource_records( $current_segment['resource_ids'], $booking_resources_arr );
1966 + unset( $current_segment['resource_signature'], $current_segment['resource_ids'] );
1967 + $segments[] = $current_segment;
1968 + }
1969 +
1970 + return $segments;
1971 + }
1972 +
1973 +
1974 + /**
1975 + * Build compact chronological date periods independently of Resource changes.
1976 + *
1977 + * This summary is used in the narrow date column. It avoids repeating dates
1978 + * for quantity bookings while preserving gaps between non-consecutive dates.
1979 + *
1980 + * @param array<string,array> $allocation_days Normalized days keyed by Y-m-d.
1981 + *
1982 + * @return array<int,string> Localized date-period labels.
1983 + */
1984 + function wpbc_booking_listing_get_allocation_date_period_labels( $allocation_days ) {
1985 +
1986 + $period_labels = array();
1987 + $start_date = '';
1988 + $end_date = '';
1989 +
1990 + foreach ( array_keys( $allocation_days ) as $date_key ) {
1991 + if ( '' === $start_date ) {
1992 + $start_date = $date_key;
1993 + $end_date = $date_key;
1994 + continue;
1995 + }
1996 +
1997 + if ( wpbc_is_next_day( $date_key, $end_date ) ) {
1998 + $end_date = $date_key;
1999 + continue;
2000 + }
2001 +
2002 + $period_labels[] = wpbc_booking_listing_format_allocation_period_label( $start_date, $end_date, $allocation_days );
2003 + $start_date = $date_key;
2004 + $end_date = $date_key;
2005 + }
2006 +
2007 + if ( '' !== $start_date ) {
2008 + $period_labels[] = wpbc_booking_listing_format_allocation_period_label( $start_date, $end_date, $allocation_days );
2009 + }
2010 +
2011 + return $period_labels;
2012 + }
2013 +
2014 +
2015 + /**
2016 + * Build the Booking Listing Resource-allocation DTO from saved date rows.
2017 + *
2018 + * Business Large stores the booking's main Resource in `booking.booking_type`.
2019 + * A date on that Resource has an empty `bookingdates.type_id`; only dates on
2020 + * another Resource contain `type_id`. Normalizing that fallback before
2021 + * counting or grouping prevents both missing labels and repeated per-date
2022 + * child labels.
2023 + *
2024 + * @param object $booking Booking with `booking_db`, `dates`, and `child_id` values.
2025 + * @param array<int,array> $booking_resources_arr Owner-filtered Resource records.
2026 + *
2027 + * @return array<string,mixed> JSON-safe Resource-allocation DTO.
2028 + */
2029 + function wpbc_booking_listing_build_resource_allocation( $booking, $booking_resources_arr ) {
2030 +
2031 + $resource_allocation = wpbc_booking_listing_get_empty_resource_allocation();
2032 + if (
2033 + empty( $booking->booking_db->booking_type )
2034 + || empty( $booking->dates )
2035 + || ! is_array( $booking->dates )
2036 + ) {
2037 + return $resource_allocation;
2038 + }
2039 +
2040 + $main_resource_id = absint( $booking->booking_db->booking_type );
2041 + $allocation_days = array();
2042 + $all_resource_ids = array();
2043 +
2044 + foreach ( $booking->dates as $date_index => $sql_booking_date ) {
2045 + $sql_booking_date = is_scalar( $sql_booking_date ) ? trim( (string) $sql_booking_date ) : '';
2046 + if ( ! preg_match( '/^(\d{4})-(\d{2})-(\d{2})(?:\s+(\d{2}):(\d{2}):(\d{2}))?$/', $sql_booking_date, $date_parts ) ) {
2047 + continue;
2048 + }
2049 +
2050 + $year = (int) $date_parts[1];
2051 + $month = (int) $date_parts[2];
2052 + $day = (int) $date_parts[3];
2053 + $hour = isset( $date_parts[4] ) ? (int) $date_parts[4] : 0;
2054 + $minute = isset( $date_parts[5] ) ? (int) $date_parts[5] : 0;
2055 + $second = isset( $date_parts[6] ) ? (int) $date_parts[6] : 0;
2056 + if (
2057 + ! checkdate( $month, $day, $year )
2058 + || $hour > 23
2059 + || $minute > 59
2060 + || $second > 59
2061 + ) {
2062 + continue;
2063 + }
2064 +
2065 + $date_key = sprintf( '%04d-%02d-%02d', $year, $month, $day );
2066 + $sql_time = isset( $date_parts[4], $date_parts[5], $date_parts[6] )
2067 + ? sprintf( '%02d:%02d:%02d', $hour, $minute, $second )
2068 + : '00:00:00';
2069 + $date_resource_id = isset( $booking->child_id[ $date_index ] ) && ! empty( $booking->child_id[ $date_index ] )
2070 + ? absint( $booking->child_id[ $date_index ] )
2071 + : $main_resource_id;
2072 +
2073 + if ( empty( $date_resource_id ) ) {
2074 + continue;
2075 + }
2076 +
2077 + if ( ! isset( $allocation_days[ $date_key ] ) ) {
2078 + $allocation_days[ $date_key ] = array(
2079 + 'date' => $date_key,
2080 + 'times' => array(),
2081 + 'resources' => array(),
2082 + );
2083 + }
2084 +
2085 + $allocation_days[ $date_key ]['times'][] = $sql_time;
2086 + $allocation_days[ $date_key ]['resources'][ $date_resource_id ] = true;
2087 + $all_resource_ids[ $date_resource_id ] = true;
2088 + }
2089 +
2090 + if ( empty( $allocation_days ) ) {
2091 + return $resource_allocation;
2092 + }
2093 +
2094 + ksort( $allocation_days, SORT_STRING );
2095 + $resource_count = count( $all_resource_ids );
2096 + $period_labels = wpbc_booking_listing_get_allocation_date_period_labels( $allocation_days );
2097 + $segments = wpbc_booking_listing_group_allocation_days( $allocation_days, $booking_resources_arr );
2098 +
2099 + $resource_allocation['is_multiple_resources'] = ( $resource_count > 1 );
2100 + $resource_allocation['resource_count'] = $resource_count;
2101 + $resource_allocation['resource_count_label'] = sprintf(
2102 + /* translators: %d: Number of booking Resources reserved by one booking. */
2103 + _n( '%d booking resource', '%d booking resources', $resource_count, 'booking' ),
2104 + $resource_count
2105 + );
2106 + $resource_allocation['date_summary_label'] = implode( ', ', $period_labels );
2107 + $resource_allocation['segment_count'] = count( $segments );
2108 + $resource_allocation['segments'] = $segments;
2109 +
2110 + return $resource_allocation;
2111 + }
2112 +
2113 +
2114 + function wpbc_ajx_parse_bookings( $bookings_arr, $resources_arr ) {
1713 2115
1714 -
1715 - function wpbc_ajx_parse_bookings( $bookings_arr, $resources_arr ) {
1716 -
1717 2116 $user_id = ( isset( $_REQUEST['wpbc_ajx_user_id'] ) ) ? intval( $_REQUEST['wpbc_ajx_user_id'] ) : wpbc_get_current_user_id(); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
1718 2117
1719 2118 foreach ( $bookings_arr as $booking_id => $booking ) {
1720 2119
@@ -1730,8 +2129,28 @@
1730 2129 if ( class_exists( 'wpdev_bk_multiuser' ) ) {
1731 2130 $resource_owner_user = ( isset( $resources_arr[ $resource_id ] ) ) ? $resources_arr[ $resource_id ]['users'] : $user_id;
1732 2131 }
1733 2132
2133 + $resource_title_listing = $resource_title;
2134 + $resource_id_listing = $resource_id;
2135 + $child_resource_id_arr = array();
2136 + if ( ( class_exists( 'wpdev_bk_biz_l' ) ) && ( ! empty( $booking->child_id ) ) && ( is_array( $booking->child_id ) ) ) {
2137 + foreach ( $booking->child_id as $child_resource_id ) {
2138 + if ( ! empty( $child_resource_id ) ) {
2139 + $child_resource_id_arr[] = (int) $child_resource_id;
2140 + }
2141 + }
2142 + $child_resource_id_arr = array_values( array_unique( $child_resource_id_arr ) );
2143 +
2144 + if ( ( 1 === count( $child_resource_id_arr ) ) && ( isset( $resources_arr[ $child_resource_id_arr[0] ] ) ) ) {
2145 + $resource_id_listing = $child_resource_id_arr[0];
2146 + $resource_title_listing = wpbc_lang( $resources_arr[ $child_resource_id_arr[0] ]['title'] );
2147 + }
2148 + }
2149 + $resource_allocation = class_exists( 'wpdev_bk_biz_l' )
2150 + ? wpbc_booking_listing_build_resource_allocation( $booking, $resources_arr )
2151 + : wpbc_booking_listing_get_empty_resource_allocation();
2152 +
1734 2153 // Parse form fields only from $booking->booking_db->form ------------------------------------------
1735 2154 $booking_data_arr = wpbc_parse_booking_data_fields( $booking->booking_db->form,
1736 2155 array( 'resource_id' => $resource_id )
1737 2156 );
@@ -1777,10 +2196,14 @@
1777 2196 // Set dates and times in correct format ---------------------------------------------------------------
1778 2197 $booking_data_arr = wpbc_parse_booking_data_fields_formats( $booking_data_arr );
1779 2198
1780 2199 // Get SHORT / WIDE Dates showing data -----------------------------------------------------------------
1781 - $short_dates_content = wpbc_get_formated_dates__short( $booking->short_dates, (boolean) $booking->approved, $booking->short_dates_child_id, $resources_arr );
1782 - $wide_dates_content = wpbc_get_formated_dates__wide( $booking->dates, (boolean) $booking->approved, $booking->child_id, $resources_arr );
2200 + $dates_attr = array(
2201 + 'date_html_tag' => 'span',
2202 + 'show_child_resource_in_dates' => false,
2203 + );
2204 + $short_dates_content = wpbc_get_formated_dates__short( $booking->short_dates, (bool) $booking->approved, $booking->short_dates_child_id, $resources_arr, $dates_attr );
2205 + $wide_dates_content = wpbc_get_formated_dates__wide( $booking->dates, (bool) $booking->approved, $booking->child_id, $resources_arr, $dates_attr );
1783 2206
1784 2207 //------------------------------------------------------------------------------------------------------
1785 2208 // Payment Status
1786 2209 //------------------------------------------------------------------------------------------------------
@@ -1849,8 +2272,10 @@
1849 2272 // Add some fields to [ 'parsed_fields' ]
1850 2273 //------------------------------------------------------------------------------------------------------
1851 2274 $booking_data_arr['resource_title'] = $resource_title;
1852 2275 $booking_data_arr['resource_id'] = $resource_id;
2276 + $booking_data_arr['resource_title_listing'] = $resource_title_listing;
2277 + $booking_data_arr['resource_id_listing'] = $resource_id_listing;
1853 2278 $booking_data_arr['resource_owner_user'] = $resource_owner_user;
1854 2279 //$booking_data_arr['short_dates_content'] = $short_dates_content;
1855 2280 //$booking_data_arr['wide_dates_content'] = $wide_dates_content;
1856 2281
@@ -1857,10 +2282,15 @@
1857 2282 //------------------------------------------------------------------------------------------------------
1858 2283 // Form Show - "Content of booking fields data" form
1859 2284 //------------------------------------------------------------------------------------------------------
1860 2285
1861 - $custom_booking_form_name = ( ! empty( $booking_data_arr['wpbc_custom_booking_form'] ) ) ? $booking_data_arr['wpbc_custom_booking_form'] : ''; // FixIn: 9.4.3.12.
1862 - $form_show_template = wpbc_get_content_booking_form_show( $resource_id , $custom_booking_form_name ); // <strong>First Name</strong>:<span class="fieldvalue">[name]</span>&nbsp;&nbsp; ...
2286 + $custom_booking_form_name = ( ! empty( $booking_data_arr['wpbc_custom_booking_form'] ) ) ? $booking_data_arr['wpbc_custom_booking_form'] : ''; // FixIn: 9.4.3.12.
2287 + $booking_data_arr['admin_edit_url'] = wpbc_get_booking_admin_edit_url(
2288 + $resource_id,
2289 + isset( $booking_data_arr['hash'] ) ? $booking_data_arr['hash'] : '',
2290 + $custom_booking_form_name
2291 + );
2292 + $form_show_template = wpbc_get_content_booking_form_show( $resource_id , $custom_booking_form_name ); // <strong>First Name</strong>:<span class="fieldvalue">[name]</span>&nbsp;&nbsp; ...
1863 2293 $parsed_form_show = wpbc_get_parsed_content_booking_form_show( $booking_data_arr, $form_show_template ); // <strong>First Name</strong>:<span class="fieldvalue">John</span>&nbsp;&nbsp; ...
1864 2294
1865 2295 //------------------------------------------------------------------------------------------------------
1866 2296 // Google Calendar link
@@ -1869,16 +2299,32 @@
1869 2299 'form_data' => $booking_data_arr,
1870 2300 'form_show' => $parsed_form_show, //wp_strip_all_tags( $parsed_form_show ),
1871 2301 'dates_short' => $booking->short_dates
1872 2302 ) );
1873 -
2303 + $booking_data_arr['visitorbookingpayurl'] = ( class_exists( 'wpdev_bk_biz_s' ) )
2304 + ? apply_bk_filter( 'wpdev_booking_set_booking_edit_link_at_email', '[visitorbookingpayurl]', $booking_id )
2305 + : '';
1874 2306 // =====================================================================================================
1875 - $bookings_arr[ $booking_id ]->parsed_fields = $booking_data_arr;
2307 + $booking_data_arr = apply_filters( 'wpbc_booking_listing_parsed_fields', $booking_data_arr, $booking_id, $booking );
2308 + $bookings_arr[ $booking_id ]->parsed_fields = $booking_data_arr;
2309 + $bookings_arr[ $booking_id ]->resource_allocation = $resource_allocation;
1876 2310
1877 2311
1878 2312 // =====================================================================================================
1879 2313 $bookings_arr[ $booking_id ]->templates = array(
1880 2314 'form_show' => $parsed_form_show,
2315 + 'form_show_simple' => wp_kses( trim( stripslashes( $parsed_form_show ) ),
2316 + // array_merge(
2317 + array(
2318 + 'span' => array( 'style'=>true , 'class'=>true , 'id'=>true ),
2319 + 'b' => array( 'style'=>true , 'class'=>true , 'id'=>true ),
2320 + 'strong' => array( 'style'=>true , 'class'=>true , 'id'=>true ),
2321 + 'i' => array( 'style'=>true , 'class'=>true , 'id'=>true ),
2322 + 'class' => array(),
2323 + 'style' => array()
2324 + )
2325 + // , wp_kses_allowed_html( 'post' ) )
2326 + ),
1881 2327 'form_show_nohtml' => wp_strip_all_tags( $parsed_form_show ),
1882 2328 'short_dates_content' => $short_dates_content,
1883 2329 'wide_dates_content' => $wide_dates_content,
1884 2330 'payment_label_template' => $payment_label_template
@@ -1888,45 +2334,96 @@
1888 2334 return $bookings_arr;
1889 2335 }
1890 2336
1891 2337
2338 + //TODO: Refactor this function to make this simpler, for prevent of issues in future.
1892 2339 /**
1893 2340 * Get SHORT Dates showing data
1894 2341 *
1895 - * @param array $short_dates_arr - Array of dates
1896 - * @param bool $is_approved - is dates approved or not
1897 - * @param type $dates_type_id_arr
1898 - * @param type $booking_resources_arr
2342 + * @param array $short_dates_arr - Array of dates.
2343 + * @param bool $is_approved - true or false
2344 + * @param $dates_type_id_arr
2345 + * @param $booking_resources_arr
2346 + * @param array $attr - [ 'date_html_tag' => 'a' ] .
1899 2347 *
1900 2348 * @return string
1901 2349 */
1902 - function wpbc_get_formated_dates__short( $short_dates_arr, $is_approved = false, $dates_type_id_arr = array() , $booking_resources_arr = array() ){
2350 + function wpbc_get_formated_dates__short( $short_dates_arr, $is_approved = false, $dates_type_id_arr = array(), $booking_resources_arr = array(), $attr = array() ) {
1903 2351
1904 - $css_class_approved = ( $is_approved ) ? 'approved' : '';
1905 - $short_dates_content = '';
1906 - $date_number = 0;
2352 + $defaults = array(
2353 + 'date_html_tag' => 'a',
2354 + 'show_child_resource_in_dates' => true,
2355 + );
2356 + $params = wp_parse_args( $attr, $defaults );
1907 2357
1908 - foreach ( $short_dates_arr as $dt ) {
2358 + $css_class_approved = ( $is_approved ) ? 'approved' : '';
2359 + $short_dates_content = '';
2360 + $short_dates_content_arr = array();
2361 + $date_number = 0;
2362 + $previous_formatted_date = '';
2363 + $previous_short_dates_content_sup;
2364 + $previous_sql_date = '';
2365 + $previous_short_date_item = '';
2366 + foreach ( $short_dates_arr as $dt ) {
1909 2367
1910 - if ( $dt == '-' ) {
2368 + if ( '-' === $dt ) {
2369 + $short_dates_content_arr[] = '<span class="date_tire"> - </span>';
2370 + } elseif ( ',' === $dt ) {
2371 + $short_dates_content_arr[] = '<span class="date_tire date_comma">, </span>';
2372 + } else {
2373 +
2374 + // Separate recurrent time slots: previous end (...02) followed by the next start (...01).
2375 + $is_next_time_slot = (
2376 + ( ! empty( $previous_sql_date ) )
2377 + && ( '02' === substr( trim( $previous_sql_date ), -2 ) )
2378 + && ( '01' === substr( trim( $dt ), -2 ) )
2379 + );
2380 + if ( $is_next_time_slot && ( ',' !== $previous_short_date_item ) ) {
2381 + if ( '-' === $previous_short_date_item ) {
2382 + array_pop( $short_dates_content_arr );
2383 + }
2384 + $short_dates_content_arr[] = '<span class="date_tire date_comma">, </span>'; // FixIn: 11.4.2.
2385 + }
2386 +
2387 + list( $formatted_date, $formatted_time ) = wpbc_get_date_in_correct_format( $dt );
1911 2388
1912 - $short_dates_content .= '<span class="date_tire"> - </span>';
2389 + $short_dates_content = '';
2390 + $short_dates_content_sup = ''; // Times and booking resources.
1913 2391
1914 - } elseif ( $dt == ',' ) {
2392 + if ( 'a' === $params['date_html_tag'] ) {
2393 + $short_dates_content .= '<a href="javascript:void(0)" onclick="javascript:wpbc_ajx_click_on_dates_toggle(this);" ';
2394 + } else {
2395 + $short_dates_content .= '<' . $params['date_html_tag'];
2396 + }
2397 + $short_dates_content .= ' class="wpbc_label wpbc_label_booking_dates ' . $css_class_approved . '">';
1915 2398
1916 - $short_dates_content .= '<span class="date_tire">, </span>';
2399 + $short_dates_content .= '<span>';
1917 2400
1918 - } else {
2401 + if ( $previous_formatted_date !== $formatted_date ) {
2402 + $short_dates_content .= $formatted_date;
2403 + $short_dates_content_sup .= '<sup class="field-booking-time">' . $formatted_time . '</sup>';
2404 + } else {
2405 + // same date (probaly it is one date) !
2406 + if ( count( $short_dates_content_arr ) > 0 ) {
2407 + // Unset tire: '-'.
2408 + array_pop( $short_dates_content_arr );
2409 + if ( ! empty( wp_strip_all_tags( $previous_short_dates_content_sup ) ) ) {
2410 + $tag_closed_span_and_a = array_pop( $short_dates_content_arr );
2411 + array_pop( $short_dates_content_arr ); // Unset time_sup.
2412 + $short_dates_content_arr[] = $tag_closed_span_and_a; // FixIn: 11.4.2.
2413 + }
2414 + $short_dates_content_sup .= '<sup class="field-booking-time"> '
2415 + . trim( wp_strip_all_tags( $previous_short_dates_content_sup ) )
2416 + . ' - '
2417 + . trim( $formatted_time )
2418 + . '</sup>'; // FixIn: 11.4.2.
2419 + }
2420 + }
1919 2421
1920 - list( $formatted_date, $formatted_time ) = wpbc_get_date_in_correct_format( $dt );
1921 -
1922 - $short_dates_content .= '<a href="javascript:void(0)" onclick="javascript:wpbc_ajx_click_on_dates_toggle(this);" class="wpbc_label wpbc_label_booking_dates ' . $css_class_approved . '"><span>';
1923 - $short_dates_content .= $formatted_date;
1924 - $short_dates_content .= '<sup class="field-booking-time">' . $formatted_time . '</sup>';
1925 -
1926 - // BL
2422 + // BL.
1927 2423 if (
1928 2424 ( class_exists( 'wpdev_bk_biz_l' ) )
2425 + && ( $params['show_child_resource_in_dates'] )
1929 2426 && ( ! empty( $dates_type_id_arr[ $date_number ] ) )
1930 2427 && ( isset( $booking_resources_arr[ $dates_type_id_arr[ $date_number ] ] ) )
1931 2428 ){
1932 2429
@@ -1938,16 +2435,27 @@
1938 2435 if ( strlen( $resource_title ) > 19 ) {
1939 2436 $resource_title = substr( $resource_title, 0, 13 ) . '...' . substr( $resource_title, - 3 );
1940 2437 }
1941 2438
1942 - $short_dates_content .= '<sup class="field-booking-time date_from_dif_type"> ' . $resource_title . '</sup>';
2439 + $short_dates_content_sup .= '<sup class="field-booking-time date_from_dif_type"> ' . $resource_title . '</sup>';
1943 2440 }
1944 2441
1945 - $short_dates_content .= '</span></a>';
1946 - }
1947 - $date_number++;
2442 + $short_dates_content_arr[] = $short_dates_content;
2443 + $short_dates_content_arr[] = $short_dates_content_sup;
2444 + $short_dates_content_arr[] = '</span></' . $params['date_html_tag'] . '>';
2445 +
2446 +
2447 +
2448 + $previous_short_dates_content_sup = $short_dates_content_sup;
2449 + $previous_formatted_date = $formatted_date;
2450 + $previous_sql_date = $dt;
2451 + }
2452 + $previous_short_date_item = $dt;
2453 + $date_number++;
1948 2454 }
1949 2455
2456 + $short_dates_content = implode( '', $short_dates_content_arr );
2457 +
1950 2458 return $short_dates_content;
1951 2459 }
1952 2460
1953 2461
@@ -1960,10 +2468,16 @@
1960 2468 * @param type $booking_resources_arr - array of booking resources objects
1961 2469 *
1962 2470 * @return string
1963 2471 */
1964 - function wpbc_get_formated_dates__wide( $dates_arr, $is_approved = false, $dates_type_id_arr = array(), $booking_resources_arr = array() ){
2472 + function wpbc_get_formated_dates__wide( $dates_arr, $is_approved = false, $dates_type_id_arr = array(), $booking_resources_arr = array(), $attr = array() ) {
1965 2473
2474 + $defaults = array(
2475 + 'date_html_tag' => 'a',
2476 + 'show_child_resource_in_dates' => true,
2477 + );
2478 + $params = wp_parse_args( $attr, $defaults );
2479 +
1966 2480 $wide_dates_arr = array();
1967 2481
1968 2482 $css_class_approved = ( $is_approved ) ? 'approved' : '';
1969 2483
@@ -1970,9 +2484,17 @@
1970 2484 foreach ( $dates_arr as $date_number => $sql_booking_date ) {
1971 2485
1972 2486 list( $formatted_date, $formatted_time ) = wpbc_get_date_in_correct_format( $sql_booking_date );
1973 2487
1974 - $wide_date = '<a href="javascript:void(0)" onclick="javascript:wpbc_ajx_click_on_dates_toggle(this);" class="wpbc_label wpbc_label_booking_dates ' . $css_class_approved . '"><span>';
2488 + $wide_date = '';
2489 + if ( 'a' === $params['date_html_tag'] ) {
2490 + $wide_date .= '<a href="javascript:void(0)" onclick="javascript:wpbc_ajx_click_on_dates_toggle(this);" ';
2491 + } else {
2492 + $wide_date .= '<' . $params['date_html_tag'];
2493 + }
2494 + $wide_date .= ' class="wpbc_label wpbc_label_booking_dates ' . $css_class_approved . '">';
2495 + $wide_date .= '<span>';
2496 +
1975 2497 $wide_date .= $formatted_date;
1976 2498 $wide_date .= '<sup class="field-booking-time">' . $formatted_time . '</sup>';
1977 2499
1978 2500 // BL
@@ -1977,8 +2499,9 @@
1977 2499
1978 2500 // BL
1979 2501 if (
1980 2502 ( class_exists( 'wpdev_bk_biz_l' ) )
2503 + && ( $params['show_child_resource_in_dates'] )
1981 2504 && ( '' != $dates_type_id_arr[ $date_number ] )
1982 2505 && ( isset( $booking_resources_arr[ $dates_type_id_arr[ $date_number ] ] ) )
1983 2506 ){
1984 2507 $resource_title = ( isset( $booking_resources_arr[ $dates_type_id_arr[ $date_number ] ] ) )
@@ -1991,14 +2514,14 @@
1991 2514 }
1992 2515 $wide_date .= '<sup class="field-booking-time date_from_dif_type"> ' . $resource_title . '</sup>';
1993 2516 }
1994 2517
1995 - $wide_date .= '</span></a>';
2518 + $wide_date .= '</span></' . $params['date_html_tag'] . '>';
1996 2519
1997 2520 $wide_dates_arr[] = $wide_date;
1998 2521 }
1999 2522
2000 - $wide_dates_content = implode( '<span class="date_tire">, </span>' , $wide_dates_arr );
2523 + $wide_dates_content = implode( '<span class="date_tire date_comma">, </span>' , $wide_dates_arr );
2001 2524
2002 2525 return $wide_dates_content;
2003 2526 }
2004 2527
@@ -2111,9 +2634,9 @@
2111 2634 [cost_hint] => &amp;#36;95
2112 2635 [rangetime] => 10:00 AM - 12:00 PM
2113 2636 [name] => test
2114 2637 [email] => test@wpbookingcalendar.com
2115 - ...
2638 + ...
2116 2639 )
2117 2640
2118 2641 * @param array $booking_system_arr array of system fields from DB
2119 2642 Array ( [booking_id] => 188
@@ -2124,9 +2647,9 @@
2124 2647 [pay_request] => 0
2125 2648 [id] => 188
2126 2649 [approved] => 0
2127 2650 )
2128 -
2651 +
2129 2652 * @param array $system_keys_arr system fields keys that need to be added, like this:
2130 2653 Array ( booking_id, trash, sync_gid, is_new, status
2131 2654 , sort_date, modification_date, hash, booking_type
2132 2655 , remark, cost, pay_status, pay_request, id, approved )
@@ -2205,64 +2728,124 @@
2205 2728
2206 2729
2207 2730 /**
2208 2731 * Get pure "Content of booking fields data" with shortcodes inside.
2209 - * it can depend on specific booking resource in Business Medium version or User in MultiUser version
2732 + * Can depend on booking resource (BM) or resource owner (MU).
2733 + * Now also supports BFB DB resolver (published/preview-aware).
2210 2734 *
2211 - * @param int $resource_id
2212 - * @param sting $custom_booking_form_name - use this custom booking form, if possible
2735 + * @param int $resource_id
2736 + * @param string $custom_booking_form_name Optional. Force this custom form if possible.
2213 2737 *
2214 2738 * @return string
2215 2739 */
2216 - function wpbc_get_content_booking_form_show( $resource_id , $custom_booking_form_name = '' ){ // FixIn: 9.4.3.12.
2740 + function wpbc_get_content_booking_form_show( $resource_id, $custom_booking_form_name = '' ) { // FixIn: 9.4.3.12.
2217 2741
2218 - if ( $resource_id == -1 ) {
2219 - if ( function_exists('get__default_type') )
2220 - $resource_id = get__default_type();
2221 - else
2222 - $resource_id = 1;
2223 - }
2742 + static $wpbc__form_show_cache = array();
2224 2743
2225 - if ( ! class_exists('wpdev_bk_personal') ) {
2744 + $resource_id = (int) $resource_id;
2745 + $custom_booking_form_name = (string) $custom_booking_form_name;
2226 2746
2227 - $booking_form_show = wpbc_simple_form__get_form_show__as_shortcodes();
2228 - $booking_form_show = wpbc_bf__replace_custom_html_shortcodes( $booking_form_show );
2747 + if ( - 1 === $resource_id ) {
2748 + if ( function_exists( 'get__default_type' ) ) {
2749 + $resource_id = (int) get__default_type();
2750 + } else {
2751 + $resource_id = 1;
2752 + }
2753 + }
2229 2754
2230 - } else {
2755 + // ------------------------------------------------------------
2756 + // Determine a stable form slug early (avoid undefined var).
2757 + // This is used for cache key and for resolver path.
2758 + // ------------------------------------------------------------
2759 + $my_booking_form_name = ( '' !== $custom_booking_form_name ) ? $custom_booking_form_name : 'standard';
2231 2760
2232 - $booking_form_show = get_bk_option( 'booking_form_show' );
2233 - $booking_form_show = wpbc_bf__replace_custom_html_shortcodes( $booking_form_show );
2761 + // Preview-aware context (optional; usually "published" in Booking Listing).
2762 + $ctx = array();
2763 + if ( function_exists( 'wpbc_get_request_form_context' ) ) {
2764 + $ctx = wpbc_get_request_form_context();
2765 + }
2766 + $form_status = ( isset( $ctx['form_status'] ) ) ? sanitize_key( $ctx['form_status'] ) : 'published';
2767 + if ( in_array( $form_status, array( 'publish', 'published' ), true ) ) {
2768 + $form_status = 'published';
2769 + }
2770 + if ( 'preview' !== $form_status ) {
2771 + $form_status = 'published';
2772 + }
2234 2773
2235 - if ( class_exists('wpdev_bk_biz_m') ) {
2774 + // Cache key (important: this function is called per booking row).
2775 + $cache_key = get_locale() . '|' . $form_status . '|' . $resource_id . '|' . $my_booking_form_name;
2776 + if ( isset( $wpbc__form_show_cache[ $cache_key ] ) ) {
2777 + return $wpbc__form_show_cache[ $cache_key ];
2778 + }
2236 2779
2237 - if ( ! empty( $custom_booking_form_name ) ) { // FixIn: 9.4.3.12.
2780 + if ( '' === $custom_booking_form_name ) {
2781 + $default_form_name = apply_bk_filter( 'wpbc_get_default_custom_form', 'standard', $resource_id );
2782 + if ( ! empty( $default_form_name ) ) {
2783 + $my_booking_form_name = $default_form_name;
2784 + }
2785 + }
2786 +
2787 + $booking_form_show = '';
2788 +
2789 + if ( class_exists( 'WPBC_FE_Form_Source_Resolver' ) && class_exists( 'WPBC_BFB_Form_Loader' ) ) {
2238 2790
2239 - $booking_form_show = apply_bk_filter( 'wpdev_get_booking_form_content', $booking_form_show, $custom_booking_form_name );
2240 - $my_booking_form_name = $custom_booking_form_name;
2241 - } else {
2242 - // BM :: Get default Custom Form of Resource
2243 - $my_booking_form_name = apply_bk_filter( 'wpbc_get_default_custom_form', 'standard', $resource_id );
2244 - if ( ( $my_booking_form_name != 'standard' ) && ( ! empty( $my_booking_form_name ) ) ) {
2245 - $booking_form_show = apply_bk_filter( 'wpdev_get_booking_form_content', $booking_form_show, $my_booking_form_name );
2246 - }
2247 - }
2248 - //MU :: if resource of "Regular User" - then GET STANDARD user form ( if ( get_bk_option( 'booking_is_custom_forms_for_regular_users' ) !== 'On' ) )
2249 - $booking_form_show = apply_bk_filter( 'wpbc_multiuser_get_booking_form_show_of_regular_user', $booking_form_show, $resource_id, $my_booking_form_name ); // FixIn: 8.1.3.19.
2791 + $req = array(
2792 + 'resource_id' => (int) $resource_id,
2793 + 'form_slug' => (string) $my_booking_form_name,
2794 + 'form_status' => $form_status,
2795 + 'custom_params' => array(),
2796 + 'ctx' => ( is_array( $ctx ) ? $ctx : array() ),
2797 + );
2250 2798
2251 - }
2252 - }
2799 + $resolved = WPBC_FE_Form_Source_Resolver::resolve( $req );
2253 2800
2254 - // Language
2255 - $booking_form_show = wpbc_lang( $booking_form_show );
2801 + // If preview requested but not found, try published as fallback.
2802 + if ( ( empty( $resolved['engine'] ) || ( 'bfb_db' !== $resolved['engine'] ) ) && ( 'preview' === $form_status ) ) {
2803 + $req['form_status'] = 'published';
2804 + $resolved = WPBC_FE_Form_Source_Resolver::resolve( $req );
2805 + }
2256 2806
2257 - $search = array( "'(<br[ ]?[/]?>)+'si", "'(<[/]?p[ ]?>)+'si" );
2258 - $replace = array( "&nbsp;&nbsp;", " &nbsp; ", " &nbsp; " );
2259 - $booking_form_show = preg_replace( $search, $replace, $booking_form_show );
2807 + if ( ! empty( $resolved['engine'] ) && ( 'bfb_db' === $resolved['engine'] ) ) {
2260 2808
2809 + $bfb_loader_args = array();
2810 + if ( ! empty( $resolved['bfb_loader_args'] ) && is_array( $resolved['bfb_loader_args'] ) ) {
2811 + $bfb_loader_args = $resolved['bfb_loader_args'];
2812 + }
2813 +
2814 + // We need "content_form" template for booking fields output.
2815 + $bfb_loader_args['return'] = 'content_form';
2816 +
2817 + $bfb_pair = wpbc_bfb_get_booking_form_pair( $bfb_loader_args );
2818 +
2819 + $content_form = '';
2820 + if ( is_array( $bfb_pair ) && isset( $bfb_pair['content'] ) ) {
2821 + $content_form = (string) $bfb_pair['content'];
2822 + }
2823 +
2824 + if ( '' !== trim( $content_form ) ) {
2825 + $booking_form_show = wpbc_bf__replace_custom_html_shortcodes( $content_form );
2826 + }
2827 + }
2828 + }
2829 +
2830 + // ------------------------------------------------------------
2831 + // Language + cleanup (keep old behavior).
2832 + // ------------------------------------------------------------
2833 + $booking_form_show = wpbc_lang( $booking_form_show );
2834 +
2835 + $search = array( "'(<br[ ]?[/]?>)+'si", "'(<[/]?p[ ]?>)+'si" );
2836 + $replace = array( "&nbsp;&nbsp;", " &nbsp; ", " &nbsp; " );
2837 + $booking_form_show = preg_replace( $search, $replace, $booking_form_show );
2838 +
2839 + // Store cache by final slug (slug may have changed in BM branch).
2840 + $final_cache_key = get_locale() . '|' . $form_status . '|' . $resource_id . '|' . $my_booking_form_name;
2841 + $wpbc__form_show_cache[ $final_cache_key ] = $booking_form_show;
2842 +
2261 2843 return $booking_form_show;
2262 2844 }
2263 2845
2264 2846
2847 +
2265 2848 /**
2266 2849 * Get parsed "Content of booking fields data" - Shortcodes replaced by Values
2267 2850 *
2268 2851 * @param array $booking_data_arr
@@ -2546,5 +3129,5 @@
2546 3129 die( '<strong>Error!</strong> Probably nonce for this page has been expired. Please <a href="javascript:void(0)" onclick="javascript:location.reload();">reload the page</a>.' );
2547 3130 }
2548 3131 }
2549 3132 add_action( 'check_ajax_referer', 'wpbc_check_ajax_referer__for_booking_listing', 2, 10 );
2550 -// </editor-fold>
3133 +// </editor-fold>