AnonSec Team
Server IP : 10.131.40.8  /  Your IP : 216.73.216.37
Web Server : Apache
System : Linux webd008.cluster131.gra.hosting.ovh.net 5.15.167-ovh-vps-grsec-zfs-classid #1 SMP Tue Sep 17 08:14:20 UTC 2024 x86_64
User : ludmqhh ( 137773)
PHP Version : 8.4.10
Disable Function : _dyuweyrj4,_dyuweyrj4r,dl
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON
Directory (0705) :  /home/ludmqhh/www/hotel-forum/wp-content/plugins/wp-hotelier/includes/

[  Home  ][  C0mmand  ][  Upload File  ]

Current File : /home/ludmqhh/www/hotel-forum/wp-content/plugins/wp-hotelier/includes/class-htl-room.php
<?php
/**
 * Room Class.
 *
 * @author   Benito Lopez <hello@lopezb.com>
 * @category Class
 * @package  Hotelier/Classes
 * @version  2.7.1
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}

if ( ! class_exists( 'HTL_Room' ) ) :

/**
 * HTL_Room Class
 */
class HTL_Room {
	/**
	 * The room (post) ID.
	 *
	 * @var int
	 */
	public $id = 0;

	/**
	 * $post Stores post data
	 *
	 * @var $post WP_Post
	 */
	public $post = null;

	/**
	 * Get things going
	 */
	public function __construct( $room ) {
		if ( is_numeric( $room ) ) {
			$this->id   = absint( $room );
			$this->post = get_post( $this->id );
		} elseif ( $room instanceof HTL_Room ) {
			$this->id   = absint( $room->id );
			$this->post = $room->post;
		} elseif ( isset( $room->ID ) ) {
			$this->id   = absint( $room->ID );
			$this->post = $room;
		}
	}

	/**
	 * __get function.
	 *
	 * @since 2.2
	 */
	public function __get( $key ) {
		$value = get_post_meta( $this->id, '_' . $key, true );

		if ( in_array( $key, array( 'max_guests' ) ) ) {
			$value = $value ? $value : 1;

		} elseif ( 'max_children' === $key ) {
			$value = $value ? $value : 0;

		}

		if ( ! empty( $value ) ) {
			$this->$key = $value;
		}

		return $value;
	}

	/**
	 * Get the room's post data.
	 *
	 * @return object
	 */
	public function get_post_data() {
		return $this->post;
	}

	/**
	 * Returns whether or not the room post exists.
	 *
	 * @return bool
	 */
	public function exists() {
		return empty( $this->post ) ? false : true;
	}

	/**
	 * Returns whether or not the room is visible.
	 *
	 * @param bool $show_out_of_stock
	 *
	 * @return bool
	 */
	public function is_visible( $show_out_of_stock = false ) {
		$visible = true;

		if ( ! $this->post ) {
			$visible = false;

		// Published/private
		} elseif ( $this->post->post_status !== 'publish' ) {
			$visible = false;

		// Out of stock visibility
		} elseif ( $this->get_stock_rooms() === 0 ) {
			$visible = $show_out_of_stock ? true : false;
		}

		return apply_filters( 'hotelier_room_is_visible', $visible, $this->id );
	}

	/**
	 * Get the title of the post.
	 *
	 * @return string
	 */
	public function get_title() {
		$title = $this->post->post_title;

		return apply_filters( 'hotelier_room_title', $title, $this );
	}

	/**
	 * Get room gallery ids.
	 *
	 * @return array
	 */
	public function get_gallery_attachment_ids() {
		return apply_filters( 'hotelier_room_gallery_attachment_ids', array_filter( (array) explode( ',', $this->room_image_gallery ) ), $this );
	}

	/**
	 * Returns the room's type.
	 *
	 * @return string type
	 */
	public function get_room_type() {
		return $this->room_type;
	}

	/**
	 * Returns the room's type formatted.
	 *
	 * @return string type
	 */
	public function get_room_type_formatted() {
		$room_type_formatted = explode( '_', $this->room_type );

		return ucfirst( $room_type_formatted[ 0 ] );
	}

	/**
	 * Checks if a room is variable.
	 *
	 * @return bool
	 */
	public function is_variable_room() {
		return $this->get_room_type() == 'variable_room' ? true : false;
	}

