PATH:
home
/
letacommog
/
laindinois
/
wp-content
/
plugins
/
woocommerce-bookings
/
includes
/
data-objects
<?php if ( ! defined( 'ABSPATH' ) ) { exit; } if ( version_compare( WC_VERSION, '3.0', '<' ) ) { include_once( WC_BOOKINGS_ABSPATH . 'includes/compatibility/class-legacy-wc-product-booking.php' ); class WC_Product_Booking_Compatibility extends Legacy_WC_Product_Booking {} } else { class WC_Product_Booking_Compatibility extends WC_Product {} } /** * Class for the booking product type. */ class WC_Product_Booking extends WC_Product_Booking_Compatibility { /** * Stores product data. * * @var array */ protected $defaults = array( 'apply_adjacent_buffer' => false, 'availability' => array(), 'block_cost' => 0, 'buffer_period' => 0, 'calendar_display_mode' => 'always_visible', 'cancel_limit_unit' => 'month', 'cancel_limit' => 1, 'check_start_block_only' => false, 'cost' => 0, 'default_date_availability' => '', 'display_cost' => '', 'duration_type' => 'fixed', 'duration_unit' => 'day', 'duration' => 1, 'enable_range_picker' => false, 'first_block_time' => '', 'has_person_cost_multiplier' => false, 'has_person_qty_multiplier' => false, 'has_person_types' => false, 'has_persons' => false, 'has_resources' => false, 'has_restricted_days' => false, 'max_date_unit' => 'month', 'max_date_value' => 12, 'max_duration' => 1, 'max_persons' => 1, 'min_date_unit' => 'day', 'min_date_value' => 0, 'min_duration' => 1, 'min_persons' => 1, 'person_types' => array(), 'pricing' => array(), 'qty' => 1, 'requires_confirmation' => false, 'resource_label' => '', 'resource_base_costs' => array(), 'resource_block_costs' => array(), 'resource_ids' => array(), 'resources_assignment' => '', 'restricted_days' => '', 'user_can_cancel' => false, ); /** * Stores availability rules once loaded. * * @var array */ public $availability_rules = array(); /** * Merges booking product data into the parent object. * * @param int|WC_Product|object $product Product to init. */ public function __construct( $product = 0 ) { $this->data = array_merge( $this->data, $this->defaults ); parent::__construct( $product ); } /** * Get the add to cart button text for the single page * * @return string */ public function single_add_to_cart_text() { return $this->get_requires_confirmation() ? apply_filters( 'woocommerce_booking_single_check_availability_text', __( 'Check Availability', 'woocommerce-bookings' ), $this ) : apply_filters( 'woocommerce_booking_single_add_to_cart_text', __( 'Book now', 'woocommerce-bookings' ), $this ); } /** * Get product price. * * @param string $context * @param bool $filters * @return string */ public function get_price( $context = 'view' ) { $price = get_post_meta( $this->get_id(), '_price', '' ); return $price ? parent::get_price( $context ) : wc_booking_calculated_base_cost( $this ); } /** * Get price HTML * @param string $price * @return string */ public function get_price_html( $price = '' ) { $base_price = wc_booking_calculated_base_cost( $this ); if ( 'incl' === get_option( 'woocommerce_tax_display_shop' ) ) { if ( function_exists( 'wc_get_price_excluding_tax' ) ) { $display_price = wc_get_price_including_tax( $this, array( 'qty' => 1, 'price' => $base_price, ) ); } else { $display_price = $this->get_price_including_tax( 1, $base_price ); } } else { if ( function_exists( 'wc_get_price_excluding_tax' ) ) { $display_price = wc_get_price_excluding_tax( $this, array( 'qty' => 1, 'price' => $base_price, ) ); } else { $display_price = $this->get_price_excluding_tax( 1, $base_price ); } } $display_price_suffix = wc_price( apply_filters( 'woocommerce_product_get_price', $display_price, $this ) ) . $this->get_price_suffix(); $original_price_suffix = wc_price( $display_price ) . $this->get_price_suffix(); if ( $original_price_suffix !== $display_price_suffix ) { $price_html = "<del>{$original_price_suffix}</del><ins>{$display_price_suffix}</ins>"; } elseif ( $display_price ) { if ( $this->has_additional_costs() || $this->get_display_cost() ) { /* translators: 1: display price */ $price_html = sprintf( __( 'From: %s', 'woocommerce-bookings' ), wc_price( $display_price ) ) . $this->get_price_suffix(); } else { $price_html = wc_price( $display_price ) . $this->get_price_suffix(); } } elseif ( ! $this->has_additional_costs() ) { $price_html = __( 'Free', 'woocommerce-bookings' ); } else { $price_html = ''; } return apply_filters( 'woocommerce_get_price_html', $price_html, $this ); } /** * Get internal type. * * @return string */ public function get_type() { return 'booking'; } /* |-------------------------------------------------------------------------- | WC 3.0 Product Type Options functions | | WooCommerce 3.0 will call this function when determining if | the product type boxes are checked. | | This ensures forward compatibility if the data source is no longer post-meta |-------------------------------------------------------------------------- */ /** * @since 1.10.0 * @return bool */ public function is_wc_booking_has_persons() { return $this->has_persons(); } /** * @since 1.10.0 * @return bool */ public function is_wc_booking_has_resources() { return $this->has_resources(); } /* |-------------------------------------------------------------------------- | CRUD Getters and setters. |-------------------------------------------------------------------------- */ /** * Get the qty available to book per block. * * @param string $context * @return integer */ public function get_qty( $context = 'view' ) { return $this->get_prop( 'qty', $context ); } /** * Set qty. * * @param integer $value */ public function set_qty( $value ) { $this->set_prop( 'qty', absint( $value ) ); } /** * Get has_persons. * * @param string $context * @return boolean */ public function get_has_persons( $context = 'view' ) { return $this->get_prop( 'has_persons', $context ); } /** * Set has_persons. * @param boolean $value */ public function set_has_persons( $value ) { $this->set_prop( 'has_persons', $value ); } /** * Get has_person_types. * * @param string $context * @return boolean */ public function get_has_person_types( $context = 'view' ) { return $this->get_prop( 'has_person_types', $context ); } /** * Set has_person_types. * * @param boolean $value */ public function set_has_person_types( $value ) { $this->set_prop( 'has_person_types', wc_bookings_string_to_bool( $value ) ); } /** * Get has_person_qty_multiplier. * * @param string $context * @return boolean */ public function get_has_person_qty_multiplier( $context = 'view' ) { return $this->get_prop( 'has_person_qty_multiplier', $context ); } /** * Set has_person_qty_multiplier. * * @param boolean $value */ public function set_has_person_qty_multiplier( $value ) { $this->set_prop( 'has_person_qty_multiplier', wc_bookings_string_to_bool( $value ) ); } /** * Get min_persons. * * @param string $context * @return integer */ public function get_min_persons( $context = 'view' ) { return $this->get_prop( 'min_persons', $context ); } /** * Set min_persons. * * @param integer $value */ public function set_min_persons( $value ) { $this->set_prop( 'min_persons', absint( $value ) ); } /** * Get max_persons. * * @param string $context * @return integer */ public function get_max_persons( $context = 'view' ) { return $this->get_prop( 'max_persons', $context ); } /** * Set max_persons. * * @param integer $value */ public function set_max_persons( $value ) { $this->set_prop( 'max_persons', absint( $value ) ); } /** * Get has_resources. * * @param string $context * @return boolean */ public function get_has_resources( $context = 'view' ) { return $this->get_prop( 'has_resources', $context ); } /** * Set has_resources. * * @param boolean $value */ public function set_has_resources( $value ) { $this->set_prop( 'has_resources', $value ); } /** * Get duration. * * @param string $context * @return integer */ public function get_duration( $context = 'view' ) { return $this->get_prop( 'duration', $context ); } /** * Set duration. * * @param integer $value */ public function set_duration( $value ) { $this->set_prop( 'duration', absint( $value ) ); } /** * Get duration_unit. * * @param string $context * @return string */ public function get_duration_unit( $context = 'view' ) { $value = $this->get_prop( 'duration_unit', $context ); if ( 'view' === $context ) { $value = apply_filters( 'woocommerce_bookings_get_duration_unit', $value, $this ); } return $value; } /** * Set duration_unit. * * @param string $value */ public function set_duration_unit( $value ) { $this->set_prop( 'duration_unit', (string) $value ); } /** * Get duration_type. * * @param string $context * @return string */ public function get_duration_type( $context = 'view' ) { return $this->get_prop( 'duration_type', $context ); } /** * Set duration_type. * * @param string $value */ public function set_duration_type( $value ) { $this->set_prop( 'duration_type', (string) $value ); } /** * Get min_duration. * * @param string $context * @return integer */ public function get_min_duration( $context = 'view' ) { return $this->get_prop( 'min_duration', $context ); } /** * Set min_duration. * * @param integer $value */ public function set_min_duration( $value ) { $this->set_prop( 'min_duration', absint( $value ) ); } /** * Get max_duration. * * @param string $context * @return integer */ public function get_max_duration( $context = 'view' ) { return $this->get_prop( 'max_duration', $context ); } /** * Set max_duration. * * @param integer $value */ public function set_max_duration( $value ) { $this->set_prop( 'max_duration', absint( $value ) ); } /** * Get enable_range_picker. * * @param string $context * @return boolean */ public function get_enable_range_picker( $context = 'view' ) { return $this->get_prop( 'enable_range_picker', $context ); } /** * Set enable_range_picker. * * @param boolean $value */ public function set_enable_range_picker( $value ) { $this->set_prop( 'enable_range_picker', wc_bookings_string_to_bool( $value ) ); } /** * Get display_cost. * * @param string $context * @return string */ public function get_display_cost( $context = 'view' ) { return $this->get_prop( 'display_cost', $context ); } /** * Set display_cost. * * @param string $value */ public function set_display_cost( $value ) { $this->set_prop( 'display_cost', (string) $value ); } /** * Get base_cost. * * @param string $context * @return float * @deprecated since 1.10.9 */ public function get_base_cost( $context = 'view' ) { return $this->get_block_cost( $context ); } /** * Set base_cost. * * @param float $value * @deprecated since 1.10.9 */ public function set_base_cost( $value ) { $this->set_block_cost( $value ); } /** * Get block_cost. * * @param string $context * @return float */ public function get_block_cost( $context = 'view' ) { return (float) $this->get_prop( 'block_cost', $context ); } /** * Set block_cost. * * @param float $value */ public function set_block_cost( $value ) { $this->set_prop( 'block_cost', wc_format_decimal( $value ) ); } /** * Get cost. * * @param string $context * @return float */ public function get_cost( $context = 'view' ) { return (float) $this->get_prop( 'cost', $context ); } /** * Set cost. * * @param float $value */ public function set_cost( $value ) { $this->set_prop( 'cost', wc_format_decimal( $value ) ); } /** * Get has_person_cost_multiplier. * * @param string $context * @return boolean */ public function get_has_person_cost_multiplier( $context = 'view' ) { return $this->get_prop( 'has_person_cost_multiplier', $context ); } /** * Set has_person_cost_multiplier. * * @param boolean $value */ public function set_has_person_cost_multiplier( $value ) { $this->set_prop( 'has_person_cost_multiplier', wc_bookings_string_to_bool( $value ) ); } /** * Get has_additional_costs. * * @param string $context * @return boolean */ public function get_has_additional_costs( $context = 'view' ) { return $this->get_prop( 'has_additional_costs', $context ); } /** * Set has_additional_costs. * * @param boolean $value */ public function set_has_additional_costs( $value ) { $this->set_prop( 'has_additional_costs', wc_bookings_string_to_bool( $value ) ); } /** * Get min_date_value. * * @param string $context * @return integer */ public function get_min_date_value( $context = 'view' ) { return $this->get_prop( 'min_date_value', $context ); } /** * Set min_date_value. * * @param integer $value */ public function set_min_date_value( $value ) { $this->set_prop( 'min_date_value', absint( $value ) ); } /** * Get min_date_unit. * * @param string $context * @return string */ public function get_min_date_unit( $context = 'view' ) { return $this->get_prop( 'min_date_unit', $context ); } /** * Set min_date_unit. * * @param string $value */ public function set_min_date_unit( $value ) { $this->set_prop( 'min_date_unit', (string) $value ); } /** * Get max_date_value. * * @param string $context * @return integer */ public function get_max_date_value( $context = 'view' ) { return $this->get_prop( 'max_date_value', $context ); } /** * Set max_date_value. * * @param integer $value */ public function set_max_date_value( $value ) { $this->set_prop( 'max_date_value', absint( $value ) ); } /** * Get max_date_unit. * * @param string $context * @return string */ public function get_max_date_unit( $context = 'view' ) { return $this->get_prop( 'max_date_unit', $context ); } /** * Set max_date_unit. * * @param string $value */ public function set_max_date_unit( $value ) { $this->set_prop( 'max_date_unit', (string) $value ); } /** * Get resources_assignment. * * @param string $context * @return string */ public function get_resources_assignment( $context = 'view' ) { return $this->get_prop( 'resources_assignment', $context ); } /** * Set resources_assignment. * * @param string $value */ public function set_resources_assignment( $value ) { $this->set_prop( 'resources_assignment', (string) $value ); } /** * Get default_date_availability. * * @param string $context * @return string */ public function get_default_date_availability( $context = 'view' ) { return $this->get_prop( 'default_date_availability', $context ); } /** * Set default_date_availability. * * @param string $value */ public function set_default_date_availability( $value ) { $this->set_prop( 'default_date_availability', (string) $value ); } /** * Get requires_confirmation. * * @param string $context * @return boolean */ public function get_requires_confirmation( $context = 'view' ) { return $this->get_prop( 'requires_confirmation', $context ); } /** * Set requires_confirmation. * * @param boolean $value */ public function set_requires_confirmation( $value ) { $this->set_prop( 'requires_confirmation', wc_bookings_string_to_bool( $value ) ); } /** * Get user_can_cancel. * * @param string $context * @return boolean */ public function get_user_can_cancel( $context = 'view' ) { return $this->get_prop( 'user_can_cancel', $context ); } /** * Set user_can_cancel. * * @param boolean $value */ public function set_user_can_cancel( $value ) { $this->set_prop( 'user_can_cancel', wc_bookings_string_to_bool( $value ) ); } /** * Get buffer_period. * * @param string $context * @return integer */ public function get_buffer_period( $context = 'view' ) { return $this->get_prop( 'buffer_period', $context ); } /** * Set buffer_period. * * @param integer $value */ public function set_buffer_period( $value ) { $this->set_prop( 'buffer_period', absint( $value ) ); } /** * Get check_start_block_only. * * @param string $context * @return bool */ public function get_check_start_block_only( $context = 'view' ) { return $this->get_prop( 'check_start_block_only', $context ); } /** * Set check_start_block_only. * * @param bool $value */ public function set_check_start_block_only( $value ) { $this->set_prop( 'check_start_block_only', wc_bookings_string_to_bool( $value ) ); } /** * Get calendar_display_mode. * * @param string $context * @return string */ public function get_calendar_display_mode( $context = 'view' ) { return $this->get_prop( 'calendar_display_mode', $context ); } /** * Set calendar_display_mode. * * @param string $value */ public function set_calendar_display_mode( $value ) { $value = in_array( $value, array( '', 'always_visible' ) ) ? $value : ''; $this->set_prop( 'calendar_display_mode', $value ); } /** * Get cancel_limit. * * @param string $context * @return integer */ public function get_cancel_limit( $context = 'view' ) { return $this->get_prop( 'cancel_limit', $context ); } /** * Set cancel_limit. * * @param integer $value */ public function set_cancel_limit( $value ) { $this->set_prop( 'cancel_limit', max( 1, absint( $value ) ) ); } /** * Get cancel_limit_unit. * * @param string $context * @return string */ public function get_cancel_limit_unit( $context = 'view' ) { return $this->get_prop( 'cancel_limit_unit', $context ); } /** * Set cancel_limit_unit. * * @param string $value */ public function set_cancel_limit_unit( $value ) { $value = in_array( $value, array( 'month', 'day', 'hour', 'minute' ) ) ? $value : 'month'; $this->set_prop( 'cancel_limit_unit', $value ); } /** * Get first_block_time. * * @param string $context * @return string */ public function get_first_block_time( $context = 'view' ) { return $this->get_prop( 'first_block_time', $context ); } /** * Set first_block_time. * * @param string $value */ public function set_first_block_time( $value ) { $this->set_prop( 'first_block_time', $value ); } /** * Get resource_label. * * @param string $context * @return string */ public function get_resource_label( $context = 'view' ) { return $this->get_prop( 'resource_label', $context ); } /** * Set resource_label. * * @param string $value */ public function set_resource_label( $value ) { $this->set_prop( 'resource_label', $value ); } /** * Get apply_adjacent_buffer. * * @param string $context * @return bool */ public function get_apply_adjacent_buffer( $context = 'view' ) { return $this->get_prop( 'apply_adjacent_buffer', $context ); } /** * Set apply_adjacent_buffer. * * @param bool $value */ public function set_apply_adjacent_buffer( $value ) { $this->set_prop( 'apply_adjacent_buffer', wc_bookings_string_to_bool( $value ) ); } /** * Get availability. * * @param string $context * @return array */ public function get_availability( $context = 'view' ) { return $this->get_prop( 'availability', $context ); } /** * Set availability. * * @param array $value */ public function set_availability( $value ) { $this->set_prop( 'availability', (array) $value ); } /** * Get pricing_rules. * * @param string $context * @return array */ public function get_pricing( $context = 'view' ) { return $this->get_prop( 'pricing', $context ); } /** * Set pricing_rules. * * @param array $value */ public function set_pricing( $value ) { $this->set_prop( 'pricing', (array) $value ); } /** * Get person_types. * * @param string $context * @return array */ public function get_person_types( $context = 'view' ) { return $this->get_prop( 'person_types', $context ); } /** * Set person_types. * * @param array $value */ public function set_person_types( $value ) { $this->set_prop( 'person_types', (array) $value ); } /** * Add a Person_Type ID to the existing list of ids. * @param WC_Product_Booking_Person_Type $person_type */ public function add_person_type( $person_type ) { $person_types = $this->get_person_types(); $person_types[] = $person_type; $this->set_person_types( $person_types ); } /** * Get resource_ids. * * @param string $context * @return array */ public function get_resource_ids( $context = 'view' ) { return $this->get_prop( 'resource_ids', $context ); } /** * Set resource_ids. * * @param array $value */ public function set_resource_ids( $value ) { $this->set_prop( 'resource_ids', wp_parse_id_list( (array) $value ) ); } /** * Add resource ID to the existing list of ids. * @param int $id */ public function add_resource_id( $id ) { $ids = $this->get_resource_ids(); $ids[] = $id; $this->set_resource_ids( $ids ); } /** * Get resource_base_costs. * * @param string $context * @return array */ public function get_resource_base_costs( $context = 'view' ) { return $this->get_prop( 'resource_base_costs', $context ); } /** * Set resource_base_costs. * * @param array $value */ public function set_resource_base_costs( $value ) { $this->set_prop( 'resource_base_costs', (array) $value ); } /** * Get resource_block_costs. * * @param string $context * @return array */ public function get_resource_block_costs( $context = 'view' ) { return $this->get_prop( 'resource_block_costs', $context ); } /** * Set resource_block_costs. * * @param array $value */ public function set_resource_block_costs( $value ) { $this->set_prop( 'resource_block_costs', (array) $value ); } /** * Get has_restricted_days. * * @param string $context * @return string */ public function get_has_restricted_days( $context = 'view' ) { return $this->get_prop( 'has_restricted_days', $context ); } /** * Set has_restricted_days. * * @param string $value */ public function set_has_restricted_days( $value ) { $this->set_prop( 'has_restricted_days', $value ); } /** * Get restricted_days. * * @param string $context * @return string */ public function get_restricted_days( $context = 'view' ) { return $this->get_prop( 'restricted_days', $context ); } /** * Set restricted_days. * * @param string $value */ public function set_restricted_days( $value ) { $this->set_prop( 'restricted_days', $value ); } /* |-------------------------------------------------------------------------- | Conditionals |-------------------------------------------------------------------------- | | Conditionals functions which return true or false. */ /** * If this product class is a skeleton/place holder class (used for booking addons). * * @return boolean */ public function is_skeleton() { return false; } /** * If this product class is an addon for bookings. * * @return boolean */ public function is_bookings_addon() { return false; } /** * Extension/plugin/add-on name for the booking addon this product refers to. * * @return string */ public function bookings_addon_title() { return ''; } /** * We want to sell bookings one at a time. * * @return boolean */ public function is_sold_individually() { return true; } /** * Bookings can always be purchased regardless of price. * * @return boolean */ public function is_purchasable() { $status = is_callable( array( $this, 'get_status' ) ) ? $this->get_status() : $this->post->post_status; return apply_filters( 'woocommerce_is_purchasable', $this->exists() && ( 'publish' === $status || current_user_can( 'edit_post', $this->get_id() ) ), $this ); } /** * See if this booking product has persons enabled. * * @return boolean */ public function has_persons() { return $this->get_has_persons(); } /** * See if this booking product has person types enabled. * * @return boolean */ public function has_person_types() { return $this->get_has_person_types(); } /** * See if persons affect the booked qty. * * @return boolean */ public function has_person_qty_multiplier() { return $this->get_has_persons() && $this->get_has_person_qty_multiplier(); } /** * See if this booking product has resources enabled. * * @return boolean */ public function has_resources() { return $this->get_has_resources(); } /** * Test duration type. * * @param string $type * @return boolean */ public function is_duration_type( $type ) { return $this->get_duration_type() === $type; } /** * is_range_picker_enabled. * * @return bool */ public function is_range_picker_enabled() { return $this->get_enable_range_picker() && 'day' === $this->get_duration_unit() && $this->is_duration_type( 'customer' ) && 1 === $this->get_duration(); } /** * Return if booking has extra costs. * * @return bool */ public function has_additional_costs() { if ( $this->get_has_additional_costs() ) { return true; } if ( $this->has_persons() && $this->get_has_person_cost_multiplier() ) { return true; } if ( $this->get_has_person_types() ) { $person_types = $this->get_person_types(); foreach ( $person_types as $person_type ) { if ( $person_type->get_cost() || $person_type->get_block_cost() ) { return true; } } } if ( $this->has_resources() ) { $resources = $this->get_resources(); foreach ( $resources as $resource ) { if ( $resource->get_base_cost() || $resource->get_block_cost() ) { return true; } } } if ( $this->get_min_duration() > 1 && $this->get_block_cost() ) { return true; } if ( $this->is_duration_type( 'customer' ) ) { return true; } $costs = $this->get_costs(); if ( ! empty( $costs ) ) { return true; } return false; } /** * How resources are assigned. * * @param string $type * @return boolean customer or automatic */ public function is_resource_assignment_type( $type ) { return $this->get_resources_assignment() === $type; } /** * Checks if a product requires confirmation. * * @return bool */ public function requires_confirmation() { return apply_filters( 'woocommerce_booking_requires_confirmation', $this->get_requires_confirmation(), $this ); } /** * See if the booking can be cancelled. * * @return boolean */ public function can_be_cancelled() { return apply_filters( 'woocommerce_booking_user_can_cancel', $this->get_user_can_cancel(), $this ); } /** * See if dates are by default bookable. * * @return bool */ public function get_default_availability() { return 'available' === $this->get_default_date_availability(); } /** * See if this booking product has restricted days. * * @return boolean */ public function has_restricted_days() { return $this->get_has_restricted_days(); } /* |-------------------------------------------------------------------------- | Non-CRUD getters |-------------------------------------------------------------------------- */ /** * Gets all formatted cost rules. * * @return array */ public function get_costs() { return WC_Product_Booking_Rule_Manager::process_cost_rules( $this->get_pricing() ); } /** * Get Min date. * * @return array|bool */ public function get_min_date() { $min_date['value'] = apply_filters( 'woocommerce_bookings_min_date_value', $this->get_min_date_value(), $this->get_id() ); $min_date['unit'] = $this->get_min_date_unit() ? apply_filters( 'woocommerce_bookings_min_date_unit', $this->get_min_date_unit(), $this->get_id() ) : 'month'; return $min_date; } /** * Get max date. * * @return array */ public function get_max_date() { $max_date['value'] = $this->get_max_date_value() ? apply_filters( 'woocommerce_bookings_max_date_value', $this->get_max_date_value(), $this->get_id() ) : 1; $max_date['unit'] = $this->get_max_date_unit() ? apply_filters( 'woocommerce_bookings_max_date_unit', $this->get_max_date_unit(), $this->get_id() ) : 'month'; return $max_date; } /** * Get max year. * * @return int */ private function get_max_year() { $max_date = $this->get_max_date(); $max_date_timestamp = strtotime( "+{$max_date['value']} {$max_date['unit']}" ); $max_year = date( 'Y', $max_date_timestamp ); if ( ! $max_year ) { $max_year = date( 'Y' ); } return $max_year; } /** * Get the Product buffer period setting. * * @since 1.9.13 introduced. * @return mixed $buffer_period */ public function get_buffer_period_minutes() { $buffer_period = $this->get_buffer_period(); // If exists always treat booking_period in minutes. if ( ! empty( $buffer_period ) && 'hour' === $this->get_duration_unit() ) { $buffer_period = $buffer_period * 60; } return $buffer_period; } /** * Get available quantity. * * @since 1.9.13 introduced. * @param $resource_id * @return bool|int */ public function get_available_quantity( $resource_id = '' ) { $booking_resource = $resource_id ? $this->get_resource( $resource_id ) : null; $available_qty = $this->has_resources() && $booking_resource && $booking_resource->has_qty() ? $booking_resource->get_qty() : $this->get_qty(); return apply_filters( 'woocommerce_bookings_get_available_quantity', $available_qty, $this, $booking_resource ); } /** * Get person type by ID. * * @param int $id * @return WP_POST object */ public function get_person( $id ) { $id = absint( $id ); $persons = $this->get_person_types(); if ( isset( $persons[ $id ] ) ) { return $persons[ $id ]; } return false; } /** * Get resource by ID. * * @param int $id * @return WC_Product_Booking_Resource object */ public function get_resource( $id ) { global $wpdb; if ( is_a( $id, 'WC_Product_Booking_Resource' ) ) { return $id; } $id = absint( $id ); if ( $id ) { $transient_name = 'book_res_' . md5( http_build_query( array( $id, $this->get_id(), WC_Cache_Helper::get_transient_version( 'bookings' ) ) ) ); $relationship_id = get_transient( $transient_name ); if ( false === $relationship_id ) { $relationship_id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->prefix}wc_booking_relationships WHERE product_id = %d AND resource_id = %d", $this->get_id(), $id ) ); set_transient( $transient_name, $relationship_id, DAY_IN_SECONDS * 30 ); } $resource = get_post( $id ); if ( 'bookable_resource' == is_object( $resource ) && $resource->post_type && 0 < $relationship_id ) { return new WC_Product_Booking_Resource( $resource, $this->get_id() ); } } return false; } /** * Get resources objects. * * @param WC_Product * * @return array( * type WC_Product_Booking_Resource * ) */ public function get_resources() { $product_resources = array(); foreach ( $this->get_resource_ids() as $resource_id ) { $product_resources[] = new WC_Product_Booking_Resource( $resource_id, $this->get_id() ); } return $product_resources; } /** * Get rules in order of `override power`. The higher the index the higher the override power. Element at index 4 will * override element at index 2. * * Within priority the rules will be ordered top to bottom. * * @return array availability_rules { * @type $resource_id => array { * * The $order_index depicts the levels override. `0` Is the lowest. `1` overrides `0` and `2` overrides `1`. * e.g. If monday is set to available in `1` and not available in `2` the results should be that Monday is * NOT available because `2` overrides `1`. * $order_index corresponds to override power. The higher the element index the higher the override power. * @type $order_index => array { * @type string $type The type of range selected in admin. * @type string $range Depending on the type this depicts what range and if available or not. * @type integer $priority * @type string $level Global, Product or Resource * @type integer $order The index for the order set in admin. * } * } */ public function get_availability_rules( $for_resource = 0 ) { if ( empty( $this->availability_rules[ $for_resource ] ) ) { $this->availability_rules[ $for_resource ] = array(); // Rule types $all_resource_rules = array(); $product_rules = $this->get_availability(); $global_rules = get_option( 'wc_global_booking_availability', array() ); // Get availability of each resource - no resource has been chosen yet if ( $this->has_resources() && ! $for_resource ) { $resources = $this->get_resources(); // If all blocks are available by default, we should not hide days if we don't know which resource is going to be used. if ( ! $this->get_default_availability() ) { foreach ( $resources as $resource ) { $temp_resource_rules = $resource->get_availability(); $resource_rules = array(); // add resource id to each rule foreach ( $temp_resource_rules as $index => $rule ) { $resource_rules[ $index ] = $rule; $resource_rules[ $index ]['resource_id'] = $resource->get_id(); } $all_resource_rules = array_merge( $all_resource_rules, $resource_rules ); } } } elseif ( $for_resource ) { $resource = new WC_Product_Booking_Resource( $for_resource ); $temp_resource_rules = $resource->get_availability(); // add resource to each rule foreach ( $temp_resource_rules as $index => $rule ) { $all_resource_rules[ $index ] = $rule; $all_resource_rules[ $index ]['resource_id'] = $for_resource; } } // The order that these rules are put into the array are important due to the way that // the rules as processed for overrides. $availability_rules = array_filter( array_merge( WC_Product_Booking_Rule_Manager::process_availability_rules( $all_resource_rules, 'resource' ), WC_Product_Booking_Rule_Manager::process_availability_rules( $product_rules, 'product' ), WC_Product_Booking_Rule_Manager::process_availability_rules( $global_rules, 'global' ) ) ); usort( $availability_rules, array( 'WC_Product_Booking_Rule_Manager', 'sort_rules_callback' ) ); $this->availability_rules[ $for_resource ] = $availability_rules; } return apply_filters( 'woocommerce_booking_get_availability_rules', $this->availability_rules[ $for_resource ], $for_resource, $this ); } /* |-------------------------------------------------------------------------- | Block calculation functions. @todo move to own manager class |-------------------------------------------------------------------------- */ /** * Check the resources availability against all the blocks. * * @param string $start_date * @param string $end_date * @param int $qty * @param WC_Product_Booking_Resource|null $booking_resource * @return string|WP_Error */ public function get_blocks_availability( $start_date, $end_date, $qty, $booking_resource = null ) { $resource_id = isset( $booking_resource ) ? $booking_resource->get_id() : 0; $interval = 'hour' === $this->get_duration_unit() ? $this->get_duration() * 60 : $this->get_duration(); /** * Grab all existing bookings for the date range. * @var array */ if ( in_array( $this->get_duration_unit(), array( 'minute', 'hour' ) ) ) { $midnight = strtotime( 'midnight', $start_date ); $next_day_midnight = strtotime( '+ 1 day', $midnight ); $bookings_for_day = WC_Bookings_Controller::get_bookings_in_date_range( $midnight, $next_day_midnight, $this->has_resources() && $resource_id ? $resource_id : $this->get_id(), true ); $bookings_start_and_end = WC_Bookings_Controller::get_bookings_star_and_end_times( $bookings_for_day ); $blocks = $this->get_blocks_in_range( $midnight, $next_day_midnight, '', $resource_id, $bookings_start_and_end ); $existing_bookings = WC_Bookings_Controller::get_bookings_in_date_range( $start_date + 1, $end_date - 1, $this->has_resources() && $resource_id ? $resource_id : $this->get_id() ); } else { $existing_bookings = WC_Bookings_Controller::get_bookings_in_date_range( $start_date + 1, $end_date - 1, $this->has_resources() && $resource_id ? $resource_id : $this->get_id() ); $blocks = $this->get_blocks_in_range( $start_date, $end_date, '', $resource_id ); } if ( empty( $blocks ) || ! in_array( $start_date, $blocks ) ) { return false; } $blocks = array_unique( array_merge( array_map( function( $booking ) { return $booking->get_start(); }, $existing_bookings ), $blocks ) ); $original_available_qty = $this->get_available_quantity( $booking_resource ); // Check all blocks availability $available_qtys = array(); foreach ( $blocks as $block ) { $available_qty = $original_available_qty; $qty_booked_in_block = 0; foreach ( $existing_bookings as $existing_booking ) { if ( ! $existing_booking->is_within_block( $block, strtotime( "+{$interval} minutes", $block ) ) ) { continue; } $qty_to_add = $this->has_person_qty_multiplier() ? $existing_booking->get_persons_total() : 1; if ( $this->has_resources() ) { if ( $existing_booking->get_resource_id() === absint( $resource_id ) || ( ! $booking_resource->has_qty() && $existing_booking->get_resource() && ! $existing_booking->get_resource()->has_qty() ) ) { $qty_booked_in_block += $qty_to_add; } } else { $qty_booked_in_block += $qty_to_add; } } $available_qty = $available_qty - $qty_booked_in_block; // Remaining places are less than requested qty, return an error. if ( $available_qty < $qty ) { $display_available_qty = $available_qty > 0 ? $available_qty : 0; if ( in_array( $this->get_duration_unit(), array( 'hour', 'minute' ) ) ) { return new WP_Error( 'Error', sprintf( /* translators: 1: available quantity */ _n( 'There is a maximum of %d place remaining', 'There are a maximum of %d places remaining', $display_available_qty , 'woocommerce-bookings' ), $display_available_qty ) ); } elseif ( ! $available_qty ) { return new WP_Error( 'Error', sprintf( /* translators: 1: available quantity 2: booking block date */ _n( 'There is a maximum of %1$d place remaining on %2$s', 'There are a maximum of %1$d places remaining on %2$s', $display_available_qty , 'woocommerce-bookings' ), $display_available_qty, date_i18n( wc_date_format(), $block ) ) ); } else { return new WP_Error( 'Error', sprintf( /* translators: 1: available quantity 2: booking block date */ _n( 'There is a maximum of %1$d place remaining on %2$s', 'There are a maximum of %1$d places remaining on %2$s', $display_available_qty , 'woocommerce-bookings' ), $display_available_qty, date_i18n( wc_date_format(), $block ) ) ); } } $available_qtys[] = $available_qty; } return min( $available_qtys ); } /** * Get an array of blocks within in a specified date range - might be days, might be blocks within days, depending on settings. * * @param $start_date * @param $end_date * @param array $intervals * @param int $resource_id * @param array $booked * * @return array */ public function get_blocks_in_range( $start_date, $end_date, $intervals = array(), $resource_id = 0, $booked = array() ) { $default_interval = 'hour' === $this->get_duration_unit() ? $this->get_duration() * 60 : $this->get_duration(); if ( empty( $intervals ) ) { $intervals = array( $default_interval, $default_interval ); } // if we're only checking against the first block the first interval // should be equal to the standard slot size. if ( $this->get_check_start_block_only() ) { $intervals[0] = $default_interval; } if ( 'day' === $this->get_duration_unit() ) { $blocks_in_range = $this->get_blocks_in_range_for_day( $start_date, $end_date, $resource_id, $booked ); } elseif ( 'month' === $this->get_duration_unit() ) { $blocks_in_range = $this->get_blocks_in_range_for_month( $start_date, $end_date, $resource_id ); } else { $blocks_in_range = $this->get_blocks_in_range_for_hour_or_minutes( $start_date, $end_date, $intervals, $resource_id, $booked ); } return array_unique( $blocks_in_range ); } /** * Get blocks/day blocks in range for day duration unit. * * @param $start_date * @param $end_date * @param integer $resource_id * @param array $bookings { $booking[0] start and $booking[1] end } * * @return array */ public function get_blocks_in_range_for_day( $start_date, $end_date, $resource_id, $bookings ) { $blocks = array(); $available_qty = $this->get_available_quantity( $resource_id ); // get booked days with a counter to specify how many bookings on that date $booked_days_with_count = array(); foreach ( $bookings as $booking ) { $booking_start = $booking[0]; $booking_end = $booking[1]; $current_booking_day = $booking_start; // < because booking end depicts an end of a day and not a start for a new day. while ( $current_booking_day < $booking_end ) { $date = date( 'Y-m-d', $current_booking_day ); if ( isset( $booked_days_with_count[ $date ] ) ) { $booked_days_with_count[ $date ]++; } else { $booked_days_with_count[ $date ] = 1; } $current_booking_day = strtotime( '+1 day', $current_booking_day ); } } // If exists always treat booking_period in minutes. $check_date = $start_date; while ( $check_date <= $end_date ) { if ( WC_Product_Booking_Rule_Manager::check_availability_rules_against_date( $this, $resource_id, $check_date ) ) { $date = date( 'Y-m-d', $check_date ); if ( ! isset( $booked_days_with_count[ $date ] ) || $booked_days_with_count[ $date ] < $available_qty ) { $blocks[] = $check_date; } } // move to next day $check_date = strtotime( '+1 day', $check_date ); } return $blocks; } /** * For months, loop each month in the range to find blocks. * * @param $start_date * @param $end_date * @param integer $resource_id * * @return array */ public function get_blocks_in_range_for_month( $start_date, $end_date, $resource_id ) { $blocks = array(); if ( 'month' !== $this->get_duration_unit() ) { return $blocks; } // Generate a range of blocks for months $from = strtotime( date( 'Y-m-01', $start_date ) ); $to = strtotime( date( 'Y-m-t', $end_date ) ); $month_diff = 0; $month_from = strtotime( '+1 MONTH', $from ); while ( $month_from <= $to ) { $month_from = strtotime( '+1 MONTH', $month_from ); $month_diff ++; } for ( $i = 0; $i <= $month_diff; $i ++ ) { $year = date( 'Y', ( $i ? strtotime( "+ {$i} month", $from ) : $from ) ); $month = date( 'n', ( $i ? strtotime( "+ {$i} month", $from ) : $from ) ); if ( ! WC_Product_Booking_Rule_Manager::check_availability_rules_against_date( $this, $resource_id, strtotime( "{$year}-{$month}-01" ) ) ) { continue; } $blocks[] = strtotime( "+ {$i} month", $from ); } return $blocks; } /** * Get blocks in range for hour or minute duration unit. * For minutes and hours find valid blocks within THIS DAY ($check_date) * * @param $start_date * @param $end_date * @param $intervals * @param integer $resource_id * @param $booked * * @return array */ public function get_blocks_in_range_for_hour_or_minutes( $start_date, $end_date, $intervals, $resource_id, $booked ) { $block_start_times_in_range = array(); $interval = $intervals[0]; $check_date = $start_date; // Setup. $first_block_time_minute = $this->get_first_block_time() ? ( date( 'H', strtotime( $this->get_first_block_time() ) ) * 60 ) + date( 'i', strtotime( $this->get_first_block_time() ) ) : 0; $default_bookable_minutes = $this->get_default_availability() ? range( $first_block_time_minute, ( 1440 + $interval ) ) : array(); $sorted_rules = $this->get_availability_rules( $resource_id ); // Work out what minutes are actually bookable on this day // Get available slot start times. $minutes_booked = $this->get_unavailable_minutes( $booked ); // Looping day by day look for available blocks // using `<=` instead of `<` because https://github.com/woothemes/woocommerce-bookings/issues/325 while ( $check_date <= $end_date ) { $bookable_minutes_for_date = array_merge( $default_bookable_minutes, WC_Product_Booking_Rule_Manager::get_minutes_from_rules( $sorted_rules, $check_date ) ); if ( ! $this->get_default_availability() ) { $bookable_minutes_for_date = $this->apply_first_block_time( $bookable_minutes_for_date, $first_block_time_minute ); } $bookable_start_and_end = $this->get_bookable_minute_start_and_end( $bookable_minutes_for_date ); $blocks = $this->get_bookable_minute_blocks_for_date( $check_date, $start_date, $end_date, $bookable_start_and_end, $intervals, $resource_id, $minutes_booked ); $block_start_times_in_range = array_merge( $blocks, $block_start_times_in_range ); $check_date = strtotime( '+1 day', $check_date );// Move to the next day } return $block_start_times_in_range; } /** * From an array of minutes for a day remove all minutes before first block time. * @since 1.10.0 * * @param array $bookable_minutes * @param int $first_block_minutes * * @return array $minutes */ public function apply_first_block_time( $bookable_minutes, $first_block_minutes ) { $minutes = array(); foreach ( $bookable_minutes as $minute ) { if ( $first_block_minutes <= $minute ) { $minutes[] = $minute; } } return $minutes; } /** * @param array $bookable_minutes * * @return array */ public function get_bookable_minute_start_and_end( $bookable_minutes ) { // Break bookable minutes into sequences - bookings cannot have breaks $bookable_minute_blocks = array(); $bookable_minute_block_from = current( $bookable_minutes ); foreach ( $bookable_minutes as $key => $minute ) { if ( isset( $bookable_minutes[ $key + 1 ] ) ) { // check if there is a break in the sequence if ( $bookable_minutes[ $key + 1 ] - 1 !== $minute ) { $bookable_minute_blocks[] = array( $bookable_minute_block_from, $minute ); $bookable_minute_block_from = $bookable_minutes[ $key + 1 ]; } } else { // We're at the end of the bookable minutes $bookable_minute_blocks[] = array( $bookable_minute_block_from, $minute ); } } // Find blocks that don't span any amount of time (same start + end) foreach ( $bookable_minute_blocks as $key => $bookable_minute_block ) { if ( $bookable_minute_block[0] === $bookable_minute_block[1] ) { $keys_to_remove[] = $key; // track which blocks need removed } } // Remove all of our blocks if ( ! empty( $keys_to_remove ) ) { foreach ( $keys_to_remove as $key ) { unset( $bookable_minute_blocks[ $key ] ); } } return $bookable_minute_blocks; } /** * Return an array of that is not available for booking. * * @since 1.9.13 introduced. * * @param array $booked. Pairs of booked slot start and end times. * @return array $booked_minutes */ public function get_unavailable_minutes( $booked ) { $minutes_not_available = array(); foreach ( $booked as $booked_block ) { for ( $i = $booked_block[0]; $i < $booked_block[1]; $i += 60 ) { array_push( $minutes_not_available, $i ); } } $minutes_not_available = array_count_values( $minutes_not_available ); return $minutes_not_available; } /** * @deprecated sine 1.9.15 * @param $booked * @return mixed */ public function get_unavailable_mintues( $booked ) { _deprecated_function( 'WooCommerce Bookings, use get_unavailable_minutes instead. ', '1.9.15' ); return $this->get_unavailable_minutes( $booked ); } /** * Returns blocks/time slots from a given start and end minute blocks. * * This function take varied inputs but always returns a block array of available slots. * Sometimes it gets the minutes and see if all is available some times it needs to make up the * minutes based on what is booked. * * It uses start and end date to figure things out. * * @since 1.9.13 introduced. * * @param $check_date * @param $start_date * @param $end_date * @param $bookable_ranges * @param $intervals * @param integer $resource_id * @param $minutes_not_available * * @return array */ protected function get_bookable_minute_blocks_for_date( $check_date, $start_date, $end_date, $bookable_ranges, $intervals, $resource_id, $minutes_not_available ) { // blocks as in an array of slots. $slot_start_times $blocks = array(); // boring interval stuff $interval = $intervals[0]; $base_interval = $intervals[1]; // get a time stamp to check from // and get a time stamp to check to $product_min_date = $this->get_min_date(); $product_max_date = $this->get_max_date(); if ( 'hour' === $product_min_date['unit'] ) { // Adding 1 hour to round up to the next whole hour to return what is expected. $product_min_date['value'] = (int) $product_min_date['value'] + 1; } $min_check_from = strtotime( "+{$product_min_date['value']} {$product_min_date['unit']}", current_time( 'timestamp' ) ); $max_check_to = strtotime( "+{$product_max_date['value']} {$product_max_date['unit']}", current_time( 'timestamp' ) ); $min_date = wc_bookings_get_min_timestamp_for_day( $start_date, $product_min_date['value'], $product_min_date['unit'] ); $available_qty = $this->get_available_quantity( $resource_id ); $current_time_stamp = current_time( 'timestamp' ); // if we have a buffer, we will shift all times accordingly by changing the from_interval // e.g. 60 min buffer shifts [ 480, 600, 720 ] into [ 480, 660, 840 ] $buffer = ( $this->get_buffer_period_minutes() ) ? $this->get_buffer_period_minutes() : 0; // For customers using buffers _and_ customer defined time slots, include the interval // in the buffer so that times are shifted accordingly, if we already have a buffer. if ( $buffer && 'customer' == $this->get_duration_type() ) { $buffer += $interval; } // if adjacency is enabled, multiply the buffer by 2 (see https://docs.woocommerce.com/document/creating-a-bookable-product/#section-8) if ( $this->get_apply_adjacent_buffer() ) { $buffer *= 2; } // Loop ranges looking for slots within foreach ( $bookable_ranges as $minutes ) { $range_start = $minutes[0]; $range_end = $minutes[1]; if ( 'hour' === $this->get_duration_unit() ) { // Adding 1 minute to round up to a full hour. $range_end += 1; } $range_start_time = strtotime( "midnight +{$range_start} minutes", $check_date ); $range_end_time = strtotime( "midnight +{$range_end} minutes", $check_date ); $minutes_for_range = $range_end - $range_start; $base_intervals_in_block = floor( $minutes_for_range / $base_interval ); for ( $i = 0; $i <= $base_intervals_in_block; $i ++ ) { $from_interval = $i * ( $base_interval + $buffer ); $to_interval = $from_interval + $interval; $start_time = strtotime( "+{$from_interval} minutes", $range_start_time ); $end_time = strtotime( "+{$to_interval} minutes", $range_start_time ); // Break if start time is after the end date being calculated. if ( $start_time > $end_date ) { break 2; } // Must be in the future if ( $start_time < $min_date || $start_time <= $current_time_stamp ) { continue; } // check that start time falls within minutes // and that the correct quantity if ( isset( $minutes_not_available[ $start_time ] ) && $minutes_not_available[ $start_time ] >= $available_qty ) { continue; } // make sure minute & hour blocks are not past minimum & max booking settings. if ( $end_time < $min_check_from || $start_time > $max_check_to ) { continue; } if ( $end_time > $range_end_time ) { continue; } // make sure slot doesn't start after the end date. if ( $start_time > $end_date ) { continue; } // if default availability is NO/False then it means the minutes we're looking at has already been // generated by using the rules so there's no need to test availability again. if ( $this->get_default_availability() && ! WC_Product_Booking_Rule_Manager::check_availability_rules_against_time( $start_time, $end_time, $resource_id, $this ) ) { continue; } if ( $this->are_all_minutes_in_block_available( $start_time, $end_time, $available_qty ) && ! in_array( $start_time, $blocks ) ) { $blocks[] = $start_time; } } } return $blocks; } /** * Checks all minutes in block for availability. Comparing it with the minutes not available. * * @since 1.9.13 * * @param integer $start_time * @param integer $end_time * @param $available_qty * * @return bool */ public function are_all_minutes_in_block_available( $start_time, $end_time, $available_qty ) { $loop_time = $start_time; while ( $loop_time < $end_time ) { if ( isset( $minutes_not_available[ $loop_time ] ) && $minutes_not_available[ $loop_time ] >= $available_qty ) { return false; } $loop_time = $loop_time + 60; } return true; } /** * Returns available blocks from a range of blocks by looking at existing bookings. * * @param array $args * @option array $blocks The blocks we'll be checking availability for. * @option array $intervals Array containing 2 items; the interval of the block (maybe user set), and the base interval for the block/product. * @option integer $resource_id Resource we're getting blocks for. Falls backs to product as a whole if 0. * @option integer $from The starting date for the set of blocks * @option integer $to Ending date for the set of blocks * * @return array The available blocks array */ public function get_available_blocks( $args ) { $args = wp_parse_args( $args, array( 'blocks' => array(), 'intervals' => array(), 'resource_id' => 0, 'from' => 0, 'to' => 0, ) ); $blocks = $args['blocks']; $intervals = $args['intervals']; $resource_id = $args['resource_id']; $from = $args['from']; $to = $args['to']; if ( empty( $intervals ) ) { $default_interval = 'hour' === $this->get_duration_unit() ? $this->get_duration() * 60 : $this->get_duration(); $intervals = array( $default_interval, $default_interval ); } $interval = absint( $intervals[0] ); $base_interval = absint( $intervals[1] ); $available_blocks = array(); $start_date = $from; if ( empty( $start_date ) ) { $start_date = reset( $blocks ); } $end_date = $to; if ( empty( $end_date ) ) { $end_date = absint( end( $blocks ) ); } if ( ! empty( $blocks ) ) { /** * Grab all existing bookings for the date range. * Extend end_date to end of last block. Note: base_interval is in minutes. * @var array */ $existing_bookings = WC_Bookings_Controller::get_bookings_in_date_range( $start_date, $end_date + ( $base_interval * 60 ), $this->has_resources() && $resource_id ? $resource_id : $this->get_id() ); // Resources booked array. Resource can be a "resource" but also just a booking if it has no resources $resources_booked = array( 0 => array() ); // Loop all existing bookings foreach ( $existing_bookings as $booking ) { $booking_resource_id = $booking->get_resource_id(); // prepare resource array for resource id $resources_booked[ $booking_resource_id ] = isset( $resources_booked[ $booking_resource_id ] ) ? $resources_booked[ $booking_resource_id ] : array(); // if person multiplier is on we should disable stuff where nothing is available $repeat = max( 1, $this->has_person_qty_multiplier() && $booking->has_persons() ? $booking->get_persons_total() : 1 ); for ( $i = 0; $i < $repeat; $i++ ) { array_push( $resources_booked[ $booking_resource_id ], array( $booking->get_start(), $booking->get_end() ) ); } } // Generate arrays that contain information about what blocks to unset if ( $this->has_resources() && ! $resource_id ) { $resources = $this->get_resources(); $available_times = array(); // Loop all resources foreach ( $resources as $resource ) { $times = $this->get_blocks_in_range( $start_date, $end_date, array( $interval, $base_interval ), $resource->ID, isset( $resources_booked[ $resource->ID ] ) ? $resources_booked[ $resource->ID ] : array() ); $available_times = array_merge( $available_times, $times ); } } else { $bookings = isset( $resources_booked[ $resource_id ] ) ? $resources_booked[ $resource_id ] : $resources_booked[0]; $available_times = $this->get_blocks_in_range( $start_date, $end_date, array( $interval, $base_interval ), $resource_id, $bookings ); } // only set available slot values once foreach ( $available_times as $time ) { if ( ! isset( $available_blocks[ $time ] ) ) { $available_blocks[] = $time; } } } sort( $available_blocks ); /** * Filter the available blocks for a product within a given range * * @since 1.9.8 introduced * * @param array $available_blocks * @param WC_Product $bookings_product * @param array $raw_range passed into this function. * @param array $intervals * @param integer $resource_id */ return apply_filters( 'wc_bookings_product_get_available_blocks', array_unique( $available_blocks ), $this, $blocks, $intervals, $resource_id ); } /** * Get the availability of all resources * * @param string $start_date * @param string $end_date * @param integer $qty * @return array| WP_Error */ public function get_all_resources_availability( $start_date, $end_date, $qty ) { $resources = $this->get_resources(); $available_resources = array(); foreach ( $resources as $resource ) { $availability = wc_bookings_get_total_available_bookings_for_range( $this, $start_date, $end_date, $resource->ID, $qty ); if ( $availability && ! is_wp_error( $availability ) ) { $available_resources[ $resource->ID ] = $availability; } } if ( empty( $available_resources ) ) { return new WP_Error( 'Error', __( 'This block cannot be booked.', 'woocommerce-bookings' ) ); } return $available_resources; } /* |-------------------------------------------------------------------------- | Deprecated Methods |-------------------------------------------------------------------------- */ /** * Get the minutes that should be available based on the rules and the date to check. * * The minutes are returned in a range from the start incrementing minutes right up to the last available minute. * * @deprecated since 1.9.14 * @param array $rules * @param int $check_date * * @return array $bookable_minutes */ public function get_minutes_from_rules( $rules, $check_date ) { return WC_Product_Booking_Rule_Manager::get_minutes_from_rules( $rules, $check_date ); } /** * Find the minimum block's timestamp based on settings. * * @deprecated Replaced with wc_bookings_get_min_timestamp_for_day * @return int */ public function get_min_timestamp_for_date( $start_date ) { $min = $this->get_min_date(); return wc_bookings_get_min_timestamp_for_day( $start_date, $min['value'], $min['unit'] ); } /** * Sort rules. * * @deprecated Replaced with WC_Product_Booking_Rule_Manager::sort_rules_callback */ public function rule_override_power_sort( $rule1, $rule2 ) { return WC_Product_Booking_Rule_Manager::sort_rules_callback( $rule1, $rule2 ); } /** * Return an array of resources which can be booked for a defined start/end date * * @deprecated Replaced with wc_bookings_get_block_availability_for_range * @param string $start_date * @param string $end_date * @param string $resource_id * @param integer $qty being booked * @return bool|WP_ERROR if no blocks available, or int count of bookings that can be made, or array of available resources */ public function get_available_bookings( $start_date, $end_date, $resource_id = '', $qty = 1 ) { return wc_bookings_get_total_available_bookings_for_range( $this, $start_date, $end_date, $resource_id, $qty ); } /** * Get existing bookings in a given date range * * @param integer $start_date * @param integer $end_date * @param int $resource_id * @return array */ public function get_bookings_in_date_range( $start_date, $end_date, $resource_id = null ) { return WC_Bookings_Controller::get_bookings_in_date_range( $start_date, $end_date, $this->has_resources() && $resource_id ? $resource_id : $this->get_id() ); } /** * Check a time against the time specific availability rules * * @param string $block_start_time timestamp to check * @param string $block_end_time timestamp to check * @return bool available or not */ public function check_availability_rules_against_time( $block_start_time, $block_end_time, $resource_id ) { return WC_Product_Booking_Rule_Manager::check_availability_rules_against_time( $block_start_time, $block_end_time, $resource_id, $this ); } /** * Check a date against the availability rules * * * @param string $check_date date to check * * @return bool available or not */ public function check_availability_rules_against_date( $check_date, $resource_id ) { return WC_Product_Booking_Rule_Manager::check_availability_rules_against_date( $this, $resource_id, $check_date ); } /** * Find available blocks and return HTML for the user to choose a block. Used in class-wc-bookings-ajax.php * @param array $blocks * @param array $intervals * @param integer $resource_id * @param string $from The starting date for the set of blocks * @return string */ public function get_available_blocks_html( $blocks, $intervals = array(), $resource_id = 0, $from = '' ) { return wc_bookings_available_blocks_html( $this, $blocks, $intervals, $resource_id, $from ); } }
[+]
..
[-] class-wc-product-booking.php
[edit]
[-] class-wc-product-booking-resource.php
[edit]
[-] class-wc-product-booking-person-type.php
[edit]
[-] class-wc-booking.php
[edit]