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 +489 -92 11.311.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
@@ -30,9 +30,9 @@
30 30 */
31 31 function wpbc_ajx_get__request_params__names_default( $structure_type = 'validate_and_default' ){
32 32
33 33 // Clean specific $_REQUEST params, if param is NOT set then return "default"
34 - $params_for_cleaning = array(
34 + $params_for_cleaning = array(
35 35 // 'wh_booking_id' => array( 'validate' => 'digit_or_date', 'default' => '' ),
36 36
37 37 // 'digit_or_csd' can check about 'digit_or_csd' in arrays, as well
38 38 'wh_booking_type' => array( 'validate' => 'digit_or_csd', 'default' => array( '0' ) ) // if ['0'] - All booking resources, ['-1'] - lost bookings in deleted resources
@@ -90,12 +90,23 @@
90 90 , 'scroll_start_date' => array( 'validate' => 'digit_or_date', 'default' => '' ) // number | date 2016-07-20
91 91 , 'scroll_day' => array( 'validate' => 'd', 'default' => 0 ) // '1' | ''
92 92 , 'scroll_month' => array( 'validate' => 'd', 'default' => 0 ) // '1' | ''
93 93 , 'limit_hours' => array( 'validate' => 'digit_or_csd', 'default' => '' ) //
94 - , '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 );
95 108
96 - );
97 -
98 109 if ( 'validate_and_default' == $structure_type ) {
99 110 return $params_for_cleaning;
100 111 }
101 112
@@ -919,12 +930,36 @@
919 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
920 931 }
921 932 }
922 933
923 - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
924 -
925 -
926 - 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'] ) {
927 962 case 'booking_id__asc':
928 963 $order_by = 'booking_id ASC ';
929 964 break;
930 965 case 'booking_id__desc':
@@ -1603,9 +1638,9 @@
1603 1638 * )
1604 1639 * [181] => stdClass Object (
1605 1640 * ....
1606 1641 */
1607 - 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 ){
1608 1643
1609 1644 $bookings_arr = array();
1610 1645 foreach ( $bookings_obj as $booking ) {
1611 1646
@@ -1709,14 +1744,376 @@
1709 1744 }
1710 1745
1711 1746 } // bookings loop: $booking_id => $booking
1712 1747
1713 - return $bookings_arr;
1714 - }
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 ) {
1715 2115
1716 -
1717 - function wpbc_ajx_parse_bookings( $bookings_arr, $resources_arr ) {
1718 -
1719 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
1720 2117
1721 2118 foreach ( $bookings_arr as $booking_id => $booking ) {
1722 2119
@@ -1748,9 +2145,11 @@
1748 2145 $resource_id_listing = $child_resource_id_arr[0];
1749 2146 $resource_title_listing = wpbc_lang( $resources_arr[ $child_resource_id_arr[0] ]['title'] );
1750 2147 }
1751 2148 }
1752 - $show_child_resource_in_dates = ( count( $child_resource_id_arr ) > 1 );
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();
1753 2152
1754 2153 // Parse form fields only from $booking->booking_db->form ------------------------------------------
1755 2154 $booking_data_arr = wpbc_parse_booking_data_fields( $booking->booking_db->form,
1756 2155 array( 'resource_id' => $resource_id )
@@ -1797,14 +2196,14 @@
1797 2196 // Set dates and times in correct format ---------------------------------------------------------------
1798 2197 $booking_data_arr = wpbc_parse_booking_data_fields_formats( $booking_data_arr );
1799 2198
1800 2199 // Get SHORT / WIDE Dates showing data -----------------------------------------------------------------
1801 - $dates_attr = array(
1802 - 'date_html_tag' => 'span',
1803 - 'show_child_resource_in_dates' => $show_child_resource_in_dates,
1804 - );
1805 - $short_dates_content = wpbc_get_formated_dates__short( $booking->short_dates, (boolean) $booking->approved, $booking->short_dates_child_id, $resources_arr, $dates_attr );
1806 - $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 );
1807 2206
1808 2207 //------------------------------------------------------------------------------------------------------
1809 2208 // Payment Status
1810 2209 //------------------------------------------------------------------------------------------------------
@@ -1883,10 +2282,15 @@
1883 2282 //------------------------------------------------------------------------------------------------------
1884 2283 // Form Show - "Content of booking fields data" form
1885 2284 //------------------------------------------------------------------------------------------------------
1886 2285
1887 - $custom_booking_form_name = ( ! empty( $booking_data_arr['wpbc_custom_booking_form'] ) ) ? $booking_data_arr['wpbc_custom_booking_form'] : ''; // FixIn: 9.4.3.12.
1888 - $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; ...
1889 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; ...
1890 2294
1891 2295 //------------------------------------------------------------------------------------------------------
1892 2296 // Google Calendar link
@@ -1899,9 +2303,11 @@
1899 2303 $booking_data_arr['visitorbookingpayurl'] = ( class_exists( 'wpdev_bk_biz_s' ) )
1900 2304 ? apply_bk_filter( 'wpdev_booking_set_booking_edit_link_at_email', '[visitorbookingpayurl]', $booking_id )
1901 2305 : '';
1902 2306 // =====================================================================================================
1903 - $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;
1904 2310
1905 2311
1906 2312 // =====================================================================================================
1907 2313 $bookings_arr[ $booking_id ]->templates = array(
@@ -1952,20 +2358,35 @@
1952 2358 $css_class_approved = ( $is_approved ) ? 'approved' : '';
1953 2359 $short_dates_content = '';
1954 2360 $short_dates_content_arr = array();
1955 2361 $date_number = 0;
1956 - $previous_formatted_date = '';
1957 - $previous_short_dates_content_sup;
1958 - 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 ) {
1959 2367
1960 2368 if ( '-' === $dt ) {
1961 2369 $short_dates_content_arr[] = '<span class="date_tire"> - </span>';
1962 - } elseif ( ',' === $dt ) {
1963 - $short_dates_content_arr[] = '<span class="date_tire date_comma">, </span>';
1964 - } 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 );
1965 2388
1966 - list( $formatted_date, $formatted_time ) = wpbc_get_date_in_correct_format( $dt );
1967 -
1968 2389 $short_dates_content = '';
1969 2390 $short_dates_content_sup = ''; // Times and booking resources.
1970 2391
1971 2392 if ( 'a' === $params['date_html_tag'] ) {
@@ -1980,19 +2401,22 @@
1980 2401 if ( $previous_formatted_date !== $formatted_date ) {
1981 2402 $short_dates_content .= $formatted_date;
1982 2403 $short_dates_content_sup .= '<sup class="field-booking-time">' . $formatted_time . '</sup>';
1983 2404 } else {
1984 - // same date (probaly it is one date) !
1985 - if ( count( $short_dates_content_arr ) > 0 ) {
1986 - // Unset tire: '-'.
1987 - unset( $short_dates_content_arr[ count( $short_dates_content_arr ) - 1 ] );
1988 - if ( ! empty( wp_strip_all_tags( $previous_short_dates_content_sup ) ) ) {
1989 - $tag_closed_span_and_a = $short_dates_content_arr[ count( $short_dates_content_arr ) - 1 ];
1990 - // unset time_sup
1991 - unset( $short_dates_content_arr[ count( $short_dates_content_arr ) - 1 ] );
1992 - $short_dates_content_arr[ count( $short_dates_content_arr ) - 1 ] = $tag_closed_span_and_a;
1993 - }
1994 - $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.
1995 2419 }
1996 2420 }
1997 2421
1998 2422 // BL.
@@ -2020,12 +2444,14 @@
2020 2444 $short_dates_content_arr[] = '</span></' . $params['date_html_tag'] . '>';
2021 2445
2022 2446
2023 2447
2024 - $previous_short_dates_content_sup = $short_dates_content_sup;
2025 - $previous_formatted_date = $formatted_date;
2026 - }
2027 - $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++;
2028 2454 }
2029 2455
2030 2456 $short_dates_content = implode( '', $short_dates_content_arr );
2031 2457
@@ -2350,54 +2776,26 @@
2350 2776 if ( isset( $wpbc__form_show_cache[ $cache_key ] ) ) {
2351 2777 return $wpbc__form_show_cache[ $cache_key ];
2352 2778 }
2353 2779
2354 - // ------------------------------------------------------------
2355 - // Legacy resolution (keep exactly as before).
2356 - // ------------------------------------------------------------
2357 - if ( ! class_exists( 'wpdev_bk_personal' ) ) {
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' ) ) {
2358 2790
2359 - $booking_form_show = wpbc_simple_form__get_form_show__as_shortcodes();
2360 - $booking_form_show = wpbc_bf__replace_custom_html_shortcodes( $booking_form_show );
2361 -
2362 - } else {
2363 -
2364 - $booking_form_show = get_bk_option( 'booking_form_show' );
2365 - $booking_form_show = wpbc_bf__replace_custom_html_shortcodes( $booking_form_show );
2366 -
2367 - // BM / MU legacy forms logic.
2368 - if ( class_exists( 'wpdev_bk_biz_m' ) ) {
2369 -
2370 - if ( '' !== $custom_booking_form_name ) { // FixIn: 9.4.3.12.
2371 - $booking_form_show = apply_bk_filter( 'wpdev_get_booking_form_content', $booking_form_show, $custom_booking_form_name );
2372 - $my_booking_form_name = $custom_booking_form_name;
2373 - } else {
2374 - // BM :: Get default Custom Form of Resource
2375 - $my_booking_form_name = apply_bk_filter( 'wpbc_get_default_custom_form', 'standard', $resource_id );
2376 - if ( ( 'standard' !== $my_booking_form_name ) && ( '' !== $my_booking_form_name ) ) {
2377 - $booking_form_show = apply_bk_filter( 'wpdev_get_booking_form_content', $booking_form_show, $my_booking_form_name );
2378 - }
2379 - }
2380 -
2381 - // MU :: if resource belongs to Regular User -> load THAT owner's form (not logged-in user).
2382 - $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.
2383 - }
2384 - }
2385 -
2386 - // ------------------------------------------------------------
2387 - // NEW: BFB resolver override (must be AFTER BM/MU legacy resolution).
2388 - // This ensures BFB "content_form" wins and legacy doesn't clobber it.
2389 - // ------------------------------------------------------------
2390 - if ( class_exists( 'WPBC_FE_Form_Source_Resolver' ) && class_exists( 'WPBC_BFB_Form_Loader' ) ) {
2391 -
2392 2791 $req = array(
2393 2792 'resource_id' => (int) $resource_id,
2394 2793 'form_slug' => (string) $my_booking_form_name,
2395 2794 'form_status' => $form_status,
2396 2795 'custom_params' => array(),
2397 - 'legacy_instance' => null,
2398 - 'ctx' => ( is_array( $ctx ) ? $ctx : array() ),
2399 - );
2796 + 'ctx' => ( is_array( $ctx ) ? $ctx : array() ),
2797 + );
2400 2798
2401 2799 $resolved = WPBC_FE_Form_Source_Resolver::resolve( $req );
2402 2800
2403 2801 // If preview requested but not found, try published as fallback.
@@ -2423,13 +2821,12 @@
2423 2821 $content_form = (string) $bfb_pair['content'];
2424 2822 }
2425 2823
2426 2824 if ( '' !== trim( $content_form ) ) {
2427 - // Keep legacy behavior: custom html shortcodes.
2428 - $booking_form_show = wpbc_bf__replace_custom_html_shortcodes( $content_form );
2429 - }
2430 - }
2431 - }
2825 + $booking_form_show = wpbc_bf__replace_custom_html_shortcodes( $content_form );
2826 + }
2827 + }
2828 + }
2432 2829
2433 2830 // ------------------------------------------------------------
2434 2831 // Language + cleanup (keep old behavior).
2435 2832 // ------------------------------------------------------------