	/**
	 * Checks if the rate exists on the room_rate taxonomy.
	 *
	 * @param string $rate_name Room rate
	 *
	 * @return bool
	 */
	public function rate_term_exists( $rate_name ) {
		$get_room_rates = get_terms( 'room_rate', 'hide_empty=0' );

		if ( empty( $get_room_rates ) || is_wp_error( $get_room_rates ) ) {
			// room_rate taxonomy empty
			return false;
		}

		$term = term_exists( $rate_name, 'room_rate' );

		if ( $term !== 0 && $term !== null ) {
			return true;
		} else {
			// term does not exist
			return false;
		}
	}

	/**
	 * Returns the number of allowed guests.
	 *
	 * @return int max_guests
	 */
	public function get_max_guests() {
		return absint( apply_filters( 'hotelier_get_max_guests', $this->max_guests, $this->id ) );
	}

	/**
	 * Returns the number of allowed children.
	 *
	 * @return int max_children
	 */
	public function get_max_children() {
		return absint( apply_filters( 'hotelier_get_max_children', $this->max_children, $this->id ) );
	}

	/**
	 * Returns the total number of rooms available in the structure.
	 *
	 * @return int stock_rooms
	 */
	public function get_stock_rooms() {
		return absint( apply_filters( 'hotelier_get_stock_rooms', $this->stock_rooms, $this->id ) );
	}

	/**
	 * Returns the number of rooms available on a given date.
	 *
	 * @param string $checkin
	 * @param string $checkout
	 * @param array $exclude
	 * @return int
	 */
	public function get_available_rooms( $checkin, $checkout = false, $exclude = array() ) {
		// Add 1 day to checkin if checkout is not provided
		if ( ! $checkout ) {
			$checkout = new DateTime( $checkin );
			$checkout = $checkout->modify( '+1 day' );
			$checkout = $checkout->format( 'Y-m-d' );
		}

		$reserved_rooms  = $this->get_reserved_rooms( $checkin, $checkout, $exclude );
		$available_rooms = $this->get_stock_rooms() - $reserved_rooms;
		$available_rooms = ( $available_rooms < 0 ) ? 0 : $available_rooms;

		return apply_filters( 'hotelier_get_available_rooms', $available_rooms, $this );
	}

	/**
	 * Get room's required minimum nights
	 *
	 * @return int
	 */
	public function get_min_nights() {
		return apply_filters( 'hotelier_per_room_minimum_nights', htl_get_option( 'booking_minimum_nights', 1 ), $this->id );
	}

	/**
	 * Get room's required maximum nights
	 *
	 * @return int
	 */
	public function get_max_nights() {
		return apply_filters( 'hotelier_per_room_maximum_nights', htl_get_option( 'booking_maximum_nights', 0 ), $this->id );
	}

	/**
	 * Check if the room requires a minimum of nights
	 *
	 * @param string $checkin
	 * @param string $checkout
	 * @return bool
	 */
	public function check_min_nights( $checkin, $checkout ) {
		$checkin               = new DateTime( $checkin );
		$checkout              = new DateTime( $checkout );
		$diff_checkin_checkout = date_diff( $checkin, $checkout )->days;

		$min_nights = $this->get_min_nights();

		$passed_check = true;

		if ( $min_nights && $diff_checkin_checkout < $min_nights ) {
			$passed_check = false;
		}

		$passed_check = apply_filters( 'hotelier_check_min_nights_passed', $passed_check, $checkin, $checkout, $this );

		return $passed_check;
	}

	/**
	 * Check if the room requires a maximum of nights
	 *
	 * @param string $checkin
	 * @param string $checkout
	 * @return bool
	 */
	public function check_max_nights( $checkin, $checkout ) {
		$checkin               = new DateTime( $checkin );
		$checkout              = new DateTime( $checkout );
		$diff_checkin_checkout = date_diff( $checkin, $checkout )->days;

		$max_nights = $this->get_max_nights();

		$passed_check = true;

		if ( $max_nights && $diff_checkin_checkout > $max_nights ) {
			$passed_check = false;
		}

		$passed_check = apply_filters( 'hotelier_check_max_nights_passed', $passed_check, $checkin, $checkout, $this );

		return $passed_check;
	}

	/**
	 * Checks if the room has enough rooms on a given date.
	 *
	 * @param string $checkin
	 * @param string $checkout
	 * @param int $qty
	 * @param array $exclude
	 * @return bool
	 */
	public function has_enough_rooms( $checkin, $checkout, $qty, $exclude = array() ) {
		$qty            = absint( $qty );
		$reserved_rooms = $this->get_reserved_rooms( $checkin, $checkout, $exclude );
		$pending_rooms  = $this->get_pending_rooms();
		$has_enough     = false;

		if ( ( $this->get_stock_rooms() > 0 ) && ( $this->get_stock_rooms() >= ( $reserved_rooms - $pending_rooms + $qty ) ) ) {
			$has_enough = true;
		}

		return apply_filters( 'hotelier_room_has_enough_rooms', $has_enough, $checkin, $checkout, $qty, $this->id );
	}

