'POST',
'callback' => [ $this, 'eshb_get_booking_prices_rest' ], // class method
'permission_callback' => function($request) {
return true;
},
'args' => [
'accomodationId' => [
'required' => true,
'sanitize_callback' => 'absint',
],
'startDate' => [
'sanitize_callback' => 'sanitize_text_field',
],
'endDate' => [
'sanitize_callback' => 'sanitize_text_field',
],
'startTime' => [
'sanitize_callback' => 'sanitize_text_field',
],
'endTime' => [
'sanitize_callback' => 'sanitize_text_field',
],
'roomQuantity' => [
'sanitize_callback' => 'absint',
],
'extraBedQuantity' => [
'sanitize_callback' => 'absint',
],
'adultQuantity' => [
'sanitize_callback' => 'absint',
],
'childrenQuantity' => [
'sanitize_callback' => 'absint',
],
'selectedServices' => [
'sanitize_callback' => function($param) {
return json_decode(sanitize_text_field($param), true);
}
],
'nonce' => [
'required' => true,
'sanitize_callback' => 'sanitize_text_field',
],
],
]);
});
}
function disable_eshb_cache_from_cacheplugin($cacheable){
// Disable LSCache for accommodation single pages
if( is_singular('eshb_accomodation') ){
return false; // don't cache
}
// Never cache the Native Checkout / customer account pages: they are
// per-visitor (reservation token + a freshly generated nonce baked
// into the page). A shared cache would serve a stale nonce to other
// visitors — which makes checkout fail for logged-out users (logged-in
// users bypass the cache, so it "only works when logged in").
if ( is_singular() ) {
global $post;
if ( $post instanceof WP_Post ) {
$eshb_content = (string) $post->post_content;
if ( has_shortcode( $eshb_content, 'eshb_native_checkout' ) || has_shortcode( $eshb_content, 'eshb_account' ) ) {
return false; // don't cache
}
}
}
return $cacheable;
}
public function update_product_price_by_id($product_id, $new_price) {
// Update the regular price
update_post_meta($product_id, '_regular_price', $new_price);
// Update the price (current price)
update_post_meta($product_id, '_price', $new_price);
// Optional: if the product is on sale, update the sale price to match the new price
//update_post_meta($product_id, '_sale_price', $new_price);
// Clear WooCommerce product cache
wc_delete_product_transients($product_id);
}
public function get_booked_dates($accomodation_id, $start_date = '', $end_date = '') {
$single_day_booking = false;
if($start_date == $end_date){
$single_day_booking = true;
}
$booked_dates = [];
$total_room_bookings_per_date = []; // Track room bookings per date
$eshb_settings = get_option('eshb_settings', []);
// Get total rooms allowed for this accommodation
$accomodation_metas = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);
$allowed_total_rooms = isset($accomodation_metas['total_rooms']) ? intval($accomodation_metas['total_rooms']) : 0;
// Find all bookings for this accommodation
$bookings_args = [
'post_type' => 'eshb_booking',
'posts_per_page' => -1,
'post_status' => ['publish', 'deposit-payment', 'pending', 'processing', 'on-hold', 'completed'],
'fields' => 'ids',
];
$bookings = new WP_Query($bookings_args);
if ($bookings->have_posts()) {
while ($bookings->have_posts()) {
$bookings->the_post();
$meta_values = get_post_meta(get_the_ID(), 'eshb_booking_metaboxes', true);
$booking_status = isset($meta_values['booking_status']) ? $meta_values['booking_status'] : '';
$completed_booking_status_maps = array(
'pending',
'deposit-payment',
'processing',
'on-hold',
'completed'
);
// Ensure required keys exist
if (is_array($meta_values) && in_array($booking_status, $completed_booking_status_maps) && isset($meta_values['booking_accomodation_id'], $meta_values['booking_start_date'], $meta_values['booking_end_date'])) {
$booking_accomodation_id = intval($meta_values['booking_accomodation_id']);
$booking_start_date = $meta_values['booking_start_date'];
$booking_end_date = $meta_values['booking_end_date'];
$booked_accomodation_ids = [];
$booking_accomodation_id = ESHB_Helper::get_main_post_id_for_translated($booking_accomodation_id);
if ($booking_accomodation_id == $accomodation_id) {
// Convert dates to DateTime objects
$booking_start_date = new DateTime($booking_start_date);
$booking_end_date = new DateTime($booking_end_date);
// if($booking_end_date == $booking_end_date) {
// $booking_end_date->modify('+1 day');
// }
while ($booking_start_date <= $booking_end_date) {
$formatted_date = $booking_start_date->format('Y-m-d');
if($meta_values['booking_end_date'] != $formatted_date){
$booked_id = get_the_ID();
$booking_metas = get_post_meta($booked_id, 'eshb_booking_metaboxes', true);
$booked_room_quantity = isset($booking_metas['room_quantity']) ? intval($booking_metas['room_quantity']) : 0;
// Track total booked rooms per date
if (!isset($total_room_bookings_per_date[$formatted_date])) {
$total_room_bookings_per_date[$formatted_date] = 0;
}
$total_room_bookings_per_date[$formatted_date] = $booked_room_quantity;
}
// Move to next day
$booking_start_date->modify('+1 day');
}
}
}
}
}
if(!$single_day_booking){
unset($total_room_bookings_per_date[$end_date]);
}
// Determine which dates should be disabled (fully booked)
foreach ($total_room_bookings_per_date as $date => $total_booked_rooms) {
// skip this booking if slots hours available
// allow external plugins to modify available slots
$available_slots = apply_filters(
'eshb_available_slots_in_booked_dates_loop',
false,
$date,
$total_booked_rooms,
$accomodation_id
);
if($available_slots) {
$total_booked_rooms = 0;
}
if ($allowed_total_rooms <= $total_booked_rooms) {
$date_obj = new DateTime($date);
$booked_dates[] = $date_obj->format('Y, m, d');
}
}
// Remove duplicate dates
$booked_dates = array_unique($booked_dates);
// Apply filter hook to allow external modifications
$booked_dates = apply_filters('eshb_modify_booked_dates', $booked_dates, $accomodation_id);
return $booked_dates;
}
public function get_holiday_dates($accomodation_id, $start_date = '', $end_date = '') {
$eshb_settings = get_option('eshb_settings', []);
$holidays = isset($eshb_settings['holidays']) ? $eshb_settings['holidays'] : [];
$finally_holidays = [];
if ( ! empty( $holidays ) ) {
foreach ( $holidays as $holiday ) {
$accommodation_ids = $holiday['accomodation-ids'] ?? [];
$holiday_date = $holiday['holiday-date'] ?? null;
// Check if holiday is applicable for all or specific accommodation
$is_applicable = empty($accommodation_ids) || (is_array($accommodation_ids) && in_array($accomodation_id, $accommodation_ids));
if ( $is_applicable && $holiday_date ) {
if ( is_array($holiday_date) && isset($holiday_date['from'], $holiday_date['to']) ) {
$start = DateTime::createFromFormat('Y-m-d', $holiday_date['from']);
$end = DateTime::createFromFormat('Y-m-d', $holiday_date['to']);
if ( $start && $end ) {
$end->modify('+1 day'); // Include end date
$interval = new DateInterval('P1D');
$dateRange = new DatePeriod($start, $interval, $end);
foreach ( $dateRange as $date ) {
$finally_holidays[] = $date->format('Y-m-d');
}
}
} else {
$finally_holidays[] = $holiday_date;
}
}
}
}
return $finally_holidays;
}
public function get_holiday_dates_in_date_ranges($accomodation_id, $start_date, $end_date){
$overlap = [];
if(!empty($accomodation_id)){
$holiday_dates = $this->get_holiday_dates($accomodation_id, $start_date, $end_date);
$overlap = [];
// Generate all dates in the range
$range_dates = [];
$current_date = new DateTime($start_date);
$end_date_obj = new DateTime($end_date);
while ($current_date <= $end_date_obj) {
$range_dates[] = $current_date->format('Y-m-d');
$current_date->modify('+1 day');
}
// Check for overlap
$overlap = array_intersect($range_dates, $holiday_dates);
}
return $overlap;
}
public function get_actual_booked_dates_in_date_ranges($accomodation_id, $start_date, $end_date){
$booked_dates = $this->get_booked_dates($accomodation_id, $start_date, $end_date); // retun arary like ['2025, 01, 27', '2025, 01, 28', '2025, 01, 13']
// Format booked dates to 'Y-m-d' for comparison
$booked_dates = array_map(function($date) {
return DateTime::createFromFormat('Y, m, d', $date)->format('Y-m-d');
}, $booked_dates);
// Generate all dates in the range
$range_dates = [];
$current_date = new DateTime($start_date);
$end_date_obj = new DateTime($end_date);
while ($current_date <= $end_date_obj) {
$range_dates[] = $current_date->format('Y-m-d');
$current_date->modify('+1 day');
}
$single_day_booking = false;
if($start_date == $end_date){
$single_day_booking = true;
}
if(!$single_day_booking){
array_pop($range_dates); // Remove the last date if it's a range booking
}
// Check for overlap
$overlap = array_intersect($range_dates, $booked_dates);
return $overlap;
}
public function save_booking_request($booking_args = array(), $customer_args = array()) {
$defaults = array(
'booking_accomodation_id' => '',
'booking_start_date' => '',
'booking_end_date' => '',
'room_quantity' => 1,
'extra_bed_quantity'=> 0,
'adult_quantity' => 1,
'children_quantity' => 0,
'details_html' => '',
'extra_services' => array(),
'extra_services_html' => '',
'booking_status' => 'pending'
);
// Merge with default values
$booking_args = wp_parse_args($booking_args, $defaults);
$accomodation_id = $booking_args['booking_accomodation_id'];
if(!empty($accomodation_id)){
$start_date = $booking_args['booking_start_date'];
$end_date = $booking_args['booking_end_date'];
// Insert the post
$post_id = wp_insert_post(array(
'post_type' => 'eshb_booking_request',
'post_title' => 'Booking request for ' . $start_date . ' - ' . $end_date,
'post_status' => 'publish',
'meta_input' => array(
'eshb_booking_request_metaboxes' => $booking_args,
'eshb_booking_request_customer_metaboxes' => $customer_args,
)
));
// Check if the post was inserted successfully
if (!is_wp_error($post_id)) {
// Update the post title to include the post ID
$accomodation_title = get_the_title($accomodation_id);
wp_update_post(array(
'ID' => $post_id,
'post_title' => 'Booking request #' . $post_id . ' for: ' . $accomodation_title,
'post_status' => 'publish' // Update status to 'publish'
));
}
}
}
public function eshb_send_reservation_request(){
// Verify nonce for security
if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field(wp_unslash($_POST['nonce'])), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action'))) {
$error = array(
'code' => 'invalid_nonce',
'message' => __('invalid_nonce', 'easy-hotel')
);
wp_send_json_error([
'error' => $error,
]);
die();
}
if(isset($_POST['accomodationId']) && !empty($_POST['accomodationId'])){
$hotel_core = new ESHB_Core();
$customer = !empty($_POST['customerInfo']) ? map_deep( sanitize_text_field( wp_unslash($_POST['customerInfo'])), 'sanitize_text_field' ) : [];
$accomodation_id = isset( $_POST['accomodationId'] ) ? (int) sanitize_text_field( wp_unslash($_POST['accomodationId']) ) : '';
$today_date = esc_html(gmdate('Y-m-d')); // Get today's date
$date = new DateTime($today_date); // Create a DateTime object from today's date
$date->modify('+1 day'); // Add one day
$tomorrow = $date->format('Y-m-d'); // Get the new date in 'Y-m-d' format
$start_date = isset( $_POST['startDate'] ) ? sanitize_text_field( wp_unslash($_POST['startDate']) ) : $today_date;
$end_date = isset( $_POST['endDate'] ) ? sanitize_text_field( wp_unslash($_POST['endDate']) ) : $tomorrow;
$start_time = isset( $_POST['startTime'] ) ? sanitize_text_field( wp_unslash($_POST['startTime']) ) : '';
$end_time = isset( $_POST['endTime'] ) ? sanitize_text_field( wp_unslash($_POST['endTime']) ) : '';
$start_day_name = $start_date ? strtolower(gmdate('l', strtotime($start_date))) : '';
$accomodation_metaboxes = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);
$eshb_settings = get_option( 'eshb_settings', [] );
$string_booking_success_msg = isset($eshb_settings['string_booking_request_success_msg']) && !empty($eshb_settings['string_booking_request_success_msg']) ? $eshb_settings['string_booking_request_success_msg'] : 'Booking request has been sent successfully.';
$string_booking_failed_msg = isset($eshb_settings['string_booking_request_failed_msg']) && !empty($eshb_settings['string_booking_request_failed_msg']) ? $eshb_settings['string_booking_request_failed_msg'] : 'Ops! Booking request can\'t be sent.';
$string_already_booked_msg = isset($eshb_settings['string_already_booked_msg']) && !empty($eshb_settings['string_already_booked_msg']) ? $eshb_settings['string_already_booked_msg'] : 'Ops! The date range is already booked:';
$room_visibility = in_array('rooms', $eshb_settings['booking-form-fields']) ? true : false;
$adult_visibility = in_array('adults', $eshb_settings['booking-form-fields']) ? true : false;
$childrens_visibility = in_array('childrens', $eshb_settings['booking-form-fields']) ? true : false;
$extra_beds_visibility = in_array('extra_beds', $eshb_settings['booking-form-fields']) ? true : false;
$eshb_week_settings = [
'string_check_in_day_error_msg' => 'Only allowed check in day is',
'eshb_booking_allowed_check_in_day' => 'all',
];
$eshb_week_settings = apply_filters( 'eshb_week_settings', $eshb_week_settings );
$allowed_check_in_day = apply_filters( 'eshb_booking_allowed_check_in_day', 'all', $accomodation_id, $accomodation_metaboxes );
$string_check_in_day_error_msg = !empty($eshb_week_settings['string_check_in_day_error_msg']) ? $eshb_week_settings['string_check_in_day_error_msg'] : 'Only allowed check in day is : ';
// Min Max Booking Configurations
$min_max_settings = [
'required_min_nights' => '',
'required_max_nights' => '',
'is_global_source_for_min_max' => true,
];
$min_max_settings = apply_filters( 'eshb_min_max_settings', $min_max_settings, $accomodation_id, $accomodation_metaboxes );
$required_min_nights = isset($min_max_settings['required_min_nights']) ? $min_max_settings['required_min_nights'] : '';
$required_max_nights = isset($min_max_settings['required_max_nights']) ? $min_max_settings['required_max_nights'] : '';
$string_required_minimum_nights_msg = esc_html__( 'Ops! This Reservation has been failed. Requried Minumum', 'easy-hotel' );
$string_required_maximum_nights_msg = esc_html__( 'Ops! This Reservation has been failed. Requried Maximum', 'easy-hotel' );
$min_stay_night_by_session = ESHB_Helper::get_eshb_min_stay_night_by_session($accomodation_id, $start_date, $end_date);
// get booked dates in the range
$actual_booked_dates = $this->get_actual_booked_dates_in_date_ranges($accomodation_id, $start_date, $end_date);
if(!empty($actual_booked_dates)){
$booked_dates_str = implode( ', ', array_map( 'esc_html', $actual_booked_dates ) );
$error_message = sprintf(
/* translators: 1: already booked message text, 2: list of booked dates */
esc_html__( '%1$s %2$s', 'easy-hotel' ),
esc_html( $string_already_booked_msg ),
$booked_dates_str
);
$error = array(
'code' => 'already_booked',
'message' => $error_message,
);
wp_send_json_error([
'error' => $error,
'booked_dates' => implode(', ', $actual_booked_dates),
]);
wp_die();
}
// check rooms capacity
if(isset($_POST['roomQuantity']) && !empty($_POST['roomQuantity'])){
$roomQuantity = isset( $_POST['roomQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['roomQuantity'] ) ) : 1;
$availableRoom = $this->get_available_room_count_by_date_range($accomodation_id, $start_date, $end_date);
if($roomQuantity > $availableRoom){
$error = array(
'code' => 'room_capacity_not_enough',
'message' => sprintf(
/* translators: %s: number of available rooms */
esc_html__( 'Selected room is not available. Available room: %s', 'easy-hotel' ),
esc_html( $availableRoom )
),
);
wp_send_json_error([
'error' => $error,
]);
}
}
// Validate check-in day
if($allowed_check_in_day != 'all' && $start_day_name != '' && !empty($allowed_check_in_day) && strpos($allowed_check_in_day, $start_day_name) === false){
$error = array(
'code' => 'check_in_day_error',
'message' => sprintf(
/* translators: %s: allowed check-in day */
esc_html__( '%1$s %1$s', 'easy-hotel' ),
esc_html( $string_check_in_day_error_msg ),
esc_html( $allowed_check_in_day )
),
);
wp_send_json_error([
'error' => $error,
]);
}
$start = new DateTime($start_date);
$end = new DateTime($end_date);
$interval = $start->diff($end);
$days_count = $interval->days;
$room_quantity = isset( $_POST['roomQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['roomQuantity'] ) ) : 1;
$extra_bed_quantity = isset( $_POST['extraBedQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['extraBedQuantity'] ) ) : 0;
$adult_quantity = isset( $_POST['adultQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['adultQuantity'] ) ) : 1;
$children_quantity = isset( $_POST['childrenQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['childrenQuantity'] ) ) : 0;
$total_guest_quantity = $adult_quantity + $children_quantity;
$selected_services = [];
if(isset($_POST['selectedServices']) && !empty($_POST['selectedServices'])){
$selected_services = sanitize_text_field(wp_unslash($_POST['selectedServices']));
$selected_services = json_decode($selected_services, true);
}
if(!empty($allowed_check_in_day) && $allowed_check_in_day != 'all'){
$days_count = 1;
}
// validate min stay night by session
if(class_exists('ESHB_ADVANCED_PRICING') && !empty($min_stay_night_by_session) && $days_count < $min_stay_night_by_session){
$error = array(
'code' => 'min_stay_night_by_session',
'message' => sprintf(
/* translators: 1: minimum nights message text, 2: required minimum nights */
esc_html__( '%1$s %2$s nights!', 'easy-hotel' ),
esc_html( $string_required_minimum_nights_msg ),
esc_html( $min_stay_night_by_session )
),
);
wp_send_json_error([
'error' => $error,
]);
}
// validate minimum nights
if(!empty($required_min_nights) && $days_count < $required_min_nights){
$error = array(
'code' => 'required_min_nights',
'message' => sprintf(
/* translators: 1: minimum nights message text, 2: required minimum nights */
esc_html__( '%1$s %2$s nights!', 'easy-hotel' ),
esc_html( $string_required_minimum_nights_msg ),
esc_html( $required_min_nights )
),
);
wp_send_json_error([
'error' => $error,
]);
}
if(!empty($required_max_nights) && $days_count > $required_max_nights){
$error = array(
'code' => 'required_max_nights',
'message' => sprintf(
/* translators: 1: maximum nights message text, 2: required maximum nights */
esc_html__( '%1$s %2$s nights allowed!', 'easy-hotel' ),
esc_html( $string_required_maximum_nights_msg ),
esc_html( $required_max_nights )
),
);
wp_send_json_error([
'error' => $error,
]);
}
if (get_post_type($accomodation_id) === 'eshb_accomodation') {
$details = [];
if ($room_visibility && $room_quantity > 0) {
$details[] = 'Room: ' . $room_quantity;
}
if ($extra_beds_visibility && $extra_bed_quantity > 0) {
$details[] = 'Extra Bed: ' . $extra_bed_quantity;
}
if ($adult_visibility && $adult_quantity > 0) {
$details[] = 'Adult: ' . $adult_quantity;
}
if ($childrens_visibility && $children_quantity > 0) {
$details[] = 'Children: ' . $children_quantity;
}
$details_html = implode(', ', $details);
$extra_service_titles = [];
$extra_services_html = '';
if(!empty($selected_services) && is_array($selected_services) && count($selected_services) > 0 ){
foreach ($selected_services as $service) {
$service_id = $service['id'];
$service_quantity = $service['quantity'];
if(!empty($service_quantity)){
$eshb_service_metaboxes = get_post_meta($service_id, 'eshb_service_metaboxes', true);
$charge_type = $eshb_service_metaboxes['service_charge_type'];
$service_title = get_the_title($service_id) . ' For ' . $service_quantity . ' ' . ucfirst(strtolower($charge_type));
if(!$room_visibility && $charge_type == 'room'){
$service_title = get_the_title($service_id);
}
}else{
$service_title = get_the_title($service_id);
}
array_push($extra_service_titles, $service_title);
}
$extra_services_html = implode(", ",$extra_service_titles);
}
$pricing = $this->calculate_booking_pricing($accomodation_id, $start_date, $end_date, $room_quantity, $extra_bed_quantity, $adult_quantity, $children_quantity, $selected_services, true, $start_time, $end_time);
$base_price = $pricing['basePrice'];
$extra_services_charge = $pricing['extraServicesPrice'];
$extra_bed_price= $pricing['extraBedPrice'];
$subtotal_price = $pricing['subtotalPrice'];
$total_price = $pricing['totalPrice'];
$dates = date_i18n( get_option('date_format'), strtotime( $start_date ) ) .' - '. date_i18n( get_option('date_format'), strtotime( $end_date ) );
if($start_date == $end_date){
$dates = date_i18n( get_option('date_format'), strtotime( $start_date ) );
}
$times = '';
if(!empty($start_time) && !empty($end_time)) {
// Get WP formatted time (according to Settings > General > Time Format)
$formated_start_timestamp = strtotime( $start_time );
$formated_end_timestamp = strtotime( $end_time );
$wp_time_format = get_option( 'time_format' ); // WP settings
$formatted_start_time = wp_date( $wp_time_format, $formated_start_timestamp );
$formatted_end_time = wp_date( $wp_time_format, $formated_end_timestamp );
$times = $formatted_start_time . ' - ' . $formatted_end_time;
}
$accomodation_title = get_the_title($accomodation_id);
$customer_name = $customer['name'];
$customer_email = $customer['email'];
$customer_phone = $customer['phone'];
$customer_message = $customer['message'];
$admin_email = get_option('admin_email');
$recipent_email = $eshb_settings['recipent_email'];
$recipent_email = empty($recipent_email) ? $admin_email : $recipent_email;
$from_name = wp_parse_url(get_site_url(), PHP_URL_HOST);
$subject = __('Booking Request!', 'easy-hotel');
$message = '';
$message .= '
';
$message .= '
Great news!
You have a new booking request.
';
$message .= '
Customer Details
';
$message .= '
';
$message .= '| Name: ' . $customer_name . ' |
';
$message .= '| Email: ' . $customer_email . ' |
';
$message .= '| Phone: ' . $customer_phone . ' |
';
$message .= '
';
$message .= '
Booking Details
';
$message .= '
';
$message .= '| Accomodation: ' . $accomodation_title . ' |
';
$message .= '| Date: ' . date_i18n( get_option('date_format'), strtotime( $start_date ) ) .' - '. date_i18n( get_option('date_format'), strtotime( $end_date ) ) . ' |
';
if(!empty($times)) {
$message .= '| Times: ' . $times . ' |
';
}
$message .= '| Details: ' . $details_html . ' |
';
if(!empty($extra_services_html)){
$message .= '| Exra Services: ' . $extra_services_html . ' |
';
}
$message .= '
';
$message .= '
Message:
'.$customer_message.'
';
$message .= '
';
// Prepare the data array to store in post meta
$form_data = [
'booking_status' => 'processing',
'booking_accomodation_id' => $accomodation_id,
'total_price' => $total_price,
'subtotal_price' => $subtotal_price,
'base_price' => $base_price,
'extra_service_price' => $extra_services_charge,
'extra_bed_price' => $extra_bed_price,
'booking_start_date' => $start_date,
'booking_end_date' => $end_date,
'booking_start_time' => $start_time,
'booking_end_time' => $end_time,
'dates' => $dates,
'room_quantity' => $room_quantity,
'extra_bed_quantity' => $extra_bed_quantity,
'adult_quantity' => $adult_quantity,
'children_quantity' => $children_quantity,
'extra_services' => $selected_services,
'details_html' => $details_html,
'extra_services_html' => $extra_services_html,
'customer' => $customer
];
if(!empty($start_time)) {
$form_data['start_time'] = $start_time;
}
if(!empty($end_time)) {
$form_data['end_time'] = $end_time;
}
if(!empty($times)) {
$form_data['times'] = $times;
}
// Insert the post
$post_id = wp_insert_post(array(
'post_type' => 'eshb_booking',
'post_title' => 'Booking for ' . $start_date . ' - ' . $end_date,
'post_status' => 'publish',
'meta_input' => array(
'eshb_booking_metaboxes' => $form_data
)
));
// Check if the post was inserted successfully
if (!is_wp_error($post_id)) {
// Update the post title to include the post ID
wp_update_post(array(
'ID' => $post_id,
'post_title' => 'Booking #' . $post_id . ' for: ' . $accomodation_title,
'post_status' => 'publish' // Update status to 'publish'
));
// Update Available Rooms Count For This Accomodation
$accomodation_metaboxes = get_post_meta( $accomodation_id, 'eshb_accomodation_metaboxes', true );
$total_rooms = !empty($accomodation_metaboxes['total_rooms']) ? floatval($accomodation_metaboxes['total_rooms']) : 1;
$current_available_rooms = !empty($accomodation_metaboxes['available_rooms']) ? floatval($accomodation_metaboxes['available_rooms']) : 0;
if(!empty($current_available_rooms)){
$available_rooms = $current_available_rooms - floatval($room_quantity);
}else{
$available_rooms = $total_rooms - floatval($room_quantity);
}
$accomodation_metaboxes['available_rooms'] = $available_rooms;
update_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', $accomodation_metaboxes);
}
$save_booking = $this->save_booking_request($form_data, $customer);
$send_email = $hotel_core->eshb_send_html_email($recipent_email, $subject, $message, $from_name, $customer_email);
if ( $send_email ) {
// Return success response
wp_send_json_success([
'message' => esc_html( $string_booking_success_msg ),
'admin_email' => esc_html( $admin_email ),
]);
} else {
$error = array(
'code' => 'email_failed',
'message' => esc_html( $string_booking_failed_msg ),
);
wp_send_json_error([
'error' => $error,
]);
}
}else{
$error = array(
'code' => 'accomodation_post_type_not_found',
'message' => esc_html( $string_booking_failed_msg ),
);
wp_send_json_error([
'error' => $error,
]);
}
wp_die();
}
}
public function apply_custom_price_to_cart_item($cart) {
// Early return for admin requests (except AJAX)
if (is_admin() && !defined('DOING_AJAX')) {
return;
}
// Use the passed cart object if valid, otherwise fallback
if (!$cart || !is_object($cart) || !method_exists($cart, 'get_cart')) {
$cart = WC()->cart;
if (!$cart || !is_object($cart) || !method_exists($cart, 'get_cart')) {
return;
}
}
$redirect_added = false;
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
if (empty($cart_item['total_price']) || $cart_item['total_price'] <= 0) {
continue;
}
if (isset($cart_item['data']) && is_object($cart_item['data'])) {
$cart_item['data']->set_price($cart_item['total_price']);
}
}
}
private function add_currency_redirect() {
static $redirect_added = false;
if ($redirect_added) {
return;
}
add_action('wp_footer', function() {
echo '';
});
$redirect_added = true;
}
public function save_custom_meta_to_order($item, $cart_item_key, $values, $order) {
if (isset($values['accomodation_id'])) {
$item->add_meta_data('Accomodation ID', $values['accomodation_id'], true);
}
if (isset($values['total_price'])) {
$item->add_meta_data('Total Price', $values['total_price'], true);
}
if (isset($values['subtotal_price'])) {
$item->add_meta_data('Subtotal Price', $values['subtotal_price'], true);
}
if (isset($values['base_price'])) {
$item->add_meta_data('Base Price', $values['base_price'], true);
}
if (isset($values['extra_services_charge'])) {
$item->add_meta_data('Extra Services Charge', $values['extra_services_charge'], true);
}
if (isset($values['extra_bed_price'])) {
$item->add_meta_data('Extra Bed Price', $values['extra_bed_price'], true);
}
if(class_exists('ESHB_CURRENCY_WOO_FUNCTIONS')){
$currency_functions = new ESHB_CURRENCY_WOO_FUNCTIONS();
if (isset($values['total_price'])) {
$item->add_meta_data('Total Price', $currency_functions->apply_custom_currency_rate($values['total_price']), true);
}
if (isset($values['subtotal_price'])) {
$item->add_meta_data('Subtotal Price', $currency_functions->apply_custom_currency_rate($values['subtotal_price']), true);
}
if (isset($values['base_price'])) {
$item->add_meta_data('Base Price', $currency_functions->apply_custom_currency_rate($values['base_price']), true);
}
if (isset($values['extra_services_charge'])) {
$item->add_meta_data('Extra Services Charge', $currency_functions->apply_custom_currency_rate($values['extra_services_charge']), true);
}
if (isset($values['extra_bed_price'])) {
$item->add_meta_data('Extra Bed Price', $currency_functions->apply_custom_currency_rate($values['extra_bed_price']), true);
}
}
if (isset($values['room_quantity'])) {
$item->add_meta_data('Rooms', $values['room_quantity'], true);
}
if (isset($values['extra_bed_quantity'])) {
$item->add_meta_data('Extra Bed', $values['extra_bed_quantity'], true);
}
if (isset($values['adult_quantity'])) {
$item->add_meta_data('Adults', $values['adult_quantity'], true);
}
if (isset($values['children_quantity'])) {
$item->add_meta_data('Children', $values['children_quantity'], true);
}
if (isset($values['start_date'])) {
$item->add_meta_data('Start Date', $values['start_date'], true);
}
if (isset($values['end_date'])) {
$item->add_meta_data('End Date', $values['end_date'], true);
}
if (isset($values['dates'])) {
$item->add_meta_data('Date', $values['dates'], true);
}
if (isset($values['start_time'])) {
$item->add_meta_data('Start Time', $values['start_time'], true);
}
if (isset($values['end_time'])) {
$item->add_meta_data('End Time', $values['end_time'], true);
}
if (!empty($values['times'])) {
$item->add_meta_data('Time', $values['times'], true);
}
if (isset($values['details_html'])) {
$item->add_meta_data('Details', $values['details_html'], true);
}
if (isset($values['extra_services'])) {
$item->add_meta_data('Extra Services IDs', $values['extra_services'], true);
}
if (isset($values['extra_services_html'])) {
$item->add_meta_data('Extra Services', $values['extra_services_html'], true);
}
}
public function capture_payment_after_checkout($order_id){
// capture payment
ESHB_Helper::eshb_capture_payment($order_id);
}
public function create_woocommerce_booking_on_checkout($order_id){
if (!$order_id) {
// error_log("Error: Missing order ID.");
return;
}
// Get the order object
$order = wc_get_order($order_id);
if (!$order) {
// error_log("Error: Invalid order ID: $order_id");
return;
}
$eshb_settings = get_option('eshb_settings', []);
// Get the order object
$order = wc_get_order($order_id);
$order_status = $order->get_status();
$booking_status = $order_status;
if ( $order && $order->is_paid() && $order->get_status() !== 'completed' && isset($eshb_settings['booking-auto-approval']) && $eshb_settings['booking-auto-approval'] == true) {
$order->update_status('completed', 'Payment successful, status updated via code.');
$booking_status = 'completed';
}
$first_name = $order->get_billing_first_name();
$last_name = $order->get_billing_last_name();
$customer_name = trim($first_name . ' ' . $last_name); // Concatenate first and last name
$customer_email = $order->get_billing_email(); // Get customer email
$customer_phone = $order->get_billing_phone(); // Get customer phone number
// Check if the booking post has already been created
if (get_post_meta($order_id, '_booking_post_created', true)) {
return; // Exit if the booking post has already been created
}
// Loop through order items
foreach ($order->get_items() as $item_id => $item) {
// Retrieve meta data saved in the order item
$accomodation_id = $item->get_meta('Accomodation ID');
$accomodation_title = get_the_title( $accomodation_id );
$room_quantity = $item->get_meta('Rooms');
$extra_bed_quantity = $item->get_meta('Extra Bed');
$adult_quantity = $item->get_meta('Adults');
$children_quantity = $item->get_meta('Children');
$start_date = $item->get_meta('Start Date');
$end_date = $item->get_meta('End Date');
$dates = $item->get_meta('Date');
$times = $item->get_meta('Time');
$start_time = $item->get_meta('Start Time');
$end_time = $item->get_meta('End Time');
$details_html = $item->get_meta('Details');
$extra_services = $item->get_meta('Extra Services IDs');
$extra_services_html = $item->get_meta('Extra Services');
$base_price = $item->get_meta('Base Price');
$extra_services_charge = $item->get_meta('Extra Service Price');
$extra_bed_price = $item->get_meta('Extra Bed Price');
$total_without_discount = $item->get_meta('Subtotal Price');
$total_price = $item->get_meta('Total Price');
// Prepare the data array to store in post meta
$cart_item_data = [
'booking_status' => $booking_status,
'order_id' => $order_id,
'booking_accomodation_id' => $accomodation_id,
'subtotal_price' => $order->get_subtotal(),
'total_price' => $total_price,
'total_paid' => 0,
'base_price' => $base_price,
'extra_service_price' => $extra_services_charge,
'extra_bed_price' => $extra_bed_price,
'booking_start_date' => $start_date,
'booking_end_date' => $end_date,
'booking_start_time' => !empty($start_time) ? $start_time : '10:00',
'booking_end_time' => !empty($end_time) ? $end_time : '22:00',
'dates' => $dates,
'room_quantity' => $room_quantity,
'extra_bed_quantity' => $extra_bed_quantity,
'adult_quantity' => $adult_quantity,
'children_quantity' => $children_quantity,
'extra_services' => $extra_services,
'start_time' => !empty($start_time) ? $start_time : '10:00',
'end_time' => !empty($end_time) ? $end_time : '22:00',
'times' => $times,
'details_html' => $details_html,
'extra_services_html' => $extra_services_html,
];
// filter for $cart_item_data;
$cart_item_data = apply_filters( 'on_booking_cart_item_data', $cart_item_data );
// Insert the booking
if($accomodation_id && !empty($accomodation_id)) {
ESHB_Helper::eshb_insert_booking($order_id, $booking_status, $cart_item_data);
}
}
}
public function display_custom_meta_in_cart_and_order($item_data, $cart_item) {
if (!empty($cart_item['discount']) && is_cart()) {
$discount = $cart_item['discount'];
$currency_symbol = $cart_item['currency_symbol'];
$item_data[] = array(
'key' => __('Save', 'easy-hotel'),
'value' => wc_price($discount)
);
}
if (isset($cart_item['dates'])) {
$dates = $cart_item['dates'];
$item_data[] = array(
'key' => __('Date', 'easy-hotel'),
'value' => esc_html( $dates )
);
}
if (!empty($cart_item['times'])) {
$times = $cart_item['times'];
$item_data[] = array(
'key' => __('Time', 'easy-hotel'),
'value' => esc_html( $times )
);
}
if (!empty($cart_item['night'])) {
$night = $cart_item['night'];
$night_label = esc_html__('Night', 'easy-hotel');
if ($night > 1) {
$night_label = esc_html__('Nights', 'easy-hotel');
}
$item_data[] = array(
'key' => $night_label,
'value' => esc_html( $night )
);
}
if (isset($cart_item['details_html'])) {
$details_html = $cart_item['details_html'];
$item_data[] = array(
'key' => __('Details', 'easy-hotel'),
'value' => esc_html( $details_html )
);
}
$extra_services_ids = isset($cart_item['extra_services']) ? $cart_item['extra_services'] : '';
if(!empty($extra_services_ids)){
if (isset($cart_item['extra_services_html'])) {
$extra_services_html = $cart_item['extra_services_html'];
$item_data[] = array(
'key' => __('Extra Services', 'easy-hotel'),
'value' => esc_html( $extra_services_html )
);
}
}
// make unique item data
$item_data = array_unique($item_data, SORT_REGULAR);
return $item_data;
}
public function hide_meta_from_display($hidden_meta_keys) {
// Add meta keys to hide
$keys_to_hide = array(
'Accomodation ID',
'Subtotal Price',
'Total Price',
'Base Price',
'Extra Services Charge',
'Extra Bed Price',
'Rooms',
'Extra Bed',
'Adults',
'Children',
'Start Date',
'End Date',
'Start Time',
'End Time',
'Save'
);
return array_merge($hidden_meta_keys, $keys_to_hide);
}
public function unset_specific_order_item_meta_data($formatted_meta, $item){
$keys_to_hide = array(
'Accomodation ID',
'Subtotal Price',
'Total Price',
'Base Price',
'Extra Services Charge',
'Extra Bed Price',
'Rooms',
'Extra Bed',
'Adults',
'Children',
'Start Date',
'End Date',
'Start Time',
'End Time',
'Save'
);
foreach($formatted_meta as $key => $meta){
if(in_array($meta->key, $keys_to_hide)) {
unset($formatted_meta[$key]);
}
}
return $formatted_meta;
}
public function calculate_booking_pricing($accomodation_id, $start_date, $end_date, $room_quantity, $extra_bed_quantity, $adult_quantity, $children_quantity, $selected_services, $currency_converter = false, $start_time = '', $end_time = '') {
if (empty($accomodation_id)) return;
$accomodation_id = (int) $accomodation_id;
$total_guest_quantity = (int) $adult_quantity + (int) $children_quantity;
$start = new DateTime($start_date);
$end = new DateTime($end_date);
$days_count = max(1, $start->diff($end)->days);
$hours_count = ESHB_Helper::eshb_calculate_time_diff($start_date, $end_date, $start_time, $end_time);
$today = new DateTime('now', new DateTimeZone('GMT'));
$today_date = $today->format('Y-m-d');
$tomorrow = $today->modify('+1 day')->format('Y-m-d');
$hotel_core = new ESHB_Core();
$metaboxes = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);
$allowed_check_in_day = apply_filters( 'eshb_booking_allowed_check_in_day', 'all', $accomodation_id, $metaboxes );
$single_day_price = 0;
// Handle week-based or same-day bookings
if (!empty($allowed_check_in_day) && $allowed_check_in_day !== 'all') {
$days_count = 1;
}
$pricing_periodicity = false;
if ($start_date === $end_date) {
$days_count = 1;
$pricing_periodicity = apply_filters( 'eshb_pricing_periodicity', false, $accomodation_id, $metaboxes );
$single_day_price = apply_filters( 'eshb_single_day_price', 0, $accomodation_id);
}
// Base price
$base_price = 0;
$base_price = $hotel_core->get_eshb_day_wise_price($start_date, $end_date, $accomodation_id, true, $days_count, $adult_quantity, $children_quantity);
$base_price = !empty($single_day_price) ? $single_day_price : $base_price;
$has_session_price = $hotel_core->has_upcoming_or_current_session_price($accomodation_id, $start_date, $end_date, $days_count, $adult_quantity, $children_quantity);
if($has_session_price){
$session_price = $hotel_core->get_eshb_price_by_session($accomodation_id, $start_date, $end_date, $days_count, $adult_quantity, $children_quantity);
}
$base_price = !empty($session_price) && $session_price > 0 ? $session_price : $base_price;
$regular_base_price = $hotel_core->get_eshb_day_wise_price($start_date, $end_date, $accomodation_id, true, $days_count, $adult_quantity, $children_quantity);
// Pricing logic
$bed_price = (int) ($metaboxes['extra_bed_price'] ?? 0);
$pricing_type = $metaboxes['pricing_type'] ?? 'room_wise';
$pricing_base = $pricing_type === 'room_wise'
? $base_price * $room_quantity
: $base_price * $total_guest_quantity;
$regular_pricing_base = $pricing_type === 'room_wise'
? $regular_base_price * $room_quantity
: $regular_base_price * $total_guest_quantity;
$extra_bed_price = $extra_bed_quantity > 0
? $extra_bed_quantity * $bed_price * $days_count
: 0;
$subtotal_price = $pricing_base + $extra_bed_price;
$regular_subtotal_price = $regular_pricing_base + $extra_bed_price;
if($pricing_periodicity && !empty($hours_count)){
$subtotal_price = $pricing_periodicity == 'per_hour' ? $subtotal_price * (int) $hours_count : $subtotal_price;
$regular_subtotal_price = $pricing_periodicity == 'per_hour' ? $regular_subtotal_price * (int) $hours_count : $regular_subtotal_price;
}
// Extra services
$extra_services_charge = 0;
if (!empty($selected_services) && is_array($selected_services)) {
$extra_services_charge = array_reduce($selected_services, function ($carry, $service) use ($days_count, $room_quantity, $total_guest_quantity) {
$service_id = !empty($service['id']) ? $service['id'] : 0;
$service_quantity = !empty($service['quantity']) ? $service['quantity'] : 0;
if(empty($service_id) || empty($service_quantity)) {
return $carry;
}
$meta = get_post_meta($service_id, 'eshb_service_metaboxes', true);
$price = $meta['service_price'] ?? 0;
$periodicity = $meta['service_periodicity'] ?? 'once';
$charge_type = $meta['service_charge_type'] ?? 'room';
//$single_price = $price * $service_quantity;
$single_price = $price ? $price : 0;
if ($periodicity == 'per_day') {
$single_price *= $days_count;
}
if($charge_type == 'room'){
$single_price *= $room_quantity;
}else{
$single_price *= $service_quantity;
}
return $carry + floatval($single_price);
}, 0);
}
$eshb_settings = get_option('eshb_settings');
$booking_type = isset($eshb_settings['booking-type']) ? $eshb_settings['booking-type'] : '';
$regular_subtotal_price = $regular_subtotal_price + $extra_services_charge;
$regular_total_price = $regular_subtotal_price;
$subtotal_price = $subtotal_price + $extra_services_charge;
$total_price = $subtotal_price;
$discount = $total_price < $regular_total_price ? abs( (float) $regular_total_price - (float) $total_price) : 0;
$currency_symbol = $hotel_core->get_eshb_currency_symbol();
$currency_symbol = html_entity_decode($currency_symbol);
$currency_position = $hotel_core->get_eshb_currency_position();
$extra_bed_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $extra_bed_price, $currency_converter);
$extra_services_charge = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $extra_services_charge, $currency_converter);
$base_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $base_price, $currency_converter);
$regular_base_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $regular_base_price, $currency_converter);
$subtotal_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $subtotal_price, $currency_converter);
$regular_subtotal_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $regular_subtotal_price, $currency_converter);
$total_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $total_price, $currency_converter);
$regular_total_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $regular_total_price, $currency_converter);
$single_day_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $single_day_price, $currency_converter);
$discount = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $discount, $currency_converter);
$single_day_price_html = $hotel_core->eshb_price( $single_day_price );
$regular_base_price_html = $hotel_core->eshb_price( $regular_base_price );
$base_price_html = $hotel_core->eshb_price( $base_price );
$extra_bed_price_html = $hotel_core->eshb_price( $extra_bed_price );
$extra_services_charge_html = $hotel_core->eshb_price( $extra_services_charge );
$subtotal_price_html = $hotel_core->eshb_price( $subtotal_price );
$regular_subtotal_price_html = $hotel_core->eshb_price( $regular_subtotal_price );
$total_price_html = $hotel_core->eshb_price( $total_price );
$regular_total_price_html = $hotel_core->eshb_price( $regular_total_price );
$discount_html = $hotel_core->eshb_price( $discount );
$is_wc_price = ($booking_type === 'woocommerce' && class_exists('WooCommerce')) ? true : false;
return [
'startDate' => $start_date,
'endDate' => $end_date,
'today' => $today_date,
'tomorrow' => $tomorrow,
'daysCount' => $days_count,
'singleDayPrice' => $single_day_price,
'extraServicesPrice' => $extra_services_charge,
'extraBedPrice' => $extra_bed_price,
'basePrice' => $base_price,
'regularBasePrice' => $regular_base_price,
'subtotalPrice' => $subtotal_price,
'regularSubtotalPrice'=> $regular_subtotal_price,
'totalPrice' => $total_price,
'regularTotalPrice' => $regular_total_price,
'discount' => $discount,
'currencySymbol' => $currency_symbol,
'currencyPosition' => $currency_position,
'singleDayPriceHtml' => $single_day_price_html,
'extraServicesPriceHtml' => $extra_services_charge_html,
'extraBedPriceHtml' => $extra_bed_price_html,
'basePriceHtml' => $base_price_html,
'regularBasePriceHtml' => $regular_base_price_html,
'subtotalPriceHtml' => $subtotal_price_html,
'regularSubtotalPriceHtml'=> $regular_subtotal_price_html,
'totalPriceHtml' => $total_price_html,
'regularTotalPriceHtml' => $regular_total_price_html,
'discountHtml' => $discount_html,
'isWcPrice' => $is_wc_price
];
}
public function eshb_add_to_cart_reservation(){
// Verify nonce for security
if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field(wp_unslash($_POST['nonce'])), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action'))) {
$error = array(
'code' => 'invalid_nonce',
'message' => __('invalid_nonce', 'easy-hotel')
);
wp_send_json_error([
'error' => $error,
]);
die();
}
if(isset($_POST['accomodationId']) && !empty($_POST['accomodationId'])){
$hotel_core = new ESHB_Core();
$accomodation_id = isset( $_POST['accomodationId'] ) ? (int) sanitize_text_field( wp_unslash($_POST['accomodationId']) ) : '';
$today_date = esc_html(gmdate('Y-m-d')); // Get today's date
$date = new DateTime($today_date); // Create a DateTime object from today's date
$date->modify('+1 day'); // Add one day
$tomorrow = $date->format('Y-m-d'); // Get the new date in 'Y-m-d' format
$start_date = isset( $_POST['startDate'] ) ? sanitize_text_field( wp_unslash($_POST['startDate']) ) : $today_date;
$end_date = isset( $_POST['endDate'] ) ? sanitize_text_field( wp_unslash($_POST['endDate']) ) : $tomorrow;
$start_day_name = $start_date ? strtolower(gmdate('l', strtotime($start_date))) : '';
$start_time = isset( $_POST['startTime'] ) ? sanitize_text_field( wp_unslash($_POST['startTime']) ) : '';
$end_time = isset( $_POST['endTime'] ) ? sanitize_text_field( wp_unslash($_POST['endTime']) ) : '';
$accomodation_metaboxes = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);
$start = new DateTime($start_date);
$end = new DateTime($end_date);
$interval = $start->diff($end);
$days_count = $interval->days;
$room_quantity = isset( $_POST['roomQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['roomQuantity'] ) ) : 1;
$extra_bed_quantity = isset( $_POST['extraBedQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['extraBedQuantity'] ) ) : 0;
$adult_quantity = isset( $_POST['adultQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['adultQuantity'] ) ) : 1;
$children_quantity = isset( $_POST['childrenQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['childrenQuantity'] ) ) : 0;
$total_guest_quantity = $adult_quantity + $children_quantity;
$selected_services = [];
if(isset($_POST['selectedServices']) && !empty($_POST['selectedServices'])){
$selected_services = sanitize_text_field(wp_unslash($_POST['selectedServices']));
$selected_services = json_decode($selected_services, true);
}
$eshb_settings = get_option( 'eshb_settings', [] );
$booking_type = isset($eshb_settings['booking-type']) && !empty($eshb_settings['booking-type']) ? $eshb_settings['booking-type'] : 'woocommerce';
$string_booking_success_msg = isset($eshb_settings['string_book_success_msg']) && !empty($eshb_settings['string_booking_success_msg']) ? $eshb_settings['string_booking_success_msg'] : 'Reservation Successfully added to your cart.';
$string_booking_failed_msg = isset($eshb_settings['string_booking_failed_msg']) && !empty($eshb_settings['string_booking_failed_msg']) ? $eshb_settings['string_booking_failed_msg'] : 'Ops! This Reservation has been failed.';
$string_already_booked_msg = isset($eshb_settings['string_already_booked_msg']) && !empty($eshb_settings['string_already_booked_msg']) ? $eshb_settings['string_already_booked_msg'] : 'Ops! The date range is already booked:';
$string_minimum_week_nights_msg = isset($eshb_settings['string_minimum_week_nights_msg']) && !empty($eshb_settings['string_minimum_week_nights_msg']) ? $eshb_settings['string_minimum_week_nights_msg'] : 'Please select more than 1 night!';
$string_time_error_msg = isset($eshb_settings['string_time_error_msg']) && !empty($eshb_settings['string_time_error_msg']) ? $eshb_settings['string_time_error_msg'] : 'Selected time slot is not available!';
$room_visibility = in_array('rooms', $eshb_settings['booking-form-fields']) ? true : false;
$adult_visibility = in_array('adults', $eshb_settings['booking-form-fields']) ? true : false;
$childrens_visibility = in_array('childrens', $eshb_settings['booking-form-fields']) ? true : false;
$extra_beds_visibility = in_array('extra_beds', $eshb_settings['booking-form-fields']) ? true : false;
$eshb_week_settings = [
'string_check_in_day_error_msg' => 'Only allowed check in day is',
'eshb_booking_allowed_check_in_day' => 'all',
];
$eshb_week_settings = apply_filters( 'eshb_week_settings', $eshb_week_settings );
$allowed_check_in_day = apply_filters( 'eshb_booking_allowed_check_in_day', 'all', $accomodation_id, $accomodation_metaboxes );
$string_check_in_day_error_msg = !empty($eshb_week_settings['string_check_in_day_error_msg']) ? $eshb_week_settings['string_check_in_day_error_msg'] : 'Only allowed check in day is : ';
// Min Max Booking Configurations
$min_max_settings = [
'required_min_nights' => '',
'required_max_nights' => '',
'is_global_source_for_min_max' => true,
];
$min_max_settings = apply_filters( 'eshb_min_max_settings', $min_max_settings, $accomodation_id, $accomodation_metaboxes );
$required_min_nights = $start_date !== $end_date && isset($min_max_settings['required_min_nights']) ? $min_max_settings['required_min_nights'] : '';
$required_max_nights = $start_date !== $end_date && isset($min_max_settings['required_max_nights']) ? $min_max_settings['required_max_nights'] : '';
$string_required_minimum_nights_msg = esc_html__( 'Ops! This Reservation has been failed. Requried Minumum', 'easy-hotel' );
$string_required_maximum_nights_msg = esc_html__( 'Ops! This Reservation has been failed. Requried Maximum', 'easy-hotel' );
$pricing_periodicity = apply_filters( 'eshb_pricing_periodicity', false, $accomodation_id, $accomodation_metaboxes );
$min_stay_night_by_session = ESHB_Helper::get_eshb_min_stay_night_by_session($accomodation_id, $start_date, $end_date);
// Validate booking type
if ( $booking_type == 'woocommerce' && ! class_exists( 'WooCommerce' ) ) {
$error = array(
'code' => 'woocommerce_not_activated',
'message' => esc_html__( 'Ops! Woocommerce not activated. Activate Woocommerce.', 'easy-hotel'),
);
wp_send_json_error( [ 'error' => $error ] );
} elseif ( $booking_type == 'surecart' && ! class_exists( 'SureCart' ) ) {
$error = array(
'code' => 'surecart_not_activated',
'message' => esc_html__( 'Ops! Surecart not activated. Activate Surecart.', 'easy-hotel' ),
);
wp_send_json_error( [ 'error' => $error ] );
} elseif ( $booking_type == 'surecart' && ! class_exists( 'ESHB_SURECART' ) ) {
$error = array(
'code' => 'surecart_addon_not_activated',
'message' => esc_html__( 'Ops! EHB Surecart addons not activated. Activate EHB Surecart.', 'easy-hotel' ),
);
wp_send_json_error( [ 'error' => $error ] );
}
$available_times = ESHB_Helper::get_available_times_by_date($accomodation_id, $start_date);
$is_valid_time = false;
if($pricing_periodicity == 'per_hour' && (!empty($accomodation_metaboxes['single_day_price']) || !empty($accomodation_metaboxes['single_day_sale_price'])) && !empty($available_times)){
$available_slots = isset($available_times['available_slots']) ? $available_times['available_slots'] : [];
if(count($available_slots) > 0) {
foreach ($available_slots as $slot) {
if ($start_time >= $slot[0] && $end_time <= $slot[1]) {
$is_valid_time = true;
break;
}
}
}else{
$is_valid_time = false;
}
if(!$is_valid_time){
$error = array('code' => 'invalid_time', 'message' => esc_html($string_time_error_msg));
wp_send_json_error([
'error' => $error,
]);
}
}
$actual_booked_dates = $this->get_actual_booked_dates_in_date_ranges($accomodation_id, $start_date, $end_date);
$booked_dates_str = '';
if(!empty($actual_booked_dates)){
$error_message = sprintf(
/* translators: 1: already booked message text, 2: list of booked dates */
esc_html__( '%1$s %2$s', 'easy-hotel' ),
esc_html( $string_already_booked_msg ),
$booked_dates_str
);
$error = array(
'code' => 'already_booked',
'message' => $error_message,
);
wp_send_json_error([
'error' => $error,
'booked_dates' => implode(', ', $actual_booked_dates),
]);
}
$holiday_dates = $this->get_holiday_dates_in_date_ranges($accomodation_id, $start_date, $end_date);
if(!empty($holiday_dates)){
$error = array('code' => 'holiday_dates', 'message' => esc_html__('Selected date range is not available. These dates are in holidays.', 'easy-hotel'));
wp_send_json_error([
'error' => $error,
'holiday_dates' => implode(', ', $holiday_dates),
]);
}
// Check cart blocking (temporary holds by other users)
$cart_block_msg = $this->eshb_check_cart_block($accomodation_id, $start_date, $end_date);
if (!empty($cart_block_msg)) {
$error = array('code' => 'cart_blocked', 'message' => esc_html($cart_block_msg));
wp_send_json_error(['error' => $error]);
}
// check rooms capacity
if(!$is_valid_time && isset($_POST['roomQuantity']) && !empty($_POST['roomQuantity'])){
$roomQuantity = isset( $_POST['roomQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['roomQuantity'] ) ) : 1;
$availableRoom = $this->get_available_room_count_by_date_range($accomodation_id, $start_date, $end_date);
if($roomQuantity > $availableRoom){
$error = array(
'code' => 'room_capacity_not_enough',
'message' => sprintf(
/* translators: %s: number of available rooms */
esc_html__( 'Selected room is not available. Available room: %s', 'easy-hotel' ),
esc_html( $availableRoom )
),
);
wp_send_json_error([
'error' => $error,
]);
}
}
// Validate check-in day
if($allowed_check_in_day != 'all' && $start_day_name != '' && !empty($allowed_check_in_day) && $allowed_check_in_day == $start_day_name) {
$error = array(
'code' => 'check_in_day_error',
'message' => sprintf(
/* translators: %s: allowed check-in day */
esc_html__( '%1$s %1$s', 'easy-hotel' ),
esc_html( $string_check_in_day_error_msg ),
esc_html( $allowed_check_in_day )
),
);
wp_send_json_error([
'error' => $error,
]);
}
if(!empty($allowed_check_in_day) && $allowed_check_in_day != 'all'){
$days_count = 1;
}
// validate min stay night by session
if(class_exists('ESHB_ADVANCED_PRICING') && !empty($min_stay_night_by_session) && $days_count < $min_stay_night_by_session){
$error = array(
'code' => 'min_stay_night_by_session',
'message' => sprintf(
/* translators: 1: minimum nights message text, 2: required minimum nights */
esc_html__( '%1$s %2$s nights!', 'easy-hotel' ),
esc_html( $string_required_minimum_nights_msg ),
esc_html( $min_stay_night_by_session )
),
);
wp_send_json_error([
'error' => $error,
]);
}
if(!empty($required_min_nights) && $days_count < $required_min_nights){
$error = array(
'code' => 'required_min_nights',
'message' => sprintf(
/* translators: 1: minimum nights message text, 2: required minimum nights */
esc_html__( '%1$s %2$s nights!', 'easy-hotel' ),
esc_html( $string_required_minimum_nights_msg ),
esc_html( $required_min_nights )
),
);
wp_send_json_error([
'error' => $error,
]);
}
if(!empty($required_max_nights) && $days_count > $required_max_nights){
$error = array(
'code' => 'required_max_nights',
'message' => sprintf(
/* translators: 1: maximum nights message text, 2: required maximum nights */
esc_html__( '%1$s %2$s nights allowed!', 'easy-hotel' ),
esc_html( $string_required_maximum_nights_msg ),
esc_html( $required_max_nights )
),
);
wp_send_json_error([
'error' => $error,
]);
}
// validate capacities
$adult_capacity = !empty($accomodation_metaboxes['adult_capacity']) ? $accomodation_metaboxes['adult_capacity'] : 0;
$children_capacity = !empty($accomodation_metaboxes['children_capacity']) ? $accomodation_metaboxes['children_capacity'] : 0;
$total_capacity = !empty($accomodation_metaboxes['total_capacity']) ? $accomodation_metaboxes['total_capacity'] : 0;
$extra_bed_capacity = !empty($accomodation_metaboxes['total_extra_beds']) ? $accomodation_metaboxes['total_extra_beds'] : 0;
// multiply total capacity by per rooms
$total_capacity = $total_capacity * $room_quantity;
if(!empty($total_capacity)){
if($adult_capacity < 1 && $children_capacity > 0){
$adult_capacity = $total_capacity - $children_quantity;
}elseif($adult_capacity < 1 && $children_capacity < 1){
$adult_capacity = $total_capacity;
}
if($children_capacity < 1 && $adult_capacity > 0){
$children_capacity = $total_capacity - $adult_quantity;
}elseif($children_capacity < 1 && $adult_capacity < 1){
$children_capacity = $total_capacity;
}
}
// multiply capacity by per rooms
$adult_capacity = $adult_capacity * $room_quantity;
$children_capacity = $children_capacity * $room_quantity;
$extra_bed_capacity = $extra_bed_capacity * $room_quantity;
if(!empty($adult_capacity) && $adult_quantity > 0 && $adult_capacity < $adult_quantity){
$error = array('code' => 'adult_capacity_not_enough', 'message' => esc_html__('Maximum Adult Capacity', 'easy-hotel') . ' ' . $adult_capacity);
wp_send_json_error([
'error' => $error,
]);
}
if(!empty($children_capacity) && $children_quantity > 0 && $children_capacity < $children_quantity){
$error = array('code' => 'children_capacity_not_enough', 'message' => esc_html__('Maximum Children Capacity', 'easy-hotel') . ' ' . $children_capacity);
wp_send_json_error([
'error' => $error,
]);
}
if($extra_bed_quantity > 0 && $extra_bed_capacity < $extra_bed_quantity){
$error = array('code' => 'extra_bed_capacity_not_enough', 'message' => esc_html__('Maximum Extra Bed Capacity', 'easy-hotel') . ' ' . $extra_bed_capacity );
wp_send_json_error([
'error' => $error,
]);
}
$pricing = $this->calculate_booking_pricing($accomodation_id, $start_date, $end_date, $room_quantity, $extra_bed_quantity, $adult_quantity, $children_quantity, $selected_services, false, $start_time, $end_time );
$base_price = $pricing['basePrice'];
$extra_services_charge = $pricing['extraServicesPrice'];
$extra_bed_price= $pricing['extraBedPrice'];
$subtotal_price = $pricing['subtotalPrice'];
$total_price = $pricing['totalPrice'];
$discount = $pricing['discount'];
$currency_symbol = $pricing['currencySymbol'];
$quantity = 1;
$details = [];
if ($room_visibility && $room_quantity > 0) {
$details[] = 'Room: ' . $room_quantity;
}
if ($extra_beds_visibility && $extra_bed_quantity > 0) {
$details[] = 'Extra Bed: ' . $extra_bed_quantity;
}
if ($adult_visibility && $adult_quantity > 0) {
$details[] = 'Adult: ' . $adult_quantity;
}
if ($childrens_visibility && $children_quantity > 0) {
$details[] = 'Children: ' . $children_quantity;
}
$details_html = implode(', ', $details);
$extra_service_titles = [];
$extra_services_html = '';
if(!empty($selected_services) && is_array($selected_services) && count($selected_services) > 0 ){
foreach ($selected_services as $service) {
$service_id = $service['id'];
$service_quantity = $service['quantity'];
if(!empty($service_quantity)){
$eshb_service_metaboxes = get_post_meta($service_id, 'eshb_service_metaboxes', true);
$charge_type = $eshb_service_metaboxes['service_charge_type'];
$service_title = get_the_title($service_id) . ' For ' . $service_quantity . ' ' . ucfirst(strtolower($charge_type));
if(!$room_visibility && $charge_type == 'room'){
$service_title = get_the_title($service_id);
}
}else{
$service_title = get_the_title($service_id);
}
array_push($extra_service_titles, $service_title);
}
$extra_services_html = implode(", ",$extra_service_titles);
}
$dates = date_i18n( get_option('date_format'), strtotime( $start_date ) ) .' - '. date_i18n( get_option('date_format'), strtotime( $end_date ) );
if($start_date == $end_date){
$dates = date_i18n( get_option('date_format'), strtotime( $start_date ) );
}
$formated_start_timestamp = strtotime( $start_time );
$formated_end_timestamp = strtotime( $end_time );
$cart_item_data = [
'accomodation_id' => $accomodation_id,
'subtotal_price' => $subtotal_price,
'total_price' => $total_price,
'base_price' => $base_price,
'discount' => $discount,
'extra_services_charge' => $extra_services_charge,
'extra_bed_price' => $extra_bed_price,
'currency_symbol' => $currency_symbol,
'start_date' => $start_date,
'end_date' => $end_date,
'night' => $days_count,
'dates' => $dates,
'room_quantity' => $room_quantity,
'adult_quantity' => $adult_quantity,
'details_html' => $details_html,
'extra_services_html' => $extra_services_html
];
if(!empty($extra_bed_quantity)) {
$cart_item_data['extra_bed_quantity'] = $extra_bed_quantity;
}
if(!empty($start_time)) {
$cart_item_data['start_time'] = $start_time;
}
if(!empty($end_time)) {
$cart_item_data['end_time'] = $end_time;
}
if(!empty($start_time) && !empty($end_time)) {
// Get WP formatted time (according to Settings > General > Time Format)
$wp_time_format = get_option( 'time_format' ); // WP settings
$formatted_start_time = wp_date( $wp_time_format, $formated_start_timestamp );
$formatted_end_time = wp_date( $wp_time_format, $formated_end_timestamp );
$times = $formatted_start_time . ' - ' . $formatted_end_time;
$cart_item_data['times'] = $times;
}
if(!empty($children_quantity)) {
$cart_item_data['children_quantity'] = $children_quantity;
}
if(!empty($selected_services)) {
$cart_item_data['extra_services'] = $selected_services;
}
if(!empty($extra_services_charge)) {
$cart_item_data['extra_services_html'] = $extra_services_html;
}
if (get_post_type($accomodation_id) === 'eshb_accomodation') {
$thumbnail_id = get_post_thumbnail_id($accomodation_id);
$price_id = 0;
$product_id = ESHB_Helper::get_product_id_for_cart($accomodation_id, $booking_type);
$product_id = apply_filters( 'eshb_product_id_for_cart', $product_id, $accomodation_id, $thumbnail_id );
$cart_item_data['product_id'] = $product_id;
$cart_item_data['price_id'] = $price_id;
do_action( 'eshb_before_add_to_cart', $booking_type, $cart_item_data, $string_booking_success_msg );
if($booking_type == 'woocommerce'){
update_post_meta($product_id, '_accomodation_id', $accomodation_id);
$this->update_product_price_by_id($product_id, $subtotal_price);
$cart_item_data['unique_key'] = uniqid( '', true );
$cart_item_key = WC()->cart->add_to_cart($product_id, $quantity, 0, [], $cart_item_data);
if ( $cart_item_key ) {
$blocked_until = $this->eshb_set_cart_block($accomodation_id, $start_date, $end_date, $room_quantity);
wp_send_json_success([
'booking-type' => $booking_type,
'message' => esc_html( $string_booking_success_msg ),
'cart_item_key' => $cart_item_key,
'cart_count' => WC()->cart->get_cart_contents_count(),
'blocked_until' => $blocked_until,
'accomodation_id' => $accomodation_id,
'start_date' => $start_date,
'end_date' => $end_date,
]);
} else {
$error = array(
'code' => 'cart_item_key_not_found',
'message' => esc_html( $string_booking_failed_msg ),
);
wp_send_json_error([
'error' => $error,
'cart_item_data' => $cart_item_data,
'product_id' => $product_id,
]);
}
}
do_action( 'eshb_after_add_to_cart', $booking_type, $cart_item_data, $string_booking_success_msg );
}else{
$error = array('code' => 'accomodation_post_type_not_found', 'message' => esc_html($string_booking_failed_msg));
wp_send_json_error([
'error' => $error,
]);
}
die();
}
}
public function eshb_get_booking_prices() {
// Ensure external filters are loaded during AJAX requests
do_action('eshb_before_calculate_pricing');
if (isset($_POST['accomodationId']) && !empty($_POST['accomodationId'])) {
// Verify nonce for security
if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action'))) {
wp_send_json_error(['message' => 'Invalid nonce']);
die();
}
$accomodation_id = (int) sanitize_text_field(wp_unslash($_POST['accomodationId']));
$start_date = sanitize_text_field(wp_unslash($_POST['startDate'] ?? $today_date));
$end_date = sanitize_text_field(wp_unslash($_POST['endDate'] ?? $tomorrow));
$start_time = sanitize_text_field(wp_unslash($_POST['startTime'] ?? ''));
$end_time = sanitize_text_field(wp_unslash($_POST['endTime'] ?? ''));
$room_quantity = (int) sanitize_text_field(wp_unslash($_POST['roomQuantity'] ?? 1));
$extra_bed_quantity = (int) sanitize_text_field(wp_unslash($_POST['extraBedQuantity'] ?? 0));
$adult_quantity = (int) sanitize_text_field(wp_unslash($_POST['adultQuantity'] ?? 1));
$children_quantity = (int) sanitize_text_field(wp_unslash($_POST['childrenQuantity'] ?? 0));
$selected_services = [];
if(isset($_POST['selectedServices']) && !empty($_POST['selectedServices'])){
$selected_services = sanitize_text_field(wp_unslash($_POST['selectedServices']));
$selected_services = json_decode($selected_services, true);
}
$pricing = $this->calculate_booking_pricing($accomodation_id, $start_date, $end_date, $room_quantity, $extra_bed_quantity, $adult_quantity, $children_quantity, $selected_services, true, $start_time, $end_time);
wp_send_json_success($pricing);
}
wp_die();
}
public function eshb_get_booking_prices_rest( $request ) {
do_action('eshb_before_calculate_pricing');
$params = $request->get_params();
// // Nonce check
if ( ! isset($params['nonce']) || ! wp_verify_nonce($params['nonce'], ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action')) ) {
return new WP_Error('invalid_nonce', 'Invalid nonce', ['status' => 403]);
}
$accomodation_id = (int) ($params['accomodationId'] ?? 0);
$start_date = $params['startDate'] ?? gmdate('Y-m-d');
$end_date = $params['endDate'] ?? gmdate('Y-m-d', strtotime('+1 day'));
$start_time = $params['startTime'] ?? '';
$end_time = $params['endTime'] ?? '';
$room_quantity = (int) ($params['roomQuantity'] ?? 1);
$extra_bed_quantity = (int) ($params['extraBedQuantity'] ?? 0);
$adult_quantity = (int) ($params['adultQuantity'] ?? 1);
$children_quantity = (int) ($params['childrenQuantity'] ?? 0);
$selected_services = $params['selectedServices'] ?? [];
$pricing = $this->calculate_booking_pricing(
$accomodation_id,
$start_date,
$end_date,
$room_quantity,
$extra_bed_quantity,
$adult_quantity,
$children_quantity,
$selected_services,
true,
$start_time,
$end_time
);
return rest_ensure_response($pricing);
}
public function eshb_get_extra_services_charge(){
// Verify nonce for security
if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field(wp_unslash($_POST['nonce'])), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action'))) {
wp_send_json_error(['message' => 'Invalid nonce']);
die();
}
if(isset($_POST['selectedServices']) && !empty($_POST['selectedServices'])){
$selected_services = array_map('sanitize_text_field', wp_unslash($_POST['selectedServices']));
$days_count = isset($_POST['dayCount']) ? sanitize_text_field(wp_unslash($_POST['dayCount'])) : 1;
$price = 0;
if(is_array($selected_services)){
foreach ($selected_services as $service) {
$service_id = $service['id'];
$quantity = $service['quantity'];
$eshb_service_metaboxes = get_post_meta($service_id, 'eshb_service_metaboxes', true);
$service_periodicity = $eshb_service_metaboxes['service_periodicity'];
if (isset($eshb_service_metaboxes['service_price'])) { // Ensure 'service_price' is set
$single_price = $eshb_service_metaboxes['service_price'] * $quantity;
if($service_periodicity == 'perday' && !empty($days_count)){
$single_price = $days_count * $single_price;
}
$price += floatval($single_price); // Add the single price to the total price
}
}
}
wp_send_json_success( ['price' => $price] );
wp_die();
}
}
public function get_available_room_count_by_date_range($accomodation_id, $start_date, $end_date, $start_time = '', $end_time = '') {
$accomodation_id = intval($accomodation_id);
$start_date_obj = new DateTime($start_date);
$end_date_obj = new DateTime($end_date);
if ($end_date_obj < $start_date_obj) {
return new WP_Error('invalid_date_range', 'End date cannot be earlier than start date.');
}
// Fetch total rooms
$accomodation_metas = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);
$total_rooms = isset($accomodation_metas['total_rooms']) ? intval($accomodation_metas['total_rooms']) : 1;
// Initialize bookings count array
$bookings_per_date = [];
// Query all bookings
$bookings_args = [
'post_type' => 'eshb_booking',
'posts_per_page' => -1,
//'post_status' => 'publish',
'post_status' => ['publish', 'completed', 'processing', 'deposit-payment', 'pending'],
'fields' => 'ids',
];
$bookings = new WP_Query($bookings_args);
if ($bookings->have_posts()) {
while ($bookings->have_posts()) {
$bookings->the_post();
$booking_id = get_the_ID();
$booking_metas = get_post_meta($booking_id, 'eshb_booking_metaboxes', true);
$booking_accomodation_id = $booking_metas['booking_accomodation_id'];
$booking_status = isset($booking_metas['booking_status']) ? $booking_metas['booking_status'] : '';
$valid_statuses = array('pending', 'processing', 'on-hold', 'completed', 'deposit-payment');
if (
is_array($booking_metas) &&
intval($booking_accomodation_id) === $accomodation_id &&
isset($booking_metas['booking_start_date'], $booking_metas['booking_end_date']) &&
in_array($booking_status, $valid_statuses)
) {
$booking_start = new DateTime($booking_metas['booking_start_date']);
$booking_end = new DateTime($booking_metas['booking_end_date']);
$booked_rooms = !empty($booking_metas['room_quantity']) ? intval($booking_metas['room_quantity']) : 1;
$accomodation_metaboxes = get_post_meta( $booking_accomodation_id, 'eshb_accomodation_metaboxes', true );
$total_rooms = !empty($accomodation_metaboxes['total_rooms']) ? $accomodation_metaboxes['total_rooms'] : 1;
if(!empty($start_time) && !empty($end_time)) {
$booking_start_time = !empty($booking_metas['booking_start_time']) ? $booking_metas['booking_start_time'] : '';
$booking_end_time = !empty($booking_metas['booking_end_time']) ? $booking_metas['booking_end_time'] : '';
if($booking_start_time !== $start_time) {
$booked_rooms = 0;
}
if($booking_start_time === $start_time && $booking_end_time === $end_time) {
$booked_rooms = 0;
}
}
// Loop through each date in this booking
$period = new DatePeriod($booking_start, new DateInterval('P1D'), (clone $booking_end)->modify('+0 day'));
if($booking_start == $booking_end) {
$period = new DatePeriod($booking_start, new DateInterval('P1D'), (clone $booking_end)->modify('+1 day'));
}
foreach ($period as $date) {
$formatted = $date->format('Y-m-d');
if (!isset($bookings_per_date[$formatted])) {
$bookings_per_date[$formatted] = 0;
}
$bookings_per_date[$formatted] += $booked_rooms;
}
}
}
wp_reset_postdata();
}
// Now calculate the max number of rooms booked in the given date range
$range_period = new DatePeriod($start_date_obj, new DateInterval('P1D'), (clone $end_date_obj)->modify('+0 day'));
$max_booked_in_range = 0;
if($start_date_obj == $end_date_obj){
$formatted = $start_date_obj->format('Y-m-d');
$available_rooms = isset($bookings_per_date[$formatted]) ? $total_rooms - $bookings_per_date[$formatted] : $total_rooms;
return $available_rooms;
}
foreach ($range_period as $date) {
$formatted = $date->format('Y-m-d');
$booked = isset($bookings_per_date[$formatted]) ? $bookings_per_date[$formatted] : 0;
if ($booked > $max_booked_in_range) {
$max_booked_in_range = $booked;
}
}
// Final available room count
$available_rooms = max(0, $total_rooms - $max_booked_in_range);
if($available_rooms < 0) {
$available_rooms = 0;
}
return $available_rooms;
}
public function eshb_get_available_rooms_counts_data(){
// Verify nonce for security
if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action'))) {
wp_send_json_error(['message' => 'Invalid nonce']);
die();
}
$accomodation_id = !empty($_POST['accomodationId']) ? sanitize_text_field( wp_unslash($_POST['accomodationId']) ) : '';
$start_date = !empty($_POST['startDate']) ? sanitize_text_field( wp_unslash($_POST['startDate']) ) : '';
$end_date = !empty($_POST['endDate']) ? sanitize_text_field( wp_unslash($_POST['endDate']) ) : '';
$start_time = !empty($_POST['startTime']) ? sanitize_text_field( wp_unslash($_POST['startTime']) ) : '';
$end_time = !empty($_POST['endTime']) ? sanitize_text_field( wp_unslash($_POST['endTime']) ) : '';
$start_date = new DateTime($start_date);
$end_date = new DateTime($end_date);
$eshb_accomodation_metaboxes = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);
$total_rooms = !empty($eshb_accomodation_metaboxes['total_rooms']) ? $eshb_accomodation_metaboxes['total_rooms'] : 0;
$available = 1;
$available = $this->get_available_room_count_by_date_range($accomodation_id, $start_date->format('Y-m-d'), $end_date->format('Y-m-d'), $start_time, $end_time);
if($available < 0 ) {
$available = 0;
}
wp_send_json_success(
array(
'available' => $available,
'total' => $total_rooms,
)
);
die();
}
public function eshb_get_accomodation_available_capacity_counts(){
if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action'))) {
wp_send_json_error(['message' => 'Invalid nonce']);
die();
}
if(isset($_POST['accomodationId']) && !empty($_POST['accomodationId']) && isset($_POST['type']) && !empty($_POST['type'])){
$type = sanitize_text_field( wp_unslash($_POST['type']) );
$accomodation_id = sanitize_text_field( wp_unslash($_POST['accomodationId']) );
$accomodation_metaboxes = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);
$total_guest_quantity = $accomodation_metaboxes['total_capacity'];
$selected_rooms_count = !empty($_POST['rooms']) ? sanitize_text_field( wp_unslash($_POST['rooms']) ) : 1;
$start_date = !empty($_POST['startDate']) ? sanitize_text_field( wp_unslash($_POST['startDate']) ) : '';
$end_date = !empty($_POST['endDate']) ? sanitize_text_field( wp_unslash($_POST['endDate']) ) : '';
$start_date = new DateTime($start_date);
$end_date = new DateTime($end_date);
$available = 1;
$msg = __('Maximum Capacity', 'easy-hotel');
if($type == 'room_quantity'){
$total = $accomodation_metaboxes['total_rooms'];
$available = $this->get_available_room_count_by_date_range($accomodation_id, $start_date->format('Y-m-d'), $end_date->format('Y-m-d'));
if($available < 1){
$msg = __('Available Room', 'easy-hotel');
}
}
if($type == 'adult_quantity'){
if(!empty($accomodation_metaboxes['adult_capacity'])){
$available = $accomodation_metaboxes['adult_capacity'];
$available = $available * $selected_rooms_count;
}else{
$childrenQuantity = !empty($_POST['childrenQuantity']) ? sanitize_text_field( wp_unslash( $_POST['childrenQuantity'] ) ) : 0;
$total_capacity = $accomodation_metaboxes['total_capacity'];
$available = $total_capacity - $childrenQuantity;
$available = $available * $selected_rooms_count;
$msg = __('Maximum Adult and Children Capacity', 'easy-hotel');
}
}
if($type == 'children_quantity'){
$total_capacity = $accomodation_metaboxes['total_capacity'];
if(!empty($accomodation_metaboxes['children_capacity'])){
$available = $accomodation_metaboxes['children_capacity'];
$available = $available * $selected_rooms_count;
}else{
$childrenQuantity = !empty($_POST['adultQuantity']) ? sanitize_text_field( wp_unslash( $_POST['adultQuantity'] ) ) : 0;
$available = $total_capacity - $childrenQuantity;
$available = $available * $selected_rooms_count;
$msg = __('Maximum Adult and Children Capacity', 'easy-hotel');
}
}
if($type == 'extra_bed_quantity'){
$available = $accomodation_metaboxes['total_extra_beds'];
$available = $available * $selected_rooms_count;
}
if($type == 'service-quantity'){
$available = $total_guest_quantity;
}
if(($type != 'room_quantity') && (empty($available) || $available < 1)){
$available = $total;
}
if($available < 0) {
$available = 0;
}
$msg = $type != 'adult_quantity' || $type != 'children_quantity' ? $msg . ' ' . $available : $msg;
wp_send_json_success(
array(
'message' => $msg,
'available' => $available,
'type' => $type,
)
);
}
}
public function get_accomodation_available_extra_bed_counts(){
// Verify nonce for security
if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action'))) {
wp_send_json_error(['message' => 'Invalid nonce']);
die();
}
if(isset($_POST['accomodationId']) && !empty($_POST['accomodationId']) && !empty($_POST['accomodationId'])){
$total_extra_beds = 0;
$accomodation_id = (int) sanitize_text_field( wp_unslash($_POST['accomodationId']) );
$accomodation_metaboxes = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);
$total_extra_beds = $accomodation_metaboxes['total_extra_beds'];
wp_send_json_success( $total_extra_beds );
}
}
public function send_email_woocommerce_style($email, $subject, $heading, $message) {
if ( ! function_exists( 'WC' ) ) {
return;
}
// Get WooCommerce mailer
$mailer = WC()->mailer();
// Wrap message with WooCommerce email template
$wrapped_message = $mailer->wrap_message($heading, $message);
// Create new WC_Email instance
$wc_email = new WC_Email();
// Style the wrapped message with WooCommerce inline styles
$html_message = $wc_email->style_inline($wrapped_message);
// Headers
$headers = array('Content-Type: text/html; charset=UTF-8');
// Send the email
$mailer->send($email, $subject, $html_message, $headers);
}
public function filter_status_based_on_booking_meta($status, $order_id) {
// Check if custom meta _booking_post_created exists
$booking_post_id = get_post_meta($order_id, '_booking_post_created', true);
$eshb_settings = get_option('eshb_settings', []);
if ( ! empty($booking_post_id) ) {
if(isset($eshb_settings['booking-auto-approval']) && $eshb_settings['booking-auto-approval'] == true){
return 'completed'; // Mark order as completed
}
}
// Otherwise, keep default status (usually 'processing')
return $status;
}
public function update_booking_status_on_woocommerce_order_status_change($order_id, $old_status, $new_status, $order) {
if($old_status == $new_status) {
return;
}
$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
//if ( $screen && $screen->id !== 'woocommerce_page_wc-orders' ) return;
if ( $screen && $screen->id === 'edit-eshb_booking' ) return;
if ( $screen && 'woocommerce_page_wc-orders' === $screen->id ) {
//return;
}
// Retrieve the order object
$order = wc_get_order($order_id);
// Get the booking post ID from order meta
$booking_post_id = get_post_meta($order_id, '_booking_post_created', true); // Adjusted to your meta key
if ($booking_post_id) {
// update booking status
$updated_booking = array(
'ID' => $booking_post_id,
'post_status' => $new_status,
);
wp_update_post( $updated_booking );
// Get the existing meta for the custom post
$booking_meta = get_post_meta($booking_post_id, 'eshb_booking_metaboxes', true);
// Ensure the meta is an array before modifying it
if (is_array($booking_meta)) {
// Update the `booking_status` field
$booking_meta['booking_status'] = $new_status;
// Save the updated meta back to the post
update_post_meta($booking_post_id, 'eshb_booking_metaboxes', $booking_meta);
}
}
}
public function update_woocommerce_order_status_on_booking_status_change($post_id, $post, $update) {
if(class_exists('ESHB_MANUAL_BOOKING') && is_admin()){
return;
}
if ( ! function_exists( 'WC' ) ) {
return;
}
// Ensure this runs only during post update
if (!$update || wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
return;
}
// Check if the post type matches
if ($post->post_type !== 'eshb_booking') {
return;
}
// Retrieve the metabox data
$eshb_booking_metaboxes = get_post_meta($post_id, 'eshb_booking_metaboxes', true) ?? [];
// Validate the required fields
if (empty($eshb_booking_metaboxes) || empty($eshb_booking_metaboxes['booking_status']) || empty($eshb_booking_metaboxes['order_id'])) {
return;
}
$booking_status = sanitize_text_field($eshb_booking_metaboxes['booking_status']);
$order_id = intval($eshb_booking_metaboxes['order_id']);
// Get the WooCommerce order object
$order = wc_get_order($order_id);
if (!$order) {
return; // Invalid order
}
// Check if the current order status matches the booking status to avoid redundant updates
if ($order->get_status() === $booking_status) {
return; // Status is already up-to-date
}
try {
$order->update_status($booking_status, 'Booking status updated to: ' . $booking_status);
} catch (Exception $e) {
// Log error for debugging
//error_log('Error updating order status: ' . $e->getMessage());
}
}
public function send_booking_email_notification_for_booking_status($post_id, $post, $update){
// Ensure this runs only during post update
if (!$update || wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
return;
}
// Check if the post type matches
if ($post->post_type !== 'eshb_booking') {
return;
}
// Retrieve the metabox data
$eshb_booking_metaboxes = get_post_meta($post_id, 'eshb_booking_metaboxes', true) ?? [];
// Validate the required fields
if (empty($eshb_booking_metaboxes) || empty($eshb_booking_metaboxes['booking_status']) || empty($eshb_booking_metaboxes['order_id'])) {
return;
}
$booking_status = $post->post_status;
$order_id = $eshb_booking_metaboxes['order_id'];
$eshb_settings = get_option('eshb_settings', []);
$booking_type = isset($eshb_settings['booking-type']) && !empty($eshb_settings['booking-type']) ? $eshb_settings['booking-type'] : 'woocommerce';
do_action('eshb_booking_status_changed', $post_id, $booking_status, $booking_type, $order_id);
if(class_exists('ESHB_Booking_Templates')) {
return;
}
// send email for woocommerce
if ( $booking_type == 'woocommerce' && function_exists( 'WC' ) ) {
$order = wc_get_order($order_id);
if (!$order) {
return; // Invalid order
}
// Trigger email manually
$mailer = WC()->mailer();
switch ( $booking_status ) {
case 'cancelled':
$to = $order->get_billing_email();
$subject = sprintf(
/* translators: %s: booking/post ID */
__( 'Your Booking #%s has been Cancelled', 'easy-hotel' ),
esc_html( $post_id )
);
$heading = __( 'Booking Cancelled', 'easy-hotel' );
$first_name = esc_html( $order->get_billing_first_name() );
$post_title = esc_html( get_the_title( $post_id ) );
$message = '' . sprintf(
/* translators: %s: customer first name */
__( 'Hi %s,', 'easy-hotel' ),
$first_name
) . '
';
$message .= '' . sprintf(
/* translators: %s: booking title */
__( 'We regret to inform you that your %s has been cancelled.', 'easy-hotel' ),
$post_title
) . '
';
$message .= '' . __( 'If you have any questions, please feel free to reply to this email.', 'easy-hotel' ) . '
';
$message .= '' . __( 'Thank you for shopping with us.', 'easy-hotel' ) . '
';
$this->send_email_woocommerce_style( $to, $subject, $heading, $message );
break;
}
}
}
// -------------------------------------------------------------------------
// Cart Blocking Methods
// -------------------------------------------------------------------------
private function eshb_get_session_token() {
// Native Checkout does not use a WooCommerce session — the visitor
// is identified by the per-visitor reservation token instead. Use
// that as the hold key so holds created during the native flow are
// attributed to (and excludable for) the right user across the
// booking form, calendar and checkout page.
if ( function_exists( 'eshb_native_checkout_is_enabled' ) && eshb_native_checkout_is_enabled()
&& function_exists( 'eshb_native_checkout_get_token' ) ) {
$native_token = eshb_native_checkout_get_token( false );
if ( ! empty( $native_token ) ) {
return 'native_' . $native_token;
}
}
if ( class_exists( 'WooCommerce' ) && WC()->session ) {
return (string) WC()->session->get_customer_id();
}
return '';
}
private function eshb_dates_overlap( $s1, $e1, $s2, $e2 ) {
return $s1 < $e2 && $s2 < $e1;
}
private function eshb_get_blocking_settings() {
$eshb_settings = get_option( 'eshb_settings', [] );
$enabled = ! empty( $eshb_settings['cart-blocking-switcher'] );
$blocking_time = ! empty( $eshb_settings['cart-blocking-time'] ) ? (int) $eshb_settings['cart-blocking-time'] : 5;
return [ 'enabled' => $enabled, 'minutes' => $blocking_time ];
}
private function eshb_set_cart_block( $accom_id, $start_date, $end_date, $room_qty ) {
$cfg = $this->eshb_get_blocking_settings();
if ( ! $cfg['enabled'] ) return 0;
$session = $this->eshb_get_session_token();
if ( empty( $session ) ) return 0;
$key = 'eshb_cart_holds_' . (int) $accom_id;
$holds = get_transient( $key );
if ( ! is_array( $holds ) ) $holds = [];
$now = time();
$until = $now + ( $cfg['minutes'] * 60 );
// Clean expired entries
foreach ( $holds as $token => $hold ) {
if ( $hold['until'] < $now ) unset( $holds[ $token ] );
}
$holds[ $session ] = [
'start_date' => $start_date,
'end_date' => $end_date,
'qty' => (int) $room_qty,
'until' => $until,
];
set_transient( $key, $holds, $cfg['minutes'] * 60 + 60 );
return $until;
}
private function eshb_check_cart_block( $accom_id, $start_date, $end_date ) {
$cfg = $this->eshb_get_blocking_settings();
if ( ! $cfg['enabled'] ) return '';
$key = 'eshb_cart_holds_' . (int) $accom_id;
$holds = get_transient( $key );
if ( ! is_array( $holds ) ) return '';
$session = $this->eshb_get_session_token();
$now = time();
foreach ( $holds as $token => $hold ) {
if ( $token === $session ) continue;
if ( $hold['until'] < $now ) continue;
if ( $this->eshb_dates_overlap( $start_date, $end_date, $hold['start_date'], $hold['end_date'] ) ) {
$remaining = (int) ceil( ( $hold['until'] - $now ) / 60 );
/* translators: %d: remaining minutes */
return sprintf( __( 'These dates are temporarily reserved by another user. Please try again in %d minute(s).', 'easy-hotel' ), $remaining );
}
}
return '';
}
/**
* Remove the current visitor's hold for one accommodation, deleting the
* transient entirely when no holds remain. Shared by the cart-removal,
* order-completion and Native Checkout release paths.
*/
private function eshb_remove_session_hold( $accom_id ) {
$accom_id = (int) $accom_id;
if ( ! $accom_id ) return;
$session = $this->eshb_get_session_token();
if ( empty( $session ) ) return;
$key = 'eshb_cart_holds_' . $accom_id;
$holds = get_transient( $key );
if ( ! is_array( $holds ) ) return;
unset( $holds[ $session ] );
if ( empty( $holds ) ) {
delete_transient( $key );
} else {
$cfg = $this->eshb_get_blocking_settings();
set_transient( $key, $holds, $cfg['minutes'] * 60 + 60 );
}
}
// -------------------------------------------------------------------------
// Public cart-blocking API (used by the Native Checkout controller, which
// is a separate class and short-circuits the WooCommerce add-to-cart flow)
// -------------------------------------------------------------------------
/**
* Place a temporary hold for a native reservation. Returns the unix
* timestamp the hold expires at, or 0 when blocking is disabled.
*/
public function eshb_block_dates_for_reservation( $accom_id, $start_date, $end_date, $room_qty ) {
return $this->eshb_set_cart_block( $accom_id, $start_date, $end_date, $room_qty );
}
/**
* Whether the given dates collide with another visitor's active hold.
* Returns a translated message on conflict, or '' when clear.
*/
public function eshb_get_cart_block_conflict( $accom_id, $start_date, $end_date ) {
return $this->eshb_check_cart_block( $accom_id, $start_date, $end_date );
}
/**
* Release the current visitor's hold for an accommodation (on
* completed booking or expired/abandoned native reservation).
*/
public function eshb_release_cart_block( $accom_id ) {
$this->eshb_remove_session_hold( $accom_id );
}
/**
* Expiry timestamp (unix) of the current visitor's own hold for an
* accommodation, or 0 when there is none. Lets the Native Checkout
* page render an accurate countdown.
*/
public function eshb_get_my_block_until( $accom_id ) {
$accom_id = (int) $accom_id;
if ( ! $accom_id ) return 0;
$holds = get_transient( 'eshb_cart_holds_' . $accom_id );
if ( ! is_array( $holds ) ) return 0;
$session = $this->eshb_get_session_token();
if ( empty( $session ) || empty( $holds[ $session ]['until'] ) ) return 0;
return (int) $holds[ $session ]['until'];
}
/**
* Expose the hold-countdown notice markup so the Native Checkout
* template can render the same banner used by the WooCommerce flow.
*/
public function eshb_cart_block_notice_html( $mode = 'inline' ) {
return $this->eshb_get_blocking_notice_html( $mode );
}
public function eshb_add_blocked_dates_to_calendar( $all_dates, $accom_id, $accom_metas ) {
$key = 'eshb_cart_holds_' . (int) $accom_id;
$holds = get_transient( $key );
$blocked_ranges = [];
if ( is_array( $holds ) ) {
$now = time();
// Show every active hold as "Reserved" on the calendar,
// including the current visitor's own. The native flow keys
// holds by a cookie token that is reliably present on this
// AJAX request, so skipping the own session here would hide
// the held dates from the holder (whereas the WooCommerce
// session token isn't consistently resolved here, so its
// holds always showed). Own-hold exclusion is kept only in
// the booking-validation path so the holder can still finish
// their own reservation.
foreach ( $holds as $token => $hold ) {
if ( $hold['until'] < $now ) continue;
$blocked_ranges[] = [
'start_date' => $hold['start_date'],
'end_date' => $hold['end_date'],
'until' => $hold['until'],
];
}
}
$all_dates['blocked_dates'] = $blocked_ranges;
return $all_dates;
}
public function eshb_get_cart_blocks_ajax() {
check_ajax_referer( ESHB_Helper::generate_secure_nonce_action( 'eshb_global_nonce_action' ), 'nonce' );
$accom_id = isset( $_POST['accomodation_id'] ) ? (int) sanitize_text_field( wp_unslash( $_POST['accomodation_id'] ) ) : 0;
if ( ! $accom_id ) {
wp_send_json_error( [ 'message' => 'Invalid accommodation ID' ] );
return;
}
$key = 'eshb_cart_holds_' . $accom_id;
$holds = get_transient( $key );
$blocked_ranges = [];
if ( is_array( $holds ) ) {
$now = time();
// Include every active hold (own included) so the calendar
// renders the held dates as "Reserved" consistently across
// the WooCommerce and Native Checkout flows. See the note in
// eshb_add_blocked_dates_to_calendar().
foreach ( $holds as $token => $hold ) {
if ( $hold['until'] < $now ) continue;
$blocked_ranges[] = [
'start_date' => $hold['start_date'],
'end_date' => $hold['end_date'],
'until' => $hold['until'],
];
}
}
wp_send_json_success( [ 'blocked_ranges' => $blocked_ranges ] );
}
public function eshb_clear_cart_block_on_removal( $cart_item_key, $cart ) {
$removed = isset( $cart->removed_cart_contents[ $cart_item_key ] ) ? $cart->removed_cart_contents[ $cart_item_key ] : null;
if ( ! $removed ) return;
$accom_id = isset( $removed['accomodation_id'] ) ? (int) $removed['accomodation_id'] : 0;
if ( ! $accom_id ) return;
$this->eshb_remove_session_hold( $accom_id );
}
public function eshb_render_calendar_legend( $accomodation_id = 0 ) {
static $rendered = false;
if ( $rendered || is_admin() ) return;
$rendered = true;
$eshb_settings = get_option( 'eshb_settings', [] );
$cart_blocking_on = ! empty( $eshb_settings['cart-blocking-switcher'] );
$items = [
'available' => [ 'class' => 'eshb-legend-available', 'label' => __( 'Available', 'easy-hotel' ) ],
'selected' => [ 'class' => 'eshb-legend-selected', 'label' => __( 'Selected', 'easy-hotel' ) ],
'booked' => [ 'class' => 'eshb-legend-booked', 'label' => __( 'Booked', 'easy-hotel' ) ],
'holiday' => [ 'class' => 'eshb-legend-holiday', 'label' => __( 'Holiday', 'easy-hotel' ) ],
];
if ( $cart_blocking_on ) {
$items['reserved'] = [ 'class' => 'eshb-legend-reserved', 'label' => __( 'Reserved', 'easy-hotel' ) ];
}
$items = apply_filters( 'eshb_calendar_legend_items', $items, $accomodation_id );
?>
'
. '⏳ ' . $msg . ' 0:00'
. '';
}
public function eshb_render_cart_block_notice_inline() {
if ( $this->eshb_notice_printed || is_admin() ) return;
$this->eshb_notice_printed = true;
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $this->eshb_get_blocking_notice_html( 'inline' );
}
public function eshb_prepend_notice_to_woo_block( $block_content, $block ) {
if ( $this->eshb_notice_printed || is_admin() ) return $block_content;
if ( ! in_array( $block['blockName'], [ 'woocommerce/cart', 'woocommerce/checkout' ], true ) ) return $block_content;
$html = $this->eshb_get_blocking_notice_html( 'inline' );
if ( ! $html ) return $block_content;
$this->eshb_notice_printed = true;
// Append for checkout to avoid breaking React hydration; prepend for cart
return $block['blockName'] === 'woocommerce/checkout'
? $block_content . $html
: $html . $block_content;
}
public function eshb_footer_notice_fallback() {
if ( $this->eshb_notice_printed || is_admin() ) return;
if ( ! is_cart() && ! is_checkout() ) return;
$html = $this->eshb_get_blocking_notice_html( 'inline' );
if ( ! $html ) return;
$this->eshb_notice_printed = true;
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $html;
}
public function eshb_clear_cart_on_block_expiry() {
check_ajax_referer( ESHB_Helper::generate_secure_nonce_action( 'eshb_global_nonce_action' ), 'nonce' );
if ( class_exists( 'WooCommerce' ) && WC()->cart ) {
WC()->cart->empty_cart();
}
wp_send_json_success( [ 'cleared' => true ] );
}
public function eshb_check_my_session_blocks() {
check_ajax_referer( ESHB_Helper::generate_secure_nonce_action( 'eshb_global_nonce_action' ), 'nonce' );
$accom_ids = isset( $_POST['accom_ids'] ) ? array_map( 'intval', (array) $_POST['accom_ids'] ) : [];
if ( empty( $accom_ids ) ) {
wp_send_json_success( [ 'active_ids' => [] ] );
return;
}
$session = $this->eshb_get_session_token();
$now = time();
$active_ids = [];
foreach ( $accom_ids as $accom_id ) {
if ( ! $accom_id ) continue;
$holds = get_transient( 'eshb_cart_holds_' . $accom_id );
if ( is_array( $holds ) && isset( $holds[ $session ] ) && $holds[ $session ]['until'] > $now ) {
$active_ids[] = $accom_id;
}
}
wp_send_json_success( [ 'active_ids' => $active_ids ] );
}
public function eshb_clear_session_cart_blocks_on_order( $order_id ) {
if ( ! $order_id ) return;
$session = $this->eshb_get_session_token();
if ( empty( $session ) ) return;
$order = wc_get_order( $order_id );
if ( ! $order ) return;
foreach ( $order->get_items() as $item ) {
$accom_id = (int) $item->get_meta( 'accomodation_id' );
if ( ! $accom_id ) continue;
$this->eshb_remove_session_hold( $accom_id );
}
}
public function eshb_checkout_order_review_qty_input( $qty_html, $cart_item, $cart_item_key ) {
if ( ! is_checkout() ) return $qty_html;
$eshb_settings = get_option( 'eshb_settings', [] );
if ( empty( $eshb_settings['direct-booking'] ) ) return $qty_html;
$nonce = wp_create_nonce( ESHB_Helper::generate_secure_nonce_action( 'eshb_global_nonce_action' ) );
$ajaxurl = esc_url( admin_url( 'admin-ajax.php' ) );
return $qty_html
. ' ';
}
public function eshb_remove_cart_item() {
check_ajax_referer( ESHB_Helper::generate_secure_nonce_action( 'eshb_global_nonce_action' ), 'nonce' );
$cart_item_key = sanitize_text_field( wp_unslash( $_POST['cart_item_key'] ?? '' ) );
if ( $cart_item_key && class_exists( 'WooCommerce' ) && WC()->cart ) {
WC()->cart->remove_cart_item( $cart_item_key );
}
wp_send_json_success();
}
}
ESHB_Booking::instance();
// Registered once on the singleton (constructor runs multiple times due to `new ESHB_Booking()` calls elsewhere)
add_filter( 'woocommerce_checkout_cart_item_quantity', [ ESHB_Booking::instance(), 'eshb_checkout_order_review_qty_input' ], 10, 3 );