| 1 |
<?php |
| 2 |
|
| 3 |
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly // FixIn: 9.8.0.4. |
| 4 |
|
| 5 |
// --------------------------------------------------------------------------------------------------------------------- |
| 6 |
// == Ajax Response on creation of new booking |
| 7 |
// --------------------------------------------------------------------------------------------------------------------- |
| 8 |
|
| 9 |
/** |
| 10 |
* Response to Ajax request, about loading calendar data |
| 11 |
* |
| 12 |
* @return void |
| 13 |
*/ |
| 14 |
function ajax_WPBC_AJX_BOOKING__CREATE() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound |
| 15 |
|
| 16 |
/** |
| 17 |
* Tip / translation / |
| 18 |
* Please note, translation was loaded on hook add_action( 'plugins_loaded', 'wpbc_load_translation', 1000 ); and use $_REQUEST['wpbc_ajx_locale'], so do not worry about it. |
| 19 |
*/ |
| 20 |
|
| 21 |
// Security ------------------------------------------------------------------------------------------------------ // in Ajax Post: 'nonce': _wpbc.get_secure_param( 'nonce' ), |
| 22 |
$action_name = 'wpbc_calendar_load_ajx' . '_wpbcnonce'; |
| 23 |
$nonce_post_key = 'nonce'; |
| 24 |
if ( wpbc_is_use_nonce_at_front_end() ) { // FixIn: 10.1.1.2. |
| 25 |
$result_check = check_ajax_referer( $action_name, $nonce_post_key ); |
| 26 |
} |
| 27 |
|
| 28 |
// Response AJAX parameters |
| 29 |
$ajx_data_arr = array(); |
| 30 |
$ajx_data_arr['status'] = 'ok'; |
| 31 |
|
| 32 |
$admin_uri = ltrim( str_replace( get_site_url( null, '', 'admin' ), '', admin_url( 'admin.php?' ) ), '/' ); // 'wp-admin/admin.php?' |
| 33 |
$server_http_referer_uri = ( ( isset( $_SERVER['HTTP_REFERER'] ) ) ? sanitize_text_field( $_SERVER['HTTP_REFERER'] ) : '' ); /* phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash */ /* FixIn: sanitize_unslash */ |
| 34 |
// Local parameters |
| 35 |
$local_params = array(); |
| 36 |
$local_params['is_from_admin_panel'] = ( false !== strpos( $server_http_referer_uri, $admin_uri ) ); // true | false |
| 37 |
$local_params['user_id'] = ( isset( $_REQUEST['wpbc_ajx_user_id'] ) ) ? intval( $_REQUEST['wpbc_ajx_user_id'] ) : wpbc_get_current_user_id(); // 1 |
| 38 |
|
| 39 |
// Request parameters for the released Appointment and Resource Selector workflows. |
| 40 |
$workflow_request_rules = array( |
| 41 |
'service_id' => array( 'validate' => 'd', 'default' => 0 ), |
| 42 |
'appointment_service_required' => array( 'validate' => 'd', 'default' => 0 ), |
| 43 |
'appointment_context_token' => array( 'validate' => 'strong', 'default' => '' ), |
| 44 |
'resource_selector_required' => array( 'validate' => 'd', 'default' => 0 ), |
| 45 |
'resource_selector_context_token' => array( 'validate' => 'strong', 'default' => '' ), |
| 46 |
); |
| 47 |
|
| 48 |
$user_request = new WPBC_AJX__REQUEST( array( // Using this class here only for escaping variables |
| 49 |
'db_option_name' => 'booking__wpbc_booking_create__request_params', // Not necessary, because we not save request, only sanitize it |
| 50 |
'user_id' => $local_params['user_id'], // Not necessary, because we not save request, only sanitize it |
| 51 |
'request_rules_structure' => array_merge( array( |
| 52 |
'resource_id' => array( 'validate' => 'd', 'default' => 1 ), // 'digit_or_csd'. |
| 53 |
'aggregate_resource_id_arr' => array( 'validate' => 'digit_or_csd', 'default' => '' ), |
| 54 |
'dates_ddmmyy_csv' => array( 'validate' => 'csv_dates', 'default' => '' ), // FixIn: 9.9.1.1. |
| 55 |
'formdata' => array( 'validate' => 'strong', 'default' => '' ), |
| 56 |
'booking_hash' => array( 'validate' => 'strong', 'default' => '' ), |
| 57 |
'custom_form' => array( 'validate' => 'strong', 'default' => '' ), |
| 58 |
'captcha_chalange' => array( 'validate' => 'strong', 'default' => '' ), |
| 59 |
'captcha_user_input' => array( 'validate' => 'strong', 'default' => '' ), |
| 60 |
'is_emails_send' => array( 'validate' => 'd', 'default' => 1 ), |
| 61 |
'active_locale' => array( 'validate' => 'strong', 'default' => '' ), |
| 62 |
'form_status' => array( 'validate' => 'strong', 'default' => 'published' ), |
| 63 |
'allow_past' => array( 'validate' => 'd', 'default' => 0 ), |
| 64 |
'classic_booking_context_token' => array( 'validate' => 'strong', 'default' => '' ), |
| 65 |
'wpbc_bfb_preview' => array( 'validate' => 'd', 'default' => 0 ), |
| 66 |
'wpbc_bfb_preview_token' => array( 'validate' => 'strong', 'default' => '' ), |
| 67 |
'wpbc_bfb_preview_form_id' => array( 'validate' => 'd', 'default' => 0 ), |
| 68 |
'wpbc_bfb_preview_nonce' => array( 'validate' => 'strong', 'default' => '' ), |
| 69 |
'wpbc_time_override_enabled' => array( 'validate' => 'd', 'default' => 0 ), |
| 70 |
'wpbc_time_override_source' => array( 'validate' => 'strong', 'default' => '' ), |
| 71 |
'wpbc_time_override_start' => array( 'validate' => 'strong', 'default' => '' ), |
| 72 |
'wpbc_time_override_end' => array( 'validate' => 'strong', 'default' => '' ), |
| 73 |
'wpbc_admin_cost_correction' => array( 'validate' => 'strong', 'default' => '' ), |
| 74 |
), $workflow_request_rules ) |
| 75 |
)); |
| 76 |
|
| 77 |
// Escape of request params in Ajax Post. We use prefix 'calendar_request_params', if Ajax sent - $_REQUEST['calendar_request_params']['resource_id'], ... |
| 78 |
$request_prefix = 'calendar_request_params'; |
| 79 |
|
| 80 |
//$_REQUEST['calendar_request_params']['dates_ddmmyy_csv'] .= "'%2b(select+'box'+from(select+sleep(2)+from+dual+where+1=1*)a)%2b'-02-21+00:00:00"; |
| 81 |
|
| 82 |
$request_params = $user_request->get_sanitized__in_request__value_or_default( $request_prefix ); // NOT Direct: $_REQUEST['calendar_request_params']['resource_id'] |
| 83 |
$server_http_referer_uri = ( ( isset( $_SERVER['HTTP_REFERER'] ) ) ? sanitize_text_field( $_SERVER['HTTP_REFERER'] ) : '' ); /* phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash */ /* FixIn: sanitize_unslash */ |
| 84 |
$request_params['request_uri'] = $server_http_referer_uri; // Parameter needed for Error in booking saving and reloading calendar again with these actual parameters. |
| 85 |
|
| 86 |
// <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- CAPTCHA " > |
| 87 |
// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized |
| 88 |
wpbc_captcha__in_ajx__check( $request_params, $local_params['is_from_admin_panel'], $_REQUEST[ $request_prefix ] ); |
| 89 |
// </editor-fold> |
| 90 |
|
| 91 |
// <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- BOOKING_RESOURCE ID " > |
| 92 |
if ( $request_params['resource_id'] <= 0 ) { |
| 93 |
$ajx_data_arr['status'] = 'error'; |
| 94 |
$ajx_data_arr['status_error'] = 'resource_id_incorrect'; |
| 95 |
// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized |
| 96 |
$ajx_data_arr['ajx_after_action_message'] = 'Wrong ID of booking resource: ' . ' [ request ID: ' . $_REQUEST['calendar_request_params']['resource_id'] . ' | parsed ID: ' . $request_params['resource_id'] . ' ]'; |
| 97 |
$ajx_data_arr['ajx_after_action_message_status'] = 'error'; |
| 98 |
wp_send_json( array( |
| 99 |
'ajx_data' => $ajx_data_arr, |
| 100 |
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized |
| 101 |
'ajx_search_params' => $_REQUEST[ $request_prefix ], |
| 102 |
'ajx_cleaned_params' => $request_params, |
| 103 |
'resource_id' => $request_params['resource_id'], |
| 104 |
) ); |
| 105 |
} |
| 106 |
// </editor-fold> |
| 107 |
|
| 108 |
$server_http_referer_uri = ( ( isset( $_SERVER['HTTP_REFERER'] ) ) ? sanitize_text_field( $_SERVER['HTTP_REFERER'] ) : '' ); /* phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash */ /* FixIn: sanitize_unslash */ |
| 109 |
|
| 110 |
$request_save_params = array( |
| 111 |
'resource_id' => $request_params['resource_id'], |
| 112 |
'dates_ddmmyy_csv' => $request_params['dates_ddmmyy_csv'], |
| 113 |
'form_data' => $request_params['formdata'], |
| 114 |
'aggregate_resource_id_arr' => $request_params['aggregate_resource_id_arr'], // Optional can be ''. |
| 115 |
'booking_hash' => $request_params['booking_hash'], |
| 116 |
'custom_form' => $request_params['custom_form'], |
| 117 |
'is_emails_send' => $request_params['is_emails_send'], |
| 118 |
'is_show_payment_form' => 1, |
| 119 |
'user_id' => $local_params['user_id'], |
| 120 |
'request_uri' => $server_http_referer_uri, |
| 121 |
'form_status' => $request_params['form_status'], |
| 122 |
'allow_past' => $request_params['allow_past'], |
| 123 |
'classic_booking_context_token' => $request_params['classic_booking_context_token'], |
| 124 |
'wpbc_bfb_preview' => $request_params['wpbc_bfb_preview'], |
| 125 |
'wpbc_bfb_preview_token' => $request_params['wpbc_bfb_preview_token'], |
| 126 |
'wpbc_bfb_preview_form_id' => $request_params['wpbc_bfb_preview_form_id'], |
| 127 |
'wpbc_bfb_preview_nonce' => $request_params['wpbc_bfb_preview_nonce'], |
| 128 |
'wpbc_time_override_enabled' => $request_params['wpbc_time_override_enabled'], |
| 129 |
'wpbc_time_override_source' => $request_params['wpbc_time_override_source'], |
| 130 |
'wpbc_time_override_start' => $request_params['wpbc_time_override_start'], |
| 131 |
'wpbc_time_override_end' => $request_params['wpbc_time_override_end'], |
| 132 |
'wpbc_admin_cost_correction' => $request_params['wpbc_admin_cost_correction'], |
| 133 |
); |
| 134 |
$request_save_params['service_id'] = $request_params['service_id']; |
| 135 |
$request_save_params['appointment_service_required'] = $request_params['appointment_service_required']; |
| 136 |
$request_save_params['appointment_context_token'] = $request_params['appointment_context_token']; |
| 137 |
$request_save_params['resource_selector_required'] = $request_params['resource_selector_required']; |
| 138 |
$request_save_params['resource_selector_context_token'] = $request_params['resource_selector_context_token']; |
| 139 |
$booking_save_arr = wpbc_booking_save( $request_save_params ); |
| 140 |
|
| 141 |
// <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- BOOKING " > |
| 142 |
if ( 'ok' !== $booking_save_arr['ajx_data']['status'] ) { |
| 143 |
|
| 144 |
wp_send_json( array( 'ajx_data' => $booking_save_arr['ajx_data'], |
| 145 |
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized |
| 146 |
'ajx_search_params' => $_REQUEST[ $request_prefix ], |
| 147 |
'ajx_cleaned_params' => $request_params, |
| 148 |
'resource_id' => $request_params['resource_id'] |
| 149 |
)); |
| 150 |
} |
| 151 |
// </editor-fold> |
| 152 |
|
| 153 |
$ajx_data_arr = $booking_save_arr['ajx_data']; |
| 154 |
|
| 155 |
|
| 156 |
|
| 157 |
// TODO: If we have the calendar with specific capacity, then maybe showing by dots (the booked child booking resources) the slots and not the time slot ! |
| 158 |
|
| 159 |
if ( empty( $ajx_data_arr['ajx_after_action_message_status'] ) ) { |
| 160 |
$ajx_data_arr['ajx_after_action_message_status'] = 'success'; |
| 161 |
} |
| 162 |
if ( empty( $ajx_data_arr['ajx_after_action_message'] ) ) { |
| 163 |
$ajx_data_arr['ajx_after_action_message'] = ''; |
| 164 |
} |
| 165 |
|
| 166 |
// $ajx_data_arr['ajx_after_action_message'] .= __( 'Booking was created with ID: ' . $booking_save_arr[ 'booking_id' ] , 'booking' ); |
| 167 |
// $ajx_data_arr['ajx_after_action_message'] .= '<hr>Total time: <strong>' . $booking_save_arr['php_performance']['total'] . ' s. </strong>'; |
| 168 |
// $ajx_data_arr['ajx_after_action_message'] .= str_replace( array( ',', '{', '}' ), '<br>', wp_json_encode( $booking_save_arr['php_performance'] ) ); |
| 169 |
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 170 |
|
| 171 |
|
| 172 |
|
| 173 |
/* if admin edit ? |
| 174 |
var my_message = '<?php echo esc_js( __('Updated successfully' ,'booking') ) ; ?>'; |
| 175 |
wpbc_admin_show_message( my_message, 'success', 3000 ); |
| 176 |
location.href='<?php echo wpbc_get_bookings_url() ;?>&tab=vm_booking_listing&wh_booking_id=<?php echo $is_edit_booking['booking_id'] ; ?>'; |
| 177 |
*/ |
| 178 |
|
| 179 |
|
| 180 |
// ----------------------------------------------------------------------------------------------------------------- |
| 181 |
// == Ajax === |
| 182 |
// ----------------------------------------------------------------------------------------------------------------- |
| 183 |
/** |
| 184 |
* Send JSON. It will make "wp_json_encode" - so pass only array, and This function call wp_die( '', '', array( 'response' => null, ) ) . |
| 185 |
* Pass JS OBJ: response_data in "jQuery.post " function on success. |
| 186 |
* |
| 187 |
* Other End Ajax actions: |
| 188 |
* $error_obj = new WP_Error( 'WPBC_CREATE', __( 'test error.' ), 'some/data' ); wp_send_json_error( $error_obj ); |
| 189 |
* wp_send_json_error( array( 'message' => 'invalid-api-key' ) ); |
| 190 |
* wp_send_json_success( array( 'message' =>'Ok:)' ) ); |
| 191 |
*/ |
| 192 |
wp_send_json( array( |
| 193 |
'booking_id' => $booking_save_arr['booking_id'], |
| 194 |
'resource_id' => $request_params['resource_id'], |
| 195 |
'ajx_data' => $ajx_data_arr, |
| 196 |
'ajx_confirmation' => $booking_save_arr['confirmation'], |
| 197 |
|
| 198 |
// For debug purpose <- comment in live serv |
| 199 |
'php_process_times' => $booking_save_arr['php_performance'], |
| 200 |
'booking_arr' => $booking_save_arr ['booking_arr'], |
| 201 |
|
| 202 |
// Not needed ? |
| 203 |
// 'ajx_search_params' => $_REQUEST[ $request_prefix ], |
| 204 |
// 'ajx_cleaned_params' => $request_params, |
| 205 |
|
| 206 |
) ); |
| 207 |
} |
| 208 |
|
| 209 |
// Ajax Hooks |
| 210 |
if ( is_admin() && ( defined( 'DOING_AJAX' ) ) && ( DOING_AJAX ) ) { |
| 211 |
add_action( 'wp_ajax_nopriv_' . 'WPBC_AJX_BOOKING__CREATE', 'ajax_' . 'WPBC_AJX_BOOKING__CREATE' ); // Client (not logged in) |
| 212 |
add_action( 'wp_ajax_' . 'WPBC_AJX_BOOKING__CREATE', 'ajax_' . 'WPBC_AJX_BOOKING__CREATE' ); // Logged In users (or admin panel) |
| 213 |
} |
| 214 |
|
| 215 |
|
| 216 |
// --------------------------------------------------------------------------------------------------------------------- |
| 217 |
// == Save Booking |
| 218 |
// --------------------------------------------------------------------------------------------------------------------- |
| 219 |
|
| 220 |
/** |
| 221 |
* Save Booking - ADD NEW or UPDATE exist booking |
| 222 |
* |
| 223 |
* @param $request_params = [ |
| 224 |
* resource_id = 2 REQUIRED Default: 1 |
| 225 |
* dates_ddmmyy_csv = '27.10.2023, 28.10.2023, 29.10.2023' REQUIRED |
| 226 |
* form_data = 'text^selected_short_dates_hint2^Fri, ...9, 2023~text^...' REQUIRED |
| 227 |
* booking_hash = '' Optional Default: '' |
| 228 |
* custom_form = '' Optional Default: '' |
| 229 |
* is_emails_send = 1 Optional Default: 1 |
| 230 |
* is_show_payment_form => 1 Optional Default: 1 |
| 231 |
* user_id = 1 Optional Default: 0 or ID of logged-in user |
| 232 |
* request_uri = 'http://beta/resource-id2/', // Optional Default: for front-end: $_SERVER['REQUEST_URI'] | ajax: $_SERVER['HTTP_REFERER'] |
| 233 |
* |
| 234 |
* 'sync_gid' => 'ghjgjgjgh5f5f45f' // Really Optional: can be passed only during import .ics |
| 235 |
* 'is_approve_booking' => 0 // Really Optional: 0 | 1 |
| 236 |
* 'save_booking_even_if_unavailable' => 0 // Really Optional: 0 | 1, if 1 then force save booking even if dates unavailable. |
| 237 |
* ] |
| 238 |
* |
| 239 |
* @return [] ok: [ |
| 240 |
* |
| 241 |
* ] |
| 242 |
* error: [ |
| 243 |
* 'ajx_data': [ 'status':'error', 'status_error':'booking_can_not_save', 'ajx_after_action_message': 'Can not save booking', 'ajx_after_action_message_status': 'warning' ] |
| 244 |
* ] |
| 245 |
* |
| 246 |
* Example: |
| 247 |
* |
| 248 |
* wpbc_booking_save( array( |
| 249 |
* 'resource_id' => 2, |
| 250 |
* 'dates_ddmmyy_csv' => '04.10.2023, 05.10.2023, 06.10.2023', |
| 251 |
* 'form_data' => 'text^cost_hint2^150.00฿~selectbox-multiple^rangetime2[]^14:00 - 16:00~text^name2^John~text^secondname2^Smith~email^email2^john.smith@server.com~selectbox-one^visitors2^2~selectbox-one^children2^0~textarea^details2^test', |
| 252 |
* 'booking_hash' => '', |
| 253 |
* 'custom_form' => '', |
| 254 |
* 'is_emails_send' => 1, |
| 255 |
* 'is_show_payment_form' => 1, |
| 256 |
* 'user_id' => 1, |
| 257 |
* 'request_uri' => 'http://beta/resource-id2/' |
| 258 |
* ) ); |
| 259 |
* |
| 260 |
*/ |
| 261 |
function wpbc_booking_save( $request_params ){ |
| 262 |
// <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > |
| 263 |
$php_performance = wpbc_php_performance_START( 'total', array() ); |
| 264 |
// </editor-fold> |
| 265 |
$ajx_data_arr = array(); |
| 266 |
$ajx_data_arr['status'] = 'ok'; |
| 267 |
|
| 268 |
// ----------------------------------------------------------------------------------------------------------------- |
| 269 |
// 1. Direct Clean Params |
| 270 |
// ----------------------------------------------------------------------------------------------------------------- |
| 271 |
$server_request_uri = ( ( isset( $_SERVER['REQUEST_URI'] ) ) ? sanitize_text_field( $_SERVER['REQUEST_URI'] ) : '' ); /* phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash */ /* FixIn: sanitize_unslash */ |
| 272 |
$server_http_referer_uri = ( ( isset( $_SERVER['HTTP_REFERER'] ) ) ? sanitize_text_field( $_SERVER['HTTP_REFERER'] ) : '' ); /* phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash */ /* FixIn: sanitize_unslash */ |
| 273 |
$validate_arr_rules = array( |
| 274 |
'resource_id' => array( 'validate' => 'd', 'default' => 1 ), // INT |
| 275 |
'dates_ddmmyy_csv' => array( 'validate' => 'csv_dates', 'default' => '' ), // FixIn: 9.9.1.1. |
| 276 |
'form_data' => array( 'validate' => 'strong', 'default' => '' ), |
| 277 |
'booking_hash' => array( 'validate' => 'strong', 'default' => '' ), |
| 278 |
'custom_form' => array( 'validate' => 'strong', 'default' => '' ), |
| 279 |
'is_emails_send' => array( 'validate' => 'd', 'default' => 1 ), // 0 | 1 |
| 280 |
'is_show_payment_form' => array( 'validate' => 'd', 'default' => 1 ), // 0 | 1 |
| 281 |
'user_id' => array( 'validate' => 'd', 'default' => wpbc_get_current_user_id() ), // INT |
| 282 |
'allow_past' => array( 'validate' => 'd', 'default' => 0 ), |
| 283 |
'classic_booking_context_token' => array( 'validate' => 'strong', 'default' => '' ), |
| 284 |
'request_uri' => array( 'validate' => 'strong', 'default' => ( ( defined( 'DOING_AJAX' ) ) && ( DOING_AJAX ) ) ? $server_http_referer_uri : $server_request_uri ), // front-end: $server_request_uri | ajax: $server_http_referer_uri |
| 285 |
// Really Optional: |
| 286 |
'aggregate_resource_id_arr' => array( 'validate' => 'digit_or_csd', 'default' => '' ), |
| 287 |
//TODO: this parameter does not transfer during saving, so here will be always default value 'bookings_only' // FixIn: 10.0.0.7. |
| 288 |
'aggregate_type' => array( 'validate' => 'strong', 'default' => 'bookings_only' ), // Optional. 'all' | 'bookings_only' <- it is depends on shortcode parameter: options="{aggregate type=bookings_only}" |
| 289 |
'is_approve_booking' => array( 'validate' => 'd', 'default' => 0 ), // 0 | 1 |
| 290 |
'save_booking_even_if_unavailable' => array( 'validate' => 'd', 'default' => 0 ), // 0 | 1 |
| 291 |
'sync_gid' => array( 'validate' => 'strong', 'default' => '' ), |
| 292 |
'is_use_booking_recurrent_time' => array( 'validate' => 'd', 'default' => intval( ( 'On' === get_bk_option( 'booking_recurrent_time' ) ) ) ), |
| 293 |
|
| 294 |
'form_status' => array( 'validate' => 'strong', 'default' => 'published' ), |
| 295 |
'wpbc_bfb_preview' => array( 'validate' => 'd', 'default' => 0 ), |
| 296 |
'wpbc_bfb_preview_token' => array( 'validate' => 'strong', 'default' => '' ), |
| 297 |
'wpbc_bfb_preview_form_id' => array( 'validate' => 'd', 'default' => 0 ), |
| 298 |
'wpbc_bfb_preview_nonce' => array( 'validate' => 'strong', 'default' => '' ), |
| 299 |
'wpbc_time_override_enabled' => array( 'validate' => 'd', 'default' => 0 ), |
| 300 |
'wpbc_time_override_source' => array( 'validate' => 'strong', 'default' => '' ), |
| 301 |
'wpbc_time_override_start' => array( 'validate' => 'strong', 'default' => '' ), |
| 302 |
'wpbc_time_override_end' => array( 'validate' => 'strong', 'default' => '' ), |
| 303 |
'wpbc_admin_cost_correction' => array( 'validate' => 'strong', 'default' => '' ), |
| 304 |
); |
| 305 |
$validate_arr_rules['service_id'] = array( 'validate' => 'd', 'default' => 0 ); |
| 306 |
$validate_arr_rules['appointment_service_required'] = array( 'validate' => 'd', 'default' => 0 ); |
| 307 |
$validate_arr_rules['appointment_context_token'] = array( 'validate' => 'strong', 'default' => '' ); |
| 308 |
$validate_arr_rules['resource_selector_required'] = array( 'validate' => 'd', 'default' => 0 ); |
| 309 |
$validate_arr_rules['resource_selector_context_token'] = array( 'validate' => 'strong', 'default' => '' ); |
| 310 |
$re_cleaned_params = wpbc_sanitize_params_in_arr( $request_params, $validate_arr_rules ); |
| 311 |
if ( ! empty( $re_cleaned_params['appointment_service_required'] ) && empty( $re_cleaned_params['service_id'] ) ) { |
| 312 |
$ajx_data_arr['status'] = 'error'; |
| 313 |
$ajx_data_arr['status_error'] = 'appointment_service_required'; |
| 314 |
$ajx_data_arr['ajx_after_action_message'] = __( 'Please select a Service.', 'booking' ); |
| 315 |
$ajx_data_arr['ajx_after_action_message_status'] = 'warning'; |
| 316 |
return array( 'ajx_data' => $ajx_data_arr ); |
| 317 |
} |
| 318 |
if ( ! empty( $re_cleaned_params['service_id'] ) ) { |
| 319 |
if ( ! function_exists( 'wpbc_booking_appointment_validate_submission_context' ) ) { |
| 320 |
$appointment_context_check = new WP_Error( 'appointment_context_unavailable', __( 'The Appointment selection cannot be verified. Please reload the page and try again.', 'booking' ) ); |
| 321 |
} else { |
| 322 |
$appointment_context_check = wpbc_booking_appointment_validate_submission_context( |
| 323 |
$re_cleaned_params['appointment_context_token'], |
| 324 |
$re_cleaned_params['service_id'], |
| 325 |
$re_cleaned_params['resource_id'] |
| 326 |
); |
| 327 |
} |
| 328 |
if ( is_wp_error( $appointment_context_check ) ) { |
| 329 |
$ajx_data_arr['status'] = 'error'; |
| 330 |
$ajx_data_arr['status_error'] = $appointment_context_check->get_error_code(); |
| 331 |
$ajx_data_arr['ajx_after_action_message'] = $appointment_context_check->get_error_message(); |
| 332 |
$ajx_data_arr['ajx_after_action_message_status'] = 'warning'; |
| 333 |
return array( 'ajx_data' => $ajx_data_arr ); |
| 334 |
} |
| 335 |
|
| 336 |
// A client value cannot enable past Appointment creation; trust only the site-authored signed context. |
| 337 |
$re_cleaned_params['allow_past'] = wpbc_booking_appointment_is_past_booking_enabled( $appointment_context_check ) ? 1 : 0; |
| 338 |
} |
| 339 |
if ( ! empty( $re_cleaned_params['resource_selector_required'] ) ) { |
| 340 |
if ( ! function_exists( 'wpbc_booking_resource_selector_validate_submission_context' ) ) { |
| 341 |
$resource_selector_context_check = new WP_Error( 'resource_selector_context_unavailable', __( 'The Booking Resource selection cannot be verified. Please reload the page and try again.', 'booking' ) ); |
| 342 |
} else { |
| 343 |
$resource_selector_context_check = wpbc_booking_resource_selector_validate_submission_context( |
| 344 |
$re_cleaned_params['resource_selector_context_token'], |
| 345 |
$re_cleaned_params['resource_id'] |
| 346 |
); |
| 347 |
} |
| 348 |
if ( is_wp_error( $resource_selector_context_check ) ) { |
| 349 |
$ajx_data_arr['status'] = 'error'; |
| 350 |
$ajx_data_arr['status_error'] = $resource_selector_context_check->get_error_code(); |
| 351 |
$ajx_data_arr['ajx_after_action_message'] = $resource_selector_context_check->get_error_message(); |
| 352 |
$ajx_data_arr['ajx_after_action_message_status'] = 'warning'; |
| 353 |
return array( 'ajx_data' => $ajx_data_arr ); |
| 354 |
} |
| 355 |
|
| 356 |
// Trust only the site-authored signed selector context for public past bookings. |
| 357 |
$re_cleaned_params['allow_past'] = wpbc_booking_resource_selector_is_past_booking_enabled( $resource_selector_context_check ) ? 1 : 0; |
| 358 |
} |
| 359 |
|
| 360 |
$admin_uri = ltrim( str_replace( get_site_url( null, '', 'admin' ), '', admin_url( 'admin.php?' ) ), '/' ); // wp-admin/admin.php? |
| 361 |
|
| 362 |
$re_cleaned_params['form_status'] = sanitize_key( $re_cleaned_params['form_status'] ); |
| 363 |
if ( 'preview' !== $re_cleaned_params['form_status'] ) { |
| 364 |
$re_cleaned_params['form_status'] = 'published'; |
| 365 |
} |
| 366 |
// FixIn: 2026-02-05 - make preview/published available to form parsing/templates during this request. |
| 367 |
wpbc_set_request_form_context( |
| 368 |
array( |
| 369 |
'form_status' => $re_cleaned_params['form_status'], |
| 370 |
'user_id' => $re_cleaned_params['user_id'], |
| 371 |
'wpbc_bfb_preview' => absint( $re_cleaned_params['wpbc_bfb_preview'] ), |
| 372 |
'wpbc_bfb_preview_token' => sanitize_key( $re_cleaned_params['wpbc_bfb_preview_token'] ), |
| 373 |
'wpbc_bfb_preview_form_id' => absint( $re_cleaned_params['wpbc_bfb_preview_form_id'] ), |
| 374 |
'wpbc_bfb_preview_nonce' => (string) $re_cleaned_params['wpbc_bfb_preview_nonce'], |
| 375 |
) |
| 376 |
); |
| 377 |
|
| 378 |
// ----------------------------------------------------------------------------------------------------------------- |
| 379 |
// Local parameters |
| 380 |
// ----------------------------------------------------------------------------------------------------------------- |
| 381 |
$local_params = array(); |
| 382 |
$local_params['is_from_admin_panel'] = ( false !== strpos( $re_cleaned_params['request_uri'], $admin_uri ) ); // true | false |
| 383 |
$local_params['user_id'] = $re_cleaned_params['user_id']; // 1 |
| 384 |
$local_params['sync_gid'] = $re_cleaned_params['sync_gid']; // '' |
| 385 |
$local_params['is_approve_booking'] = $re_cleaned_params['is_approve_booking']; // 0 | 1 |
| 386 |
$local_params['is_use_booking_recurrent_time'] = ( 1 === $re_cleaned_params['is_use_booking_recurrent_time'] ); // false | true |
| 387 |
$request_action = isset( $_REQUEST['action'] ) && is_scalar( $_REQUEST['action'] ) |
| 388 |
? sanitize_key( (string) wp_unslash( $_REQUEST['action'] ) ) |
| 389 |
: ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended |
| 390 |
$is_authorized_admin_booking_request = $local_params['is_from_admin_panel'] |
| 391 |
&& is_user_logged_in() |
| 392 |
&& class_exists( 'WPBC_Add_Booking_Component' ) |
| 393 |
&& WPBC_Add_Booking_Component::current_user_can_add_booking() |
| 394 |
&& wpbc_is_mu_user_can_be_here( 'activated_user' ); |
| 395 |
$is_public_booking_create_request = wp_doing_ajax() |
| 396 |
&& 'wpbc_ajx_booking__create' === strtolower( $request_action ) |
| 397 |
&& ! $is_authorized_admin_booking_request; |
| 398 |
|
| 399 |
// Time overrides belong exclusively to the capability-protected Add Booking administration workflow. |
| 400 |
$re_cleaned_params = wpbc_restrict_booking_time_override_to_authorized_admin( $re_cleaned_params, $is_authorized_admin_booking_request ); |
| 401 |
// Cost corrections belong exclusively to capability-protected administrator booking workflows. |
| 402 |
$re_cleaned_params = wpbc_restrict_booking_cost_correction_to_authorized_admin( $re_cleaned_params, $is_authorized_admin_booking_request ); |
| 403 |
|
| 404 |
// ----------------------------------------------------------------------------------------------------------------- |
| 405 |
// Parse Local parameters for later use |
| 406 |
// ----------------------------------------------------------------------------------------------------------------- |
| 407 |
/** |
| 408 |
* Get parsed booking form: = [ name = "John", secondname = "Smith", email = "john.smith@server.com", visitors = "2",... ] |
| 409 |
*/ |
| 410 |
$local_params['structured_booking_data_arr'] = wpbc_get_parsed_booking_data_arr( $re_cleaned_params["form_data"], $re_cleaned_params["resource_id"], array( 'get' => 'value' ) ); |
| 411 |
$local_params['all_booking_data_arr'] = wpbc_get_parsed_booking_data_arr( $re_cleaned_params["form_data"], $re_cleaned_params["resource_id"] ); |
| 412 |
$local_params['time_override_arr'] = wpbc_get_booking_time_override__as_arr( $re_cleaned_params ); |
| 413 |
if ( ! empty( $local_params['time_override_arr'] ) ) { |
| 414 |
unset( $local_params['structured_booking_data_arr']['rangetime'], $local_params['structured_booking_data_arr']['durationtime'] ); |
| 415 |
$local_params['structured_booking_data_arr']['starttime'] = $local_params['time_override_arr']['start']; |
| 416 |
$local_params['structured_booking_data_arr']['endtime'] = $local_params['time_override_arr']['end']; |
| 417 |
|
| 418 |
unset( $local_params['all_booking_data_arr']['rangetime'], $local_params['all_booking_data_arr']['durationtime'] ); |
| 419 |
$local_params['all_booking_data_arr']['starttime'] = array( |
| 420 |
'type' => 'text', |
| 421 |
'original_name' => 'starttime' . $re_cleaned_params['resource_id'], |
| 422 |
'name' => 'starttime', |
| 423 |
'value' => $local_params['time_override_arr']['start'], |
| 424 |
); |
| 425 |
$local_params['all_booking_data_arr']['endtime'] = array( |
| 426 |
'type' => 'text', |
| 427 |
'original_name' => 'endtime' . $re_cleaned_params['resource_id'], |
| 428 |
'name' => 'endtime', |
| 429 |
'value' => $local_params['time_override_arr']['end'], |
| 430 |
); |
| 431 |
} |
| 432 |
// Important! : [ 64800, 72000 ] |
| 433 |
$local_params['time_as_seconds_arr'] = wpbc_get_in_booking_form__time_to_book_as_seconds_arr( $local_params['structured_booking_data_arr'] ); |
| 434 |
$local_params['appointment_service'] = array(); |
| 435 |
if ( ! empty( $re_cleaned_params['service_id'] ) && function_exists( 'wpbc_appointment_services_repository' ) ) { |
| 436 |
$range_time_value = isset( $local_params['structured_booking_data_arr']['rangetime'] ) ? $local_params['structured_booking_data_arr']['rangetime'] : ''; |
| 437 |
$start_time_value = isset( $local_params['structured_booking_data_arr']['starttime'] ) ? $local_params['structured_booking_data_arr']['starttime'] : ''; |
| 438 |
$range_time_value = is_array( $range_time_value ) ? implode( '', $range_time_value ) : $range_time_value; |
| 439 |
$start_time_value = is_array( $start_time_value ) ? implode( '', $start_time_value ) : $start_time_value; |
| 440 |
$has_appointment_time = ! empty( $local_params['time_override_arr'] ) |
| 441 |
|| '' !== trim( (string) $range_time_value ) |
| 442 |
|| '' !== trim( (string) $start_time_value ); |
| 443 |
if ( ! $has_appointment_time ) { |
| 444 |
$ajx_data_arr['status'] = 'error'; |
| 445 |
$ajx_data_arr['status_error'] = 'appointment_service_time_required'; |
| 446 |
$ajx_data_arr['ajx_after_action_message'] = __( 'A Service appointment requires a start time. Add a time field to the Booking Form and select a time.', 'booking' ); |
| 447 |
$ajx_data_arr['ajx_after_action_message_status'] = 'warning'; |
| 448 |
return array( 'ajx_data' => $ajx_data_arr ); |
| 449 |
} |
| 450 |
$appointment_service = wpbc_appointment_services_repository()->find_active_for_resource( $re_cleaned_params['service_id'], $re_cleaned_params['resource_id'] ); |
| 451 |
if ( is_wp_error( $appointment_service ) ) { |
| 452 |
$ajx_data_arr['status'] = 'error'; |
| 453 |
$ajx_data_arr['status_error'] = 'appointment_service_unavailable'; |
| 454 |
$ajx_data_arr['ajx_after_action_message'] = $appointment_service->get_error_message(); |
| 455 |
$ajx_data_arr['ajx_after_action_message_status'] = 'warning'; |
| 456 |
return array( 'ajx_data' => $ajx_data_arr ); |
| 457 |
} |
| 458 |
if ( count( $local_params['time_as_seconds_arr'] ) < 2 || ! function_exists( 'wpbc_appointment_services_resolve_end_seconds' ) ) { |
| 459 |
$ajx_data_arr['status'] = 'error'; |
| 460 |
$ajx_data_arr['status_error'] = 'appointment_service_duration_invalid'; |
| 461 |
$ajx_data_arr['ajx_after_action_message'] = __( 'The selected Service duration is invalid. Please contact the website administrator.', 'booking' ); |
| 462 |
$ajx_data_arr['ajx_after_action_message_status'] = 'warning'; |
| 463 |
return array( 'ajx_data' => $ajx_data_arr ); |
| 464 |
} |
| 465 |
$maximum_duration_minutes = absint( apply_filters( 'wpbc_booking_appointment_maximum_duration_minutes', 24 * 60, array() ) ); |
| 466 |
$service_end_second = wpbc_appointment_services_resolve_end_seconds( $appointment_service, $local_params['time_as_seconds_arr'][0], $maximum_duration_minutes ); |
| 467 |
if ( is_wp_error( $service_end_second ) ) { |
| 468 |
$ajx_data_arr['status'] = 'error'; |
| 469 |
$ajx_data_arr['status_error'] = $service_end_second->get_error_code(); |
| 470 |
$ajx_data_arr['ajx_after_action_message'] = $service_end_second->get_error_message(); |
| 471 |
$ajx_data_arr['ajx_after_action_message_status'] = 'warning'; |
| 472 |
return array( 'ajx_data' => $ajx_data_arr ); |
| 473 |
} |
| 474 |
$local_params['time_as_seconds_arr'][1] = $service_end_second; |
| 475 |
$local_params['appointment_service'] = $appointment_service; |
| 476 |
$service_start_time = wpbc_transform__seconds__in__24_hours_his( $local_params['time_as_seconds_arr'][0] ); |
| 477 |
$service_end_time = wpbc_transform__seconds__in__24_hours_his( $local_params['time_as_seconds_arr'][1] ); |
| 478 |
unset( $local_params['structured_booking_data_arr']['rangetime'], $local_params['structured_booking_data_arr']['durationtime'] ); |
| 479 |
$local_params['structured_booking_data_arr']['starttime'] = $service_start_time; |
| 480 |
$local_params['structured_booking_data_arr']['endtime'] = $service_end_time; |
| 481 |
unset( $local_params['all_booking_data_arr']['rangetime'], $local_params['all_booking_data_arr']['durationtime'] ); |
| 482 |
$local_params['all_booking_data_arr']['starttime'] = array( 'type' => 'text', 'original_name' => 'starttime' . $re_cleaned_params['resource_id'], 'name' => 'starttime', 'value' => $service_start_time ); |
| 483 |
$local_params['all_booking_data_arr']['endtime'] = array( 'type' => 'text', 'original_name' => 'endtime' . $re_cleaned_params['resource_id'], 'name' => 'endtime', 'value' => $service_end_time ); |
| 484 |
} |
| 485 |
if ( function_exists( 'wpbc_appointment_services_sync_service_hint_booking_data' ) ) { |
| 486 |
$service_hint_booking_data = wpbc_appointment_services_sync_service_hint_booking_data( |
| 487 |
$local_params['structured_booking_data_arr'], |
| 488 |
$local_params['all_booking_data_arr'], |
| 489 |
$local_params['appointment_service'], |
| 490 |
$re_cleaned_params['resource_id'] |
| 491 |
); |
| 492 |
$local_params['structured_booking_data_arr'] = $service_hint_booking_data['structured_booking_data']; |
| 493 |
$local_params['all_booking_data_arr'] = $service_hint_booking_data['all_booking_data']; |
| 494 |
} |
| 495 |
// [ "18:00:00", "20:00:00" ] |
| 496 |
$time_as_seconds_arr = $local_params['time_as_seconds_arr']; |
| 497 |
$time_as_seconds_arr[0] = ( 0 != $time_as_seconds_arr[0] ) ? $time_as_seconds_arr[0] + 1 : $time_as_seconds_arr[0]; // set check in time with ended 1 second |
| 498 |
$time_as_seconds_arr[1] = ( ( 24 * 60 * 60 ) != $time_as_seconds_arr[1] ) ? $time_as_seconds_arr[1] + 2 : $time_as_seconds_arr[1]; // set check out time with ended 2 seconds |
| 499 |
if ( ( 0 != $time_as_seconds_arr[0] ) && ( ( 24 * 60 * 60 ) == $time_as_seconds_arr[1] ) ) { |
| 500 |
//FixIn: 10.0.0.49 - in case if we have start time != 00:00 and end time as 24:00 then set end time as 23:59:52 |
| 501 |
$time_as_seconds_arr[1] += - 8; |
| 502 |
} |
| 503 |
$local_params['time_as_his_arr'] = array( |
| 504 |
wpbc_transform__seconds__in__24_hours_his( $time_as_seconds_arr[0] ), |
| 505 |
wpbc_transform__seconds__in__24_hours_his( $time_as_seconds_arr[1] ) |
| 506 |
); |
| 507 |
// [ '2023-09-10', '2023-09-11' ] |
| 508 |
$local_params['dates_only_sql_arr'] = wpbc_convert_dates_str__dd_mm_yyyy__to__yyyy_mm_dd( $re_cleaned_params["dates_ddmmyy_csv"] ); |
| 509 |
$local_params['dates_only_sql_arr'] = explode( ',', $local_params['dates_only_sql_arr'] ); |
| 510 |
|
| 511 |
$has_verified_classic_context = false; |
| 512 |
if ( ! empty( $re_cleaned_params['classic_booking_context_token'] ) && function_exists( 'wpbc_classic_booking_context_validate_submission' ) ) { |
| 513 |
$classic_context = wpbc_classic_booking_context_validate_submission( |
| 514 |
$re_cleaned_params['classic_booking_context_token'], |
| 515 |
$re_cleaned_params['resource_id'], |
| 516 |
$local_params['dates_only_sql_arr'], |
| 517 |
$re_cleaned_params['custom_form'], |
| 518 |
$re_cleaned_params['aggregate_resource_id_arr'] |
| 519 |
); |
| 520 |
if ( is_wp_error( $classic_context ) ) { |
| 521 |
$ajx_data_arr['status'] = 'error'; |
| 522 |
$ajx_data_arr['status_error'] = $classic_context->get_error_code(); |
| 523 |
$ajx_data_arr['ajx_after_action_message'] = $classic_context->get_error_message(); |
| 524 |
$ajx_data_arr['ajx_after_action_message_status'] = 'warning'; |
| 525 |
return array( 'ajx_data' => $ajx_data_arr ); |
| 526 |
} |
| 527 |
|
| 528 |
$has_verified_classic_context = true; |
| 529 |
$re_cleaned_params['allow_past'] = ! empty( $classic_context['allow_past'] ) ? 1 : 0; |
| 530 |
} |
| 531 |
|
| 532 |
$has_verified_workflow_context = ( |
| 533 |
( ! empty( $re_cleaned_params['service_id'] ) && ! empty( $re_cleaned_params['appointment_context_token'] ) ) |
| 534 |
|| ( ! empty( $re_cleaned_params['resource_selector_required'] ) && ! empty( $re_cleaned_params['resource_selector_context_token'] ) ) |
| 535 |
); |
| 536 |
if ( $is_public_booking_create_request && ! $has_verified_classic_context && ! $has_verified_workflow_context ) { |
| 537 |
$re_cleaned_params['allow_past'] = 0; |
| 538 |
$re_cleaned_params['request_uri'] = remove_query_arg( 'allow_past', $re_cleaned_params['request_uri'] ); |
| 539 |
} |
| 540 |
|
| 541 |
if ( |
| 542 |
( ! empty( $local_params['time_override_arr'] ) ) |
| 543 |
&& ( 'times_availability' === $local_params['time_override_arr']['source'] ) |
| 544 |
&& ( count( array_filter( $local_params['dates_only_sql_arr'] ) ) > 1 ) |
| 545 |
) { |
| 546 |
$local_params['is_use_booking_recurrent_time'] = true; |
| 547 |
} |
| 548 |
|
| 549 |
$local_params['is_show_payment_form'] = $re_cleaned_params["is_show_payment_form"]; |
| 550 |
|
| 551 |
// FixIn: 9.9.0.35. |
| 552 |
if ( $local_params['is_show_payment_form'] ) { |
| 553 |
$local_params['is_show_payment_form'] = ( false !== strpos( $re_cleaned_params['request_uri'], 'is_show_payment_form=Off' ) ) |
| 554 |
? 0 |
| 555 |
: $local_params['is_show_payment_form']; // 1|0 |
| 556 |
} |
| 557 |
|
| 558 |
// Get EDIT booking data |
| 559 |
$local_params['edit_resource_id'] = ''; |
| 560 |
$local_params['skip_booking_id'] = ''; |
| 561 |
$local_params['is_edit_booking'] = 0; |
| 562 |
$local_params['is_duplicate_booking'] = 0; |
| 563 |
$is_edit_booking = wpbc_get_data__if_edit_booking( $re_cleaned_params['booking_hash'], $re_cleaned_params['request_uri'] ); |
| 564 |
if ( false !== $is_edit_booking ) { |
| 565 |
$local_params['edit_resource_id'] = $is_edit_booking['resource_id']; // can be parent booking resource, where we edit the booking |
| 566 |
$local_params['skip_booking_id'] = $is_edit_booking['booking_id']; // booking ID |
| 567 |
$local_params['is_edit_booking'] = $is_edit_booking['booking_id']; // booking ID |
| 568 |
if ( |
| 569 |
( ! empty( $local_params['structured_booking_data_arr']['wpbc_other_action'] ) ) |
| 570 |
&& ( 'duplicate_booking' === $local_params['structured_booking_data_arr']['wpbc_other_action'] ) |
| 571 |
){ |
| 572 |
$local_params['is_duplicate_booking'] = 1; |
| 573 |
} |
| 574 |
} |
| 575 |
|
| 576 |
$is_frontend_ajax_edit = wp_doing_ajax() |
| 577 |
&& 'wpbc_ajx_booking__create' === strtolower( $request_action ) |
| 578 |
&& 0 !== $local_params['is_edit_booking']; |
| 579 |
$is_authorized_admin_edit = $is_authorized_admin_booking_request; |
| 580 |
|
| 581 |
if ( |
| 582 |
$is_frontend_ajax_edit |
| 583 |
&& ! $is_authorized_admin_edit |
| 584 |
&& ! wpbc_is_visitor_booking_action_allowed( $local_params['is_edit_booking'] ) |
| 585 |
) { |
| 586 |
$ajx_data_arr['status'] = 'error'; |
| 587 |
$ajx_data_arr['status_error'] = 'visitor_booking_dates_in_past'; |
| 588 |
$ajx_data_arr['ajx_after_action_message'] = __( 'This booking can no longer be edited because its dates have already passed.', 'booking' ); |
| 589 |
$ajx_data_arr['ajx_after_action_message_status'] = 'warning'; |
| 590 |
return array( 'ajx_data' => $ajx_data_arr ); |
| 591 |
} |
| 592 |
// It can be request resource ID or if we edit booking, it can be 'edit resource' - (e.g. child resource) |
| 593 |
$local_params['initial_resource_id'] = ( ! empty( $local_params['edit_resource_id'] ) ) ? $local_params['edit_resource_id'] : $re_cleaned_params['resource_id']; |
| 594 |
|
| 595 |
// 2 |
| 596 |
$local_params['how_many_items_to_book'] = wpbc_get__how_many_items_to_book__in_booking_form( $local_params['structured_booking_data_arr'], $local_params['initial_resource_id'] ); |
| 597 |
|
| 598 |
|
| 599 |
$local_params['aggregate_resource_id_arr'] = explode( ',', $re_cleaned_params['aggregate_resource_id_arr'] ); |
| 600 |
$local_params['aggregate_resource_id_arr'] = array_filter( $local_params['aggregate_resource_id_arr'] ); // All entries of array equal to FALSE (0, '', '0' ) will be removed. |
| 601 |
$local_params['aggregate_resource_id_arr'] = array_unique( $local_params['aggregate_resource_id_arr'] ); // Erase duplicates |
| 602 |
|
| 603 |
// ----------------------------------------------------------------------------------------------------------------- |
| 604 |
// Here GO |
| 605 |
// ----------------------------------------------------------------------------------------------------------------- |
| 606 |
|
| 607 |
// Force - resource saving parameters, instead of wpbc__where_to_save_booking() |
| 608 |
if ( ! empty( $re_cleaned_params["save_booking_even_if_unavailable"] ) ) { |
| 609 |
|
| 610 |
$local_params['how_many_items_to_book'] = 1; |
| 611 |
|
| 612 |
$dates_keys_arr = array_values( $local_params['dates_only_sql_arr'] ); // [ '2023-09-23', '2023-09-24' ] |
| 613 |
|
| 614 |
$resources_in_dates = array_fill_keys( $dates_keys_arr , array( $local_params['initial_resource_id'] ) ); // [ 2023-09-23 = [ 2 ], 2023-09-24 = [ 2 ] ] |
| 615 |
|
| 616 |
$where_to_save_booking = array(); |
| 617 |
$where_to_save_booking['result'] = 'ok'; |
| 618 |
$where_to_save_booking['resources_in_dates'] = $resources_in_dates; // [ 2023-09-23 = [ 2, 10, 11 ], 2023-09-24 = [ 2, 10, 11 ] |
| 619 |
$where_to_save_booking['time_to_book'] = $local_params['time_as_his_arr']; // [ "00:00:00", "24:00:00" ] |
| 620 |
$where_to_save_booking['main__resource_id'] = $local_params['initial_resource_id']; // here edit or request (parent/single) resource |
| 621 |
|
| 622 |
} else { |
| 623 |
// <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > |
| 624 |
$php_performance = wpbc_php_performance_START( 'wpbc__where_to_save_booking' , $php_performance ); |
| 625 |
// </editor-fold> |
| 626 |
|
| 627 |
/** |
| 628 |
* Get slots [] where we can save booking = [ 'resources_in_dates' => [ 2023-10-18 = [ 2, 12, 10, 11 ] |
| 629 |
* 2023-10-19 = [ 2, 12, 10, 11 ] |
| 630 |
* 2023-10-20 = [ 2, 12, 10, 11 ] |
| 631 |
* ], |
| 632 |
* 'time_to_book' => [ "14:00:01" , "12:00:01" ], |
| 633 |
* 'result' => 'ok' |
| 634 |
* 'main__resource_id' => 2 |
| 635 |
* ] |
| 636 |
* OR |
| 637 |
* [ 'result' => 'error', 'message' => 'Booking can not be saved ...' ] |
| 638 |
*/ |
| 639 |
$where_to_save_booking = wpbc__where_to_save_booking( array( |
| 640 |
'resource_id' => $local_params['initial_resource_id'], // 2 //TODO: If edit booking. What to pass 'edit' or 'parent' resource ID? |
| 641 |
'skip_booking_id' => $local_params['skip_booking_id'], // '', | 125 if edit booking |
| 642 |
'dates_only_sql_arr' => $local_params['dates_only_sql_arr'], // [ "2023-10-18", "2023-10-25", "2023-11-25" ] |
| 643 |
'time_as_seconds_arr' => $local_params['time_as_seconds_arr'], // [ 36000, 39600 ] |
| 644 |
'how_many_items_to_book' => $local_params['how_many_items_to_book'], // 1 |
| 645 |
'request_uri' => $re_cleaned_params['request_uri'], // 'http://beta/resource-id2/' |
| 646 |
'allow_past' => ! empty( $re_cleaned_params['allow_past'] ), |
| 647 |
'is_use_booking_recurrent_time' => $local_params['is_use_booking_recurrent_time'], // true | false |
| 648 |
'time_override_source' => ! empty( $local_params['time_override_arr']['source'] ) ? $local_params['time_override_arr']['source'] : '', |
| 649 |
'as_single_resource' => false, // false |
| 650 |
'aggregate_resource_id_arr' => $local_params['aggregate_resource_id_arr'], // Optional can be '' |
| 651 |
'aggregate_type' => $re_cleaned_params['aggregate_type'], //TODO: this parameter does not transfer during saving, so here will be always default value 'bookings_only' // FixIn: 10.0.0.7. |
| 652 |
'custom_form' => $re_cleaned_params['custom_form'] // FixIn: 10.0.0.10. |
| 653 |
)); |
| 654 |
// <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- NO SLOTS TO SAVE " > |
| 655 |
if ( 'error' == $where_to_save_booking['result'] ) { |
| 656 |
$ajx_data_arr['status'] = 'error'; |
| 657 |
$ajx_data_arr['status_error'] = 'booking_can_not_save'; |
| 658 |
$ajx_data_arr['ajx_after_action_message'] = $where_to_save_booking['message']; |
| 659 |
$ajx_data_arr['ajx_after_action_message_status'] = 'warning'; |
| 660 |
return array( 'ajx_data' => $ajx_data_arr ); |
| 661 |
} |
| 662 |
// </editor-fold> |
| 663 |
|
| 664 |
// <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > |
| 665 |
$php_performance = wpbc_php_performance_END( 'wpbc__where_to_save_booking' , $php_performance ); |
| 666 |
// </editor-fold> |
| 667 |
} |
| 668 |
|
| 669 |
if ( ! empty( $local_params['appointment_service'] ) && function_exists( 'wpbc_appointment_services_check_buffer_conflicts' ) ) { |
| 670 |
$buffer_check = wpbc_appointment_services_check_buffer_conflicts( |
| 671 |
$local_params['appointment_service'], |
| 672 |
$where_to_save_booking['main__resource_id'], |
| 673 |
array_keys( $where_to_save_booking['resources_in_dates'] ), |
| 674 |
$local_params['time_as_seconds_arr'], |
| 675 |
$local_params['skip_booking_id'] |
| 676 |
); |
| 677 |
if ( is_wp_error( $buffer_check ) ) { |
| 678 |
$ajx_data_arr['status'] = 'error'; |
| 679 |
$ajx_data_arr['status_error'] = 'appointment_service_buffer_conflict'; |
| 680 |
$ajx_data_arr['ajx_after_action_message'] = $buffer_check->get_error_message(); |
| 681 |
$ajx_data_arr['ajx_after_action_message_status'] = 'warning'; |
| 682 |
return array( 'ajx_data' => $ajx_data_arr ); |
| 683 |
} |
| 684 |
} |
| 685 |
|
| 686 |
|
| 687 |
// Get parameters, from REQUEST |
| 688 |
$create_params = $local_params; |
| 689 |
$create_params['resource_id'] = ( ! empty( $local_params['edit_resource_id'] ) ) |
| 690 |
? $local_params['edit_resource_id'] // If we edit, then use original resource ??? |
| 691 |
: $where_to_save_booking['main__resource_id']; // Here is important TIP, resource can be where is free, and not where we submit |
| 692 |
/** |
| 693 |
* TODO: I think it's resolved! Just test about this situation, when we edit the booking - and it's means that we have $local_params['edit_resource_id'] |
| 694 |
* but what, if $where_to_save_booking do not contain this $local_params['edit_resource_id'] as available resource. |
| 695 |
* or even we have $local_params['edit_resource_id'] = 2 and $where_to_save_booking contain resources like [ 1, 2, 3, 4 ] |
| 696 |
* we make booking for 3 slots |
| 697 |
* in this case, main resource will be 2 |
| 698 |
* but then when we loop resources in wpbc_db__booking_save() we will save child booking resources for dates like: 2, 3, 4 ( and it's wrong ) |
| 699 |
* "(205, '2023-10-04 00:00:00', 0, NULL)" <- main resource '2' e.g. $local_params['edit_resource_id'] = 2 |
| 700 |
* "(205, '2023-10-04 00:00:00', 0, 2)" ? <- child resource '2' e.g. [ .., 2, .. ] in $where_to_save_booking WHICH IS WRONG |
| 701 |
*/ |
| 702 |
$create_params['is_emails_send'] = $re_cleaned_params['is_emails_send']; |
| 703 |
$create_params['custom_form'] = $re_cleaned_params['custom_form']; |
| 704 |
|
| 705 |
make_bk_action( 'check_multiuser_params_for_client_side', $create_params['resource_id'] ); // Activate working with specific user in WP MU |
| 706 |
|
| 707 |
// <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > |
| 708 |
$php_performance = wpbc_php_performance_START( 'wpbc_db__booking_save' , $php_performance ); |
| 709 |
// </editor-fold> |
| 710 |
|
| 711 |
// ----------------------------------------------------------------------------------------------------------------- |
| 712 |
// == CREATE_THE 'NEW_BOOKING' == |
| 713 |
// ----------------------------------------------------------------------------------------------------------------- |
| 714 |
$create_booking_params = array( |
| 715 |
'resource_id' => $create_params['resource_id'], |
| 716 |
'custom_form' => $create_params['custom_form'], |
| 717 |
'all_booking_data_arr' => $create_params['all_booking_data_arr'], |
| 718 |
'dates_only_sql_arr' => $create_params['dates_only_sql_arr'], |
| 719 |
'time_as_his_arr' => $create_params['time_as_his_arr'], |
| 720 |
'is_from_admin_panel' => $create_params['is_from_admin_panel'], |
| 721 |
'is_edit_booking' => $create_params['is_edit_booking'], |
| 722 |
'is_duplicate_booking' => $create_params['is_duplicate_booking'], |
| 723 |
'is_approve_booking' => $create_params['is_approve_booking'], |
| 724 |
'how_many_items_to_book' => $create_params['how_many_items_to_book'], |
| 725 |
'is_use_booking_recurrent_time' => $create_params['is_use_booking_recurrent_time'] // true | false |
| 726 |
); |
| 727 |
if ( ! empty( $create_params['appointment_service'] ) ) { $create_booking_params['appointment_service'] = $create_params['appointment_service']; } |
| 728 |
if ( ! empty( $create_params['sync_gid'] ) ) { $create_booking_params['sync_gid'] = $create_params['sync_gid']; } |
| 729 |
|
| 730 |
$booking_new_arr = wpbc_db__booking_save( $create_booking_params, $where_to_save_booking ); |
| 731 |
|
| 732 |
// <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- BOOKING CREATION " > |
| 733 |
if ( 'ok' !== $booking_new_arr['status'] ) { |
| 734 |
$ajx_data_arr['status'] = $booking_new_arr['status']; |
| 735 |
$ajx_data_arr['status_error'] = 'booking_can_not_save'; |
| 736 |
$ajx_data_arr['ajx_after_action_message'] = $booking_new_arr['message']; |
| 737 |
$ajx_data_arr['ajx_after_action_message_status'] = 'error'; |
| 738 |
return array( 'ajx_data' => $ajx_data_arr ); |
| 739 |
} |
| 740 |
// </editor-fold> |
| 741 |
|
| 742 |
do_action( 'wpbc_booking_after_save', $booking_new_arr['booking_id'], $create_booking_params, $where_to_save_booking ); |
| 743 |
|
| 744 |
// FixIn: 9.9.0.36. |
| 745 |
if ( |
| 746 |
( 0 !== $create_params['is_edit_booking'] ) // If edit booking |
| 747 |
&& ( 1 != $create_params['is_duplicate_booking'] ) // If not duplicate |
| 748 |
) { |
| 749 |
// Log the cost info. |
| 750 |
$is_add_timezone_offset = true; |
| 751 |
$booking_note = wpbc_date_localized( gmdate( 'Y-m-d H:i:s' ), '[Y-m-d H:i]', $is_add_timezone_offset ) . ' '; |
| 752 |
$booking_note .= __( 'The booking has been edited', 'booking' ) . '. | Edit URL: ' . esc_url_raw( $re_cleaned_params['request_uri'] ) . ''; |
| 753 |
make_bk_action( 'wpdev_make_update_of_remark', $booking_new_arr['booking_id'], $booking_note, true ); |
| 754 |
} |
| 755 |
// <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > |
| 756 |
$php_performance = wpbc_php_performance_END( 'wpbc_db__booking_save' , $php_performance ); |
| 757 |
// </editor-fold> |
| 758 |
|
| 759 |
// ----------------------------------------------------------------------------------------------------------------- |
| 760 |
// Get payment form(s) and Update COST of the booking |
| 761 |
// ----------------------------------------------------------------------------------------------------------------- |
| 762 |
$payment_params = array(); |
| 763 |
|
| 764 |
// Usually we have this: ( $str_dates__dd_mm_yyyy == $create_params['dates_only_sql_arr'] ) - but for ensure, use saved dates, e.g. $str_dates__dd_mm_yyyy |
| 765 |
$payment_params['booked_dates_times_arr'] = array( |
| 766 |
'dates_ymd_arr' => array_keys( $where_to_save_booking['resources_in_dates'] ), // [ 2023-10-20=>[], 2023-10-25=>[] ] -> [ "2023-10-20", "2023-10-25" ] |
| 767 |
'times_his_arr' => $where_to_save_booking['time_to_book'] // ['16:00:01', '18:00:02'] |
| 768 |
); |
| 769 |
$str_dates__dd_mm_yyyy = wpbc_convert_dates_arr__yyyy_mm_dd__to__dd_mm_yyyy( $payment_params['booked_dates_times_arr']['dates_ymd_arr'] ); // ['2023-10-20','2023-10-25'] => ['20.10.2023','25.10.2023'] |
| 770 |
$payment_params['str_dates__dd_mm_yyyy'] = implode( ',', $str_dates__dd_mm_yyyy ); // REQUIRED -- '14.11.2023, 15.11.2023, 16.11.2023, 17.11.2023' |
| 771 |
$payment_params['booking_id'] = $booking_new_arr['booking_id']; // REQUIRED -- '2' |
| 772 |
$payment_params['resource_id'] = $create_params['resource_id']; // REQUIRED -- '2' can be child resource (changed in wpbc_where_to_save() ) |
| 773 |
$payment_params['service_id'] = ! empty( $create_params['appointment_service']['service_id'] ) ? absint( $create_params['appointment_service']['service_id'] ) : 0; |
| 774 |
$payment_params['initial_resource_id'] = $local_params['initial_resource_id']; // REQUIRED -- '2' initial calendar - parent resource |
| 775 |
$payment_params['form_data'] = $booking_new_arr['form_data']; // we re-save it, because here can be sync_guid and custom form new data from wpbc_db__booking_save(..) // REQUIRED -- 'text^selected_short_timedates_hint4^06/11/2018 14:00...' |
| 776 |
$payment_params['times_array'] = array( |
| 777 |
explode( ':', $where_to_save_booking['time_to_book'][0] ), // ["10","00","00"] |
| 778 |
explode( ':', $where_to_save_booking['time_to_book'][1] ) // ["12","00","00"] |
| 779 |
); |
| 780 |
// Additional options |
| 781 |
$payment_params['is_edit_booking'] = $create_params['is_edit_booking']; // => 0 0 | int - ID of the booking |
| 782 |
$payment_params['custom_form'] = $create_params['custom_form']; // => '' '' | 'some_name' |
| 783 |
$payment_params['is_duplicate_booking'] = $create_params['is_duplicate_booking']; // => 0 0 | 1 |
| 784 |
$payment_params['is_from_admin_panel'] = $create_params['is_from_admin_panel']; // => false true | false |
| 785 |
$payment_params['is_show_payment_form'] = $create_params['is_show_payment_form']; // => 1 0 | 1 |
| 786 |
$payment_params['wpbc_admin_cost_correction'] = $re_cleaned_params['wpbc_admin_cost_correction']; |
| 787 |
if ( $payment_params['is_from_admin_panel'] ) { |
| 788 |
// $payment_params['is_show_payment_form'] = 0; // FixIn: 9.9.0.21. |
| 789 |
} |
| 790 |
// <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > |
| 791 |
$php_performance = wpbc_php_performance_START( 'wpbc_maybe_get_payment_form' , $php_performance ); |
| 792 |
// </editor-fold> |
| 793 |
|
| 794 |
// GET PAYMENT FORMS =============================================================================================== |
| 795 |
if ( function_exists( 'wpbc_maybe_get_payment_form' ) ) { |
| 796 |
|
| 797 |
$response__payment_form__arr = wpbc_maybe_get_payment_form( $payment_params ); |
| 798 |
|
| 799 |
// <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- COSTS || PAYMENT_SYSTEMS " > |
| 800 |
if ( |
| 801 |
( ! empty( $response__payment_form__arr['status'] ) ) |
| 802 |
&& ( 'ok' != $response__payment_form__arr['status'] ) |
| 803 |
) { |
| 804 |
$ajx_data_arr['status'] = $response__payment_form__arr['status']; |
| 805 |
$ajx_data_arr['status_error'] = 'booking_can_not_save'; |
| 806 |
$ajx_data_arr['ajx_after_action_message'] = $response__payment_form__arr['message']; |
| 807 |
$ajx_data_arr['ajx_after_action_message_status'] = 'error'; |
| 808 |
return array( 'ajx_data' => $ajx_data_arr ); |
| 809 |
} |
| 810 |
// </editor-fold> |
| 811 |
|
| 812 |
if ( ! empty( $response__payment_form__arr['costs_arr']['form_data'] ) ) { |
| 813 |
$payment_params['form_data'] = $response__payment_form__arr['costs_arr']['form_data']; // we re-save it, because here can be [cost_correction] shortcode data |
| 814 |
} |
| 815 |
//TODO: Do we really need this in output $ajx_data_arr ???, because it stored in $confirmation |
| 816 |
if ( ! empty( $response__payment_form__arr['gateways_output_arr'] ) ) { |
| 817 |
$ajx_data_arr['gateways_output_arr'] = $response__payment_form__arr['gateways_output_arr']; |
| 818 |
} |
| 819 |
if ( function_exists( 'wpbc_if_zero_cost__approve_booking_dates' ) ) { |
| 820 |
wpbc_if_zero_cost__approve_booking_dates( $payment_params['booking_id'] ); |
| 821 |
} |
| 822 |
|
| 823 |
} else { |
| 824 |
$response__payment_form__arr = $payment_params; |
| 825 |
$response__payment_form__arr['status'] = 'ok'; |
| 826 |
} |
| 827 |
|
| 828 |
|
| 829 |
// <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > |
| 830 |
$php_performance = wpbc_php_performance_END( 'wpbc_maybe_get_payment_form' , $php_performance ); |
| 831 |
|
| 832 |
$php_performance = wpbc_php_performance_START( 'emails_sending' , $php_performance ); |
| 833 |
// </editor-fold> |
| 834 |
|
| 835 |
// ----------------------------------------------------------------------------------------------------------------- |
| 836 |
// == Emails === |
| 837 |
// ----------------------------------------------------------------------------------------------------------------- |
| 838 |
if ( 1 == $re_cleaned_params['is_emails_send'] ) { |
| 839 |
|
| 840 |
$email_content = $payment_params['form_data']; |
| 841 |
|
| 842 |
// If we output any text, then probably it's errors or warnings, we need to catch them |
| 843 |
ob_start(); |
| 844 |
ob_clean(); |
| 845 |
|
| 846 |
if ( |
| 847 |
( 0 === $local_params['is_edit_booking'] ) |
| 848 |
|| ( 1 === $local_params['is_duplicate_booking'] ) // FixIn: 10.0.0.42. |
| 849 |
){ |
| 850 |
|
| 851 |
// New booking to Admin |
| 852 |
wpbc_send_email_new_admin( $payment_params['booking_id'], $payment_params['resource_id'], $email_content ); |
| 853 |
|
| 854 |
// New pending to Visitor |
| 855 |
wpbc_send_email_new_visitor( $payment_params['booking_id'], $payment_params['resource_id'], $email_content ) ; |
| 856 |
|
| 857 |
$is_booking_approved = wpbc_is_booking_approved( $payment_params['booking_id'] ); |
| 858 |
if ( $is_booking_approved ) { |
| 859 |
// New approved to Visitor / Admin |
| 860 |
wpbc_send_email_approved( $payment_params['booking_id'], 1 ); |
| 861 |
} |
| 862 |
|
| 863 |
do_action( 'wpbc_booking_is_approved_during_creation' , $payment_params['booking_id'] , (int) $is_booking_approved ); // FixIn: 10.10.1.1. |
| 864 |
|
| 865 |
// Payment request from admin panel, if needed |
| 866 |
if( |
| 867 |
( $payment_params['is_from_admin_panel'] ) |
| 868 |
&& ( 'On' == get_bk_option( 'booking_payment_request_auto_send_in_bap' ) ) |
| 869 |
&& ( function_exists( 'wpbc_send_email_payment_request' ) ) |
| 870 |
){ |
| 871 |
$payment_reason = ''; |
| 872 |
$is_send = wpbc_send_email_payment_request( $payment_params['booking_id'], $payment_params['resource_id'], $email_content , $payment_reason ); |
| 873 |
} |
| 874 |
|
| 875 |
|
| 876 |
|
| 877 |
} else { |
| 878 |
|
| 879 |
// Edited booking to Visitor / Admin |
| 880 |
if ( function_exists( 'wpbc_send_email_modified' ) ) { |
| 881 |
wpbc_send_email_modified( $payment_params['booking_id'], $payment_params['resource_id'], $email_content ); |
| 882 |
} |
| 883 |
} |
| 884 |
|
| 885 |
$errors_on_email_sending_html = ob_get_contents(); |
| 886 |
ob_end_clean(); |
| 887 |
|
| 888 |
if ( ! empty( $errors_on_email_sending_html ) ) { |
| 889 |
// Show these messages as warning after creation of the booking |
| 890 |
$errors_on_email_sending_html = wp_strip_all_tags( $errors_on_email_sending_html ); |
| 891 |
$errors_on_email_sending_html = esc_attr( $errors_on_email_sending_html ); |
| 892 |
$errors_on_email_sending_html = str_replace( "\\n", '', $errors_on_email_sending_html ); |
| 893 |
|
| 894 |
$ajx_data_arr['ajx_after_action_message_status'] = 'warning'; |
| 895 |
$ajx_data_arr['ajx_after_action_message'] = $errors_on_email_sending_html; |
| 896 |
} |
| 897 |
} |
| 898 |
|
| 899 |
// <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > |
| 900 |
$php_performance = wpbc_php_performance_END( 'emails_sending' , $php_performance ); |
| 901 |
// </editor-fold> |
| 902 |
|
| 903 |
// ----------------------------------------------------------------------------------------------------------------- |
| 904 |
// == Track booking - New | Edit === |
| 905 |
// ----------------------------------------------------------------------------------------------------------------- |
| 906 |
/** |
| 907 |
* Useful hook for Google Ads Conversion tracking. How to use this hook? |
| 908 |
* |
| 909 |
* Add code similar to this in your functions.php file in your theme, or in some other php file: |
| 910 |
* |
| 911 |
// Track adding new booking |
| 912 |
// |
| 913 |
// @param $params = array ( |
| 914 |
// 'str_dates__dd_mm_yyyy' => '08.10.2023,09.10.2023,10.10.2023,11.10.2023', |
| 915 |
// 'booking_id' => 254, |
| 916 |
// 'resource_id' => 11, // child or parent or single |
| 917 |
// 'initial_resource_id' => 2, // parent or single |
| 918 |
// 'form_data' => 'text^selected_short_dates_hint11^Sun...', |
| 919 |
// 'times_array' => array ( array ( '14', '00', '01' ), array( '12', '00', '02' ) ), |
| 920 |
// 'is_edit_booking' => 0, |
| 921 |
// 'custom_form' => '', |
| 922 |
// 'is_duplicate_booking' => 0, |
| 923 |
// 'is_from_admin_panel' => false, |
| 924 |
// 'is_show_payment_form' => 1 |
| 925 |
// ) |
| 926 |
function my_booking_tracking( $params ){ |
| 927 |
// Your code here |
| 928 |
?><!-- Google Code for Booking Conversion Page --> |
| 929 |
<script type="text/javascript"> |
| 930 |
// Insert bellow your Google Conversion Code |
| 931 |
</script><?php |
| 932 |
} |
| 933 |
add_action( 'wpbc_track_new_booking', 'my_booking_tracking' ); |
| 934 |
* |
| 935 |
* |
| 936 |
* |
| 937 |
* Useful hook booking edit tracking |
| 938 |
* |
| 939 |
* Add code similar to this in your functions.php file in your theme, or in some other php file: |
| 940 |
* |
| 941 |
// Track edit existing booking |
| 942 |
// |
| 943 |
// @param $params = array ( |
| 944 |
// 'str_dates__dd_mm_yyyy' => '08.10.2023,09.10.2023,10.10.2023,11.10.2023', |
| 945 |
// 'booking_id' => 254, |
| 946 |
// 'resource_id' => 11, // child or parent or single |
| 947 |
// 'initial_resource_id' => 2, // parent or single |
| 948 |
// 'form_data' => 'text^selected_short_dates_hint11^Sun...', |
| 949 |
// 'times_array' => array ( array ( '14', '00', '01' ), array( '12', '00', '02' ) ), |
| 950 |
// 'is_edit_booking' => 1, |
| 951 |
// 'custom_form' => '', |
| 952 |
// 'is_duplicate_booking' => 0, |
| 953 |
// 'is_from_admin_panel' => false, |
| 954 |
// 'is_show_payment_form' => 1 |
| 955 |
// ) |
| 956 |
function my_edit_booking_tracking( $params ){ |
| 957 |
// Your code here |
| 958 |
?><!-- Google Code for Booking Conversion Page --> |
| 959 |
<script type="text/javascript"> |
| 960 |
// Insert bellow your Google Conversion Code |
| 961 |
</script><?php |
| 962 |
|
| 963 |
} |
| 964 |
add_action( 'wpbc_track_edit_booking', 'my_edit_booking_tracking' ); |
| 965 |
*/ |
| 966 |
if ( 0 === $local_params['is_edit_booking'] ) { |
| 967 |
do_action( 'wpbc_track_new_booking', $payment_params ); |
| 968 |
} else { |
| 969 |
do_action( 'wpbc_track_edit_booking', $payment_params ); |
| 970 |
} |
| 971 |
|
| 972 |
|
| 973 |
// <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > |
| 974 |
$php_performance = wpbc_php_performance_START( 'confirmation' , $php_performance ); |
| 975 |
// </editor-fold> |
| 976 |
|
| 977 |
// <editor-fold defaultstate="collapsed" desc=" == Confirmation data == " > |
| 978 |
|
| 979 |
|
| 980 |
$confirmation_params_arr = array( |
| 981 |
'is_from_admin_panel' => $payment_params['is_from_admin_panel'], |
| 982 |
|
| 983 |
'booking_id' => $booking_new_arr['booking_id'], // 16102023 |
| 984 |
'resource_id' => $payment_params['resource_id'], // 1 |
| 985 |
'form_data' => $payment_params['form_data'], // 'text^selected_short_dates_hint11^Sun...', |
| 986 |
'dates_ymd_arr' => $payment_params['booked_dates_times_arr']['dates_ymd_arr'], // [ '2023-10-20', '2023-10-25' ] |
| 987 |
'times_his_arr' => $payment_params['booked_dates_times_arr']['times_his_arr'], // [ '16:00:01', '18:00:02' ] |
| 988 |
|
| 989 |
'total_cost' => ( isset( $response__payment_form__arr['costs_arr'] ) && isset( $response__payment_form__arr['costs_arr']['total_cost'] ) ) |
| 990 |
? $response__payment_form__arr['costs_arr']['total_cost'] |
| 991 |
: 0, |
| 992 |
'deposit_cost' => ( isset( $response__payment_form__arr['costs_arr'] ) && isset( $response__payment_form__arr['costs_arr']['deposit_cost'] ) ) |
| 993 |
? $response__payment_form__arr['costs_arr']['deposit_cost'] |
| 994 |
: 0, |
| 995 |
'booking_summary' => ( ( ! empty( $response__payment_form__arr['gateways_output_arr'] ) ) && ( ! empty( $response__payment_form__arr['gateways_output_arr']['booking_summary'] ) ) ) |
| 996 |
? $response__payment_form__arr['gateways_output_arr']['booking_summary'] |
| 997 |
: '', |
| 998 |
'gateway_rows' => ( ( ! empty( $response__payment_form__arr['gateways_output_arr'] ) ) && ( ! empty( $response__payment_form__arr['gateways_output_arr']['gateway_rows'] ) ) ) |
| 999 |
? $response__payment_form__arr['gateways_output_arr']['gateway_rows'] |
| 1000 |
: '' |
| 1001 |
); |
| 1002 |
// It will not show payment form in Booking > Add booking page and if defined, do not make redirect |
| 1003 |
if ( $payment_params['is_from_admin_panel'] ) { |
| 1004 |
|
| 1005 |
$confirmation_params_arr['ty_is_redirect'] = 'message'; // Do not make redirect, if it's in admin panel! |
| 1006 |
|
| 1007 |
// But if we edit / duplicate the booking, then do redirection to Booking Listing page // FixIn: 9.9.0.3. |
| 1008 |
if ( |
| 1009 |
( 0 !== $local_params['is_edit_booking'] ) |
| 1010 |
// && ( empty( $local_params['is_duplicate_booking'] ) ) |
| 1011 |
){ |
| 1012 |
$confirmation_params_arr['ty_is_redirect'] = 'page'; |
| 1013 |
$confirmation_params_arr['ty_url'] = wpbc_get_bookings_url() . '&tab=vm_booking_listing&wh_booking_id=' . $confirmation_params_arr['booking_id']; |
| 1014 |
} |
| 1015 |
} |
| 1016 |
$confirmation = wpbc_booking_confirmation( $confirmation_params_arr ); |
| 1017 |
|
| 1018 |
// </editor-fold> |
| 1019 |
|
| 1020 |
// <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > |
| 1021 |
$php_performance = wpbc_php_performance_END( 'confirmation' , $php_performance ); |
| 1022 |
// </editor-fold> |
| 1023 |
|
| 1024 |
|
| 1025 |
make_bk_action( 'finish_check_multiuser_params_for_client_side', $create_params['resource_id'] ); // Deactivate working with specific user in WP MU |
| 1026 |
|
| 1027 |
|
| 1028 |
// <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > |
| 1029 |
$php_performance = wpbc_php_performance_END( 'total' , $php_performance ); |
| 1030 |
$php_performance['other_code'] = - 1 * array_reduce( $php_performance, |
| 1031 |
function ( $sum, $item ) { |
| 1032 |
$sum += $item; |
| 1033 |
return $sum; |
| 1034 |
} |
| 1035 |
, - 2 * $php_performance['total'] ); // PERFORMANCE OTHER - after TOTAL |
| 1036 |
// </editor-fold> |
| 1037 |
|
| 1038 |
wpbc_clear_request_form_context(); |
| 1039 |
|
| 1040 |
return array( 'ajx_data' => $ajx_data_arr, // [ 'status' => "ok", 'wpbc_payment_output' => "<p>Dear John<br..." ] |
| 1041 |
'booking_id' => $booking_new_arr['booking_id'], // 254 |
| 1042 |
'booking_arr' => $payment_params, |
| 1043 |
'php_performance' => $php_performance, // [ ... ] |
| 1044 |
'confirmation' => $confirmation // [ ] |
| 1045 |
); |
| 1046 |
} |
| 1047 |
|
| 1048 |
|
| 1049 |
// --------------------------------------------------------------------------------------------------------------------- |
| 1050 |
// New booking creation sub functions |
| 1051 |
// --------------------------------------------------------------------------------------------------------------------- |
| 1052 |
|
| 1053 |
/** |
| 1054 |
* Save booking in DB |
| 1055 |
* |
| 1056 |
* @param array $create_params = [ |
| 1057 |
* 'resource_id' => 10, |
| 1058 |
* 'dates_only_sql_arr' => [ '2023-10-04', '2023-10-05', '2023-10-06'], |
| 1059 |
* 'time_as_his_arr' => [ '14:00:01', '16:00:02' ], |
| 1060 |
* 'is_from_admin_panel' => false, |
| 1061 |
* 'is_edit_booking' => 0, |
| 1062 |
* 'is_duplicate_booking' => 0, |
| 1063 |
* 'is_approve_booking' => 0, |
| 1064 |
* 'how_many_items_to_book' => 2, |
| 1065 |
* 'custom_form' => '', |
| 1066 |
* 'is_use_booking_recurrent_time' => false, |
| 1067 |
* 'all_booking_data_arr' => [ 'rangetime' => [ |
| 1068 |
* 'type' => 'selectbox-multiple', |
| 1069 |
* 'original_name' => 'rangetime2[]', //NOTE: here RESOURCE ID (2) can be from Parent resource, but resource_id can rely on child (10) resource |
| 1070 |
* 'name' => 'rangetime', |
| 1071 |
* 'value' => '14:00 - 16:00', |
| 1072 |
* ], |
| 1073 |
* 'name' => [ 'type' => 'text', 'original_name' => 'name2', ... ], |
| 1074 |
* ... |
| 1075 |
* ] |
| 1076 |
* ] |
| 1077 |
* |
| 1078 |
* @param $where_to_save_booking = [ |
| 1079 |
* 'result' = 'ok', |
| 1080 |
* 'main__resource_id' = 2 |
| 1081 |
* 'resources_in_dates' = [ 2023-10-18 = [ 2, 12, 10, 11 ] |
| 1082 |
* 2023-10-19 = [ 2, 12, 10, 11 ] |
| 1083 |
* 2023-10-20 = [ 2, 12, 10, 11 ] |
| 1084 |
* ], |
| 1085 |
* 'time_to_book' = [ "14:00:01" , "16:00:02" ] |
| 1086 |
* ] |
| 1087 |
* |
| 1088 |
* @return [ |
| 1089 |
* 'status' => 'ok' 'ok' | 'error' | 'warning' |
| 1090 |
* 'booking_id' => 100 int |
| 1091 |
* 'message' => '' 'If error, then here can be description of error' |
| 1092 |
* 'form_data' => If 'ok' form data can be different here, 'custom_form' parameter, so it can add 'wpbc_custom_booking_form' field for identification, what custom booking form was used, |
| 1093 |
* ] |
| 1094 |
*/ |
| 1095 |
function wpbc_db__booking_save( &$create_params, &$where_to_save_booking ) { |
| 1096 |
//FixIn: 10.11.5.4 |
| 1097 |
/** |
| 1098 |
* Tip: $create_params['all_booking_data_arr'] - contain: [ 'field_name' => [ 'type' = "checkbox", 'original_name' = "fixed_fee2[]", 'name' = "fixed_fee", 'value' = "true" ] , ... ] |
| 1099 |
* $create_params['structured_booking_data_arr'] - contain: [ 'field_name' => 'field_value' , ... ] |
| 1100 |
*/ |
| 1101 |
|
| 1102 |
// <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- 'Wrong resource ID " > |
| 1103 |
if ( empty( $create_params['resource_id'] ) ) { |
| 1104 |
return array( 'status' => 'error', 'message' => 'Wrong ID of booking resource: ' . $create_params['resource_id'] ); |
| 1105 |
} |
| 1106 |
// </editor-fold> |
| 1107 |
|
| 1108 |
|
| 1109 |
$defaults = array( |
| 1110 |
'is_use_booking_recurrent_time' => ( 'On' === get_bk_option( 'booking_recurrent_time' ) ) |
| 1111 |
); |
| 1112 |
$create_params = wp_parse_args( $create_params, $defaults ); |
| 1113 |
|
| 1114 |
|
| 1115 |
$sql_field_arr = array(); |
| 1116 |
|
| 1117 |
|
| 1118 |
|
| 1119 |
// Is it was used custom booking form ? |
| 1120 |
if ( ! empty( $create_params['custom_form'] ) ) { |
| 1121 |
$create_params['all_booking_data_arr']['wpbc_custom_booking_form'] = array( |
| 1122 |
'type' => 'text', |
| 1123 |
'original_name' => 'wpbc_custom_booking_form' . $create_params['resource_id'], |
| 1124 |
'name' => 'wpbc_custom_booking_form', |
| 1125 |
'value' => $create_params['custom_form'] |
| 1126 |
); |
| 1127 |
} |
| 1128 |
|
| 1129 |
if ( ! empty( $create_params['sync_gid'] ) ) { |
| 1130 |
/** |
| 1131 |
* Such fields are comming from '../wp-content/plugins/booking/core/sync/wpbc-gcal-class.php' in function run() |
| 1132 |
*/ |
| 1133 |
|
| 1134 |
// Escape any XSS injection from values in booking form |
| 1135 |
list( $create_params['sync_gid'] ) = wpbc_escape_any_xss_in_arr( array( $create_params['sync_gid'] ) ); |
| 1136 |
|
| 1137 |
$sql_field_arr[] = array( 'name' => 'sync_gid', 'type' => '%s', 'value' => $create_params['sync_gid'] ); |
| 1138 |
} |
| 1139 |
|
| 1140 |
// Escape any XSS injection from values in booking form |
| 1141 |
$create_params['all_booking_data_arr'] = wpbc_escape_any_xss_in_arr( $create_params['all_booking_data_arr'] ); |
| 1142 |
|
| 1143 |
|
| 1144 |
//Set LAST check out day as AVAILABLE - remove it |
| 1145 |
if ( |
| 1146 |
( 'On' === get_bk_option( 'booking_last_checkout_day_available' ) ) |
| 1147 |
&& ( ! empty( $create_params['dates_only_sql_arr'] ) ) |
| 1148 |
&& ( count( $create_params['dates_only_sql_arr'] ) > 1 ) |
| 1149 |
) { |
| 1150 |
unset( $create_params['dates_only_sql_arr'][ ( count( $create_params['dates_only_sql_arr'] ) - 1 ) ] ); // Remove LAST selected day in calendar // FixIn: 6.2.3.6. |
| 1151 |
// Delete last item // FixIn: 9.9.0.19. |
| 1152 |
$resources_in_dates_last_key = key( array_slice( $where_to_save_booking['resources_in_dates'], - 1, 1, true ) ); |
| 1153 |
unset( $where_to_save_booking['resources_in_dates'][ $resources_in_dates_last_key ] ); |
| 1154 |
} |
| 1155 |
|
| 1156 |
// :: ERROR :: |
| 1157 |
if ( empty( $create_params['dates_only_sql_arr'] ) ) { // No dates :? |
| 1158 |
return array( 'status' => 'error', 'message' => 'Sent request with no dates.' ); |
| 1159 |
} |
| 1160 |
|
| 1161 |
// <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- CHECK_IN_DATE_OLDER_THAN_CHECK_OUT " > |
| 1162 |
$is_no_dates_booking = ( |
| 1163 |
function_exists( 'wpbc_is_these_dates__for__no_dates' ) |
| 1164 |
&& wpbc_is_these_dates__for__no_dates( $create_params['dates_only_sql_arr'] ) |
| 1165 |
); |
| 1166 |
if ( ( count( $create_params['dates_only_sql_arr'] ) == 1 ) && ( ! $is_no_dates_booking ) ) { // Is it single selected date ? |
| 1167 |
|
| 1168 |
// Is 'check in' date/time older than 'check out' date/time when SINGLE day for booking? Then show error. |
| 1169 |
|
| 1170 |
/** |
| 1171 |
* If we are having "change over" days activated and selected only 1 day in calendar, |
| 1172 |
* then we can have error: "Warning! Number of check in != check out times.", because "check in" day older than "check out" date. |
| 1173 |
*/ |
| 1174 |
|
| 1175 |
$is_apply__check_in_out__10s = false; |
| 1176 |
$datestamp_check_in = wpbc_convert__sql_date__to_seconds( $create_params['dates_only_sql_arr'][0] . ' ' . $create_params['time_as_his_arr'][0], $is_apply__check_in_out__10s ); |
| 1177 |
$datestamp_check_out = wpbc_convert__sql_date__to_seconds( $create_params['dates_only_sql_arr'][0] . ' ' . $create_params['time_as_his_arr'][1], $is_apply__check_in_out__10s ); |
| 1178 |
|
| 1179 |
|
| 1180 |
if ( $datestamp_check_in > $datestamp_check_out ) { |
| 1181 |
$error_message = sprintf( 'Error! Your check in date %s older than check out date %s. <br>Try to select more dates or use different time.' |
| 1182 |
, '<strong>' . wpbc_convert__seconds__to_sql_date( $datestamp_check_in, $is_apply__check_in_out__10s ) . '</strong>' |
| 1183 |
, '<strong>' . wpbc_convert__seconds__to_sql_date( $datestamp_check_out, $is_apply__check_in_out__10s ) . '</strong>' |
| 1184 |
); |
| 1185 |
$error_message .= '<br>' . '<strong>Settings that can be reason of the issue:</strong> '; |
| 1186 |
if( 'On' === get_bk_option( 'booking_last_checkout_day_available' )){ |
| 1187 |
$error_message .= '<br>' . 'You have enabled <strong>"Set check out date as available"</strong> option at Booking > Settings General page in "Calendar" section. '; |
| 1188 |
} |
| 1189 |
if ( 'On' === get_bk_option( 'booking_range_selection_time_is_active' ) ){ |
| 1190 |
$error_message .= '<br>' . 'You have enabled <strong>"Use changeover days"</strong> option at Booking > Settings General page in "Calendar" section with check-in/out times: ' . get_bk_option( 'booking_range_selection_start_time' ) . '/' . get_bk_option( 'booking_range_selection_end_time' ); |
| 1191 |
} |
| 1192 |
if ( $create_params['is_use_booking_recurrent_time'] ) { |
| 1193 |
$error_message .= '<br>' . 'You have enabled <strong>"Use time selections as recurrent time slots"</strong> option at Booking > Settings General page in "Calendar" section. '; |
| 1194 |
} |
| 1195 |
return array( 'status' => 'error', 'message' => $error_message ); |
| 1196 |
} |
| 1197 |
} |
| 1198 |
// </editor-fold> |
| 1199 |
|
| 1200 |
// Compose form data for DB. Can be different resource: 'selectbox-multiple^rangetime10[]^14..' <-> 'selectbox-multiple^rangetime2[]^14..' -> 'rangetime10' - child res. Previously 'rangetime2' - parent |
| 1201 |
$form_data = wpbc_encode_booking_data_to_string( $create_params['all_booking_data_arr'], $create_params['resource_id'] ); |
| 1202 |
|
| 1203 |
|
| 1204 |
// ----------------------------------------------------------------------------------------------------------------- |
| 1205 |
// APPROVED / PENDING |
| 1206 |
// ----------------------------------------------------------------------------------------------------------------- |
| 1207 |
// Is approve booking |
| 1208 |
$auto_approve_new_bookings_is_active = trim( get_bk_option( 'booking_auto_approve_new_bookings_is_active' ) ); |
| 1209 |
$is_approved_dates = ( $auto_approve_new_bookings_is_active == 'On' ) ? 1 : intval( $create_params['is_approve_booking'] ); |
| 1210 |
|
| 1211 |
// Auto approve only for specific booking resources |
| 1212 |
/** |
| 1213 |
* How to use "Auto approve bookings only for specific booking resources" ? |
| 1214 |
* Add code similar to this in your functions.php file in your theme, or in some other php file: |
| 1215 |
* |
| 1216 |
function my_wpbc_get_booking_resources_arr_to_auto_approve( $resources_to_approve ) { |
| 1217 |
$resources_to_approve = array( 9, 12, 33 ); // Array of booking resources ID, which you need to auto approve |
| 1218 |
return $resources_to_approve; |
| 1219 |
} |
| 1220 |
add_filter( 'wpbc_get_booking_resources_arr_to_auto_approve', 'my_wpbc_get_booking_resources_arr_to_auto_approve' ); |
| 1221 |
*/ |
| 1222 |
$booking_resources_to_approve = array(); |
| 1223 |
$booking_resources_to_approve = apply_filters( 'wpbc_get_booking_resources_arr_to_auto_approve', $booking_resources_to_approve ); // FixIn: 8.5.2.27. |
| 1224 |
if ( in_array( $create_params['resource_id'], $booking_resources_to_approve ) ) { |
| 1225 |
$is_approved_dates = 1; |
| 1226 |
} |
| 1227 |
|
| 1228 |
if ( |
| 1229 |
( $create_params['is_from_admin_panel'] ) // true | false |
| 1230 |
&& ( get_bk_option( 'booking_auto_approve_bookings_if_added_in_admin_panel' ) == 'On' ) |
| 1231 |
){ // FixIn: 8.1.3.27. |
| 1232 |
$is_approved_dates = 1; |
| 1233 |
} |
| 1234 |
|
| 1235 |
// If the booking auto-approved, then we need to mark it as "Read". |
| 1236 |
if ( $is_approved_dates ) { |
| 1237 |
$sql_field_arr[] = array( |
| 1238 |
'name' => 'is_new', |
| 1239 |
'type' => '%d', |
| 1240 |
'value' => 0, |
| 1241 |
); |
| 1242 |
} |
| 1243 |
|
| 1244 |
// <editor-fold defaultstate="collapsed" desc=" == Save Booking == " > |
| 1245 |
// ----------------------------------------------------------------------------------------------------------------- |
| 1246 |
// Save Booking |
| 1247 |
// ----------------------------------------------------------------------------------------------------------------- |
| 1248 |
global $wpdb; |
| 1249 |
|
| 1250 |
$sql_field_arr[] = array( 'name' => 'form', 'type' => '%s', 'value' => $form_data ); |
| 1251 |
$sql_field_arr[] = array( 'name' => 'booking_type', 'type' => '%d', 'value' => $create_params['resource_id'] ); |
| 1252 |
$sql_field_arr[] = array( 'name' => 'modification_date', 'type' => '%s', 'value' => gmdate( 'Y-m-d H:i:s' ) ); |
| 1253 |
$sql_field_arr[] = array( 'name' => 'sort_date', 'type' => '%s', 'value' => $create_params['dates_only_sql_arr'][0] . ' ' . $create_params['time_as_his_arr'][0] ); |
| 1254 |
$sql_field_arr[] = array( 'name' => 'hash', 'type' => 'MD5(%s)', 'value' => time() . '_' . wp_rand( 1000, 1000000 ) ); |
| 1255 |
|
| 1256 |
|
| 1257 |
if ( |
| 1258 |
( 0 == $create_params['is_edit_booking'] ) || // If not edit, then INSERT. |
| 1259 |
( 1 == $create_params['is_duplicate_booking'] ) // If duplicate, then INSERT. |
| 1260 |
) { |
| 1261 |
// Saved only for new booking creation. |
| 1262 |
$sql_field_arr[] = array( |
| 1263 |
'name' => 'creation_date', |
| 1264 |
'type' => '%s', |
| 1265 |
'value' => gmdate( 'Y-m-d H:i:s' ), |
| 1266 |
); |
| 1267 |
|
| 1268 |
$sql_prepare_arr = array(); |
| 1269 |
$sql_prepare_arr['name'] = array_map( function ( $value ) { return $value['name']; }, $sql_field_arr ); |
| 1270 |
$sql_prepare_arr['type'] = array_map( function ( $value ) { return $value['type']; }, $sql_field_arr ); |
| 1271 |
$sql_prepare_arr['value'] = array_map( function ( $value ) { return $value['value']; }, $sql_field_arr ); |
| 1272 |
|
| 1273 |
$sql_prepare_arr['name'] = implode( ', ', $sql_prepare_arr['name'] ); |
| 1274 |
$sql_prepare_arr['type'] = implode( ', ', $sql_prepare_arr['type'] ); |
| 1275 |
/* phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare */ |
| 1276 |
$sql = $wpdb->prepare( "INSERT INTO {$wpdb->prefix}booking " . " ( {$sql_prepare_arr['name']} )" . " VALUES ( {$sql_prepare_arr['type']} )", $sql_prepare_arr['value'] ); |
| 1277 |
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter |
| 1278 |
if ( false === $wpdb->query( $sql ) ) { |
| 1279 |
return array( 'status' => 'error', 'message' => 'Error. INSERT New Data in DB.' . ' FILE:' . __FILE__ . ' LINE:' . __LINE__ . ' SQL:' . $sql ); |
| 1280 |
} |
| 1281 |
// Get ID of booking |
| 1282 |
$booking_id = (int) $wpdb->insert_id; |
| 1283 |
|
| 1284 |
} else { // Edit - UPDATE |
| 1285 |
|
| 1286 |
$booking_id = (int) $create_params['is_edit_booking']; |
| 1287 |
|
| 1288 |
$sql_prepare_arr = array(); |
| 1289 |
$sql_prepare_arr['set'] = array_map( function ( $value ) { return $value['name'] . '=' . $value['type']; }, $sql_field_arr ); |
| 1290 |
$sql_prepare_arr['value'] = array_map( function ( $value ) { return $value['value']; }, $sql_field_arr ); |
| 1291 |
|
| 1292 |
$sql_prepare_arr['set'] = implode( ', ', $sql_prepare_arr['set'] ); |
| 1293 |
|
| 1294 |
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare |
| 1295 |
$sql = $wpdb->prepare( "UPDATE {$wpdb->prefix}booking SET {$sql_prepare_arr['set']} WHERE booking_id={$booking_id};", $sql_prepare_arr['value'] ); |
| 1296 |
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter |
| 1297 |
if ( false === $wpdb->query( $sql ) ) { |
| 1298 |
return array( 'status' => 'error', |
| 1299 |
'message' => 'Error. UPDATE Exist Data in DB.' . ' FILE:' . __FILE__ . ' LINE:' . __LINE__ . ' SQL:' . $sql, |
| 1300 |
); |
| 1301 |
} |
| 1302 |
|
| 1303 |
// Check if dates previously was approved. |
| 1304 |
$slct_sql = "SELECT approved FROM {$wpdb->prefix}bookingdates WHERE booking_id IN ({$booking_id}) LIMIT 0,1"; |
| 1305 |
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter |
| 1306 |
$slct_sql_results = $wpdb->get_results( $slct_sql ); |
| 1307 |
$is_approved_dates = ( count( $slct_sql_results ) > 0 ) ? $slct_sql_results[0]->approved : $is_approved_dates; |
| 1308 |
|
| 1309 |
|
| 1310 |
$delete_sql = "DELETE FROM {$wpdb->prefix}bookingdates WHERE booking_id IN ({$booking_id})"; |
| 1311 |
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter |
| 1312 |
if ( false === $wpdb->query( $delete_sql ) ) { |
| 1313 |
return array( 'status' => 'error', 'message' => 'Error. DELETE Old Dates in DB.' . ' FILE:' . __FILE__ . ' LINE:' . __LINE__ . ' SQL:' . $delete_sql ); |
| 1314 |
} |
| 1315 |
} |
| 1316 |
// </editor-fold> |
| 1317 |
|
| 1318 |
|
| 1319 |
// <editor-fold defaultstate="collapsed" desc=" == Compose D A T E S for DB == " > |
| 1320 |
// ----------------------------------------------------------------------------------------------------------------- |
| 1321 |
// Compose D A T E S for DB |
| 1322 |
// ----------------------------------------------------------------------------------------------------------------- |
| 1323 |
|
| 1324 |
if ( class_exists( 'wpdev_bk_biz_l' ) ) { |
| 1325 |
$field_names_arr = array( 'booking_id', 'booking_date', 'approved', 'type_id' ); |
| 1326 |
} else { |
| 1327 |
$field_names_arr = array( 'booking_id', 'booking_date', 'approved' ); |
| 1328 |
} |
| 1329 |
$field_names = implode( ', ', $field_names_arr ); |
| 1330 |
|
| 1331 |
$dates_sql = "INSERT INTO {$wpdb->prefix}bookingdates ( {$field_names} ) VALUES "; |
| 1332 |
$insert_dates_arr = array(); |
| 1333 |
|
| 1334 |
$how_many_items_to_book = $create_params['how_many_items_to_book']; |
| 1335 |
// $i - INDEX of child booking resource to book (if $how_many_items_to_book=1, then index always = 0 ) in [ 'resources_in_dates' = [ '2023-10-18' = [ 9, 12, 10, 11 ], ... ]...] - e.g. here = 9 |
| 1336 |
for( $i = 0; $i < $how_many_items_to_book; $i++) { |
| 1337 |
|
| 1338 |
$date_number = 0; |
| 1339 |
foreach ( $where_to_save_booking['resources_in_dates'] as $only_date_sql => $resources_in_date_arr ) { |
| 1340 |
|
| 1341 |
$date_resource_id = $resources_in_date_arr[ $i ]; |
| 1342 |
|
| 1343 |
// $create_params['resource_id'] <- Main resource (saved in wp_booking ) |
| 1344 |
// $only_date_sql <- '2023-09-12' |
| 1345 |
// $date_resource_id <- Child resource (need to save in wp_bookingdates) OR if ( $create_params['resource_id'] == $date_resource_id ) then NULL |
| 1346 |
|
| 1347 |
// --------------------------------------------------------------------------------------------------------- |
| 1348 |
// Is full day booking: |
| 1349 |
if ( |
| 1350 |
( '00:00' === substr( $where_to_save_booking['time_to_book'][0], 0, 5 ) ) |
| 1351 |
&& ( |
| 1352 |
( '24:00' === substr( $where_to_save_booking['time_to_book'][1], 0, 5 ) ) |
| 1353 |
|| ( '00:00' === substr( $where_to_save_booking['time_to_book'][1], 0, 5 ) ) |
| 1354 |
) |
| 1355 |
){ |
| 1356 |
// Full days ******************************************************************************************* |
| 1357 |
$full_date_sql = $only_date_sql . ' 00:00:00'; |
| 1358 |
|
| 1359 |
$insert_dates_arr[] = wpbc_prepare_date_row( $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id, $create_params['resource_id'] ); |
| 1360 |
|
| 1361 |
} else { // Times |
| 1362 |
|
| 1363 |
if ( |
| 1364 |
( $create_params['is_use_booking_recurrent_time'] ) // Activated option to book times as 'time-slots' OR |
| 1365 |
|| ( 1 === count( $where_to_save_booking['resources_in_dates'] ) ) // Selected only 1 date, so use time as time-slot |
| 1366 |
) { |
| 1367 |
// Time slots in each day ************************************************************************** |
| 1368 |
|
| 1369 |
// Start Time |
| 1370 |
$full_date_sql = $only_date_sql . ' ' . $where_to_save_booking['time_to_book'][0]; |
| 1371 |
$insert_dates_arr[] = wpbc_prepare_date_row( $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id, $create_params['resource_id'] ); |
| 1372 |
|
| 1373 |
// End Time |
| 1374 |
$full_date_sql = $only_date_sql . ' ' . $where_to_save_booking['time_to_book'][1]; |
| 1375 |
$insert_dates_arr[] = wpbc_prepare_date_row( $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id, $create_params['resource_id'] ); |
| 1376 |
|
| 1377 |
} else { |
| 1378 |
// Check in/out ************************************************************************************ |
| 1379 |
|
| 1380 |
if ( 0 == $date_number ) { // Is check in ? |
| 1381 |
|
| 1382 |
$full_date_sql = $only_date_sql . ' ' . $where_to_save_booking['time_to_book'][0]; |
| 1383 |
|
| 1384 |
} else if ( ( count( $where_to_save_booking['resources_in_dates'] ) - 1 ) == $date_number ) { // Is check out ? |
| 1385 |
|
| 1386 |
$full_date_sql = $only_date_sql . ' ' . $where_to_save_booking['time_to_book'][1]; |
| 1387 |
|
| 1388 |
} else { // Middle date - Full Date |
| 1389 |
$full_date_sql = $only_date_sql . ' 00:00:00'; |
| 1390 |
} |
| 1391 |
|
| 1392 |
$insert_dates_arr[] = wpbc_prepare_date_row( $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id, $create_params['resource_id'] ); |
| 1393 |
|
| 1394 |
} |
| 1395 |
} |
| 1396 |
// --------------------------------------------------------------------------------------------------------- |
| 1397 |
$date_number++; |
| 1398 |
} |
| 1399 |
} |
| 1400 |
|
| 1401 |
$dates_sql .= implode( ', ', $insert_dates_arr ); |
| 1402 |
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter |
| 1403 |
if ( false === $wpdb->query( $dates_sql ) ) { |
| 1404 |
return array( 'status' => 'error', 'message' => 'Error. INSERT "D A T E S" in DB.' . ' FILE:' . __FILE__ . ' LINE:' . __LINE__ . ' SQL:' . $dates_sql ); |
| 1405 |
} |
| 1406 |
|
| 1407 |
// ----------------------------------------------------------------------------------------------------------------- |
| 1408 |
// End D A T E S |
| 1409 |
// ----------------------------------------------------------------------------------------------------------------- |
| 1410 |
// </editor-fold> |
| 1411 |
|
| 1412 |
|
| 1413 |
return array( |
| 1414 |
'status' => 'ok' |
| 1415 |
, 'booking_id' => $booking_id |
| 1416 |
, 'form_data' => $form_data |
| 1417 |
, 'message' => '' |
| 1418 |
); |
| 1419 |
} |
| 1420 |
|
| 1421 |
|
| 1422 |
/** |
| 1423 |
* Get SQL ROWs of VALUES for INSERT to DB |
| 1424 |
* |
| 1425 |
* @param int $booking_id 101 ID of the booking |
| 1426 |
* @param string $full_date_sql '2023-09-12 10:00:01' SQL date |
| 1427 |
* @param int $is_approved_dates 1 1 - approved, 0 - pending |
| 1428 |
* @param int $date_resource_id ( >= biz_l ): 4 ID of child booking resource (if we save ONE booking in SEVERAL booking resources) field 'type_id' in wp_bookingdates |
| 1429 |
* @param int $main_resource_id ( >= biz_l ): 1 ID of main (parent booking resource) |
| 1430 |
* |
| 1431 |
* @return string - SQL for dates VALUES to insert |
| 1432 |
*/ |
| 1433 |
function wpbc_prepare_date_row( $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id, $main_resource_id ) { |
| 1434 |
|
| 1435 |
global $wpdb; |
| 1436 |
|
| 1437 |
if ( class_exists( 'wpdev_bk_biz_l' ) ) { |
| 1438 |
$insert_dates_arr = ( $main_resource_id != $date_resource_id ) |
| 1439 |
? $wpdb->prepare( "(%d, %s, %d, %d)", $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id ) |
| 1440 |
: $wpdb->prepare( "(%d, %s, %d, NULL)", $booking_id, $full_date_sql, $is_approved_dates ); |
| 1441 |
} else { |
| 1442 |
$insert_dates_arr = $wpdb->prepare( "(%d, %s, %d)", $booking_id, $full_date_sql, $is_approved_dates ); |
| 1443 |
} |
| 1444 |
|
| 1445 |
return $insert_dates_arr; |
| 1446 |
} |
| 1447 |
|
| 1448 |
// == Help functions == |
| 1449 |
function wpbc_set_request_form_context( $ctx ) { |
| 1450 |
$GLOBALS['wpbc_request_form_context'] = ( is_array( $ctx ) ) ? $ctx : array(); |
| 1451 |
} |
| 1452 |
|
| 1453 |
function wpbc_get_request_form_context() { |
| 1454 |
return ( isset( $GLOBALS['wpbc_request_form_context'] ) && is_array( $GLOBALS['wpbc_request_form_context'] ) ) |
| 1455 |
? $GLOBALS['wpbc_request_form_context'] : array(); |
| 1456 |
} |
| 1457 |
|
| 1458 |
function wpbc_clear_request_form_context() { |
| 1459 |
if ( isset( $GLOBALS['wpbc_request_form_context'] ) ) { |
| 1460 |
unset( $GLOBALS['wpbc_request_form_context'] ); |
| 1461 |
} |
| 1462 |
} |
| 1463 |
|
| 1464 |
// --------------------------------------------------------------------------------------------------------------------- |
| 1465 |
// Support |
| 1466 |
// --------------------------------------------------------------------------------------------------------------------- |
| 1467 |
|
| 1468 |
/** |
| 1469 |
* Get booking_id and resource_id if we are editing the booking, by booking hash |
| 1470 |
* |
| 1471 |
* @param $booking_hash |
| 1472 |
* @param $server_request_url |
| 1473 |
* |
| 1474 |
* @return array | false false if not edit Otherwise [ 'booking_id': 100, 'resource_id': 3 ] |
| 1475 |
*/ |
| 1476 |
function wpbc_get_data__if_edit_booking( $booking_hash, $server_request_url ) { |
| 1477 |
|
| 1478 |
$is_edit_booking = false; |
| 1479 |
if ( ! empty( $booking_hash ) ) { |
| 1480 |
|
| 1481 |
$my_booking_id_type = wpbc_hash__get_booking_id__resource_id( $booking_hash ); |
| 1482 |
if ( $my_booking_id_type !== false ) { |
| 1483 |
|
| 1484 |
$is_edit_booking = array(); |
| 1485 |
$is_edit_booking['booking_id'] = intval( $my_booking_id_type[0] ); |
| 1486 |
$is_edit_booking['resource_id'] = intval( $my_booking_id_type[1] ); |
| 1487 |
|
| 1488 |
//TODO: test it. Check situation when we have editing "child booking resource", so need to re-update calendar and form to have it for parent resource. // FixIn: 6.1.1.9. |
| 1489 |
// FixIn: 10.10.1.2 |
| 1490 |
//if ( strpos( $server_request_url, 'resource_no_update' ) === false ) { // FixIn: 9.4.2.3. |
| 1491 |
|
| 1492 |
if ( ( function_exists( 'wpbc_is_this_child_resource' ) ) && ( wpbc_is_this_child_resource( $is_edit_booking['resource_id'] ) ) ) { |
| 1493 |
$bk_parent_br_id = wpbc_get_parent_resource( $is_edit_booking['resource_id'] ); |
| 1494 |
|
| 1495 |
$is_edit_booking['resource_id'] = intval( $bk_parent_br_id ); |
| 1496 |
} |
| 1497 |
//} |
| 1498 |
} |
| 1499 |
} |
| 1500 |
return $is_edit_booking; |
| 1501 |
} |
| 1502 |
|
| 1503 |
|
| 1504 |
/** |
| 1505 |
* Get how many items to book. Usually it's from [selectbox visitors "1" ... ] field. |
| 1506 |
* |
| 1507 |
* @param booking_form_data__arr = [ |
| 1508 |
* selected_short_dates_hint = "September 27, 2023 - September 28, 2023" |
| 1509 |
* days_number_hint = "2" |
| 1510 |
* rangetime = "16:00 - 18:00" |
| 1511 |
* starttime = "21:00" |
| 1512 |
* durationtime = "00:30" |
| 1513 |
* name = "John" |
| 1514 |
* secondname = "Smith" |
| 1515 |
* email = "john.smith@server.com" |
| 1516 |
* visitors = "1" |
| 1517 |
* children = "0" |
| 1518 |
* details = "" |
| 1519 |
* ] |
| 1520 |
* |
| 1521 |
* @return int |
| 1522 |
*/ |
| 1523 |
function wpbc_get__how_many_items_to_book__in_booking_form( $booking_form_data__arr, $resource_id ){ |
| 1524 |
|
| 1525 |
$how_many_items_to_book = 1; |
| 1526 |
|
| 1527 |
//TODO: Check about some URL parameter: '&resource_no_update' to book parent resource as single resource! // FixIn: 10.10.1.2 |
| 1528 |
if ( |
| 1529 |
( class_exists( 'wpdev_bk_biz_l' ) ) |
| 1530 |
&& ( 0 !== wpbc_get_child_resources_number( $resource_id ) ) // Here several child booking resources |
| 1531 |
) { |
| 1532 |
$booking_capacity_field = wpbc_get__booking_capacity_field__name(); |
| 1533 |
if ( |
| 1534 |
( ! empty( $booking_capacity_field ) ) |
| 1535 |
&& ( isset( $booking_form_data__arr[ $booking_capacity_field ] ) ) |
| 1536 |
){ |
| 1537 |
$how_many_items_to_book = intval( $booking_form_data__arr[ $booking_capacity_field ] ); // Get value of how many booking resources to book |
| 1538 |
$how_many_items_to_book = ( $how_many_items_to_book > 0 ) ? $how_many_items_to_book : 1; |
| 1539 |
} |
| 1540 |
} |
| 1541 |
|
| 1542 |
return $how_many_items_to_book; |
| 1543 |
} |
| 1544 |
|
| 1545 |
|
| 1546 |
/** |
| 1547 |
* Get capacity field -- 'pure name' |
| 1548 |
* |
| 1549 |
* @return string - field name, or empty string - '' if not defined |
| 1550 |
* |
| 1551 |
* In DB, we are saved field name type and possible name of custom booking form in format: 'custom_form_name^field_type^capacity_field_name' -> 'minimal^select^adults' |
| 1552 |
* or for standard form: 'select^visitors' |
| 1553 |
* and here we get only field name: 'visitors' |
| 1554 |
*/ |
| 1555 |
function wpbc_get__booking_capacity_field__name() { |
| 1556 |
|
| 1557 |
if ( class_exists( 'wpdev_bk_biz_l' ) ) { |
| 1558 |
|
| 1559 |
if ( 'On' == get_bk_option( 'booking_quantity_control' ) ) { |
| 1560 |
|
| 1561 |
$booking_capacity_field = get_bk_option( 'booking_capacity_field' ); |
| 1562 |
|
| 1563 |
if ( ! empty( $booking_capacity_field ) ) { |
| 1564 |
|
| 1565 |
$booking_capacity_field = explode( '^', $booking_capacity_field ); |
| 1566 |
|
| 1567 |
if ( ! empty( $booking_capacity_field ) ) { |
| 1568 |
|
| 1569 |
$booking_capacity_field_name = $booking_capacity_field[ count( $booking_capacity_field ) - 1 ]; |
| 1570 |
|
| 1571 |
return $booking_capacity_field_name; |
| 1572 |
} |
| 1573 |
} |
| 1574 |
} |
| 1575 |
} |
| 1576 |
return ''; |
| 1577 |
} |
| 1578 |
|
| 1579 |
|
| 1580 |
/** |
| 1581 |
* Get time for booking from the booking form, as array of seconds: [ 0, 24 * 60 * 60 ] OR [ 10*60*60, 14*60*60 ]. If timefields not exist, then get time for full day booking. |
| 1582 |
* @param $booking_form_data__arr |
| 1583 |
* |
| 1584 |
* @return array [ 0, 24 * 60 * 60 ] OR [ 10*60*60, 14*60*60 ] <- start and end time in seconds |
| 1585 |
* |
| 1586 |
* Example: |
| 1587 |
* |
| 1588 |
* // Firstly, we need to Get parsed booking form: [ name = "John", secondname = "Smith", email = "john.smith@server.com", visitors = "2",... ] |
| 1589 |
* $structured_booking_data_arr = wpbc_get_parsed_booking_data_arr( $params["form_data"], $params["resource_id"], array( 'get' => 'value' ) ); |
| 1590 |
* |
| 1591 |
* // Now get start/end times as seconds: [ 64800, 72000 ] |
| 1592 |
* $time_as_seconds_arr = wpbc_get_in_booking_form__time_to_book_as_seconds_arr( $structured_booking_data_arr ); |
| 1593 |
*/ |
| 1594 |
function wpbc_get_in_booking_form__time_to_book_as_seconds_arr( $booking_form_data__arr ){ |
| 1595 |
|
| 1596 |
$selected_time_fields = wpbc_get__selected_time_fields__in_booking_form__as_arr( $booking_form_data__arr ); |
| 1597 |
|
| 1598 |
// 2.2 Get selected SECONDS to book --------------------------------------------------------------------------- |
| 1599 |
$time_as_seconds_arr = array( 0, 24 * 60 * 60 ); // Full day booking by default |
| 1600 |
|
| 1601 |
foreach ( $selected_time_fields as $time_fields_obj ) { // { times_as_seconds: [ 21600, 23400 ], value_option_24h: '06:00 - 06:30', name: 'rangetime'} |
| 1602 |
|
| 1603 |
if ( false !== strpos( $time_fields_obj['name'], 'rangetime' ) ) { |
| 1604 |
$time_as_seconds_arr[ 0 ] = $time_fields_obj['times_as_seconds'][ 0 ]; |
| 1605 |
$time_as_seconds_arr[ 1 ] = $time_fields_obj['times_as_seconds'][ 1 ]; |
| 1606 |
//break; // If we have range-time then skip this loop |
| 1607 |
} |
| 1608 |
if ( false !== strpos( $time_fields_obj['name'], 'starttime' ) ) { |
| 1609 |
$time_as_seconds_arr[ 0 ] = $time_fields_obj['times_as_seconds'][ 0 ]; |
| 1610 |
} |
| 1611 |
if ( false !== strpos( $time_fields_obj['name'], 'endtime' ) ) { |
| 1612 |
$time_as_seconds_arr[ 1 ] = $time_fields_obj['times_as_seconds'][ 0 ]; |
| 1613 |
} |
| 1614 |
} |
| 1615 |
|
| 1616 |
// For duration time we need to make a new loop, because we need to be sure that was defined START_TIME before this, |
| 1617 |
// and end time was NOT defined, e.g. == (otherwise it's means that we already used END_TIME or RANGE_TIME) |
| 1618 |
if ( |
| 1619 |
( ( 0 ) !== $time_as_seconds_arr[ 0 ] ) |
| 1620 |
&& ( (24 * 60 * 60 ) === $time_as_seconds_arr[ 1 ] ) |
| 1621 |
){ |
| 1622 |
foreach ( $selected_time_fields as $time_fields_obj ) { // { times_as_seconds: [ 21600 ], value_option_24h: '06:00', name: 'durationtime'} |
| 1623 |
|
| 1624 |
if ( false !== strpos( $time_fields_obj['name'], 'durationtime' ) ) { |
| 1625 |
$time_as_seconds_arr[ 1 ] = $time_as_seconds_arr[ 0 ] + $time_fields_obj['times_as_seconds'][ 0 ]; |
| 1626 |
// FixIn: 10.14.7.1. |
| 1627 |
while ( $time_as_seconds_arr[1] > ( 24 * 60 * 60 ) ) { |
| 1628 |
$time_as_seconds_arr[1] = $time_as_seconds_arr[1] - ( 24 * 60 * 60 ); |
| 1629 |
} |
| 1630 |
break; |
| 1631 |
} |
| 1632 |
} |
| 1633 |
} |
| 1634 |
|
| 1635 |
return $time_as_seconds_arr; |
| 1636 |
} |
| 1637 |
|
| 1638 |
|
| 1639 |
/** |
| 1640 |
* Remove administrator time-override values from an unauthorized booking request. |
| 1641 |
* |
| 1642 |
* The public booking endpoint intentionally accepts unauthenticated requests, so |
| 1643 |
* sanitizing these values is not sufficient authorization. Clearing every related |
| 1644 |
* value here prevents a public client from replacing the Booking Form's configured |
| 1645 |
* time while preserving the capability-protected Add Booking workflow. |
| 1646 |
* |
| 1647 |
* @param array $request_params Sanitized booking request parameters. |
| 1648 |
* @param bool $is_authorized_admin_booking_request Whether the current request is an authorized Add Booking administration request. |
| 1649 |
* |
| 1650 |
* @return array Booking request parameters with unauthorized override values removed. |
| 1651 |
*/ |
| 1652 |
function wpbc_restrict_booking_time_override_to_authorized_admin( $request_params, $is_authorized_admin_booking_request ) { |
| 1653 |
|
| 1654 |
$request_params = is_array( $request_params ) ? $request_params : array(); |
| 1655 |
if ( $is_authorized_admin_booking_request ) { |
| 1656 |
return $request_params; |
| 1657 |
} |
| 1658 |
|
| 1659 |
$request_params['wpbc_time_override_enabled'] = 0; |
| 1660 |
$request_params['wpbc_time_override_source'] = ''; |
| 1661 |
$request_params['wpbc_time_override_start'] = ''; |
| 1662 |
$request_params['wpbc_time_override_end'] = ''; |
| 1663 |
|
| 1664 |
return $request_params; |
| 1665 |
} |
| 1666 |
|
| 1667 |
|
| 1668 |
/** |
| 1669 |
* Authorize and normalize an administrator cost-correction request value. |
| 1670 |
* |
| 1671 |
* Booking creation is intentionally public, so a sanitized numeric value is |
| 1672 |
* not sufficient authorization. Only capability-protected Add Booking and |
| 1673 |
* Add Appointment workflows in Business Small or higher may retain this value. |
| 1674 |
* Missing, malformed, out-of-range, public, and unsupported-edition values |
| 1675 |
* are reduced to an empty sentinel, which preserves automatic calculation. |
| 1676 |
* |
| 1677 |
* @param array $request_params Sanitized booking request parameters. |
| 1678 |
* @param bool $is_authorized_admin_booking_request Whether this is an authorized administrator booking request. |
| 1679 |
* |
| 1680 |
* @return array Booking request parameters with a normalized or empty cost correction. |
| 1681 |
*/ |
| 1682 |
function wpbc_restrict_booking_cost_correction_to_authorized_admin( $request_params, $is_authorized_admin_booking_request ) { |
| 1683 |
|
| 1684 |
$request_params = is_array( $request_params ) ? $request_params : array(); |
| 1685 |
$raw_cost = isset( $request_params['wpbc_admin_cost_correction'] ) ? $request_params['wpbc_admin_cost_correction'] : ''; |
| 1686 |
|
| 1687 |
$request_params['wpbc_admin_cost_correction'] = ''; |
| 1688 |
if ( ! $is_authorized_admin_booking_request || ! class_exists( 'wpdev_bk_biz_s' ) ) { |
| 1689 |
return $request_params; |
| 1690 |
} |
| 1691 |
|
| 1692 |
$request_params['wpbc_admin_cost_correction'] = wpbc_sanitize_booking_cost_correction( $raw_cost ); |
| 1693 |
|
| 1694 |
return $request_params; |
| 1695 |
} |
| 1696 |
|
| 1697 |
|
| 1698 |
/** |
| 1699 |
* Sanitize one exact administrator-entered Booking total. |
| 1700 |
* |
| 1701 |
* @param mixed $raw_cost Raw request value. |
| 1702 |
* |
| 1703 |
* @return string Normalized decimal without trailing zeroes, or an empty string when invalid. |
| 1704 |
*/ |
| 1705 |
function wpbc_sanitize_booking_cost_correction( $raw_cost ) { |
| 1706 |
|
| 1707 |
if ( ! is_scalar( $raw_cost ) ) { |
| 1708 |
return ''; |
| 1709 |
} |
| 1710 |
|
| 1711 |
$raw_cost = trim( sanitize_text_field( (string) $raw_cost ) ); |
| 1712 |
if ( '' === $raw_cost || ! preg_match( '/^[0-9]{1,10}(?:\.[0-9]{1,8})?$/', $raw_cost ) ) { |
| 1713 |
return ''; |
| 1714 |
} |
| 1715 |
|
| 1716 |
$normalized_cost = (float) $raw_cost; |
| 1717 |
if ( ! is_finite( $normalized_cost ) || $normalized_cost < 0 || $normalized_cost > 1000000000 ) { |
| 1718 |
return ''; |
| 1719 |
} |
| 1720 |
|
| 1721 |
$normalized_cost = rtrim( rtrim( number_format( $normalized_cost, 8, '.', '' ), '0' ), '.' ); |
| 1722 |
|
| 1723 |
return '' === $normalized_cost ? '0' : $normalized_cost; |
| 1724 |
} |
| 1725 |
|
| 1726 |
|
| 1727 |
/** |
| 1728 |
* Get explicit admin-selected time override from Add Booking modal request. |
| 1729 |
* |
| 1730 |
* @param array $request_params Sanitized booking request params. |
| 1731 |
* |
| 1732 |
* @return array Empty array or array with start/end HH:MM values. |
| 1733 |
*/ |
| 1734 |
function wpbc_get_booking_time_override__as_arr( $request_params ) { |
| 1735 |
|
| 1736 |
if ( empty( $request_params['wpbc_time_override_enabled'] ) ) { |
| 1737 |
return array(); |
| 1738 |
} |
| 1739 |
|
| 1740 |
$start_time = wpbc_sanitize_booking_time_override__hm( isset( $request_params['wpbc_time_override_start'] ) ? $request_params['wpbc_time_override_start'] : '' ); |
| 1741 |
$end_time = wpbc_sanitize_booking_time_override__hm( isset( $request_params['wpbc_time_override_end'] ) ? $request_params['wpbc_time_override_end'] : '' ); |
| 1742 |
|
| 1743 |
if ( |
| 1744 |
( '' === $start_time ) |
| 1745 |
|| ( '' === $end_time ) |
| 1746 |
|| ( wpbc_booking_time_override__hm_to_seconds( $start_time ) >= wpbc_booking_time_override__hm_to_seconds( $end_time ) ) |
| 1747 |
) { |
| 1748 |
return array(); |
| 1749 |
} |
| 1750 |
|
| 1751 |
return array( |
| 1752 |
'start' => $start_time, |
| 1753 |
'end' => $end_time, |
| 1754 |
'source' => isset( $request_params['wpbc_time_override_source'] ) ? sanitize_key( $request_params['wpbc_time_override_source'] ) : '', |
| 1755 |
); |
| 1756 |
} |
| 1757 |
|
| 1758 |
|
| 1759 |
/** |
| 1760 |
* Sanitize HH:MM value for admin booking time override. |
| 1761 |
* |
| 1762 |
* @param string $time_value Time value. |
| 1763 |
* |
| 1764 |
* @return string |
| 1765 |
*/ |
| 1766 |
function wpbc_sanitize_booking_time_override__hm( $time_value ) { |
| 1767 |
|
| 1768 |
$time_value = trim( sanitize_text_field( (string) $time_value ) ); |
| 1769 |
|
| 1770 |
if ( ! preg_match( '/^([0-9]{1,2}):([0-9]{2})$/', $time_value, $matches ) ) { |
| 1771 |
return ''; |
| 1772 |
} |
| 1773 |
|
| 1774 |
$hour = absint( $matches[1] ); |
| 1775 |
$minute = absint( $matches[2] ); |
| 1776 |
|
| 1777 |
if ( $hour > 24 || $minute > 59 || ( 24 === $hour && 0 !== $minute ) ) { |
| 1778 |
return ''; |
| 1779 |
} |
| 1780 |
|
| 1781 |
return sprintf( '%02d:%02d', $hour, $minute ); |
| 1782 |
} |
| 1783 |
|
| 1784 |
|
| 1785 |
/** |
| 1786 |
* Convert HH:MM to seconds. |
| 1787 |
* |
| 1788 |
* @param string $time_value Time value. |
| 1789 |
* |
| 1790 |
* @return int |
| 1791 |
*/ |
| 1792 |
function wpbc_booking_time_override__hm_to_seconds( $time_value ) { |
| 1793 |
|
| 1794 |
$time_arr = explode( ':', (string) $time_value ); |
| 1795 |
|
| 1796 |
return ( absint( $time_arr[0] ) * 60 * 60 ) + ( absint( $time_arr[1] ) * 60 ); |
| 1797 |
} |
| 1798 |
|
| 1799 |
|
| 1800 |
/** |
| 1801 |
* Get all time fields in the booking form as array of objects |
| 1802 |
* |
| 1803 |
* @param booking_form_data__arr = [ |
| 1804 |
* selected_short_dates_hint = "September 27, 2023 - September 28, 2023" |
| 1805 |
* days_number_hint = "2" |
| 1806 |
* rangetime = "16:00 - 18:00" |
| 1807 |
* starttime = "21:00" |
| 1808 |
* durationtime = "00:30" |
| 1809 |
* name = "John" |
| 1810 |
* secondname = "Smith" |
| 1811 |
* email = "john.smith@server.com" |
| 1812 |
* visitors = "1" |
| 1813 |
* children = "0" |
| 1814 |
* details = "" |
| 1815 |
* ] |
| 1816 |
* @returns [] |
| 1817 |
* |
| 1818 |
* Example: |
| 1819 |
* [ |
| 1820 |
* [ |
| 1821 |
* name = "rangetime" |
| 1822 |
* value_option_24h = "16:00 - 18:00" |
| 1823 |
* times_as_seconds = [ 57600, 64800 ] |
| 1824 |
* ] |
| 1825 |
* [ |
| 1826 |
* name = "starttime" |
| 1827 |
* value_option_24h = "21:00" |
| 1828 |
* times_as_seconds = [ 75600 ] |
| 1829 |
* ] |
| 1830 |
* [ |
| 1831 |
* name = "durationtime" |
| 1832 |
* value_option_24h = "00:30" |
| 1833 |
* times_as_seconds = [ 1800 ] |
| 1834 |
* ] |
| 1835 |
* ] |
| 1836 |
*/ |
| 1837 |
function wpbc_get__selected_time_fields__in_booking_form__as_arr( $booking_form_data__arr ){ |
| 1838 |
|
| 1839 |
/** |
| 1840 |
* Fields with [] like this select[name="rangetime1[]"] |
| 1841 |
* it's when we have 'multiple' in shortcode: [select* rangetime multiple "06:00 - 06:30" ... ] |
| 1842 |
*/ |
| 1843 |
$time_fields_arr = array( 'rangetime', 'starttime', 'endtime', 'durationtime' ); |
| 1844 |
|
| 1845 |
$time_fields_obj_arr = array(); |
| 1846 |
|
| 1847 |
// Loop all Time Fields |
| 1848 |
for ( $ctf = 0; $ctf < count( $time_fields_arr ); $ctf ++ ) { |
| 1849 |
|
| 1850 |
$time_field = $time_fields_arr[ $ctf ]; |
| 1851 |
if ( isset( $booking_form_data__arr[ $time_field ] ) ) { |
| 1852 |
|
| 1853 |
$value_option_seconds_arr = explode( '-', $booking_form_data__arr[ $time_field ] ); |
| 1854 |
$times_as_seconds_arr = array(); |
| 1855 |
|
| 1856 |
foreach ( $value_option_seconds_arr as $time_val ) { |
| 1857 |
$time_val = trim( $time_val ); |
| 1858 |
if ( ! empty( $time_val ) ) { |
| 1859 |
$start_end_times_arr = explode( ':', $time_val ); |
| 1860 |
$time_in_seconds = intval( $start_end_times_arr[0] ) * 60 * 60 + intval( $start_end_times_arr[1] ) * 60; |
| 1861 |
$times_as_seconds_arr[] = $time_in_seconds; |
| 1862 |
} |
| 1863 |
} |
| 1864 |
|
| 1865 |
if (! empty($times_as_seconds_arr)) { |
| 1866 |
|
| 1867 |
$time_fields_obj_arr[] = array( |
| 1868 |
'name' => $time_field, |
| 1869 |
'value_option_24h' => $booking_form_data__arr[ $time_field ], |
| 1870 |
'times_as_seconds' => $times_as_seconds_arr |
| 1871 |
); |
| 1872 |
} |
| 1873 |
} |
| 1874 |
} |
| 1875 |
|
| 1876 |
return $time_fields_obj_arr; |
| 1877 |
} |
| 1878 |
|
| 1879 |
|
| 1880 |
//TODO: 2023-10-13 16:37 |
| 1881 |
// - create new function for confirmation section |
| 1882 |
// - Update payment request |
| 1883 |
// - create redirection to the "Thank you." page and show there conformation, and payment request" |
| 1884 |
// - define in the settings new Stripe and PayPal button design as default ! |
| 1885 |
// - Be sure that 'booking_log_booking_actions' active by default |
| 1886 |
// - test it in dark theme |
| 1887 |
// - test closing booked dates if all time slot was booked - it's relative to 'different time slots in dif dates' |
| 1888 |
// - add migrate support old dates selection variables |
| 1889 |
// - check and remove other global Js vars |
| 1890 |
// - Create wizard booking form style with steps ? |
| 1891 |
// - Check Booking > Availability page relative new functionality of calendar_load ! |
| 1892 |
// - Update last func in wpbc-booking-new.php and remove it. |
| 1893 |
// - Test capacity in dates and time slots |
| 1894 |
// - Next 9.9 Customizer Wizard |
| 1895 |
// - Next 9.9 Update search admin UI |
| 1896 |
// - Next 9.9 - update functionality in Search functionality based on similar to where_to_save function. |
| 1897 |
// - Next 9.9 refactor Dates functions. |
| 1898 |
// Done. - Next 9.9 Update Booking > Settings General page to show tabs vertically in left column |
| 1899 |
// Create the same navigation panel at the Pro Booking > Settings > Form page. At left column custom forms, at top tolbar selectio of Booking form and "Content of booking fields data" form. |
| 1900 |
// Create the same navigation for Emails. |
| 1901 |
/** |
| 1902 |
* TODO: Performance improvement: |
| 1903 |
* "other_code": 0.003080129623413086 |
| 1904 |
* "wpbc__where_to_save_booking": 0.060331106185913086 |
| 1905 |
* "wpbc_db__booking_save": 0.023384809494018555 |
| 1906 |
* "wpbc_maybe_get_payment_form": 1.3650128841400146 <- |
| 1907 |
* "emails_sending": 1.5024309158325195 <- |
| 1908 |
* "total": 2.9542438983917236 |
| 1909 |
*/ |
| 1910 |
|