	/**
	 * Checks if the room is available on a given date.
	 *
	 * @param string $checkin
	 * @param string $checkout
	 * @param int $qty
	 * @param array $exclude
	 * @param bool $force
	 * @return bool
	 */
	public function is_available( $checkin, $checkout = false, $qty = 1, $exclude = array(), $force = false ) {
		$checkout         = $checkout ? $checkout : $checkin;
		$is_available     = false;
		$has_enough_rooms = $this->has_enough_rooms( $checkin, $checkout, $qty, $exclude ) ? true : false;

		if ( $has_enough_rooms && $this->check_min_nights( $checkin, $checkout ) && $this->check_max_nights( $checkin, $checkout ) ) {
			$is_available = true;
		}

		$is_available = apply_filters( 'hotelier_room_is_available', $is_available, $this->id, $checkin, $checkout, $qty, $exclude );

		// When forcing a booking, we want at least the number of rooms to be available
		$is_available = $force && $has_enough_rooms ? true : $is_available;

		return $is_available;
	}

	/**
	 * Checks if the room is available on a given date
	 * and if not, get the reason.
	 *
	 * @param string $checkin
	 * @param string $checkout
	 * @param int $qty
	 * @param array $exclude
	 * @param bool $force
	 * @return array
	 */
	public function is_available_with_reason( $checkin, $checkout = false, $qty = 1, $exclude = array(), $force = false ) {
		$reason           = '';
		$checkout         = $checkout ? $checkout : $checkin;
		$is_available     = false;
		$has_enough_rooms = $this->has_enough_rooms( $checkin, $checkout, $qty, $exclude ) ? true : false;
		$has_min_nights   = $this->check_min_nights( $checkin, $checkout );
		$has_max_nights   = $this->check_max_nights( $checkin, $checkout );

		if ( ! $has_min_nights || ! $has_max_nights ) {
			$min_nights = $this->get_min_nights();
			$max_nights = $this->get_max_nights();
			$reason     = htl_get_room_not_available_min_max_info( $min_nights, $max_nights, $this );
		}

		if ( $has_enough_rooms && $has_min_nights && $has_max_nights ) {
			$is_available = true;
		}

		$is_available = apply_filters( 'hotelier_room_is_available', $is_available, $this->id, $checkin, $checkout, $qty, $exclude );
		$reason       = apply_filters( 'hotelier_room_is_available_reason_text', $reason, $is_available, $this->id, $checkin, $checkout, $qty, $exclude );

		// When forcing a booking, we want at least the number of rooms to be available
		$is_available = $force && $has_enough_rooms ? true : $is_available;

		return array(
			'is_available' => $is_available,
			'reason'       => $reason,
		);
	}

	/**
	 * Gets the count of reserved rooms on a given date.
	 *
	 * @param string $checkin
	 * @param string $checkout
	 * @param array $exclude
	 * @return int
	 */
	public function get_reserved_rooms( $checkin, $checkout, $exclude = array() ) {
		global $wpdb;

		$sql          = $wpdb->prepare( "SELECT room_id, checkin, checkout, rb.reservation_id FROM {$wpdb->prefix}hotelier_rooms_bookings rb, {$wpdb->prefix}hotelier_bookings b WHERE rb.reservation_id = b.reservation_id AND rb.room_id = %d AND (%s < b.checkout AND %s > b.checkin) AND b.status <> 'cancelled' AND b.status <> 'refunded' AND b.status <> 'completed'", $this->id, $checkin, $checkout );
		$reservations = $wpdb->get_results( $sql );

		// Iterate each day to calculate the exact number of reservations
		$checkin              = new DateTime( $checkin );
		$checkout             = new DateTime( $checkout );
		$interval             = new DateInterval( 'P1D' );
		$daterange            = new DatePeriod( $checkin, $interval ,$checkout );
		$reserved_rooms_total = array();

		foreach( $daterange as $date ) {
			$reserved_rooms = 0;

			foreach ( $reservations as $reservation ) {
				if ( is_array( $exclude ) && in_array( $reservation->reservation_id, $exclude ) ) {
					continue;
				}

				$reservation_checkin  = new DateTime( $reservation->checkin );
				$reservation_checkout = new DateTime( $reservation->checkout );

				if ( $date >= $reservation_checkin && $date < $reservation_checkout ) {
					$reserved_rooms++;
				}
			}

			$reserved_rooms_total[] = $reserved_rooms;
		}

		$count = count( $reserved_rooms_total ) > 0 ? max( $reserved_rooms_total ) : 0;

		return apply_filters( 'hotelier_get_reserved_rooms', $count, $this );
	}

