Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/tourfic/inc/Admin/TF_API_Documentation.php
+++ b/tourfic/inc/Admin/TF_API_Documentation.php
@@ -997,9 +997,8 @@
'url' => '/orders',
'description' => __( 'Get booking orders list with optional filtering and calendar event data.', 'tourfic' ),
'parameters' => array(
- array( 'name' => 'user_id', 'type' => 'integer', 'required' => false, 'description' => __( 'Target user ID. Defaults to current user.', 'tourfic' ) ),
array( 'name' => 'checkinout', 'type' => 'string', 'required' => false, 'description' => __( 'Check-in status filter (in, out, not).', 'tourfic' ) ),
- array( 'name' => 'post_type', 'type' => 'string', 'required' => false, 'description' => __( 'Booking type filter (tf_hotel, tf_tours, tf_apartment, tf_carrental).', 'tourfic' ) ),
+ array( 'name' => 'post_type', 'type' => 'string', 'required' => true, 'description' => __( 'Booking type filter (hotel, tour, apartment, car). CPT aliases are also accepted: tf_hotel, tf_tours, tf_apartment, tf_carrental.', 'tourfic' ) ),
array( 'name' => 'post_id', 'type' => 'integer', 'required' => false, 'description' => __( 'Filter bookings for a specific post ID.', 'tourfic' ) ),
array( 'name' => 'order_status', 'type' => 'string', 'required' => false, 'description' => __( 'Order status filter.', 'tourfic' ) ),
),
@@ -1048,8 +1047,7 @@
'url' => '/enquiries',
'description' => __( 'Get enquiry list by user role context with optional filters.', 'tourfic' ),
'parameters' => array(
- array( 'name' => 'user_id', 'type' => 'integer', 'required' => false, 'description' => __( 'Target user ID. Defaults to current user.', 'tourfic' ) ),
- array( 'name' => 'post_type', 'type' => 'string', 'required' => true, 'description' => __( 'Post type for enquiries (tf_hotel, tf_tours, tf_apartment, tf_carrental).', 'tourfic' ) ),
+ array( 'name' => 'post_type', 'type' => 'string', 'required' => true, 'description' => __( 'Post type for enquiries (tf_hotel, tf_tours, tf_apartment).', 'tourfic' ) ),
array( 'name' => 'post_id', 'type' => 'integer', 'required' => false, 'description' => __( 'Filter by specific post ID.', 'tourfic' ) ),
array( 'name' => 'filters', 'type' => 'string', 'required' => false, 'description' => __( 'Status filter (for example: replied, responded, not-replied, not-responded).', 'tourfic' ) ),
),
@@ -1279,4 +1277,4 @@
);
}
-}
No newline at end of file
+}
--- a/tourfic/inc/App/Without_Payment/Hotel_Offline_Booking.php
+++ b/tourfic/inc/App/Without_Payment/Hotel_Offline_Booking.php
@@ -50,7 +50,18 @@
$check_out = isset( $_POST['check_out_date'] ) ? sanitize_text_field( $_POST['check_out_date'] ) : '';
$deposit = isset( $_POST['deposit'] ) ? sanitize_text_field( $_POST['deposit'] ) : false;
$airport_service = isset( $_POST['airport_service'] ) ? sanitize_text_field( $_POST['airport_service'] ) : '';
- $extras = isset( $_POST['extras'] ) ? $_POST['extras'] : [];
+ $extras = isset( $_POST['extras'] ) ? wp_unslash( $_POST['extras'] ) : [];
+ $hotel_extra_quantities = isset( $_POST['hotel_extra_quantity'] ) ? Helper::tf_sanitize_extra_quantities( wp_unslash( $_POST['hotel_extra_quantity'] ) ) : [];
+
+ if ( is_string( $extras ) ) {
+ $extras = explode( ',', sanitize_text_field( $extras ) );
+ }
+
+ if ( is_array( $extras ) ) {
+ $extras = array_map( 'sanitize_text_field', $extras );
+ } else {
+ $extras = [];
+ }
$total_people = $adult + $child;
@@ -98,6 +109,10 @@
if ( $avail_by_date ) {
$avail_date = ! empty( $room_meta['avail_date'] ) ? json_decode( $room_meta['avail_date'], true ) : [];
}
+ $use_explicit_availability_pricing = false;
+ if ( $avail_by_date && function_exists( 'is_tf_pro' ) && is_tf_pro() ) {
+ $use_explicit_availability_pricing = Availability::has_explicit_available_rules( $avail_date );
+ }
$room_name = get_the_title( $room_id );
$pricing_by = $room_meta['pricing-by'];
$price_multi_day = ! empty( $room_meta['price_multi_day'] ) ? $room_meta['price_multi_day'] : false;
@@ -125,8 +140,13 @@
if(function_exists( 'is_tf_pro' ) && is_tf_pro() && !empty($hotel_extra_option)){
$hotel_extras = ! empty( $meta['hotel-extra'] ) ? Helper::tf_data_types($meta['hotel-extra']) : [];
foreach ( $extras as $key => $extra ) {
- $extra_service = Helper::tf_hotel_extras_title_price( $post_id, $adult, $child, $extra );
- $total_extras_title[] = $hotel_extras[$extra]['title'];
+ if ( empty( $hotel_extras[ $extra ] ) ) {
+ continue;
+ }
+ $extra_quantity = ! empty( $hotel_extra_quantities[ $key ] ) ? $hotel_extra_quantities[ $key ] : 1;
+ $extra_service = Helper::tf_hotel_extras_title_price( $post_id, $adult, $child, $extra, $extra_quantity );
+ $extra_price_type = ! empty( $hotel_extras[ $extra ]['price_type'] ) ? $hotel_extras[ $extra ]['price_type'] : 'fixed';
+ $total_extras_title[] = 'quantity' === $extra_price_type && ! empty( $extra_service['title'] ) ? $hotel_extras[$extra]['title'] . ' (' . wp_strip_all_tags( $extra_service['title'] ) . ')' : $hotel_extras[$extra]['title'];
$total_extras_price += $extra_service['price'];
}
}
@@ -315,7 +335,7 @@
/**
* Calculate Pricing
*/
- if ( $avail_by_date && function_exists( 'is_tf_pro' ) && is_tf_pro() ) {
+ if ( $use_explicit_availability_pricing ) {
// Check availability by date option
$period = new DatePeriod(
--- a/tourfic/inc/Classes/Enqueue.php
+++ b/tourfic/inc/Classes/Enqueue.php
@@ -269,9 +269,23 @@
/**
* Google Map
*/
- if ( 'googlemap' === $tf_openstreet_map ) {
+ $tf_should_enqueue_google_map = 'googlemap' === $tf_openstreet_map;
+ if ( is_singular( array( 'tf_hotel', 'tf_tours', 'tf_apartment', 'tf_carrental' ) ) ) {
+ $tf_should_enqueue_google_map = false;
+ }
+
+ if ( $tf_should_enqueue_google_map ) {
$tf_map_api_key = ! empty( Helper::tfopt( 'tf-googlemapapi' ) ) ? Helper::tfopt( 'tf-googlemapapi' ) : '';
- wp_enqueue_script( 'googleapis', '//maps.googleapis.com/maps/api/js?key=' . $tf_map_api_key . '&sensor=false&libraries=places', array(), TOURFIC, true );
+ $tf_google_map_url = add_query_arg(
+ array(
+ 'key' => $tf_map_api_key,
+ 'libraries' => 'places',
+ 'loading' => 'async',
+ ),
+ 'https://maps.googleapis.com/maps/api/js'
+ );
+
+ wp_enqueue_script( 'googleapis', $tf_google_map_url, array(), TOURFIC, true );
wp_enqueue_script( 'markerclusterer', TF_ASSETS_URL . 'app/libs/markerclusterer.min.js', array(), TOURFIC, true );
wp_enqueue_script('map-marker-label', TF_ASSETS_URL . 'app/libs/markerwithlabel.js', array(), TOURFIC, true);
}
@@ -357,6 +371,7 @@
$tf_tour_global_template = ! empty( Helper::tf_data_types( Helper::tfopt( 'tf-template' ) )['single-tour'] ) ? Helper::tf_data_types( Helper::tfopt( 'tf-template' ) )['single-tour'] : 'design-1';
$tf_tour_selected_template = ! empty( $tf_tour_single_template ) ? $tf_tour_single_template : $tf_tour_global_template;
$tour_type = ! empty( $meta['type'] ) ? $meta['type'] : '';
+ $pricing_rule = ! empty( $meta['pricing'] ) ? $meta['pricing'] : '';
$tour_date_format_for_users = ! empty( Helper::tfopt( "tf-date-format-for-users" ) ) ? Helper::tfopt( "tf-date-format-for-users" ) : "Y/m/d";
$raw_tour_availability = $meta['tour_availability'] ?? '';
@@ -376,6 +391,7 @@
$single_tour_form_data['tf_tour_selected_template'] = $tf_tour_selected_template;
$single_tour_form_data['tour_type'] = $tour_type;
+ $single_tour_form_data['pricing_rule'] = $pricing_rule;
$single_tour_form_data['first_day_of_week'] = !empty(Helper::tfopt("tf-week-day-flatpickr")) ? Helper::tfopt("tf-week-day-flatpickr") : 0;
$single_tour_form_data['select_time_text'] = esc_html__( "Select Time", "tourfic" );
$single_tour_form_data['date_format'] = esc_html( $tour_date_format_for_users );
@@ -485,6 +501,18 @@
'car_mobile_button_hide' => esc_html__( 'Hide', 'tourfic' ),
'car_mobile_button_book_now' => esc_html__( 'Book Now', 'tourfic' ),
'car_location_required_msg' => esc_html__( 'Select Pickup & Dropoff Location', 'tourfic' ),
+ 'car_location_invalid_msg' => esc_html__(
+ 'Please select supported Pick-up and Drop-off locations from the suggestions.',
+ 'tourfic'
+ ),
+ 'car_pickup_location_invalid_msg' => esc_html__(
+ 'Please select a supported Pick-up location from the suggestions.',
+ 'tourfic'
+ ),
+ 'car_dropoff_location_invalid_msg' => esc_html__(
+ 'Please select a supported Drop-off location from the suggestions.',
+ 'tourfic'
+ ),
'car_date_required_msg' => esc_html__( 'Select Pickup & Dropoff Date', 'tourfic' ),
'open_street_map_text' => esc_html__( 'OpenStreetMap', 'tourfic' ),
'required' => esc_html__( 'This field is required.', 'tourfic'),
--- a/tourfic/inc/Classes/Helper.php
+++ b/tourfic/inc/Classes/Helper.php
@@ -469,27 +469,40 @@
}
- static function tf_hotel_extras_title_price( $post_id, $adult, $child, $key ) {
+ static function tf_hotel_extras_title_price( $post_id, $adult, $child, $key, $quantity = 1 ) {
$meta = get_post_meta( $post_id, 'tf_hotels_opt', true );
$hotel_extras = ! empty( $meta['hotel-extra'] ) ? $meta['hotel-extra'] : '';
if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && ! empty( $hotel_extras[$key] ) ) {
if ( !empty($hotel_extras[$key]['price']) ) {
+ $extra_price = $hotel_extras[$key]['price'];
+ $extra_quantity = 0 < intval( $quantity ) ? intval( $quantity ) : 1;
+ $extra_price_type = ! empty( $hotel_extras[$key]['price_type'] ) ? $hotel_extras[$key]['price_type'] : 'fixed';
- if ( "fixed" == $hotel_extras[$key]['price_type'] ) {
+ if ( "fixed" == $extra_price_type ) {
$airport_service_arr = array(
'title' => __( 'Fixed Price', 'tourfic' ),
- 'price' => $hotel_extras[$key]['price']
+ 'price' => $extra_price
);
}
- if ( "person" == $hotel_extras[$key]['price_type'] ) {
+ if ( "person" == $extra_price_type ) {
$airport_service_arr = array(
/* translators: %1$s: number of adult and %2$s: extra price */
'title' => sprintf( __( 'Adult ( %1$s × %2$s )', 'tourfic' ),
$adult,
- wp_strip_all_tags( wc_price( $hotel_extras[$key]['price'] ) )
+ wp_strip_all_tags( wc_price( $extra_price ) )
),
- 'price' => $hotel_extras[$key]['price'] * (int) $adult
+ 'price' => $extra_price * (int) $adult
+ );
+ }
+ if ( "quantity" == $extra_price_type ) {
+ $airport_service_arr = array(
+ /* translators: %1$s: extra quantity and %2$s: extra price */
+ 'title' => sprintf( __( 'Quantity ( %1$s × %2$s )', 'tourfic' ),
+ $extra_quantity,
+ wp_strip_all_tags( wc_price( $extra_price ) )
+ ),
+ 'price' => $extra_price * $extra_quantity
);
}
}
@@ -497,6 +510,23 @@
return !empty( $airport_service_arr ) ? $airport_service_arr : array( 'title' => '', 'price' => 0 );
}
+
+ static function tf_sanitize_extra_quantities( $quantities ) {
+ if ( is_string( $quantities ) ) {
+ $quantities = explode( ',', sanitize_text_field( $quantities ) );
+ }
+
+ if ( ! is_array( $quantities ) ) {
+ return [];
+ }
+
+ return array_map(
+ function( $quantity ) {
+ return 0 < intval( $quantity ) ? intval( $quantity ) : 1;
+ },
+ $quantities
+ );
+ }
/**
* Template 3 Compatible to others Themes
@@ -1038,6 +1068,82 @@
return $template;
}
+ private static function tf_order_table_select_sql( $select ) {
+ $select = '*' === trim( $select ) ? '*' : $select;
+ $allowed_columns = array(
+ 'id',
+ 'order_id',
+ 'post_id',
+ 'post_type',
+ 'room_number',
+ 'room_id',
+ 'check_in',
+ 'check_out',
+ 'billing_details',
+ 'shipping_details',
+ 'order_details',
+ 'customer_id',
+ 'payment_method',
+ 'ostatus',
+ 'order_date',
+ 'checkinout',
+ 'checkinout_by',
+ );
+
+ if ( '*' === $select ) {
+ return '*';
+ }
+
+ $columns = array_map( 'trim', explode( ',', $select ) );
+ $columns = array_values( array_intersect( $columns, $allowed_columns ) );
+
+ return ! empty( $columns ) ? implode( ', ', $columns ) : '*';
+ }
+
+ private static function tf_order_table_structured_sql( $query, &$values ) {
+ $sql = '';
+ $allowed_columns = array(
+ 'order_id' => '%d',
+ 'post_id' => '%d',
+ 'customer_id' => '%d',
+ 'room_id' => '%s',
+ 'ostatus' => '%s',
+ 'checkinout' => '%s',
+ );
+
+ if ( ! empty( $query['where'] ) && is_array( $query['where'] ) ) {
+ foreach ( $query['where'] as $column => $value ) {
+ if ( ! isset( $allowed_columns[ $column ] ) || '' === $value || null === $value ) {
+ continue;
+ }
+
+ $sql .= " AND {$column} = {$allowed_columns[ $column ]}";
+ $values[] = '%d' === $allowed_columns[ $column ] ? absint( $value ) : sanitize_text_field( $value );
+ }
+ }
+
+ if ( ! empty( $query['orderby'] ) ) {
+ $allowed_orderby = array( 'id', 'order_id', 'order_date', 'check_in', 'check_out' );
+ $orderby = sanitize_key( $query['orderby'] );
+ if ( in_array( $orderby, $allowed_orderby, true ) ) {
+ $order = ! empty( $query['order'] ) && 'ASC' === strtoupper( $query['order'] ) ? 'ASC' : 'DESC';
+ $sql .= " ORDER BY {$orderby} {$order}";
+ }
+ }
+
+ if ( ! empty( $query['limit'] ) && is_array( $query['limit'] ) ) {
+ $offset = ! empty( $query['limit']['offset'] ) ? absint( $query['limit']['offset'] ) : 0;
+ $per_page = ! empty( $query['limit']['per_page'] ) ? absint( $query['limit']['per_page'] ) : 0;
+ if ( ! empty( $per_page ) ) {
+ $sql .= ' LIMIT %d, %d';
+ $values[] = $offset;
+ $values[] = $per_page;
+ }
+ }
+
+ return $sql;
+ }
+
/*
* Retrive Orders Data
*
@@ -1048,10 +1154,14 @@
*/
static function tourfic_order_table_data( $query ) {
global $wpdb;
- $query_type = $query['post_type'];
- $query_select = $query['select'];
- $query_where = $query['query'];
- $tf_tour_book_orders = $wpdb->get_results( $wpdb->prepare( "SELECT $query_select FROM {$wpdb->prefix}tf_order_data WHERE post_type = %s $query_where", $query_type ), ARRAY_A );
+ $query_type = sanitize_key( $query['post_type'] );
+ $query_select = self::tf_order_table_select_sql( $query['select'] );
+ $values = array( $query_type );
+ $query_where = isset( $query['where'] ) && is_array( $query['where'] )
+ ? self::tf_order_table_structured_sql( $query, $values )
+ : $query['query'];
+
+ $tf_tour_book_orders = $wpdb->get_results( $wpdb->prepare( "SELECT $query_select FROM {$wpdb->prefix}tf_order_data WHERE post_type = %s $query_where", $values ), ARRAY_A );
return $tf_tour_book_orders;
}
@@ -3877,7 +3987,7 @@
$has_deposit = ! empty( $room['allow_deposit'] ) && $room['allow_deposit'] == true;
if ( $has_deposit == true ) {
if ( $room['deposit_type'] == 'percent' ) {
- $deposit_amount = $price * ( intval( $room['deposit_amount'] ) / 100 );
+ $deposit_amount = $price * ( floatval( $room['deposit_amount'] ) / 100 );
} else {
$deposit_amount = $room['deposit_amount'];
}
--- a/tourfic/inc/Classes/Hotel/Hotel.php
+++ b/tourfic/inc/Classes/Hotel/Hotel.php
@@ -392,7 +392,8 @@
<tbody>
<?php
echo wp_kses_post( ob_get_clean() );
- $error = $rows = null;
+ $error = esc_html__( 'No rooms available for the selected date.', 'tourfic' );
+ $rows = null;
$has_room = false;
// generate table rows
@@ -2656,7 +2657,13 @@
// room
$room_selected = ! empty( $_GET['room'] ) ? absint( wp_unslash( $_GET['room'] ) ) : 1;
// Check-in & out date
- $check_in_out = ! empty( $_GET['check-in-out-date'] ) ? sanitize_text_field( $_GET['check-in-out-date'] ) : '';
+ $check_in_out = ! empty( $_GET['check-in-out-date'] ) ? sanitize_text_field( wp_unslash( $_GET['check-in-out-date'] ) ) : '';
+ if ( empty( $check_in_out ) ) {
+ $hotel_current_timestamp = current_time( 'timestamp' );
+ $hotel_default_check_in = wp_date( 'Y/m/d', $hotel_current_timestamp );
+ $hotel_default_check_out = wp_date( 'Y/m/d', strtotime( '+1 day', $hotel_current_timestamp ) );
+ $check_in_out = $hotel_default_check_in . ' - ' . $hotel_default_check_out;
+ }
//get features
$features = ! empty( $_GET['features'] ) ? sanitize_text_field( $_GET['features'] ) : '';
@@ -3371,11 +3378,13 @@
<div class="tf-booking-content-service">
<?php foreach ( $hotel_extras as $key => $extra ) {
$extra_service = Helper::tf_hotel_extras_title_price( $post_id, $adult, $child, $key );
+ $hotel_extra_pricetype = ! empty( $extra['price_type'] ) ? $extra['price_type'] : 'fixed';
?>
<div class="tf-single-hotel-service tour-extra-single">
<label for="service-<?php echo esc_attr( $key ) . '_' . esc_attr($room_id); ?>">
<div class="tf-service-radio">
<input type="checkbox" value="<?php echo esc_attr( $key ); ?>" id="service-<?php echo esc_attr( $key) . '_' . esc_attr($room_id); ?>" name="extra_service">
+ <span class="tf-checkmark"></span>
</div>
<div class="tf-service-content">
<h5>
@@ -3384,6 +3393,20 @@
<p><?php echo esc_html($extra_service['title']); ?> = <?php echo wp_kses_post(wc_price( $extra_service['price'] )); ?></p>
</div>
</label>
+ <?php if ( "quantity" == $hotel_extra_pricetype ) : ?>
+ <div class="tf-field-group tf-mt-16 tf_quantity-acrselection">
+ <div class="tf-field quanity-acr-fields">
+ <div class="quanity-acr-label">
+ <?php echo esc_html__( "Select Quantity", "tourfic" ); ?>
+ </div>
+ <div class="quanity-acr-select tf-flex">
+ <div class="quanity-acr-dec">-</div>
+ <input type="number" name="extra-quantity" min="1" value="1">
+ <div class="quanity-acr-inc">+</div>
+ </div>
+ </div>
+ </div>
+ <?php endif; ?>
</div>
<?php } ?>
</div>
@@ -4160,7 +4183,7 @@
<div class="tf-section-title-and-location">
<!-- Title -->
<?php if( $show_title == 'yes' ): ?>
- <h2 class="tf-section-title"><a href="<?php echo esc_url( get_the_permalink() ); ?>"><?php echo esc_html( Helper::tourfic_character_limit_callback( get_the_title(), $title_length ) ); ?></a></h2>
+ <h2 class="tf-section-title"><a href="<?php echo esc_url( $url ); ?>"><?php echo esc_html( Helper::tourfic_character_limit_callback( get_the_title(), $title_length ) ); ?></a></h2>
<?php endif; ?>
<!-- Location -->
--- a/tourfic/inc/Classes/REST_API/TF_API_Routes.php
+++ b/tourfic/inc/Classes/REST_API/TF_API_Routes.php
@@ -147,13 +147,40 @@
register_rest_route( 'tf/v1', '/orders', array(
'methods' => 'GET',
'callback' => array( $api, 'tf_get_orders' ),
- 'permission_callback' => array( $api, 'tf_permission_callback' ),
+ 'permission_callback' => array( $api, 'tf_order_permission_callback' ),
+ 'args' => array(
+ 'post_type' => array(
+ 'required' => true,
+ 'sanitize_callback' => 'sanitize_key',
+ 'validate_callback' => function( $value ) {
+ return in_array( $value, array( 'hotel', 'tf_hotel', 'tour', 'tf_tours', 'apartment', 'tf_apartment', 'car', 'tf_carrental' ), true );
+ },
+ ),
+ 'post_id' => array(
+ 'sanitize_callback' => 'absint',
+ 'validate_callback' => function( $value ) {
+ return '' === $value || null === $value || ( is_numeric( $value ) && absint( $value ) > 0 );
+ },
+ ),
+ 'checkinout' => array(
+ 'sanitize_callback' => 'sanitize_key',
+ 'validate_callback' => function( $value ) {
+ return '' === $value || null === $value || in_array( $value, array( 'in', 'out', 'not' ), true );
+ },
+ ),
+ 'order_status' => array(
+ 'sanitize_callback' => 'sanitize_key',
+ 'validate_callback' => function( $value ) {
+ return '' === $value || null === $value || in_array( $value, array( 'pending', 'processing', 'on-hold', 'completed', 'cancelled', 'refunded', 'failed', 'trash' ), true );
+ },
+ ),
+ ),
) );
register_rest_route( 'tf/v1', '/order/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => array( $api, 'tf_get_order_details' ),
- 'permission_callback' => array( $api, 'tf_permission_callback' ),
+ 'permission_callback' => array( $api, 'tf_order_permission_callback' ),
) );
}
@@ -163,13 +190,34 @@
register_rest_route( 'tf/v1', '/enquiries', array(
'methods' => 'GET',
'callback' => array( $api, 'tf_get_enquiries' ),
- 'permission_callback' => array( $api, 'tf_permission_callback' ),
+ 'permission_callback' => array( $api, 'tf_enquiry_permission_callback' ),
+ 'args' => array(
+ 'post_type' => array(
+ 'required' => true,
+ 'sanitize_callback' => 'sanitize_key',
+ 'validate_callback' => function( $value ) {
+ return in_array( $value, array( 'tf_hotel', 'tf_tours', 'tf_apartment' ), true );
+ },
+ ),
+ 'post_id' => array(
+ 'sanitize_callback' => 'absint',
+ 'validate_callback' => function( $value ) {
+ return '' === $value || null === $value || ( is_numeric( $value ) && absint( $value ) > 0 );
+ },
+ ),
+ 'filters' => array(
+ 'sanitize_callback' => 'sanitize_key',
+ 'validate_callback' => function( $value ) {
+ return '' === $value || null === $value || in_array( $value, array( 'read', 'unread', 'replied', 'responded', 'not-replied', 'not-responded' ), true );
+ },
+ ),
+ ),
) );
register_rest_route( 'tf/v1', '/enquiries/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => array( $api, 'tf_get_enquiry_details' ),
- 'permission_callback' => array( $api, 'tf_permission_callback' ),
+ 'permission_callback' => array( $api, 'tf_enquiry_permission_callback' ),
) );
}
@@ -185,7 +233,7 @@
register_rest_route( 'tf/v1', '/user/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => array( $api, 'tf_get_user' ),
- 'permission_callback' => array( $api, 'tf_permission_callback' ),
+ 'permission_callback' => array( $api, 'tf_user_permission_callback' ),
) );
register_rest_route( 'tf/v1', '/user-bookings', array(
--- a/tourfic/inc/Classes/REST_API/TF_Booking_Rest_API.php
+++ b/tourfic/inc/Classes/REST_API/TF_Booking_Rest_API.php
@@ -25,43 +25,57 @@
* @author Foysal
*/
public function tf_get_orders( $request ) {
- $current_user_id = $request->get_param( 'user_id' ) ? $request->get_param( 'user_id' ) : get_current_user_id();
- $checkinout = $request->get_param( 'checkinout' ) ? $request->get_param( 'checkinout' ) : '';
- $post_type = $request->get_param( 'post_type' ) ? $request->get_param( 'post_type' ) : '';
- $post_id = $request->get_param( 'post_id' ) ? $request->get_param( 'post_id' ) : '';
- $order_status = $request->get_param( 'order_status' ) ? $request->get_param( 'order_status' ) : '';
-
- $tf_filter_query = "";
- if ( $checkinout ) {
- $tf_filter_query .= " AND checkinout = '$checkinout'";
- }
- if ( $post_id ) {
- $tf_filter_query .= " AND post_id = '$post_id'";
- }
- if ( $order_status ) {
- $tf_filter_query .= " AND ostatus = '$order_status'";
- }
- if ( $this->user_has_role( $current_user_id, 'administrator' ) || $this->user_has_role( $current_user_id, 'tf_manager' ) ) {
+ $current_user_id = get_current_user_id();
+ $post_type = $this->tf_validate_allowed_param( $request, 'post_type', $this->tf_order_post_types(), true );
+ $post_id = $this->tf_get_rest_absint_param( $request, 'post_id' );
+ $checkinout = $this->tf_validate_allowed_param( $request, 'checkinout', $this->tf_checkinout_statuses() );
+ $order_status = $this->tf_validate_allowed_param( $request, 'order_status', $this->tf_order_statuses() );
+
+ foreach ( array( $post_type, $post_id, $checkinout, $order_status ) as $validation_error ) {
+ if ( is_wp_error( $validation_error ) ) {
+ return $validation_error;
+ }
+ }
+ $post_type = $this->tf_normalize_order_post_type( $post_type );
+
+ $filters = array();
+ if ( ! empty( $checkinout ) ) {
+ $filters['checkinout'] = $checkinout;
+ }
+ if ( ! empty( $post_id ) ) {
+ $filters['post_id'] = $post_id;
+ }
+ if ( ! empty( $order_status ) ) {
+ $filters['ostatus'] = $order_status;
+ }
+
+ $orders_result = array();
+ if ( $this->tf_current_user_can_manage_records() ) {
$tf_orders_select = array(
'select' => "*",
'post_type' => $post_type,
- 'query' => " $tf_filter_query ORDER BY order_date DESC"
+ 'where' => $filters,
+ 'orderby' => 'order_date',
+ 'order' => 'DESC'
);
$orders_result = Helper::tourfic_order_table_data( $tf_orders_select );
- }
- if ( $this->user_has_role( $current_user_id, 'tf_vendor' ) ) {
+ } elseif ( $this->user_has_role( $current_user_id, 'tf_vendor' ) ) {
$tf_orders_select = array(
'select' => "*",
'post_type' => $post_type,
'author' => $current_user_id,
- 'query' => " $tf_filter_query ORDER BY order_date DESC",
+ 'where' => $filters,
+ 'orderby' => 'order_date',
+ 'order' => 'DESC',
'limit' => ""
);
$orders_result = tourfic_vendor_order_table_data( $tf_orders_select );
+ } else {
+ return new WP_Error( 'rest_forbidden', esc_html__( 'You are not authorized to access this endpoint.', 'tourfic' ), array( 'status' => 403 ) );
}
$events = array();
$orders_data = array();
@@ -150,8 +164,15 @@
*/
public function tf_get_order_details( $request ) {
global $wpdb;
- $id = $request->get_param( 'id' );
+ $id = absint( $request->get_param( 'id' ) );
$order = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tf_order_data WHERE id = %d", $id ), ARRAY_A );
+ if ( empty( $order ) ) {
+ return new WP_Error( 'tf_order_not_found', esc_html__( 'Order not found.', 'tourfic' ), array( 'status' => 404 ) );
+ }
+ if ( ! $this->tf_current_user_can_access_order( $order ) ) {
+ return new WP_Error( 'rest_forbidden', esc_html__( 'You are not authorized to access this order.', 'tourfic' ), array( 'status' => 403 ) );
+ }
+
$order_details = json_decode( $order['order_details'] );
//post title
@@ -162,11 +183,11 @@
//order date
if ( ! empty( $order['order_date'] ) ) {
$order['order_detail']['order_date'] = esc_html(gmdate('F d, Y',strtotime($order['order_date'])));
- }
+ }
//booked by
- $tf_booking_by = get_user_by('id', $order->customer_id);
- if("offline"==$order->payment_method && empty($tf_booking_by)){
+ $tf_booking_by = get_user_by('id', $order['customer_id']);
+ if("offline"==$order['payment_method'] && empty($tf_booking_by)){
$order['order_detail']['booked_by'] = "Administrator";
}else{
$order['order_detail']['booked_by'] = !empty($tf_booking_by->roles[0]) ? esc_html($tf_booking_by->roles[0]) : 'Administrator';
@@ -260,6 +281,9 @@
//total person
$total_person = 0;
+ $adult_count = array();
+ $child_count = array();
+ $infant_count = array();
if(!empty($order_details->adult)){
$adult_count = explode( " × ", $order_details->adult );
$total_person += $adult_count[0] ? $adult_count[0] : 0;
@@ -272,9 +296,9 @@
$infant_count = explode( " × ", $order_details->infants );
$total_person += $infant_count[0] ? $infant_count[0] : 0;
}
- $order['adult_count'] = $adult_count[0] ? $adult_count[0] : '';
- $order['child_count'] = $child_count[0] ? $child_count[0] : '';
- $order['infant_count'] = $infant_count[0] ? $infant_count[0] : '';
+ $order['adult_count'] = ! empty( $adult_count[0] ) ? $adult_count[0] : '';
+ $order['child_count'] = ! empty( $child_count[0] ) ? $child_count[0] : '';
+ $order['infant_count'] = ! empty( $infant_count[0] ) ? $infant_count[0] : '';
$order['total_person'] = $total_person;
return $order;
@@ -282,4 +306,4 @@
}
}
-TF_Booking_Rest_API::get_instance();
No newline at end of file
+TF_Booking_Rest_API::get_instance();
--- a/tourfic/inc/Classes/REST_API/TF_Enquiry_Rest_API.php
+++ b/tourfic/inc/Classes/REST_API/TF_Enquiry_Rest_API.php
@@ -25,30 +25,47 @@
* @author Foysal
*/
public function tf_get_enquiries( $request ) {
- $current_user_id = $request->get_param( 'user_id' ) ? $request->get_param( 'user_id' ) : get_current_user_id();
- $post_type = $request->get_param( 'post_type' ) ? $request->get_param( 'post_type' ) : '';
- $post_id = $request->get_param( 'post_id' ) ? $request->get_param( 'post_id' ) : '';
- $filters = $request->get_param( 'filters' ) ? $request->get_param( 'filters' ) : '';
-
- $tf_filter_query = "";
- if ( $post_id ) {
- $tf_filter_query .= " AND post_id = '$post_id'";
- }
- if( !empty($filters) ) {
- if( $filters == 'not-replied') {
- $tf_filter_query .= sprintf(' AND enquiry_status != "%s"', 'replied' );
- } elseif( $filters == 'not-responded') {
- $tf_filter_query .= sprintf(' AND enquiry_status != "%s"', 'responded' );
- } else {
- $tf_filter_query .= sprintf(' AND enquiry_status = "%s"', $filters );
+ $current_user_id = get_current_user_id();
+ $post_type = $this->tf_validate_allowed_param( $request, 'post_type', $this->tf_enquiry_post_types(), true );
+ $post_id = $this->tf_get_rest_absint_param( $request, 'post_id' );
+ $filters = $this->tf_validate_allowed_param( $request, 'filters', $this->tf_enquiry_status_filters() );
+
+ foreach ( array( $post_type, $post_id, $filters ) as $validation_error ) {
+ if ( is_wp_error( $validation_error ) ) {
+ return $validation_error;
}
}
global $wpdb;
- if ( $this->user_has_role( $current_user_id, 'administrator' ) || $this->user_has_role( $current_user_id, 'tf_manager' ) ) {
- $hotel_enquiry_result = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tf_enquiry_data WHERE post_type = %s {$tf_filter_query} ORDER BY id DESC", $post_type ), ARRAY_A );
+ $where = array( 'post_type = %s' );
+ $values = array( $post_type );
+
+ if ( ! empty( $post_id ) ) {
+ $where[] = 'post_id = %d';
+ $values[] = $post_id;
+ }
+
+ if ( ! empty( $filters ) ) {
+ if ( 'not-replied' === $filters ) {
+ $where[] = 'enquiry_status != %s';
+ $values[] = 'replied';
+ } elseif ( 'not-responded' === $filters ) {
+ $where[] = 'enquiry_status != %s';
+ $values[] = 'responded';
+ } else {
+ $where[] = 'enquiry_status = %s';
+ $values[] = $filters;
+ }
+ }
+
+ if ( $this->tf_current_user_can_manage_records() ) {
+ $hotel_enquiry_result = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tf_enquiry_data WHERE " . implode( ' AND ', $where ) . " ORDER BY id DESC", $values ), ARRAY_A );
} elseif ( $this->user_has_role( $current_user_id, 'tf_vendor' ) ) {
- $hotel_enquiry_result = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tf_enquiry_data WHERE post_type = %s {$tf_filter_query} AND author_id = %d ORDER BY id DESC", $post_type, $current_user_id ), ARRAY_A );
+ $where[] = 'author_id = %d';
+ $values[] = $current_user_id;
+ $hotel_enquiry_result = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tf_enquiry_data WHERE " . implode( ' AND ', $where ) . " ORDER BY id DESC", $values ), ARRAY_A );
+ } else {
+ return new WP_Error( 'rest_forbidden', esc_html__( 'You are not authorized to access this endpoint.', 'tourfic' ), array( 'status' => 403 ) );
}
$enquirys_data = array();
@@ -68,8 +85,15 @@
*/
public function tf_get_enquiry_details( $request ){
global $wpdb;
- $id = $request->get_param( 'id' );
+ $id = absint( $request->get_param( 'id' ) );
$enquiry = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tf_enquiry_data WHERE id = %d", $id ), ARRAY_A );
+ if ( empty( $enquiry ) ) {
+ return new WP_Error( 'tf_enquiry_not_found', esc_html__( 'Enquiry not found.', 'tourfic' ), array( 'status' => 404 ) );
+ }
+ if ( ! $this->tf_current_user_can_access_enquiry( $enquiry ) ) {
+ return new WP_Error( 'rest_forbidden', esc_html__( 'You are not authorized to access this enquiry.', 'tourfic' ), array( 'status' => 403 ) );
+ }
+
$reply_data = !empty( $enquiry["reply_data"] ) ? json_decode($enquiry["reply_data"], true) : array();
if(class_exists('TourficCoreEnquiry')){
@@ -102,4 +126,4 @@
}
}
-TF_Enquiry_Rest_API::get_instance();
No newline at end of file
+TF_Enquiry_Rest_API::get_instance();
--- a/tourfic/inc/Classes/REST_API/TF_Rest_API.php
+++ b/tourfic/inc/Classes/REST_API/TF_Rest_API.php
@@ -59,6 +59,9 @@
return false;
}
$user_meta = get_userdata( $user_id );
+ if ( empty( $user_meta ) || empty( $user_meta->roles ) ) {
+ return false;
+ }
$user_roles = $user_meta->roles;
return in_array( $role_name, $user_roles );
@@ -110,13 +113,208 @@
*/
public function tf_admin_permission_callback( WP_REST_Request $request ) {
$current_user_id = get_current_user_id();
- if ( is_user_logged_in() && $this->user_has_role( $current_user_id, 'administrator' ) || $this->user_has_role( $current_user_id, 'tf_manager' ) ) {
+ if ( is_user_logged_in() && ( $this->user_has_role( $current_user_id, 'administrator' ) || $this->user_has_role( $current_user_id, 'tf_manager' ) ) ) {
return true;
} else {
return new WP_Error( 'rest_forbidden', esc_html__( 'You are not authorized to access this endpoint.' ), array( 'status' => 403 ) );
}
}
+ public function tf_user_permission_callback( WP_REST_Request $request ) {
+ if ( ! is_user_logged_in() ) {
+ return new WP_Error( 'rest_forbidden', esc_html__( 'You are not authorized to access this endpoint.', 'tourfic' ), array( 'status' => 403 ) );
+ }
+
+ if ( $this->tf_current_user_can_access_user( $request->get_param( 'id' ) ) ) {
+ return true;
+ }
+
+ return new WP_Error( 'rest_forbidden', esc_html__( 'You are not authorized to access this user.', 'tourfic' ), array( 'status' => 403 ) );
+ }
+
+ public function tf_order_permission_callback( WP_REST_Request $request ) {
+ return $this->tf_admin_vendor_permission_callback();
+ }
+
+ public function tf_enquiry_permission_callback( WP_REST_Request $request ) {
+ return $this->tf_admin_vendor_permission_callback();
+ }
+
+ protected function tf_admin_vendor_permission_callback() {
+ $current_user_id = get_current_user_id();
+
+ if (
+ is_user_logged_in()
+ && (
+ $this->user_has_role( $current_user_id, 'administrator' )
+ || $this->user_has_role( $current_user_id, 'tf_manager' )
+ || $this->user_has_role( $current_user_id, 'tf_vendor' )
+ )
+ ) {
+ return true;
+ }
+
+ return new WP_Error( 'rest_forbidden', esc_html__( 'You are not authorized to access this endpoint.', 'tourfic' ), array( 'status' => 403 ) );
+ }
+
+ protected function tf_current_user_can_manage_records() {
+ $current_user_id = get_current_user_id();
+
+ return $this->user_has_role( $current_user_id, 'administrator' ) || $this->user_has_role( $current_user_id, 'tf_manager' );
+ }
+
+ protected function tf_current_user_can_access_user( $user_id ) {
+ $user_id = absint( $user_id );
+ $current_user_id = get_current_user_id();
+
+ if ( empty( $user_id ) || empty( $current_user_id ) ) {
+ return false;
+ }
+
+ if ( $user_id === $current_user_id ) {
+ return true;
+ }
+
+ return $this->tf_current_user_can_manage_records()
+ || current_user_can( 'list_users' )
+ || current_user_can( 'edit_user', $user_id );
+ }
+
+ protected function tf_current_user_can_manage_vendor_record( $post_id = 0, $author_id = 0 ) {
+ $current_user_id = get_current_user_id();
+
+ if ( ! $this->user_has_role( $current_user_id, 'tf_vendor' ) ) {
+ return false;
+ }
+
+ if ( ! empty( $author_id ) && absint( $author_id ) === $current_user_id ) {
+ return true;
+ }
+
+ return ! empty( $post_id ) && absint( get_post_field( 'post_author', absint( $post_id ) ) ) === $current_user_id;
+ }
+
+ protected function tf_current_user_can_access_order( $order ) {
+ if ( $this->tf_current_user_can_manage_records() ) {
+ return true;
+ }
+
+ return ! empty( $order['post_id'] ) && $this->tf_current_user_can_manage_vendor_record( $order['post_id'] );
+ }
+
+ protected function tf_current_user_can_access_enquiry( $enquiry ) {
+ if ( $this->tf_current_user_can_manage_records() ) {
+ return true;
+ }
+
+ $post_id = ! empty( $enquiry['post_id'] ) ? $enquiry['post_id'] : 0;
+ $author_id = ! empty( $enquiry['author_id'] ) ? $enquiry['author_id'] : 0;
+
+ return $this->tf_current_user_can_manage_vendor_record( $post_id, $author_id );
+ }
+
+ protected function tf_order_post_types() {
+ return array_keys( $this->tf_order_post_type_map() );
+ }
+
+ protected function tf_order_post_type_map() {
+ return array(
+ 'hotel' => 'hotel',
+ 'tf_hotel' => 'hotel',
+ 'tour' => 'tour',
+ 'tf_tours' => 'tour',
+ 'apartment' => 'apartment',
+ 'tf_apartment' => 'apartment',
+ 'car' => 'car',
+ 'tf_carrental' => 'car',
+ );
+ }
+
+ protected function tf_normalize_order_post_type( $post_type ) {
+ $post_type = sanitize_key( $post_type );
+ $post_map = $this->tf_order_post_type_map();
+
+ return ! empty( $post_map[ $post_type ] ) ? $post_map[ $post_type ] : $post_type;
+ }
+
+ protected function tf_enquiry_post_types() {
+ return array( 'tf_hotel', 'tf_tours', 'tf_apartment' );
+ }
+
+ protected function tf_checkinout_statuses() {
+ return array( 'in', 'out', 'not' );
+ }
+
+ protected function tf_order_statuses() {
+ return array( 'pending', 'processing', 'on-hold', 'completed', 'cancelled', 'refunded', 'failed', 'trash' );
+ }
+
+ protected function tf_enquiry_status_filters() {
+ return array( 'read', 'unread', 'replied', 'responded', 'not-replied', 'not-responded' );
+ }
+
+ protected function tf_validate_allowed_param( WP_REST_Request $request, $param, $allowed, $required = false ) {
+ $value = $request->get_param( $param );
+
+ if ( '' === $value || null === $value ) {
+ if ( $required ) {
+ return new WP_Error(
+ 'tf_rest_invalid_param',
+ sprintf( esc_html__( '%s is required.', 'tourfic' ), esc_html( $param ) ),
+ array( 'status' => 400 )
+ );
+ }
+
+ return '';
+ }
+
+ if ( ! is_scalar( $value ) ) {
+ return new WP_Error(
+ 'tf_rest_invalid_param',
+ sprintf( esc_html__( 'Invalid %s value.', 'tourfic' ), esc_html( $param ) ),
+ array( 'status' => 400 )
+ );
+ }
+
+ $value = sanitize_key( $value );
+ if ( ! in_array( $value, $allowed, true ) ) {
+ return new WP_Error(
+ 'tf_rest_invalid_param',
+ sprintf( esc_html__( 'Invalid %s value.', 'tourfic' ), esc_html( $param ) ),
+ array( 'status' => 400 )
+ );
+ }
+
+ return $value;
+ }
+
+ protected function tf_get_rest_absint_param( WP_REST_Request $request, $param ) {
+ $value = $request->get_param( $param );
+
+ if ( '' === $value || null === $value ) {
+ return 0;
+ }
+
+ if ( ! is_scalar( $value ) || ! is_numeric( $value ) ) {
+ return new WP_Error(
+ 'tf_rest_invalid_param',
+ sprintf( esc_html__( 'Invalid %s value.', 'tourfic' ), esc_html( $param ) ),
+ array( 'status' => 400 )
+ );
+ }
+
+ $value = absint( $value );
+ if ( empty( $value ) ) {
+ return new WP_Error(
+ 'tf_rest_invalid_param',
+ sprintf( esc_html__( 'Invalid %s value.', 'tourfic' ), esc_html( $param ) ),
+ array( 'status' => 400 )
+ );
+ }
+
+ return $value;
+ }
+
static function convert_to_wp_timezone($date_string, $format = 'Y-m-d H:i:s') {
$timezone = wp_timezone();
@@ -168,4 +366,4 @@
}
}
-TF_Rest_API::get_instance();
No newline at end of file
+TF_Rest_API::get_instance();
--- a/tourfic/inc/Classes/REST_API/TF_User_Rest_API.php
+++ b/tourfic/inc/Classes/REST_API/TF_User_Rest_API.php
@@ -93,6 +93,10 @@
return new WP_Error( 'rest_forbidden', esc_html__( 'You are not authorized to access this endpoint.' ), array( 'status' => 403 ) );
}
+ if ( ! $this->tf_current_user_can_access_user( $user->ID ) ) {
+ return new WP_Error( 'rest_forbidden', esc_html__( 'You are not authorized to access this user.', 'tourfic' ), array( 'status' => 403 ) );
+ }
+
$user_data = array(
'id' => $user->ID,
'username' => $user->user_login,
@@ -173,9 +177,14 @@
* @auther Foysal
*/
public function tf_user_bookings( $request ) {
- $current_user_id = $request->get_param( 'user_id' ) ? $request->get_param( 'user_id' ) : get_current_user_id();
- $booking_type = $request->get_param( 'booking_type' ) ? $request->get_param( 'booking_type' ) : 'all';
+ $current_user_id = get_current_user_id();
+ $booking_type = $request->get_param( 'booking_type' ) ? sanitize_key( $request->get_param( 'booking_type' ) ) : 'all';
$disable_services = ! empty( Helper::tfopt( 'disable-services' ) ) ? Helper::tfopt( 'disable-services' ) : [];
+ $user_hotel_orders_result = array();
+
+ if ( ! in_array( $booking_type, array( 'all', 'hotel', 'tour', 'apartment', 'car' ), true ) ) {
+ return new WP_Error( 'tf_rest_invalid_param', esc_html__( 'Invalid booking_type value.', 'tourfic' ), array( 'status' => 400 ) );
+ }
if ( $this->user_has_role( $current_user_id, 'customer' ) ) {
@@ -239,7 +248,7 @@
* @auther Foysal
*/
public function tf_user_wishlist( $request ) {
- $current_user_id = $request->get_param( 'user_id' ) ? $request->get_param( 'user_id' ) : get_current_user_id();
+ $current_user_id = get_current_user_id();
$remove = $request->get_param( 'remove' ) ? $request->get_param( 'remove' ) : false;
$postId = $request->get_param( 'post_id' ) ? $request->get_param( 'post_id' ) : '';
$wishlist_data = array();
--- a/tourfic/inc/Classes/Tour/Tour.php
+++ b/tourfic/inc/Classes/Tour/Tour.php
@@ -1059,7 +1059,7 @@
<input type='text' name='check-in-out-date' id='check-in-out-date' class='tf-field tours-check-in-out' onkeypress="return false;" placeholder='<?php esc_html_e( "Select Date", "tourfic" ); ?>'
value='' required/>
</div>
- <?php if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && $tour_type != 'fixed' ) { ?>
+ <?php if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && $tour_type != 'fixed' && 'package' !== $pricing_rule ) { ?>
<div class="tf-field-group check-in-time-div tf-mt-8" id="" style="display: none;">
<i class="fa-regular fa-clock"></i>
<select class="tf-field" name="check-in-time" id="" style="min-width: 100px;"></select>
@@ -1225,7 +1225,7 @@
<input type="text" class="tf-field tours-check-in-out" placeholder="<?php esc_html_e( "Select Date", "tourfic" ); ?>" value="" required/>
</div>
- <?php if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && $tour_type != 'fixed' ) { ?>
+ <?php if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && $tour_type != 'fixed' && 'package' !== $pricing_rule ) { ?>
<div class="tf-bottom-booking-field check-in-time-div" id="" style="display: none;">
<div class="tf-bottom-booking-field-icon">
<i class="ri-time-line"></i>
@@ -1266,7 +1266,7 @@
<input type='text' name='check-in-out-date' id='check-in-out-date' class='tf-field tours-check-in-out' onkeypress="return false;" placeholder='<?php esc_html_e( "Select Date", "tourfic" ); ?>'
value='' required/>
</div>
- <?php if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && $tour_type != 'fixed') { ?>
+ <?php if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && $tour_type != 'fixed' && 'package' !== $pricing_rule ) { ?>
<div class="tf-field-group check-in-time-div tf-mt-8 tf-field-calander" id="" style="display: none;">
<i class="fa-regular fa-clock"></i>
<select class="tf-field" name="check-in-time" id="" style="min-width: 100px;"></select>
@@ -1454,7 +1454,7 @@
<input type="text" class="tf-field tours-check-in-out" placeholder="<?php esc_html_e( "Select Date", "tourfic" ); ?>" value="" required/>
</div>
- <?php if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && $tour_type != 'fixed' && !empty($allowed_times)) { ?>
+ <?php if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && $tour_type != 'fixed' && 'package' !== $pricing_rule && !empty($allowed_times)) { ?>
<div class="tf-bottom-booking-field check-in-time-div" id="" style="display: none;">
<select class="tf-field" name="check-in-time" id=""></select>
</div>
@@ -1623,7 +1623,7 @@
<input type="text" class="tf-field tours-check-in-out" placeholder="<?php esc_html_e( "Select Date", "tourfic" ); ?>" value="" required/>
</div>
- <?php if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && $tour_type != 'fixed' && !empty($allowed_times)) { ?>
+ <?php if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && $tour_type != 'fixed' && 'package' !== $pricing_rule && !empty($allowed_times)) { ?>
<div class="tf-bottom-booking-field check-in-time-div" id="" style="display: none;">
<select class="tf-field" name="check-in-time" id=""></select>
</div>
@@ -1850,7 +1850,7 @@
</label>
</div>
- <?php if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && $tour_type != 'fixed' ) { ?>
+ <?php if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && $tour_type != 'fixed' && 'package' !== $pricing_rule ) { ?>
<div class='tf_form-row check-in-time-div' id="" style="display: none;">
<label class='tf_label-row'>
<div class='tf_form-inner'>
@@ -1998,12 +1998,14 @@
$tour_extras = unserialize( $tour_extras_unserial );
}
- $traveller_info_coll_global = function_exists( 'is_tf_pro' ) && is_tf_pro() && ! empty( Helper::tfopt( 'disable_traveller_info' ) ) ? Helper::tfopt( 'disable_traveller_info' ) : '';
-
- $traveller_info_coll = function_exists( 'is_tf_pro' ) && is_tf_pro() && ! empty( $meta['tour-traveler-info'] ) ? $meta['tour-traveler-info'] : $traveller_info_coll_global;
+ $traveller_info_coll = function_exists( 'tf_tour_is_traveler_info_enabled' ) ? tf_tour_is_traveler_info_enabled( $meta ) : false;
$tf_booking_by = ! empty( $meta['booking-by'] ) ? $meta['booking-by'] : 1;
$pricing_type = function_exists( 'is_tf_pro' ) && is_tf_pro() && ! empty( $meta['pricing'] ) ? $meta['pricing'] : '';
$package_pricing = function_exists( 'is_tf_pro' ) && is_tf_pro() && ! empty( $meta['package_pricing'] ) ? $meta['package_pricing'] : '';
+ $booking_info_step = ! empty( $traveller_info_coll ) ? 4 : 3;
+ if ( empty( $traveller_info_coll ) && $pricing_type == 'package' && $package_pricing && empty( $tour_extras ) ) {
+ $booking_info_step = 2;
+ }
$active_steps = [];
if( ($pricing_type!='package' || empty($package_pricing)) && empty( $tour_extras ) && empty( $traveller_info_coll ) && 3 != $tf_booking_by ){ ?>
<li class="tf-booking-step tf-booking-step-1 active">
@@ -2033,9 +2035,9 @@
<?php }
$tf_booking_by = ! empty( $meta['booking-by'] ) ? $meta['booking-by'] : 1;
if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && 3 == $tf_booking_by ) {
- $active_steps[4] = 4;
+ $active_steps[ $booking_info_step ] = $booking_info_step;
?>
- <li class="tf-booking-step tf-booking-step-<?php echo ($pricing_type!='package' || empty( $package_pricing )) && empty( $tour_extras ) && empty( $traveller_info_coll ) ? esc_attr( "3" ) : esc_attr( "4" ); ?> <?php echo ($pricing_type!='package' || empty( $package_pricing )) && empty( $tour_extras ) && empty( $traveller_info_coll ) ? esc_attr( 'active' ) : ''; ?>">
+ <li class="tf-booking-step tf-booking-step-<?php echo esc_attr( $booking_info_step ); ?> <?php echo ($pricing_type!='package' || empty( $package_pricing )) && empty( $tour_extras ) && empty( $traveller_info_coll ) ? esc_attr( 'active' ) : ''; ?>">
<i class="ri-calendar-check-line"></i> <?php echo esc_html__( "Booking info", "tourfic" ); ?>
</li>
<?php } ?>
@@ -2241,7 +2243,7 @@
?>
<!-- Popup Booking Confirmation -->
- <div class="tf-booking-content tf-booking-content-<?php echo ($pricing_type!='package' || empty( $package_pricing )) && empty( $tour_extras ) && empty( $traveller_info_coll ) ? esc_attr( "3" ) : esc_attr( "4" ); ?> <?php echo ($pricing_type!='package' || empty( $package_pricing )) && empty( $tour_extras ) && empty( $traveller_info_coll ) ? esc_attr( 'show' ) : ''; ?>">
+ <div class="tf-booking-content tf-booking-content-<?php echo esc_attr( $booking_info_step ); ?> <?php echo ($pricing_type!='package' || empty( $package_pricing )) && empty( $tour_extras ) && empty( $traveller_info_coll ) ? esc_attr( 'show' ) : ''; ?>">
<p><?php echo esc_html( $traveler_details_text ); ?></p>
<div class="tf-booking-content-traveller">
<div class="tf-single-tour-traveller">
@@ -2453,10 +2455,10 @@
if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && 3 == $tf_booking_by ) {
?>
<!-- Popup Booking Confirmation -->
- <div class="tf-control-pagination tf-pagination-content-<?php echo ($pricing_type!='package' || empty( $package_pricing )) && empty( $tour_extras ) && empty( $traveller_info_coll ) ? esc_attr( "3" ) : esc_attr( "4" ); ?> <?php echo ($pricing_type!='package' || empty( $package_pricing )) && empty( $tour_extras ) && empty( $traveller_info_coll ) ? esc_attr( 'show' ) : ''; ?>">
+ <div class="tf-control-pagination tf-pagination-content-<?php echo esc_attr( $booking_info_step ); ?> <?php echo ($pricing_type!='package' || empty( $package_pricing )) && empty( $tour_extras ) && empty( $traveller_info_coll ) ? esc_attr( 'show' ) : ''; ?>">
<?php
- if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && ( $tour_extras || $traveller_info_coll ) ) { ?>
- <a href="#" class="tf-back-control tf-step-back" data-step="4"><i class="fa fa-angle-left"></i><?php echo esc_html__( "Back", "tourfic" ); ?></a>
+ if ( function_exists( 'is_tf_pro' ) && is_tf_pro() && ( $tour_extras || $traveller_info_coll || ( $pricing_type == 'package' && $package_pricing ) ) ) { ?>
+ <a href="#" class="tf-back-control tf-step-back" data-step="<?php echo esc_attr( $booking_info_step ); ?>"><i class="fa fa-angle-left"></i><?php echo esc_html__( "Back", "tourfic" ); ?></a>
<?php } ?>
<button type="submit" class="tf-book-confirm-error tf_btn"><?php echo esc_html__( "Continue", "tourfic" ); ?></button>
</div>
@@ -4127,7 +4129,7 @@
// Tour date
$tour_date = ! empty( $_POST['check_in_date'] ) ? sanitize_text_field( $_POST['check_in_date'] ) : '';
$tour_time = isset( $_POST['check_in_time'] ) ? sanitize_text_field( $_POST['check_in_time'] ) : null;
- $selectedPackage = ! empty( $_POST['selectedPackage'] ) ? sanitize_text_field( wp_unslash( $_POST['selectedPackage'] ) ) : '';
+ $selectedPackage = isset( $_POST['selectedPackage'] ) ? sanitize_text_field( wp_unslash( $_POST['selectedPackage'] ) ) : '';
// var_dump($tour_time);
$post_id = isset( $_POST['post_id'] ) ? intval( sanitize_text_field( $_POST['post_id'] ) ) : '';
@@ -4138,6 +4140,8 @@
$disable_child_price = ! empty( $meta['disable_child_price'] ) ? $meta['disable_child_price'] : false;
$disable_infant_price = ! empty( $meta['disable_infant_price'] ) ? $meta['disable_infant_price'] : false;
$tf_package_pricing = ! empty( $meta['package_pricing'] ) ? $meta['package_pricing'] : '';
+ $default_min_people = ! empty( $meta['min_person'] ) ? absint( $meta['min_person'] ) : 0;
+ $default_max_people = ! empty( $meta['max_person'] ) ? absint( $meta['max_person'] ) : 0;
/**
* If fixed is selected but pro is not activated
@@ -4210,8 +4214,8 @@
$start_date = ! empty( $matched_availability['check_in'] ) ? $matched_availability['check_in'] : '';
$end_date = ! empty( $matched_availability['check_out'] ) ? $matched_availability['check_out'] : '';
- $min_people = ! empty( $matched_availability['min_person'] ) ? $matched_availability['min_person'] : '';
- $max_people = ! empty( $matched_availability['max_person'] ) ? $matched_availability['max_person'] : '';
+ $min_people = ! empty( $matched_availability['min_person'] ) ? $matched_availability['min_person'] : $default_min_people;
+ $max_people = ! empty( $matched_availability['max_person'] ) ? $matched_availability['max_person'] : $default_max_people;
$tf_tour_booking_limit = ! empty( $matched_availability['max_capacity'] ) ? $matched_availability['max_capacity'] : 0;
// Fixed tour maximum capacity limit
@@ -4267,8 +4271,8 @@
// $pricing_rule = ! empty( $matched_availability['pricing_type'] ) ? $matched_availability['pricing_type'] : '';
- $min_people = ! empty( $matched_availability['min_person'] ) ? $matched_availability['min_person'] : '';
- $max_people = ! empty( $matched_availability['max_person'] ) ? $matched_availability['max_person'] : '';
+ $min_people = ! empty( $matched_availability['min_person'] ) ? $matched_availability['min_person'] : $default_min_people;
+ $max_people = ! empty( $matched_availability['max_person'] ) ? $matched_availability['max_person'] : $default_max_people;
$allowed_times_field = ! empty( $matched_availability['allowed_time'] ) ? $matched_availability['allowed_time'] : [''];
@@ -4422,8 +4426,8 @@
// frontend selected date value
$front_date = strtotime( str_replace( '/', '-', $tour_date ) );
// Backend continuous min/max people values
- $min_people = ! empty( $matched_availability['min_person'] ) ? $matched_availability['min_person'] : '';
- $max_people = ! empty( $matched_availability['max_person'] ) ? $matched_availability['max_person'] : '';
+ $min_people = ! empty( $matched_availability['min_person'] ) ? $matched_availability['min_person'] : $default_min_people;
+ $max_people = ! empty( $matched_availability['max_person'] ) ? $matched_availability['max_person'] : $default_max_people;
/* translators: %s: minimum number of people */
$min_text = sprintf( _n( '%s person', '%s people', $min_people, 'tourfic' ), $min_people );
/* translators: %s: maximum number of people */
@@ -4794,7 +4798,8 @@
}
- $traveller_info_fields = ! empty( Helper::tfopt( 'without-payment-field' ) ) ? Helper::tf_data_types( Helper::tfopt( 'without-payment-field' ) ) : '';
+ $traveller_info_coll = function_exists( 'tf_tour_is_traveler_info_enabled' ) ? tf_tour_is_traveler_info_enabled( $meta ) : false;
+ $traveller_info_fields = ! empty( $traveller_info_coll ) && ! empty( Helper::tfopt( 'without-payment-field' ) ) ? Helper::tf_data_types( Helper::tfopt( 'without-payment-field' ) ) : '';
$response['traveller_info'] = '';
$response['traveller_summery'] = '';
@@ -4928,10 +4933,10 @@
$passenger_type_map = function_exists( 'tf_tour_get_passenger_type_map' ) ? tf_tour_get_passenger_type_map( $adults, $children, $infant ) : array();
- if ( 'single' === $traveler_info_collection_mode ) {
+ if ( ! empty( $traveller_info_coll ) && 'single' === $traveler_info_collection_mode ) {
$single_passenger_type = ! empty( $passenger_type_map[1] ) ? $passenger_type_map[1] : 'adult';
$response['traveller_info'] .= $render_traveller_block( 1, esc_html__( 'Traveler Information', 'tourfic' ), $single_passenger_type, esc_html__( 'Traveler', 'tourfic' ) );
- } else {
+ } elseif ( ! empty( $traveller_info_coll ) ) {
$traveller_groups = array(
'adult' => array(
'title' => esc_html__( 'Adults', 'tourfic' ),
--- a/tourfic/inc/Core/Enquiry.php
+++ b/tourfic/inc/Core/Enquiry.php
@@ -717,25 +717,35 @@
global $wpdb;
$enquiry_data = array();
- $tf_filter_query = "";
+ $where = array( 'post_type = %s' );
+ $values = array( sanitize_key( $post_type ) );
+
if ( $post_id ) {
- $tf_filter_query .= " AND post_id = '$post_id'";
+ $where[] = 'post_id = %d';
+ $values[] = absint( $post_id );
}
if( !empty($status) ) {
+ $status = sanitize_key( $status );
if( $status == 'not-replied') {
- $tf_filter_query .= sprintf(' AND enquiry_status != "%s"', 'replied' );
+ $where[] = 'enquiry_status != %s';
+ $values[] = 'replied';
} elseif( $status == 'not-responded') {
- $tf_filter_query .= sprintf(' AND enquiry_status != "%s"', 'responded' );
+ $where[] = 'enquiry_status != %s';
+ $values[] = 'responded';
} else {
- $tf_filter_query .= sprintf(' AND enquiry_status = "%s"', $status );
+ $where[] = 'enquiry_status = %s';
+ $values[] = $status;
}
}
+ $query_limit = '';
if( !empty( $offset ) && !empty( $per_page ) ) {
- $tf_filter_query .= sprintf(' LIMIT %d, %d', $offset, $per_page);
+ $query_limit = ' LIMIT %d, %d';
+ $values[] = absint( $offset );
+ $values[] = absint( $per_page );
}
- $results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tf_enquiry_data WHERE post_type = %s {$tf_filter_query} ORDER BY id DESC", $post_type ), ARRAY_A );
+ $results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tf_enquiry_data WHERE " . implode( ' AND ', $where ) . " ORDER BY id DESC{$query_limit}", $values ), ARRAY_A );
if( !empty($results) ) {
foreach( $results as $result ) {
@@ -1270,4 +1280,4 @@
}
}
-}
No newline at end of file
+}
--- a/tourfic/