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 +622 -107 10.1111.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
@@ -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.
@@ -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_the_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,11 +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 - $dates_attr = array( 'date_html_tag' => 'span' );
1782 - $short_dates_content = wpbc_get_formated_dates__short( $booking->short_dates, (boolean) $booking->approved, $booking->short_dates_child_id, $resources_arr, $dates_attr );
1783 - $wide_dates_content = wpbc_get_formated_dates__wide( $booking->dates, (boolean) $booking->approved, $booking->child_id, $resources_arr, $dates_attr );
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 );
1784 2206
1785 2207 //------------------------------------------------------------------------------------------------------
1786 2208 // Payment Status
1787 2209 //------------------------------------------------------------------------------------------------------
@@ -1850,8 +2272,10 @@
1850 2272 // Add some fields to [ 'parsed_fields' ]
1851 2273 //------------------------------------------------------------------------------------------------------
1852 2274 $booking_data_arr['resource_title'] = $resource_title;
1853 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;
1854 2278 $booking_data_arr['resource_owner_user'] = $resource_owner_user;
1855 2279 //$booking_data_arr['short_dates_content'] = $short_dates_content;
1856 2280 //$booking_data_arr['wide_dates_content'] = $wide_dates_content;
1857 2281
@@ -1858,10 +2282,15 @@
1858 2282 //------------------------------------------------------------------------------------------------------
1859 2283 // Form Show - "Content of booking fields data" form
1860 2284 //------------------------------------------------------------------------------------------------------
1861 2285
1862 - $custom_booking_form_name = ( ! empty( $booking_data_arr['wpbc_custom_booking_form'] ) ) ? $booking_data_arr['wpbc_custom_booking_form'] : ''; // FixIn: 9.4.3.12.
1863 - $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; ...
1864 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; ...
1865 2294
1866 2295 //------------------------------------------------------------------------------------------------------
1867 2296 // Google Calendar link
@@ -1874,9 +2303,11 @@
1874 2303 $booking_data_arr['visitorbookingpayurl'] = ( class_exists( 'wpdev_bk_biz_s' ) )
1875 2304 ? apply_bk_filter( 'wpdev_booking_set_booking_edit_link_at_email', '[visitorbookingpayurl]', $booking_id )
1876 2305 : '';
1877 2306 // =====================================================================================================
1878 - $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;
1879 2310
1880 2311
1881 2312 // =====================================================================================================
1882 2313 $bookings_arr[ $booking_id ]->templates = array(
@@ -1919,8 +2350,9 @@
1919 2350 function wpbc_get_formated_dates__short( $short_dates_arr, $is_approved = false, $dates_type_id_arr = array(), $booking_resources_arr = array(), $attr = array() ) {
1920 2351
1921 2352 $defaults = array(
1922 2353 'date_html_tag' => 'a',
2354 + 'show_child_resource_in_dates' => true,
1923 2355 );
1924 2356 $params = wp_parse_args( $attr, $defaults );
1925 2357
1926 2358 $css_class_approved = ( $is_approved ) ? 'approved' : '';
@@ -1926,20 +2358,35 @@
1926 2358 $css_class_approved = ( $is_approved ) ? 'approved' : '';
1927 2359 $short_dates_content = '';
1928 2360 $short_dates_content_arr = array();
1929 2361 $date_number = 0;
1930 - $previous_formatted_date = '';
1931 - $previous_short_dates_content_sup;
1932 - foreach ( $short_dates_arr as $dt ) {
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 ) {
1933 2367
1934 2368 if ( '-' === $dt ) {
1935 2369 $short_dates_content_arr[] = '<span class="date_tire"> - </span>';
1936 - } elseif ( ',' === $dt ) {
1937 - $short_dates_content_arr[] = '<span class="date_tire date_comma">, </span>';
1938 - } else {
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 );
1939 2388
1940 - list( $formatted_date, $formatted_time ) = wpbc_get_date_in_correct_format( $dt );
1941 -
1942 2389 $short_dates_content = '';
1943 2390 $short_dates_content_sup = ''; // Times and booking resources.
1944 2391
1945 2392 if ( 'a' === $params['date_html_tag'] ) {
@@ -1954,19 +2401,22 @@
1954 2401 if ( $previous_formatted_date !== $formatted_date ) {
1955 2402 $short_dates_content .= $formatted_date;
1956 2403 $short_dates_content_sup .= '<sup class="field-booking-time">' . $formatted_time . '</sup>';
1957 2404 } else {
1958 - // same date (probaly it is one date) !
1959 - if ( count( $short_dates_content_arr ) > 0 ) {
1960 - // Unset tire: '-'.
1961 - unset( $short_dates_content_arr[ count( $short_dates_content_arr ) - 1 ] );
1962 - if ( ! empty( wp_strip_all_tags( $previous_short_dates_content_sup ) ) ) {
1963 - $tag_closed_span_and_a = $short_dates_content_arr[ count( $short_dates_content_arr ) - 1 ];
1964 - // unset time_sup
1965 - unset( $short_dates_content_arr[ count( $short_dates_content_arr ) - 1 ] );
1966 - $short_dates_content_arr[ count( $short_dates_content_arr ) - 1 ] = $tag_closed_span_and_a;
1967 - }
1968 - $short_dates_content_sup .= '<sup class="field-booking-time">' . wp_strip_all_tags( $previous_short_dates_content_sup ) . ' - ' . $formatted_time . '</sup>';
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.
1969 2419 }
1970 2420 }
1971 2421
1972 2422 // BL.
@@ -1971,8 +2421,9 @@
1971 2421
1972 2422 // BL.
1973 2423 if (
1974 2424 ( class_exists( 'wpdev_bk_biz_l' ) )
2425 + && ( $params['show_child_resource_in_dates'] )
1975 2426 && ( ! empty( $dates_type_id_arr[ $date_number ] ) )
1976 2427 && ( isset( $booking_resources_arr[ $dates_type_id_arr[ $date_number ] ] ) )
1977 2428 ){
1978 2429
@@ -1993,12 +2444,14 @@
1993 2444 $short_dates_content_arr[] = '</span></' . $params['date_html_tag'] . '>';
1994 2445
1995 2446
1996 2447
1997 - $previous_short_dates_content_sup = $short_dates_content_sup;
1998 - $previous_formatted_date = $formatted_date;
1999 - }
2000 - $date_number++;
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++;
2001 2454 }
2002 2455
2003 2456 $short_dates_content = implode( '', $short_dates_content_arr );
2004 2457
@@ -2019,8 +2472,9 @@
2019 2472 function wpbc_get_formated_dates__wide( $dates_arr, $is_approved = false, $dates_type_id_arr = array(), $booking_resources_arr = array(), $attr = array() ) {
2020 2473
2021 2474 $defaults = array(
2022 2475 'date_html_tag' => 'a',
2476 + 'show_child_resource_in_dates' => true,
2023 2477 );
2024 2478 $params = wp_parse_args( $attr, $defaults );
2025 2479
2026 2480 $wide_dates_arr = array();
@@ -2045,8 +2499,9 @@
2045 2499
2046 2500 // BL
2047 2501 if (
2048 2502 ( class_exists( 'wpdev_bk_biz_l' ) )
2503 + && ( $params['show_child_resource_in_dates'] )
2049 2504 && ( '' != $dates_type_id_arr[ $date_number ] )
2050 2505 && ( isset( $booking_resources_arr[ $dates_type_id_arr[ $date_number ] ] ) )
2051 2506 ){
2052 2507 $resource_title = ( isset( $booking_resources_arr[ $dates_type_id_arr[ $date_number ] ] ) )
@@ -2179,9 +2634,9 @@
2179 2634 [cost_hint] => &amp;#36;95
2180 2635 [rangetime] => 10:00 AM - 12:00 PM
2181 2636 [name] => test
2182 2637 [email] => test@wpbookingcalendar.com
2183 - ...
2638 + ...
2184 2639 )
2185 2640
2186 2641 * @param array $booking_system_arr array of system fields from DB
2187 2642 Array ( [booking_id] => 188
@@ -2192,9 +2647,9 @@
2192 2647 [pay_request] => 0
2193 2648 [id] => 188
2194 2649 [approved] => 0
2195 2650 )
2196 -
2651 +
2197 2652 * @param array $system_keys_arr system fields keys that need to be added, like this:
2198 2653 Array ( booking_id, trash, sync_gid, is_new, status
2199 2654 , sort_date, modification_date, hash, booking_type
2200 2655 , remark, cost, pay_status, pay_request, id, approved )
@@ -2273,64 +2728,124 @@
2273 2728
2274 2729
2275 2730 /**
2276 2731 * Get pure "Content of booking fields data" with shortcodes inside.
2277 - * 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).
2278 2734 *
2279 - * @param int $resource_id
2280 - * @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.
2281 2737 *
2282 2738 * @return string
2283 2739 */
2284 - 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.
2285 2741
2286 - if ( $resource_id == -1 ) {
2287 - if ( function_exists('get__default_type') )
2288 - $resource_id = get__default_type();
2289 - else
2290 - $resource_id = 1;
2291 - }
2742 + static $wpbc__form_show_cache = array();
2292 2743
2293 - if ( ! class_exists('wpdev_bk_personal') ) {
2744 + $resource_id = (int) $resource_id;
2745 + $custom_booking_form_name = (string) $custom_booking_form_name;
2294 2746
2295 - $booking_form_show = wpbc_simple_form__get_form_show__as_shortcodes();
2296 - $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 + }
2297 2754
2298 - } 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';
2299 2760
2300 - $booking_form_show = get_bk_option( 'booking_form_show' );
2301 - $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 + }
2302 2773
2303 - 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 + }
2304 2779
2305 - 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' ) ) {
2306 2790
2307 - $booking_form_show = apply_bk_filter( 'wpdev_get_booking_form_content', $booking_form_show, $custom_booking_form_name );
2308 - $my_booking_form_name = $custom_booking_form_name;
2309 - } else {
2310 - // BM :: Get default Custom Form of Resource
2311 - $my_booking_form_name = apply_bk_filter( 'wpbc_get_default_custom_form', 'standard', $resource_id );
2312 - if ( ( $my_booking_form_name != 'standard' ) && ( ! empty( $my_booking_form_name ) ) ) {
2313 - $booking_form_show = apply_bk_filter( 'wpdev_get_booking_form_content', $booking_form_show, $my_booking_form_name );
2314 - }
2315 - }
2316 - //MU :: if resource of "Regular User" - then GET STANDARD user form ( if ( get_bk_option( 'booking_is_custom_forms_for_regular_users' ) !== 'On' ) )
2317 - $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 + );
2318 2798
2319 - }
2320 - }
2799 + $resolved = WPBC_FE_Form_Source_Resolver::resolve( $req );
2321 2800
2322 - // Language
2323 - $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 + }
2324 2806
2325 - $search = array( "'(<br[ ]?[/]?>)+'si", "'(<[/]?p[ ]?>)+'si" );
2326 - $replace = array( "&nbsp;&nbsp;", " &nbsp; ", " &nbsp; " );
2327 - $booking_form_show = preg_replace( $search, $replace, $booking_form_show );
2807 + if ( ! empty( $resolved['engine'] ) && ( 'bfb_db' === $resolved['engine'] ) ) {
2328 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 +
2329 2843 return $booking_form_show;
2330 2844 }
2331 2845
2332 2846
2847 +
2333 2848 /**
2334 2849 * Get parsed "Content of booking fields data" - Shortcodes replaced by Values
2335 2850 *
2336 2851 * @param array $booking_data_arr
@@ -2614,5 +3129,5 @@
2614 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>.' );
2615 3130 }
2616 3131 }
2617 3132 add_action( 'check_ajax_referer', 'wpbc_check_ajax_referer__for_booking_listing', 2, 10 );
2618 -// </editor-fold>
3133 +// </editor-fold>