	/**
	 * Checks if there are some pending reservations.
	 *
	 * @return int
	 */
	public function get_pending_rooms() {
		global $wpdb;

		$reservation_id = null !== HTL()->session ? absint( HTL()->session->get( 'reservation_awaiting_payment' ) ) : 0;

		if ( ! $reservation_id > 0 ) {
			$count = 0;
		} else {
			$sql      = $wpdb->prepare( "SELECT room_id FROM {$wpdb->prefix}hotelier_rooms_bookings rb, {$wpdb->prefix}hotelier_bookings b WHERE b.status = 'pending' OR b.status = 'failed' AND rb.reservation_id = b.reservation_id AND b.reservation_id = %d AND rb.room_id = %d", $reservation_id, $this->id  );
			$result   = $wpdb->get_results( $sql );
			$count    = count( $result );
		}

		return apply_filters( 'hotelier_get_pending_rooms', $count, $this );
	}

	/**
	 * Returns the room facilities.
	 *
	 * @return string
	 */
	public function get_facilities() {
		$facilities = array();

		// Get room categories
		$terms = get_the_terms( $this->id, 'room_facilities' );

		if ( $terms && ! is_wp_error( $terms ) ) {
			foreach ( $terms as $term ) {
				$facilities[] = $term->name;
			}

			$facilities = implode( ', ', $facilities );
		}

		return $facilities;
	}

	/**
	 * Returns the room's bed size.
	 *
	 * @return string bed_size
	 */
	public function get_bed_size() {
		return $this->bed_size;
	}

	/**
	 * Returns the room's number of beds.
	 *
	 * @return int beds
	 */
	public function get_beds() {
		return absint( $this->beds );
	}

	/**
	 * Returns the room's number of bathrooms.
	 *
	 * @return int bathrooms
	 */
	public function get_bathrooms() {
		return absint( $this->bathrooms );
	}

	/**
	 * Returns the room's size.
	 *
	 * @return string room_size
	 */
	public function get_room_size() {
		return $this->room_size;
	}

	/**
	 * Returns the room's size with unit symbol.
	 *
	 * @return string get_formatted_room_size
	 */
	public function get_formatted_room_size() {
		$formatted_room_size = $this->room_size ? $this->room_size . ' ' . htl_get_option( 'room_size_unit', 'm²' ) : '';

		return apply_filters( 'hotelier_room_size', $formatted_room_size, $this );
	}

	/**
	 * Returns the room's additional details.
	 *
	 * @return string _room_additional_details
	 */
	public function get_additional_details() {
		return $this->room_additional_details;
	}

	/**
	 * Returns the room's price type.
	 *
	 * @return string price_type
	 */
	public function get_price_type() {
		return $this->price_type;
	}

	/**
	 * Checks if the price is per day.
	 *
	 * @return bool
	 */
	public function is_price_per_day() {
		return ( $this->get_price_type() == 'per_day' ) ? true : false;
	}

	/**
	 * Checks if the room has a seasonal price.
	 *
	 * @return bool
	 */
	public function has_seasonal_price() {
		return ( $this->get_price_type() == 'seasonal_price' ) ? true : false;
	}

	/**
	 * Returns the room's regular price.
	 *
	 * @return mixed int price or false if there are none
	 */
	public function get_regular_price( $checkin, $checkout = false ) {
		$checkin   = new DateTime( $checkin );
		$checkout  = $checkout ? new DateTime( $checkout ) : $checkin;
		$interval  = new DateInterval( 'P1D' );
		$daterange = new DatePeriod( $checkin, $interval ,$checkout );

		$price = 0;

		if ( $this->is_price_per_day() ) {
			if ( $this->regular_price_day ) {
				// Different price for each day
				foreach( $daterange as $date ) {

					// 0 (for Sunday) through 6 (for Saturday)
					$day_index = $date->format( 'w' );

					// We need to sum the price of each day
					if ( $this->regular_price_day[ $day_index ] ) {
						$price += $this->regular_price_day[ $day_index ];
					}
				}

			} else {
				// The room has a price per day but empty price
				$price = 0;
			}

		} else {
			// Same price for all days
			foreach( $daterange as $date ) {
				if ( $this->regular_price ) {
					$price += $this->regular_price;
				}
			}
		}

		$price = apply_filters( 'hotelier_get_regular_price', $price, $checkin, $checkout, $this );

		if ( $price > 0 ) {

			return $price;

		} else {

			return false;

		}
	}

	/**
	 * Returns the room's sale price.
	 *
	 * @return mixed int price or false if there are none
	 */
	public function get_sale_price( $checkin, $checkout = false ) {
		$checkin   = new DateTime( $checkin );
		$checkout  = $checkout ? new DateTime( $checkout ) : $checkin;
		$interval  = new DateInterval( 'P1D' );
		$daterange = new DatePeriod( $checkin, $interval ,$checkout );

		$price = 0;

		if ( $this->is_price_per_day() ) {
			if ( $this->sale_price_day ) {
				// Different price for each day
				foreach( $daterange as $date ) {

					// 0 (for Sunday) through 6 (for Saturday)
					$day_index = $date->format( 'w' );

					// We need to sum the price of each day
					if ( $this->sale_price_day[ $day_index ] ) {
						$price += $this->sale_price_day[ $day_index ];
					}
				}

			} else {
				// The room has a price per day but empty price
				$price = 0;
			}

		} else {
			// Same price for all days
			foreach( $daterange as $date ) {
				if ( $this->sale_price ) {
					$price += $this->sale_price;
				}
			}
		}

		$price = apply_filters( 'hotelier_get_sale_price', $price, $checkin, $checkout, $this );

		if ( $price > 0 ) {
			return $price;

		} else {

			return false;

		}
	}

	/**
	 * Returns the room's seasonal price.
	 *
	 * @return mixed int price or false if there are none
	 */
	public function get_seasonal_price( $checkin, $checkout = false ) {
		$checkin   = new DateTime( $checkin );
		$checkout  = $checkout ? new DateTime( $checkout ) : $checkin;

		$interval  = new DateInterval( 'P1D' );
		$daterange = new DatePeriod( $checkin, $interval ,$checkout );

		$price = 0;
		$rules = htl_get_seasonal_prices_schema();

		if ( is_array( $rules ) ) {
			// Reverse the array, last rules have a higher precedence
			$rules = array_reverse( $rules );
		}

		foreach( $daterange as $date ) {
			$curr_date = $date->getTimestamp();

			if ( $rules ) {
				$has_seasonal_price = false;

				foreach ( $rules as $key => $rule ) {
					$begin = new DateTime( $rule[ 'from' ] );
					$end   = new DateTime( $rule[ 'to' ] );

					// Check if the seasonal range repeats every year
					$repeats_every_year = isset( $rule[ 'every_year' ] ) ? true : false;

					if ( $repeats_every_year ) {
						$checkin_year = $checkin->format('Y');
						$begin_year   = $begin->format('Y');
						$years_diff   = $checkin_year - $begin_year;

						// Add 'x' years to the seasonal rule
						if ( $years_diff > 0 ) {
							$begin->add( new DateInterval( 'P' . $years_diff . 'Y' ) );
							$end->add( new DateInterval( 'P' . $years_diff . 'Y' ) );
						}
					}

					if ( $curr_date >= $begin->getTimestamp() && $curr_date <= $end->getTimestamp() ) {

						if ( isset( $this->seasonal_price[ $rule[ 'index' ] ] ) && $this->seasonal_price[ $rule[ 'index' ] ] > 0 ) {
							// Rule found, use seasonal price
							$price += $this->seasonal_price[ $rule[ 'index' ] ];
							$has_seasonal_price = true;

							// Exit
							break;
						}
					}
				}

				if ( ! $has_seasonal_price ) {
					// Rule not found, use default price
					if ( $this->seasonal_base_price ) {
						$price += $this->seasonal_base_price;
					}
				}
			}
		}

		if ( $price > 0 ) {
			return apply_filters( 'hotelier_get_seasonal_price', $price, $this );

		} else {

			return false;

		}
	}

	/**
	 * Returns whether or not the room is on sale.
	 *
	 * @return bool
	 */
	public function is_on_sale( $checkin, $checkout = false ) {
		$checkout   = $checkout ? $checkout : $checkin;
		$is_on_sale = ( ! $this->has_seasonal_price() && $this->get_sale_price( $checkin, $checkout ) && $this->get_regular_price( $checkin, $checkout ) && $this->get_sale_price( $checkin, $checkout ) < $this->get_regular_price( $checkin, $checkout ) ) ? true : false;

		return apply_filters( 'hotelier_room_is_on_sale', $is_on_sale, $checkin, $checkout, $this );
	}

	/**
	 * Returns the room's price.
	 *
	 * @return mixed int price or false if there are none
	 */
	public function get_price( $checkin, $checkout = false, $use_this = false ) {
		$checkout = $checkout ? $checkout : $checkin;

		if ( class_exists( 'HTL_APS_Room' ) && ! $use_this ) {
			$room  = new HTL_APS_Room( $this );
			$price = $room->get_price( $checkin, $checkout );

		} else {

			if ( $this->has_seasonal_price() ) {
				$price = $this->get_seasonal_price( $checkin, $checkout );
			} else if ( $this->is_on_sale( $checkin, $checkout ) ) {
				$price = $this->get_sale_price( $checkin, $checkout );
			} else {
				$price = $this->get_regular_price( $checkin, $checkout );
			}
		}

		return apply_filters( 'hotelier_get_price', $price, $checkin, $checkout, $this );
	}

	/**
	 * Returns the room's price in html format.
	 *
	 * @return string
	 */
	public function get_price_html( $checkin, $checkout, $use_this = false ) {
		if ( class_exists( 'HTL_APS_Room' ) && ! $use_this ) {
			$room = new HTL_APS_Room( $this );

			return $room->get_price_html( $checkin, $checkout );

		} else {
			if ( $this->is_variable_room() ) {
				$variations       = $this->get_room_variations();
				$count_variations = count( $variations );
				$prices           = array();

				for ( $i = 1; $i <= $count_variations; $i++ ) {
					$variation = $this->get_room_variation( $i );

					if ( $variation->get_price( $checkin, $checkout ) ) {
						$prices[] = $variation->get_price( $checkin, $checkout );
					}
				}

				$min_price = false;

				if ( ! empty( $prices ) ) {
					// Get min price of rates
					$min_price = min( $prices ) / 100; // (prices are stored as integers)
				}

				if ( $min_price && $min_price > 0 ) {

					$min_price = sprintf( _x( 'From %s', 'min_price', 'wp-hotelier' ), htl_price( $min_price ) );
					$price     = apply_filters( 'hotelier_get_rate_price_html', $min_price, $this );

				} else {

					$price = apply_filters( 'hotelier_empty_price_html', '', $this );

				}

			} elseif ( $get_price = $this->get_price( $checkin, $checkout ) ) {

				if ( $this->is_on_sale( $checkin, $checkout ) ) {

					$from  = $this->get_regular_price( $checkin, $checkout ) / 100; // (prices are stored as integers)
					$to    = $this->get_sale_price( $checkin, $checkout ) / 100; // (prices are stored as integers)
					$price = sprintf( _x( 'Price: %s', 'price', 'wp-hotelier' ), $this->get_price_html_from_to( $from, $to ) );

					$price = apply_filters( 'hotelier_sale_price_html', $price, $this );

				} else {

					$price = htl_price( $get_price / 100 ); // (prices are stored as integers)
					$price = sprintf( _x( 'Price: %s', 'price', 'wp-hotelier' ), $price );
					$price = apply_filters( 'hotelier_get_price_html', $price, $this );

				}

			} else {

				$price = apply_filters( 'hotelier_empty_price_html', '', $this );

			}

			return $price;
		}
	}

	/**
	 * Functions for getting parts of a price, in html, used by get_price_html.
	 *
	 * @param  string $from String or float to wrap with 'from' text
	 * @param  mixed $to String or float to wrap with 'to' text
	 * @return string
	 */
	public function get_price_html_from_to( $from, $to ) {
		$price = '<del>' . ( ( is_numeric( $from ) ) ? htl_price( $from ) : $from ) . '</del> <ins>' . ( ( is_numeric( $to ) ) ? htl_price( $to ) : $to ) . '</ins>';

		return apply_filters( 'hotelier_get_price_html_from_to', $price, $from, $to, $this );
	}

	/**
	 * Returns the low room's price in html format (variations included).
	 *
	 * @return string
	 */
	public function get_min_price_html( $use_this = false ) {
		if ( class_exists( 'HTL_APS_Room' ) && ! $use_this ) {
			$room = new HTL_APS_Room( $this );

			return $room->get_min_price_html();
		} else {
			$min_price = 0;

			if ( $this->is_variable_room() ) {
				$variations       = $this->get_room_variations();
				$count_variations = count( $variations );
				$prices           = array();

				for ( $i = 1; $i <= $count_variations; $i++ ) {
					$variation = $this->get_room_variation( $i );

					if ( $variation->has_seasonal_price() ) {
						// seasonal price schema
						$rules = htl_get_seasonal_prices_schema();

						// check only the rules stored in the schema
						// we don't allow 'orphan' rules
						foreach ( $rules as $key => $value ) {

							// check if this rule has a price
							if ( isset( $variation->variation[ 'seasonal_price' ][ $key ] ) && $variation->variation[ 'seasonal_price' ][ $key ] > 0 ) {
								$prices[] = $variation->variation[ 'seasonal_price' ][ $key ];
							}
						}

						// get also the default price
						$prices[] = $variation->variation[ 'seasonal_base_price' ];

					} else if  ( $variation->is_price_per_day() ) {
						if ( $variation->variation[ 'sale_price_day' ] ) {
							$variation_min_price = min( $variation->variation[ 'sale_price_day' ] );
							$prices[] = $variation_min_price;

						} elseif ( $variation->variation[ 'price_day' ] ) {
							$variation_min_price = min( $variation->variation[ 'price_day' ] );
							$prices[] = $variation_min_price;
						}

					} else {

						if ( $variation->variation[ 'sale_price' ] ) {
							$variation_min_price = $variation->variation[ 'sale_price' ];
							$prices[] = $variation_min_price;

						} elseif ( $variation->variation[ 'regular_price' ] ) {
							$variation_min_price = $variation->variation[ 'regular_price' ];
							$prices[] = $variation_min_price;
						}
					}
				}

				$min_price = $prices ? min( $prices ) / 100 : 0; // (prices are stored as integers)

				if ( $min_price > 0 ) {
					$min_price = sprintf( __( 'Rates from %s per night', 'wp-hotelier' ), htl_price( $min_price ) );
				} else {
					$min_price = apply_filters( 'hotelier_empty_price_html', '', $this );
				}

			} else {

				if ( $this->has_seasonal_price() ) {
					$prices = array();

					// seasonal price schema
					$rules = htl_get_seasonal_prices_schema();

					if ( is_array( $rules ) ) {
						// get room seasonal prices
						$seasonal_prices = $this->seasonal_price;

						// check only the rules stored in the schema
						// we don't allow 'orphan' rules
						foreach ( $rules as $key => $value ) {

							// check if this rule has a price
							if ( isset( $seasonal_prices[ $key ] ) && $seasonal_prices[ $key ] > 0 ) {
								$prices[] = $seasonal_prices[ $key ];
							}
						}

						// get also the default price
						$prices[] = $this->seasonal_base_price;
					}

					$min_price = $prices ? min( $prices ) / 100 : 0; // (prices are stored as integers)

					if ( $min_price > 0 ) {
						$min_price = sprintf( __( 'Rates from %s per night', 'wp-hotelier' ), htl_price( $min_price ) );
					} else {
						$min_price = apply_filters( 'hotelier_empty_price_html', '', $this );
					}

				} else if ( $this->is_price_per_day() ) {

					if ( $this->sale_price_day ) {
						$min_price = min( $this->sale_price_day ) / 100; // (prices are stored as integers)

					} elseif ( $this->regular_price_day ) {
						$min_price = min( $this->regular_price_day ) / 100; // (prices are stored as integers)
					}

					if ( $min_price > 0 ) {
						$min_price = sprintf( __( 'Rates from %s per night', 'wp-hotelier' ), htl_price( $min_price ) );
					} else {
						$min_price = apply_filters( 'hotelier_empty_price_html', '', $this );
					}

				} else {

					if ( $this->sale_price ) {
						$min_price = $this->sale_price / 100; // (prices are stored as integers)

					} elseif ( $this->regular_price ) {
						$min_price = $this->regular_price / 100; // (prices are stored as integers)
					}

					if ( $min_price > 0 ) {
						if ( $this->sale_price && $this->regular_price ) {
							$from  = $this->regular_price / 100; // (prices are stored as integers)
							$to    = $this->sale_price / 100; // (prices are stored as integers)
							$min_price = sprintf( __( '%s per night', 'wp-hotelier' ), $this->get_price_html_from_to( $from, $to ) );
						} else {
							$min_price = sprintf( __( '%s per night', 'wp-hotelier' ), htl_price( $min_price ) );
						}
					} else {
						$min_price = apply_filters( 'hotelier_empty_price_html', '', $this );
					}
				}

			}

			$min_price = apply_filters( 'hotelier_min_price_html', $min_price, $this );

			return $min_price;
		}
	}

	/**
	 * Returns the room's conditions.
	 *
	 * @return array conditions
	 */
	public function get_room_conditions() {
		$room_conditions = array();

		// we just need a flat array to output the conditions on the front-end
		foreach ( $this->room_conditions as $key => $value ) {
			if ( isset( $value[ 'name' ] ) ) {
				$room_conditions[] = $value[ 'name' ];
			}
		}

		$room_conditions = array_filter( $room_conditions );

		return apply_filters( 'hotelier_room_conditions', $room_conditions, $this );
	}

	/**
	 * Checks if the room has some conditions.
	 *
	 * @return bool
	 */
	public function has_conditions() {
		$room_conditions = $this->get_room_conditions();

		return empty( $room_conditions ) ? false : true;
	}

	/**
	 * Checks if the room requires a deposit.
	 *
	 * @return bool
	 */
	public function needs_deposit() {
		$require_deposit = $this->require_deposit;

		return $require_deposit ? true : false;
	}

	/**
	 * Returns the deposit amount
	 *
	 * @return int percentage of total price
	 */
	public function get_deposit() {
		$percentage = $this->needs_deposit() ? $this->deposit_amount : 0;

		return apply_filters( 'hotelier_room_deposit', $percentage, $this );
	}

	/**
	 * Returns the deposit amount with percentage symbol
	 *
	 * @return int percentage of total price
	 */
	public function get_formatted_deposit() {
		$percentage = $this->get_deposit() . '%';

		return apply_filters( 'hotelier_room_formatted_deposit', $percentage, $this );
	}

	/**
	 * Returns the deposit amount with a more descriptive text
	 *
	 * @return int percentage of total price
	 */
	public function get_long_formatted_deposit() {
		$text = $this->get_deposit() === '100' ? __( 'Requires an immediate payment', 'wp-hotelier' ) : sprintf( __( 'Requires an immediate payment (%s%% of the total)', 'wp-hotelier' ), $this->get_deposit() );

		return apply_filters( 'hotelier_room_long_formatted_deposit', $text, $this );
	}

	/**
	 * Returns the name of the rate
	 *
	 * @param int $rate_id
	 * @return string
	 */
	public function get_rate_name( $rate_id ) {
		$variations = $this->get_room_variations();

		return isset( $variations[ $rate_id ][ 'room_rate' ] ) ? $variations[ $rate_id ][ 'room_rate' ] : '';
	}

	/**
	 * Returns the main room image.
	 *
	 * @param string $size (default: 'room_thumbnail')
	 * @return string
	 */
	public function get_image( $size = 'room_thumbnail', $attr = array() ) {
		if ( has_post_thumbnail( $this->id ) ) {
			$image = get_the_post_thumbnail( $this->id, $size, $attr );
		} else {
			$image = htl_placeholder_img( $size );
		}

		return $image;
	}

	/**
	 * Returns the room categories.
	 *
	 * @param string $sep (default: ', ')
	 * @param string $before (default: '')
	 * @param string $after (default: '')
	 * @return string
	 */
	public function get_categories( $sep = ', ', $before = '', $after = '' ) {
		return get_the_term_list( $this->id, 'room_cat', $before, $sep, $after );
	}

	/**
	 * Returns the room's variations (rates).
	 *
	 * @return array room_variations
	 */
	public function get_room_variations() {
		return array_filter( (array) $this->room_variations );
	}

	/**
	 * Returns a variation from $rate_id.
	 *
	 * @param int $rate_id Rate ID
	 * @return HTL_Room_Variation on success, false on failure
	 */
	public function get_room_variation( $rate_id ) {
		$variations = $this->get_room_variations();
		$variation  = isset( $variations[ $rate_id ] ) ? $variations[ $rate_id ] : false;

		if ( ! $variation ) {
			return false;
		}

		return new HTL_Room_Variation( $variation, $this->id );
	}

	/**
	 * Get an array of category IDs associated to the room.
	 *
	 * @todo Perhaps we may include also the 'room_facilities' taxonomy?
	 * @return array Array of category IDs
	 */
	public function get_terms_related() {
		$cats = array();

		// Get room categories
		$terms = get_the_terms( $this->id, 'room_cat' );

		if ( $terms && ! is_wp_error( $terms ) ) {
			foreach ( $terms as $term ) {
				$cats[] = $term->term_id;
			}
		}

		return $cats;
	}

	/**
	 * Checks if a room is cancellable.
	 *
	 * @return bool
	 */
	public function is_cancellable() {
		$non_cancellable = $this->non_cancellable;

		return $non_cancellable ? false : true;
	}
}

endif;

AnonSec - 2021