File: /storage/v4513/tepnot/public_html/wp-content/plugins/dokan-pro/modules/booking/module.php
<?php
namespace WeDevs\DokanPro\Modules\Booking;
use WC_Booking_Data_Store;
use WeDevs\Dokan\Cache;
use WeDevs\Dokan\ProductCategory\Helper;
use WeDevs\DokanPro\Brands\FormFields;
use WeDevs\DokanPro\Modules\Booking\BookingCache;
/**
* Dokan_WC_Booking class
*
* @class Dokan_WC_Booking The class that holds the entire Dokan_WC_Booking plugin
*/
class Module {
/**
* Constructor for the Dokan_WC_Booking class
*
* Sets up all the appropriate hooks and actions
* within our plugin.
*
* @uses register_activation_hook()
* @uses register_deactivation_hook()
* @uses is_admin()
* @uses add_action()
*/
public function __construct() {
// Define all constant
define( 'DOKAN_WC_BOOKING_PLUGIN_VERSION', DOKAN_PRO_PLUGIN_VERSION );
define( 'DOKAN_WC_BOOKING_DIR', dirname( __FILE__ ) );
define( 'DOKAN_WC_BOOKING_PLUGIN_ASSET', plugins_url( 'assets', __FILE__ ) );
define( 'DOKAN_WC_BOOKING_TEMPLATE_PATH', untrailingslashit( plugin_dir_path( __FILE__ ) ) . '/templates/' );
define( 'DOKAN_WC_BOOKING_PLUGIN_URL', untrailingslashit( plugins_url( basename( plugin_dir_path( __FILE__ ) ), basename( __FILE__ ) ) ) );
add_action( 'dokan_activated_module_booking', array( $this, 'activate' ) );
// flush rewrite rules
add_action( 'woocommerce_flush_rewrite_rules', [ $this, 'flush_rewrite_rules' ] );
include_once DOKAN_WC_BOOKING_DIR . '/includes/DependencyNotice.php';
$dependency = new DependencyNotice();
if ( $dependency->is_missing_dependency() ) {
return;
}
add_filter( 'dokan_get_all_cap', array( $this, 'add_capabilities' ) );
add_filter( 'dokan_get_all_cap_labels', array( $this, 'add_caps_labels' ) );
// Loads frontend scripts and styles
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
add_action( 'init', array( $this, 'init_hooks' ) );
// insert booking order into dokan_order_table if it's created by admin
if ( is_admin() ) {
add_action( 'woocommerce_bookings_create_booking_page_add_order_item', 'dokan_sync_insert_order' );
}
add_action( 'dokan_new_product_added', array( $this, 'save_booking_data' ), 10 );
add_action( 'dokan_product_updated', array( $this, 'save_booking_data' ), 10 );
if ( method_exists( \WeDevs\Dokan\Product\Hooks::class, 'save_per_product_commission_options' ) ) {
$product_class = \WeDevs\Dokan\Product\Hooks::class;
} else {
$product_class = \WeDevs\DokanPro\Products::class;
}
// save per product commission for bookable product
add_action( 'woocommerce_process_product_meta_booking', array( $product_class, 'save_per_product_commission_options' ), 20 );
//ajax
add_action( 'wp_ajax_add_new_resource', array( $this, 'add_new_resource' ) );
add_action( 'wp_ajax_nopriv_add_new_resource', array( $this, 'add_new_resource' ) );
add_action( 'wp_ajax_delete_resource', array( $this, 'delete_resource' ) );
add_action( 'wp_ajax_nopriv_delete_resource', array( $this, 'delete_resource' ) );
add_action( 'wp_ajax_dokan_wc_booking_change_status', array( $this, 'change_booking_status' ) );
add_action( 'wp_ajax_noprivdokan_wc_booking_change_status', array( $this, 'change_booking_status' ) );
add_action( 'template_redirect', array( $this, 'update_resource_data' ) );
//booking modification
add_action( 'woocommerce_new_booking', array( $this, 'add_seller_id_meta' ) );
add_action( 'shutdown', array( $this, 'add_seller_manage_cap' ) );
add_action( 'wp_ajax_dokan-wc-booking-confirm', array( $this, 'mark_booking_confirmed' ) );
// booking person type delete
add_action( 'wp_ajax_woocommerce_remove_bookable_person', array( $this, 'dokan_remove_bookable_person' ) );
// booking page filters
add_filter( 'dokan_booking_menu', array( $this, 'dokan_get_bookings_menu' ) );
add_filter( 'dokan_booking_menu_title', array( $this, 'dokan_get_bookings_menu_title' ) );
add_filter( 'dokan_set_template_path', array( $this, 'load_booking_templates' ), 10, 3 );
// insert bookable porduct type
add_filter( 'dokan_get_product_types', array( $this, 'insert_bookable_product_type' ) );
add_filter( 'dokan_get_coupon_types', [ $this, 'add_booking_discount' ] );
add_filter( 'dokan_get_edit_product_url', [ $this, 'modify_edit_product_url' ], 10, 2 );
// Clear addon notices on manual booking creation
add_action( 'template_redirect', [ $this, 'clear_addons_validation_notices' ], 10 );
add_action( 'wp_footer', [ $this, 'load_add_category_modal' ], 10 );
// Init accommodation booking
$this->init_accommodation_booking();
//remove product type filter for booking product list
add_filter( 'dokan_product_listing_filter_args', [ $this, 'remove_product_type_filter' ] );
add_action( 'dokan_product_edit_after_main', [ $this, 'load_linked_product_content' ], 15, 2 );
add_filter( 'dokan_hide_inventory_template', [ $this, 'maybe_disable_inventory_template_for_booking' ], 10, 2 );
// Prevent coupon validation for booking person product.
add_filter( 'dokan_coupon_should_validate', [ $this, 'should_validate_coupon' ], 10, 4 );
add_action( 'woocommerce_after_checkout_validation', [ $this, 'maybe_cancelled_unpaid_booking_from_checkout' ] );
}
/**
* Get plugin path
*
* @since 2.0
*
* @return void
**/
public function plugin_path() {
return untrailingslashit( plugin_dir_path( __FILE__ ) );
}
/**
* Load Dokan Booking templates
*
* @since 2.0
*
* @return void
**/
public function load_booking_templates( $template_path, $template, $args ) {
if ( isset( $args['is_booking'] ) && $args['is_booking'] ) {
return $this->plugin_path() . '/templates';
}
return $template_path;
}
/**
* Insert bookable product type
*
* @param array $types
*
* @return array
*/
public function insert_bookable_product_type( $types ) {
$types['booking'] = __( 'Bookable Product', 'dokan' );
return $types;
}
/**
* Placeholder for activation function
*
* Nothing being called here yet.
*/
public function activate() {
global $wp_roles;
if ( class_exists( 'WP_Roles' ) && ! isset( $wp_roles ) ) {
// @codingStandardsIgnoreLine
$wp_roles = new \WP_Roles();
}
$all_cap = array(
'dokan_view_booking_menu',
'dokan_add_booking_product',
'dokan_edit_booking_product',
'dokan_delete_booking_product',
'dokan_manage_booking_products',
'dokan_manage_booking_calendar',
'dokan_manage_bookings',
'dokan_manage_booking_resource',
);
foreach ( $all_cap as $key => $cap ) {
$wp_roles->add_cap( 'seller', $cap );
$wp_roles->add_cap( 'administrator', $cap );
$wp_roles->add_cap( 'shop_manager', $cap );
}
// flush rewrite rules after plugin is activate
$this->flush_rewrite_rules();
}
/**
* Flush rewrite rules
*
* @since 3.3.1
*
* @return void
*/
public function flush_rewrite_rules() {
add_filter( 'dokan_query_var_filter', array( $this, 'register_booking_queryvar' ) );
dokan()->rewrite->register_rule();
flush_rewrite_rules( true );
}
/**
* Enqueue admin scripts
*
* Allows plugin assets to be loaded.
*
* @uses wp_enqueue_script()
* @uses wp_localize_script()
* @uses wp_enqueue_style
*/
public function enqueue_scripts() {
global $wp, $post;
if ( ! is_admin() && isset( $wp->query_vars['booking'] ) ) {
/**
* All styles goes here
*/
// @codingStandardsIgnoreLine
wp_enqueue_style( 'dokan_wc_booking-styles' );
/**
* All scripts goes here
*/
wp_enqueue_script( 'dokan_wc_booking-scripts' );
// Accommodation scripts
$this->enqueue_accommodation_scripts();
wp_enqueue_script( 'jquery-ui-datepicker' );
wp_enqueue_script( 'jquery-tiptip' );
wp_enqueue_style( 'dokan_wc_bookings_admin_styles' );
wp_enqueue_style( 'woocommerce_admin_styles' );
wp_enqueue_style( 'jquery-ui-style' );
add_filter( 'dokan_dashboard_nav_active', array( $this, 'set_booking_menu_as_active' ) );
wp_enqueue_script( 'wc-enhanced-select' );
$post_id = isset( $post->ID ) ? $post->ID : '';
if ( dokan_is_seller_dashboard() ) {
// @codingStandardsIgnoreLine
if ( isset( $_GET['product_id'] ) ) {
// @codingStandardsIgnoreLine
$post_id = absint( wp_unslash( $_GET['product_id'] ) );
} else {
$post_id = '';
}
}
$params = array(
'i18n_remove_person' => esc_js( __( 'Are you sure you want to remove this person type?', 'dokan' ) ),
'nonce_delete_person' => wp_create_nonce( 'delete-bookable-person' ),
'nonce_add_person' => wp_create_nonce( 'add-bookable-person' ),
'nonce_unlink_person' => wp_create_nonce( 'unlink-bookable-person' ),
'i18n_remove_resource' => esc_js( __( 'Are you sure you want to remove this resource?', 'dokan' ) ),
'nonce_delete_resource' => wp_create_nonce( 'delete-bookable-resource' ),
'nonce_add_resource' => wp_create_nonce( 'add-bookable-resource' ),
'i18n_minutes' => esc_js( __( 'minutes', 'dokan' ) ),
'i18n_days' => esc_js( __( 'days', 'dokan' ) ),
'i18n_new_resource_name' => esc_js( __( 'Enter a name for the new resource', 'dokan' ) ),
'post' => $post_id,
'plugin_url' => WC()->plugin_url(),
'ajax_url' => admin_url( 'admin-ajax.php' ),
'calendar_image' => WC()->plugin_url() . '/assets/images/calendar.png',
);
wp_localize_script( 'wc_bookings_writepanel_js', 'wc_bookings_writepanel_js_params', $params );
wp_enqueue_script( 'wc_bookings_writepanel_js' );
}
// Multi-step category box ui.
if ( ( isset( $wp->query_vars['booking'] ) && $wp->query_vars['booking'] === 'new-product' ) || ( isset( $wp->query_vars['booking'] ) && $wp->query_vars['booking'] === 'edit' ) ) {
Helper::enqueue_and_localize_dokan_multistep_category();
}
}
/**
* Register Scripts
*
* @since 3.7.4
*/
public function register_scripts() {
global $post, $wp_scripts;
[ $suffix, $script_version ] = dokan_get_script_suffix_and_version();
wp_register_style( 'dokan_wc_booking-styles', plugins_url( 'assets/css/style.css', __FILE__ ), [], $script_version );
wp_register_script( 'dokan_wc_booking-scripts', plugins_url( 'assets/js/script.js', __FILE__ ), array( 'jquery' ), $script_version, true );
$accommodation_i18n = \Dokan_Booking_Accommodation_Helper::get_accommodation_booking_i18n_strings();
wp_register_script( 'dokan_accommodation_booking_script', plugins_url( 'assets/js/accommodation.js', __FILE__ ), [ 'jquery', 'dokan-util-helper' ], $script_version, true );
wp_localize_script( 'dokan_accommodation_booking_script', 'dokan_accommodation_i18n', $accommodation_i18n );
wp_register_script( 'wc_bookings_writepanel_js', DOKAN_WC_BOOKING_PLUGIN_ASSET . '/js/writepanel.min.js', array( 'jquery', 'jquery-ui-datepicker' ), $script_version, true );
wp_register_script( 'wc_bookings_settings_js', WC_BOOKINGS_PLUGIN_URL . '/assets/js/settings' . $suffix . '.js', array( 'jquery' ), WC_BOOKINGS_VERSION, true );
$require_dompurify = version_compare( WC()->version, '10.0.2', '>' );
if ( $require_dompurify && ! wp_script_is( 'dompurify', 'registered' ) ) {
wp_register_script( 'dompurify', WC()->plugin_url() . '/assets/js/dompurify/purify' . $suffix . '.js', array(), WC()->version, false );
}
if ( ! wp_script_is( 'jquery-tiptip', 'registered' ) ) {
wp_register_script( 'jquery-tiptip', WC()->plugin_url() . '/assets/js/jquery-tiptip/jquery.tipTip' . $suffix . '.js', $require_dompurify ? [ 'jquery', 'dompurify' ] : [ 'jquery' ], WC()->version, true );
}
wp_register_style( 'dokan_wc_bookings_admin_styles', DOKAN_WC_BOOKING_PLUGIN_ASSET . '/css/admin.css', null, DOKAN_WC_BOOKING_PLUGIN_VERSION );
wp_register_style( 'woocommerce_admin_styles', WC()->plugin_url() . '/assets/css/admin.css', null, WC_VERSION );
// @codingStandardsIgnoreLine
$jquery_version = isset( $wp_scripts->registered['jquery-ui-core']->ver ) ? $wp_scripts->registered['jquery-ui-core']->ver : '1.9.2';
wp_register_style( 'jquery-ui-style', '//ajax.googleapis.com/ajax/libs/jqueryui/' . $jquery_version . '/themes/smoothness/jquery-ui.css' );
wp_register_script( 'wc-enhanced-select', WC()->plugin_url() . '/assets/js/admin/wc-enhanced-select' . $suffix . '.js', array( 'jquery', 'selectWoo' ), WC_VERSION );
wp_localize_script(
'wc-enhanced-select', 'wc_enhanced_select_params', array(
'i18n_matches_1' => _x( 'One result is available, press enter to select it.', 'enhanced select', 'dokan' ),
'i18n_matches_n' => _x( '%qty% results are available, use up and down arrow keys to navigate.', 'enhanced select', 'dokan' ),
'i18n_no_matches' => _x( 'No matches found', 'enhanced select', 'dokan' ),
'i18n_ajax_error' => _x( 'Loading failed', 'enhanced select', 'dokan' ),
'i18n_input_too_short_1' => _x( 'Please enter 1 or more characters', 'enhanced select', 'dokan' ),
'i18n_input_too_short_n' => _x( 'Please enter %qty% or more characters', 'enhanced select', 'dokan' ),
'i18n_input_too_long_1' => _x( 'Please delete 1 character', 'enhanced select', 'dokan' ),
'i18n_input_too_long_n' => _x( 'Please delete %qty% characters', 'enhanced select', 'dokan' ),
'i18n_selection_too_long_1' => _x( 'You can only select 1 item', 'enhanced select', 'dokan' ),
'i18n_selection_too_long_n' => _x( 'You can only select %qty% items', 'enhanced select', 'dokan' ),
'i18n_load_more' => _x( 'Loading more results…', 'enhanced select', 'dokan' ),
'i18n_searching' => _x( 'Searching…', 'enhanced select', 'dokan' ),
'ajax_url' => admin_url( 'admin-ajax.php' ),
'search_customers_nonce' => wp_create_nonce( 'search-customers' ),
)
);
}
/**
* Loaded all dependency hooks
*
* @return void
*/
public function init_hooks() {
add_filter( 'dokan_get_dashboard_nav', array( $this, 'add_booking_page' ), 11 );
add_action( 'dokan_load_custom_template', array( $this, 'load_template_from_plugin' ) );
add_filter( 'dokan_query_var_filter', array( $this, 'register_booking_queryvar' ) );
add_filter( 'dokan_add_new_product_redirect', array( $this, 'set_redirect_url' ), 10, 2 );
add_filter( 'dokan_product_listing_exclude_type', array( $this, 'exclude_booking_type_from_product_listing' ) );
add_action( 'delete_post', array( $this, 'handle_deleted_bookable_product' ), 10, 1 );
// Init Cache
include_once DOKAN_WC_BOOKING_DIR . '/includes/BookingCache.php';
new BookingCache();
if ( ! class_exists( 'WC_Product_Booking' ) && defined( 'WC_BOOKINGS_MAIN_FILE' ) ) {
$wcb_path = preg_replace( '(woocommmerce-bookings.php)', '', WC_BOOKINGS_MAIN_FILE );
include_once $wcb_path . 'includes/class-wc-product-booking.php';
}
if ( ! is_admin() ) {
include_once DOKAN_WC_BOOKING_DIR . '/includes/class-wc-booking-calendar.php';
include_once DOKAN_WC_BOOKING_DIR . '/includes/class-dokan-wc-booking-helper.php';
include_once DOKAN_WC_BOOKING_DIR . '/includes/class-dokan-wc-booking-cost-calculation.php';
}
//override emails
add_filter( 'woocommerce_email_classes', array( $this, 'load_dokan_booking_cancelled_emails' ), 13 );
add_filter( 'woocommerce_email_actions', array( $this, 'register_dokan_booking_cancelled_actions' ) );
add_filter( 'woocommerce_email_classes', array( $this, 'load_dokan_booking_new_emails' ), 14 );
add_filter( 'woocommerce_email_actions', array( $this, 'register_dokan_booking_new_actions' ) );
add_filter( 'dokan_email_list', array( $this, 'set_email_template_directory' ) );
add_action( 'woocommerce_email_after_order_table', [ $this, 'fix_order_edit_link' ], 1, 4 );
$this->register_scripts();
}
public function load_dokan_booking_cancelled_emails( $wc_emails ) {
$wc_emails['Dokan_Email_Booking_Cancelled'] = include DOKAN_WC_BOOKING_DIR . '/includes/emails/class-dokan-booking-email-cancelled.php';
return $wc_emails;
}
public function register_dokan_booking_cancelled_actions( $actions ) {
$actions[] = 'woocommerce_bookings_cancelled_booking';
return $actions;
}
public function load_dokan_booking_new_emails( $wc_emails ) {
$wc_emails['Dokan_Email_Booking_New'] = include DOKAN_WC_BOOKING_DIR . '/includes/emails/class-dokan-booking-email-new.php';
return $wc_emails;
}
public function register_dokan_booking_new_actions( $actions ) {
$actions[] = 'woocommerce_admin_new_booking_notification';
return $actions;
}
/**
* Filter template for New Booking Email template path
*
* @since 1.1.2
*
* @param array $emails
*
* @return $emails
*/
public function setup_emails( $emails ) {
if ( ! isset( $emails['WC_Email_New_Booking'] ) ) {
return;
}
$email = $emails['WC_Email_New_Booking'];
$email->title = __( 'Dokan New Booking', 'dokan' );
$email->description = __( 'New booking emails are sent to the admin when a new booking is created and paid. This email is also received when a Pending confirmation booking is created.', 'dokan' );
$email->template_base = DOKAN_WC_BOOKING_TEMPLATE_PATH;
$email->recipient = '[email protected]';
return $emails;
}
/**
* Filter Email recipient for New booking orders
*
* @since 1.1.2
*
* @param string $recipient
*
* @param WC_Booking $booking
*
* @return $recipient
*/
public function set_seller_as_email_recipient( $recipient, $booking ) {
if ( ! $booking ) {
return $recipient;
}
$seller = get_post_field( 'post_author', $booking->product_id );
$sellerdata = get_userdata( $seller );
return apply_filters( 'dokan_booking_new_email_recipient', $sellerdata->user_email, $booking );
}
/**
* Add menu on seller dashboard
* @since 1.0
* @param array $urls
* @return array $urls
*/
public function add_booking_page( $urls ) {
$menu = [
'title' => esc_html__( 'Booking', 'dokan' ),
'icon' => '<i class="far fa-calendar-alt"></i>',
'url' => dokan_get_navigation_url( 'booking' ),
'pos' => 180,
'icon_name' => 'CalendarCheck',
];
if ( ! current_user_can( 'dokan_view_booking_menu' ) ) {
return $urls;
}
$urls['booking'] = $menu;
return $urls;
}
/**
* Register page templates
*
* @since 1.0
*
* @param array $query_vars
*
* @return array $query_vars
*/
public function load_template_from_plugin( $query_vars ) {
if ( isset( $query_vars['booking'] ) ) {
if ( ! current_user_can( 'dokan_view_booking_menu' ) ) {
dokan_get_template_part(
'global/dokan-error', '', array(
'deleted' => false,
'message' => __( 'You have no permission to view this booking page', 'dokan' ),
)
);
} else {
dokan_get_template_part( 'booking/booking', '', array( 'is_booking' => true ) );
}
return;
}
}
/**
* Register dokan query vars
*
* @since 1.0
*
* @param array $vars
*
* @return array new $vars
*/
public function register_booking_queryvar( $vars ) {
$vars[] = 'booking';
return $vars;
}
/**
* Save Booking meta data
*
* @since 1.0
*
* @global Array $wpdb
*
* @param int $post_id
*
* @return void
*/
public function save_booking_data( $post_id ) {
global $wpdb;
$post_data = wp_unslash( $_POST ); // phpcs:ignore
$product_type = empty( $post_data['product_type'] ) ? 'simple' : sanitize_title( stripslashes( $post_data['product_type'] ) );
if ( 'booking' !== $product_type ) {
return;
}
$product = new \WC_Product_Booking( $post_id );
if ( ! is_a( $product, 'WC_Product_Booking' ) ) {
return;
}
// Save shipping class
$product_shipping_class = isset( $post_data['product_shipping_class'] ) && $post_data['product_shipping_class'] > 0 ? absint( $post_data['product_shipping_class'] ) : '';
wp_set_object_terms( $post_id, $product_shipping_class, 'product_shipping_class' );
$resources = $this->get_posted_resources();
$posted_props = array(
'apply_adjacent_buffer' => isset( $post_data['_wc_booking_apply_adjacent_buffer'] ),
'availability' => $this->get_posted_availability(),
'block_cost' => wc_clean( $post_data['_wc_booking_block_cost'] ),
'buffer_period' => wc_clean( $post_data['_wc_booking_buffer_period'] ),
'calendar_display_mode' => wc_clean( $post_data['_wc_booking_calendar_display_mode'] ),
'cancel_limit_unit' => wc_clean( $post_data['_wc_booking_cancel_limit_unit'] ),
'cancel_limit' => wc_clean( $post_data['_wc_booking_cancel_limit'] ),
'check_start_block_only' => 'start' === $post_data['_wc_booking_check_availability_against'],
'cost' => wc_clean( $post_data['_wc_booking_cost'] ),
'default_date_availability' => wc_clean( $post_data['_wc_booking_default_date_availability'] ),
'display_cost' => wc_clean( $post_data['_wc_display_cost'] ),
'duration_type' => wc_clean( $post_data['_wc_booking_duration_type'] ),
'duration_unit' => wc_clean( $post_data['_wc_booking_duration_unit'] ),
'duration' => wc_clean( $post_data['_wc_booking_duration'] ),
'enable_range_picker' => isset( $post_data['_wc_booking_enable_range_picker'] ),
'first_block_time' => wc_clean( $post_data['_wc_booking_first_block_time'] ),
'has_person_cost_multiplier' => isset( $post_data['_wc_booking_person_cost_multiplier'] ),
'has_person_qty_multiplier' => isset( $post_data['_wc_booking_person_qty_multiplier'] ),
'has_person_types' => isset( $post_data['_wc_booking_has_person_types'] ),
'has_persons' => isset( $post_data['_wc_booking_has_persons'] ),
'has_resources' => isset( $post_data['_wc_booking_has_resources'] ),
'max_date_unit' => wc_clean( $post_data['_wc_booking_max_date_unit'] ),
'max_date_value' => wc_clean( $post_data['_wc_booking_max_date'] ),
'max_duration' => wc_clean( $post_data['_wc_booking_max_duration'] ),
'max_persons' => isset( $post_data['_wc_booking_max_persons_group'] ) ? wc_clean( $post_data['_wc_booking_max_persons_group'] ) : '',
'min_date_unit' => wc_clean( $post_data['_wc_booking_min_date_unit'] ),
'min_date_value' => wc_clean( $post_data['_wc_booking_min_date'] ),
'min_duration' => wc_clean( $post_data['_wc_booking_min_duration'] ),
'min_persons' => isset( $post_data['_wc_booking_min_persons_group'] ) ? wc_clean( $post_data['_wc_booking_min_persons_group'] ) : '',
'person_types' => $this->get_posted_person_types( $product ),
'pricing' => $this->get_posted_pricing(),
'qty' => wc_clean( $post_data['_wc_booking_qty'] ),
'requires_confirmation' => isset( $post_data['_wc_booking_requires_confirmation'] ),
'resource_label' => isset( $post_data['_wc_booking_resource_label'] ) ? wc_clean( $post_data['_wc_booking_resource_label'] ) : '',
'resource_base_costs' => wp_list_pluck( $resources, 'base_cost' ),
'resource_block_costs' => wp_list_pluck( $resources, 'block_cost' ),
'resource_ids' => array_keys( $resources ),
'resources_assignment' => isset( $post_data['_wc_booking_resources_assignment'] ) ? wc_clean( $post_data['_wc_booking_resources_assignment'] ) : '',
'user_can_cancel' => isset( $post_data['_wc_booking_user_can_cancel'] ) ? wc_clean( $post_data['_wc_booking_user_can_cancel'] ) : '',
'has_restricted_days' => isset( $post_data['_wc_booking_has_restricted_days'] ) ? wc_clean( $post_data['_wc_booking_has_restricted_days'] ) : '',
'restricted_days' => isset( $post_data['_wc_booking_restricted_days'] ) ? wc_clean( $post_data['_wc_booking_restricted_days'] ) : '',
);
$product->set_props( $posted_props );
// Update virtual
$_virtual = isset( $post_data['_virtual'] ) ? wc_clean( $post_data['_virtual'] ) : '';
$is_virtual = 'on' === $_virtual ? 'yes' : 'no';
update_post_meta( $post_id, '_virtual', $is_virtual );
if ( ! empty( $post_data['chosen_product_cat'] ) ) {
$chosen_cat = Helper::product_category_selection_is_single() ? [ reset( $post_data['chosen_product_cat'] ) ] : $post_data['chosen_product_cat'];
} else {
$chosen_cat = [ absint( get_option( 'default_product_cat' ) ) ];
}
Helper::set_object_terms_from_chosen_categories( $product->get_id(), $chosen_cat );
$product->save();
/**
* Fires after a product is saved.
*
* @since 3.4.2 added product and post_data params in hook args
*
* @param WC_Product $product The product object.
* @param array $post_data The $_POST data.
*/
do_action( 'dokan_booking_after_product_data_saved', $product, $post_data );
}
/**
* Filter Redirect url after new booking product added
*
* @since 1.0
*
* @param string $url
*
* @param int $product_id
*
* @return $url
*/
public function set_redirect_url( $url, $product_id ) {
$post_data = wp_unslash( $_POST ); // phpcs:ignore
$product_type = isset( $post_data['product_type'] ) ? $post_data['product_type'] : '';
// @codingStandardsIgnoreLine
$tab = isset( $_GET['tab'] ) ? $_GET['tab'] : '';
if ( 'booking' === $product_type ) {
$url = add_query_arg( array( 'product_id' => $product_id ), dokan_get_navigation_url( 'booking' ) . 'edit/' );
return $url;
}
if ( 'booking' === $tab ) {
$url = add_query_arg( array(), dokan_get_navigation_url( 'booking' ) );
return $url;
}
return $url;
}
/**
* Add new resource via ajax
*
* @since 1.0
*
* @return void
*/
public function add_new_resource() {
if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['_wpnonce'] ), 'dokan-booking-resource-nonce' ) ) {
wp_send_json_error( esc_html__( 'Nonce verification failed!', 'dokan' ) );
}
if ( empty( $_POST['add_resource_name'] ) ) {
wp_send_json_error( esc_html__( 'Please provide a resource name', 'dokan' ) );
}
$add_resource_name = sanitize_text_field( wp_unslash( $_POST['add_resource_name'] ) );
$resource = array(
'post_title' => $add_resource_name,
'post_content' => '',
'post_status' => 'publish',
'post_author' => dokan_get_current_user_id(),
'post_type' => 'bookable_resource',
'meta_input' => [ 'qty' => 1 ],
);
$resource_id = wp_insert_post( $resource );
$edit_url = dokan_get_navigation_url( 'booking' ) . 'resources/edit/?id=' . $resource_id;
ob_start();
?>
<tr>
<td><a href="<?php echo $edit_url; ?>"><?php echo $add_resource_name; ?></a></td>
<td><?php esc_attr_e( 'N/A', 'dokan' ); ?></td>
<td>
<a class="dokan-btn dokan-btn-sm dokan-btn-theme" href ="<?php echo $edit_url; ?>"><?php esc_attr_e( 'Edit', 'dokan' ); ?></a>
<button class="dokan-btn dokan-btn-theme dokan-btn-sm btn-remove" data-id="<?php echo $resource_id; ?>"><?php esc_attr_e( 'Remove', 'dokan' ); ?></button>
</td>
</tr>
<?php
$output = ob_get_clean();
wp_send_json_success( $output );
}
/**
* Update Resource Data via ajax
*
* @since 1.0
*
* @return void
*/
public function update_resource_data() {
$post_data = wp_unslash( $_POST ); // phpcs:ignore
if ( ! isset( $post_data['dokan_booking_resource_update'] ) ) {
return;
}
$post_id = intval( $post_data['resource_id'] );
$post = get_post( $post_id );
$post->post_title = sanitize_text_field( $post_data['post_title'] );
wp_update_post( $post );
// Qty field
update_post_meta( $post_id, 'qty', wc_clean( $post_data['_wc_booking_qty'] ) );
// Availability
$availability = array();
$row_size = isset( $post_data['wc_booking_availability_type'] ) ? count( $post_data['wc_booking_availability_type'] ) : 0;
for ( $i = 0; $i < $row_size; $i ++ ) {
$availability[ $i ]['type'] = wc_clean( $post_data['wc_booking_availability_type'][ $i ] );
$availability[ $i ]['bookable'] = wc_clean( $post_data['wc_booking_availability_bookable'][ $i ] );
$availability[ $i ]['priority'] = intval( $post_data['wc_booking_availability_priority'][ $i ] );
switch ( $availability[ $i ]['type'] ) {
case 'custom':
$availability[ $i ]['from'] = wc_clean( $post_data['wc_booking_availability_from_date'][ $i ] );
$availability[ $i ]['to'] = wc_clean( $post_data['wc_booking_availability_to_date'][ $i ] );
break;
case 'months':
$availability[ $i ]['from'] = wc_clean( $post_data['wc_booking_availability_from_month'][ $i ] );
$availability[ $i ]['to'] = wc_clean( $post_data['wc_booking_availability_to_month'][ $i ] );
break;
case 'weeks':
$availability[ $i ]['from'] = wc_clean( $post_data['wc_booking_availability_from_week'][ $i ] );
$availability[ $i ]['to'] = wc_clean( $post_data['wc_booking_availability_to_week'][ $i ] );
break;
case 'days':
$availability[ $i ]['from'] = wc_clean( $post_data['wc_booking_availability_from_day_of_week'][ $i ] );
$availability[ $i ]['to'] = wc_clean( $post_data['wc_booking_availability_to_day_of_week'][ $i ] );
break;
case 'time':
case 'time:1':
case 'time:2':
case 'time:3':
case 'time:4':
case 'time:5':
case 'time:6':
case 'time:7':
$availability[ $i ]['from'] = wc_booking_sanitize_time( $post_data['wc_booking_availability_from_time'][ $i ] );
$availability[ $i ]['to'] = wc_booking_sanitize_time( $post_data['wc_booking_availability_to_time'][ $i ] );
break;
case 'time:range':
$availability[ $i ]['from'] = wc_booking_sanitize_time( $post_data['wc_booking_availability_from_time'][ $i ] );
$availability[ $i ]['to'] = wc_booking_sanitize_time( $post_data['wc_booking_availability_to_time'][ $i ] );
$availability[ $i ]['from_date'] = wc_clean( $post_data['wc_booking_availability_from_date'][ $i ] );
$availability[ $i ]['to_date'] = wc_clean( $post_data['wc_booking_availability_to_date'][ $i ] );
break;
}
}
update_post_meta( $post_id, '_wc_booking_availability', $availability );
// Clear resource transients.
if (
class_exists( 'WC_Product_Booking_Resource' )
&& class_exists( 'WC_Product_Booking_Resource_Data_Store_CPT' )
) {
$resource = new \WC_Product_Booking_Resource( $post_id );
$data_store = new \WC_Product_Booking_Resource_Data_Store_CPT();
$resource->apply_changes();
$data_store->flush_resource_transients( $resource );
}
$redirect_url = dokan_get_navigation_url( 'booking' ) . 'resources/edit/?id=' . $post_id;
wp_safe_redirect( add_query_arg( array( 'message' => 'success' ), $redirect_url ) );
}
/**
* Delete Booking resource
*
* @since 1.0
*
* @return JSON Success | Error
*/
public function delete_resource() {
// @codingStandardsIgnoreLine
$post_id = wc_clean( $_POST['resource_id'] );
if ( wp_delete_post( $post_id ) ) {
wp_send_json_success();
} else {
wp_send_json_error();
}
}
/**
* Highlight Booking menu as active on Dokan Dashboard
*
* @since 1.0
*
* @param string $active_menu
*
* @return string
*/
public function set_booking_menu_as_active( $active_menu ) {
return 'booking';
}
/**
* Add Seller meta to newly created Booking
*
* @since 1.0
*
* @param int $booking_id Newly created booking id
*
* @return void
*/
public function add_seller_id_meta( $booking_id ) {
$product_id = get_post_meta( $booking_id, '_booking_product_id', true );
$seller_id = get_post_field( 'post_author', $product_id );
update_post_meta( $booking_id, '_booking_seller_id', $seller_id );
}
/**
* Exclude Booking type products from dokan product listing
*
* @since 1.0
*
* @param array $product_types
*
* @return array $product_types
*/
public function exclude_booking_type_from_product_listing( $product_types ) {
$product_types[] = 'booking';
return $product_types;
}
/**
* Add Booking Manage capability to seller
*
* @since 1.0
*
* @global type $wp_roles
*
* @return void
*/
public function add_seller_manage_cap() {
global $wp_roles;
if ( is_object( $wp_roles ) ) {
$wp_roles->add_cap( 'seller', 'manage_bookings' );
}
}
/**
* Confirm bookings from seller dashboard with additional security checks
*
* @since 1.0
*
* @return void
*/
public function mark_booking_confirmed() {
if ( ! current_user_can( 'dokan_manage_bookings' ) ) {
wp_die( __( 'You do not have sufficient permissions to access this page.', 'dokan' ) );
}
if ( ! check_admin_referer( 'wc-booking-confirm' ) ) {
wp_die( __( 'You have taken too long. Please go back and retry.', 'dokan' ) );
}
$booking_id = isset( $_GET['booking_id'] ) && (int) $_GET['booking_id'] ? (int) $_GET['booking_id'] : '';
if ( ! $booking_id ) {
die;
}
// Additional check to see if Seller id is same as current user
$seller = get_post_meta( $booking_id, '_booking_seller_id', true );
if ( (int) $seller !== dokan_get_current_user_id() ) {
wp_die( __( 'You do not have sufficient permissions to access this page.', 'dokan' ) );
}
$booking = get_wc_booking( $booking_id );
if ( $booking->get_status() !== 'confirmed' ) {
$booking->update_status( 'confirmed' );
}
/**
* Fires a Booking Confirm Action.
*
* @since 3.4.2
*
* @param \WC_Booking $booking
*/
do_action( 'dokan_after_booking_confirmed', $booking );
wp_safe_redirect( wp_get_referer() );
die();
}
public function change_booking_status() {
check_ajax_referer( 'dokan_wc_booking_change_status' );
$post_data = wp_unslash( $_POST ); // phpcs:ignore
$booking_id = intval( $post_data['booking_id'] );
$booking = get_wc_booking( $booking_id );
$status = wc_clean( $post_data['booking_order_status'] );
if ( $booking->update_status( $status ) ) {
$html = '<label class="dokan-label dokan-booking-label-' . esc_attr( $status ) . ' ">' . get_post_status_object( $status )->label . '</label>';
/**
* Fires a Booking Status Change Action
*
* @param int $booking_id
*
* @since 3.4.2
*/
do_action( 'dokan_booking_change_status', $booking_id );
wp_send_json_success( $html );
} else {
echo _e( 'Error Occured', 'dokan' );
}
exit();
}
/**
* Returns the Booking menu Items
*
* @since 1.1
* @return array
*/
public function dokan_get_bookings_menu( $bookings ) {
$bookings = array(
'' => array(
'title' => __( 'All Booking Product', 'dokan' ),
'tabs' => true,
),
'new-product' => array(
'title' => __( 'Add Booking Product', 'dokan' ),
'tabs' => false,
),
'my-bookings' => array(
'title' => __( 'Manage Bookings', 'dokan' ),
'tabs' => current_user_can( 'dokan_manage_bookings' ),
),
'calendar' => array(
'title' => __( 'Calendar', 'dokan' ),
'tabs' => current_user_can( 'dokan_manage_booking_calendar' ),
),
'resources' => array(
'title' => __( 'Manage Resources', 'dokan' ),
'tabs' => current_user_can( 'dokan_manage_booking_resource' ),
),
'edit' => array(
'title' => __( 'Edit Booking Product', 'dokan' ),
'tabs' => false,
),
'resources/edit' => array(
'title' => __( 'Edit Resource', 'dokan' ),
'tabs' => false,
),
'booking-details' => array(
'title' => __( 'Edit Booking', 'dokan' ),
'tabs' => false,
),
'add-booking' => array(
'title' => __( 'Add Booking', 'dokan' ),
'tabs' => false,
),
);
return apply_filters( 'dokan_booking_nav_titles', $bookings );
}
/**
* Returns the Booking menu Items Title
*
* @since 1.1
* @return array
*/
public function dokan_get_bookings_menu_title( $current_page ) {
$menus = apply_filters( 'dokan_booking_menu', '' );
foreach ( $menus as $key => $value ) {
// @codingStandardsIgnoreLine
if ( $current_page == $key ) {
$title = $value['title'];
}
}
return $title;
}
private function get_posted_availability() {
$post_data = wp_unslash( $_POST ); // phpcs:ignore
$availability = array();
$row_size = isset( $post_data['wc_booking_availability_type'] ) ? count( $post_data['wc_booking_availability_type'] ) : 0;
for ( $i = 0; $i < $row_size; $i ++ ) {
$availability[ $i ]['type'] = wc_clean( $post_data['wc_booking_availability_type'][ $i ] );
$availability[ $i ]['bookable'] = wc_clean( $post_data['wc_booking_availability_bookable'][ $i ] );
$availability[ $i ]['priority'] = intval( $post_data['wc_booking_availability_priority'][ $i ] );
switch ( $availability[ $i ]['type'] ) {
case 'custom':
$availability[ $i ]['from'] = wc_clean( $post_data['wc_booking_availability_from_date'][ $i ] );
$availability[ $i ]['to'] = wc_clean( $post_data['wc_booking_availability_to_date'][ $i ] );
break;
case 'months':
$availability[ $i ]['from'] = wc_clean( $post_data['wc_booking_availability_from_month'][ $i ] );
$availability[ $i ]['to'] = wc_clean( $post_data['wc_booking_availability_to_month'][ $i ] );
break;
case 'weeks':
$availability[ $i ]['from'] = wc_clean( $post_data['wc_booking_availability_from_week'][ $i ] );
$availability[ $i ]['to'] = wc_clean( $post_data['wc_booking_availability_to_week'][ $i ] );
break;
case 'days':
$availability[ $i ]['from'] = wc_clean( $post_data['wc_booking_availability_from_day_of_week'][ $i ] );
$availability[ $i ]['to'] = wc_clean( $post_data['wc_booking_availability_to_day_of_week'][ $i ] );
break;
case 'time':
case 'time:1':
case 'time:2':
case 'time:3':
case 'time:4':
case 'time:5':
case 'time:6':
case 'time:7':
$availability[ $i ]['from'] = wc_booking_sanitize_time( $post_data['wc_booking_availability_from_time'][ $i ] );
$availability[ $i ]['to'] = wc_booking_sanitize_time( $post_data['wc_booking_availability_to_time'][ $i ] );
break;
case 'time:range':
$availability[ $i ]['from'] = wc_booking_sanitize_time( $post_data['wc_booking_availability_from_time'][ $i ] );
$availability[ $i ]['to'] = wc_booking_sanitize_time( $post_data['wc_booking_availability_to_time'][ $i ] );
$availability[ $i ]['from_date'] = wc_clean( $post_data['wc_booking_availability_from_date'][ $i ] );
$availability[ $i ]['to_date'] = wc_clean( $post_data['wc_booking_availability_to_date'][ $i ] );
break;
}
}
return $availability;
}
/**
* Get posted pricing fields and format.
*
* @return array
*/
private function get_posted_pricing() {
$post_data = wp_unslash( $_POST ); // phpcs:ignore
$pricing = array();
$row_size = isset( $post_data['wc_booking_pricing_type'] ) ? count( $post_data['wc_booking_pricing_type'] ) : 0;
for ( $i = 0; $i < $row_size; $i ++ ) {
$pricing[ $i ]['type'] = wc_clean( $post_data['wc_booking_pricing_type'][ $i ] );
$pricing[ $i ]['cost'] = wc_clean( $post_data['wc_booking_pricing_cost'][ $i ] );
$pricing[ $i ]['modifier'] = wc_clean( $post_data['wc_booking_pricing_cost_modifier'][ $i ] );
$pricing[ $i ]['base_cost'] = wc_clean( $post_data['wc_booking_pricing_base_cost'][ $i ] );
$pricing[ $i ]['base_modifier'] = wc_clean( $post_data['wc_booking_pricing_base_cost_modifier'][ $i ] );
switch ( $pricing[ $i ]['type'] ) {
case 'custom':
$pricing[ $i ]['from'] = wc_clean( $post_data['wc_booking_pricing_from_date'][ $i ] );
$pricing[ $i ]['to'] = wc_clean( $post_data['wc_booking_pricing_to_date'][ $i ] );
break;
case 'months':
$pricing[ $i ]['from'] = wc_clean( $post_data['wc_booking_pricing_from_month'][ $i ] );
$pricing[ $i ]['to'] = wc_clean( $post_data['wc_booking_pricing_to_month'][ $i ] );
break;
case 'weeks':
$pricing[ $i ]['from'] = wc_clean( $post_data['wc_booking_pricing_from_week'][ $i ] );
$pricing[ $i ]['to'] = wc_clean( $post_data['wc_booking_pricing_to_week'][ $i ] );
break;
case 'days':
$pricing[ $i ]['from'] = wc_clean( $post_data['wc_booking_pricing_from_day_of_week'][ $i ] );
$pricing[ $i ]['to'] = wc_clean( $post_data['wc_booking_pricing_to_day_of_week'][ $i ] );
break;
case 'time':
case 'time:1':
case 'time:2':
case 'time:3':
case 'time:4':
case 'time:5':
case 'time:6':
case 'time:7':
$pricing[ $i ]['from'] = wc_booking_sanitize_time( $post_data['wc_booking_pricing_from_time'][ $i ] );
$pricing[ $i ]['to'] = wc_booking_sanitize_time( $post_data['wc_booking_pricing_to_time'][ $i ] );
break;
case 'time:range':
$pricing[ $i ]['from'] = wc_booking_sanitize_time( $post_data['wc_booking_pricing_from_time'][ $i ] );
$pricing[ $i ]['to'] = wc_booking_sanitize_time( $post_data['wc_booking_pricing_to_time'][ $i ] );
$pricing[ $i ]['from_date'] = wc_clean( $post_data['wc_booking_pricing_from_date'][ $i ] );
$pricing[ $i ]['to_date'] = wc_clean( $post_data['wc_booking_pricing_to_date'][ $i ] );
break;
default:
$pricing[ $i ]['from'] = wc_clean( $post_data['wc_booking_pricing_from'][ $i ] );
$pricing[ $i ]['to'] = wc_clean( $post_data['wc_booking_pricing_to'][ $i ] );
break;
}
}
return $pricing;
}
/**
* Get posted person types.
*
* @return array
*/
private function get_posted_person_types( $product ) {
$post_data = wp_unslash( $_POST ); // phpcs:ignore
$person_types = array();
if ( isset( $post_data['person_id'] ) && isset( $post_data['_wc_booking_has_persons'] ) ) {
$person_ids = $post_data['person_id'];
$person_menu_order = $post_data['person_menu_order'];
$person_name = $post_data['person_name'];
$person_cost = $post_data['person_cost'];
$person_block_cost = $post_data['person_block_cost'];
$person_description = $post_data['person_description'];
$person_min = $post_data['person_min'];
$person_max = $post_data['person_max'];
$max_loop = max( array_keys( $post_data['person_id'] ) );
for ( $i = 0; $i <= $max_loop; $i ++ ) {
if ( ! isset( $person_ids[ $i ] ) ) {
continue;
}
$person_id = absint( $person_ids[ $i ] );
$person_type = new \WC_Product_Booking_Person_Type( $person_id );
$person_type->set_props(
array(
'name' => wc_clean( stripslashes( $person_name[ $i ] ) ),
'description' => wc_clean( stripslashes( $person_description[ $i ] ) ),
'sort_order' => absint( $person_menu_order[ $i ] ),
'cost' => floatval( wc_clean( $person_cost[ $i ] ) ),
'block_cost' => floatval( wc_clean( $person_block_cost[ $i ] ) ),
'min' => wc_clean( $person_min[ $i ] ),
'max' => wc_clean( $person_max[ $i ] ),
'parent_id' => $product->get_id(),
)
);
$person_types[] = $person_type;
}
}
return $person_types;
}
/**
* Get posted resources. Resources are global, but booking products store information about the relationship.
*
* @return array
*/
private function get_posted_resources() {
$post_data = wp_unslash( $_POST ); // phpcs:ignore
$resources = array();
if ( isset( $post_data['resource_id'] ) && isset( $post_data['_wc_booking_has_resources'] ) ) {
$resource_ids = $post_data['resource_id'];
$resource_menu_order = $post_data['resource_menu_order'];
$resource_base_cost = $post_data['resource_cost'];
$resource_block_cost = $post_data['resource_block_cost'];
$max_loop = max( array_keys( $post_data['resource_id'] ) );
$resource_base_costs = array();
$resource_block_costs = array();
foreach ( $resource_menu_order as $key => $value ) {
$resources[ absint( $resource_ids[ $key ] ) ] = array(
'base_cost' => wc_clean( $resource_base_cost[ $key ] ),
'block_cost' => wc_clean( $resource_block_cost[ $key ] ),
);
}
}
return $resources;
}
/**
* Delete bookable person type
* @since 2.7.3
*/
public function dokan_remove_bookable_person() {
$post_data = wp_unslash( $_POST ); // phpcs:ignore
// @codingStandardsIgnoreLine
if ( ! isset( $post_data['action'] ) && $post_data['action'] != 'woocommerce_remove_bookable_person' ) {
return;
}
if ( ! wp_verify_nonce( $post_data['security'], 'delete-bookable-person' ) ) {
return;
}
wp_delete_post( intval( $post_data['person_id'] ) );
exit;
}
/**
* Add capabilities
*
* @since 1.0.0
*
* @return void
*/
public function add_capabilities( $capabilities ) {
$capabilities['menu']['dokan_view_booking_menu'] = __( 'View booking menu', 'dokan' );
$capabilities['booking'] = array(
'dokan_manage_booking_products' => __( 'Manage booking products', 'dokan' ),
'dokan_manage_booking_calendar' => __( 'Manage booking calendar', 'dokan' ),
'dokan_manage_bookings' => __( 'Manage bookings', 'dokan' ),
'dokan_manage_booking_resource' => __( 'Manage booking resource', 'dokan' ),
'dokan_add_booking_product' => __( 'Add booking product', 'dokan' ),
'dokan_edit_booking_product' => __( 'Edit booking product', 'dokan' ),
'dokan_delete_booking_product' => __( 'Delete booking product', 'dokan' ),
);
return $capabilities;
}
/**
* Add caps labels
*
* @since 3.0.0
*
* @param string $caps
*
* @return array
*/
public function add_caps_labels( $caps ) {
$caps['booking'] = __( 'Booking', 'dokan' );
return $caps;
}
/**
* Add booking discount type
*
* @since 2.9.13
*
* @param array $types
*
* @return array
*/
public function add_booking_discount( $types ) {
$types['booking_person'] = __( 'Booking Person Discount (Amount Off Per Person)', 'dokan' );
return $types;
}
/**
* @since 3.1.4
* @param $url
* @param $product
*
* @return mixed|string
*/
public function modify_edit_product_url( $url, $product ) {
if ( $product->get_type() === 'booking' ) {
$url = add_query_arg(
[
'product_id' => $product->get_id(),
'action' => 'edit',
],
dokan_get_navigation_url( 'booking' ) . '/edit/'
);
}
return $url;
}
/**
* Set Proper template directory.
*
* @param array $template_array
*
* @return array
*/
public function set_email_template_directory( $template_array ) {
array_push( $template_array, 'dokan-admin-new-booking.php', 'dokan-customer-booking-cancelled.php' );
return $template_array;
}
/**
* Clears addon validation notices while creating manual booking
*
* @since 3.3.6
*/
public function clear_addons_validation_notices() {
if ( class_exists( 'WC_Product_Addons_Cart' ) && 'add-booking' === get_query_var( 'booking' ) ) {
wc_clear_notices();
}
}
/**
* Get Booking duration unit label.
*
* @since 3.3.4
*
* @param string $unit Duration unit.
*
* @return string
*/
public static function get_booking_duration_unit_label( $unit ) {
switch ( $unit ) {
case 'month':
$unit_label = __( 'Month(s)', 'dokan' );
break;
case 'day':
$unit_label = __( 'Day(s)', 'dokan' );
break;
case 'hour':
$unit_label = __( 'Hour(s)', 'dokan' );
break;
case 'minute':
$unit_label = __( 'Minute(s)', 'dokan' );
break;
default:
$unit_label = $unit;
}
return $unit_label;
}
/**
* Initializes accommodation booking manager
*
* @since 3.4.2
*
* @return void
*/
private function init_accommodation_booking() {
// Load vendor and frontend manager class
if ( ! is_admin() ) {
include_once DOKAN_WC_BOOKING_DIR . '/includes/accommodation/class-dokan-booking-accommodation-manager.php';
new \Dokan_Booking_Accommodation_Manager();
}
// Load admin manager class
if ( is_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
include_once DOKAN_WC_BOOKING_DIR . '/includes/accommodation/admin/class-dokan-booking-accommodation-admin.php';
new \Dokan_Booking_Accommodation_Admin();
}
// Load helper class
include_once DOKAN_WC_BOOKING_DIR . '/includes/accommodation/class-dokan-booking-accommodation-helper.php';
}
/**
* Enqueue scripts and styles for Accommodation Booking
*
* @since 3.4.2
*
* @return void
*/
public function enqueue_accommodation_scripts() {
wp_enqueue_script( 'dokan_accommodation_booking_script' );
// Timepicker
wp_enqueue_style( 'dokan-timepicker' );
wp_enqueue_script( 'dokan-timepicker' );
}
/**
* Unlink the resources on delete of bookable products
*
* @since 3.5.2
*
* @param $post_id
*/
public function handle_deleted_bookable_product( $post_id ) {
$product = wc_get_product( absint( $post_id ) );
if ( ! is_a( $product, 'WC_Product' ) || 'booking' !== $product->get_type() ) {
return;
}
\WC_Bookings_Tools::unlink_resource( $post_id );
}
/**
* Returns new category select ui html elements.
*
* @since 3.7.5
*
* @return void
*/
public function load_add_category_modal() {
/**
* Checking if dokan dashboard or add product page or product edit page or product list.
* Because without those page we don't need to load category modal.
*/
global $wp;
if ( ( isset( $wp->query_vars['booking'] ) && $wp->query_vars['booking'] === 'new-product' ) || ( isset( $wp->query_vars['booking'] ) && $wp->query_vars['booking'] === 'edit' ) ) {
dokan_get_template_part( 'products/dokan-category-ui', '', array() );
}
}
/**
* Fix order edit link for vendor.
*
* @since 3.7.15
*
* @param \WC_Order $order Order Instance.
* @param bool $sent_to_admin send to admin.
* @param bool $plain_text Plain text.
* @param \WC_Email $email The email class.
*
* @return void
*/
public function fix_order_edit_link( $order, $sent_to_admin, $plain_text, $email ) {
$correct_email_template = 'dokan_vendor_new_order' === $email->id || 'dokan_vendor_completed_order' === $email->id;
if ( ! $correct_email_template || ! $sent_to_admin || $plain_text ) {
return;
}
$booking_ids = \WC_Booking_Data_Store::get_order_contains_only_bookings( $order );
if ( empty( $booking_ids ) ) {
return;
}
dokan_remove_hook_for_anonymous_class( 'woocommerce_email_after_order_table', \WC_Booking_Order_Manager::class, 'add_admin_calender_link', 10 );
$order_url = esc_url(
add_query_arg(
[
'order_id' => $order->get_order_number(),
'_view_mode' => 'email',
'permission' => '1',
], dokan_get_navigation_url( 'orders' )
)
);
if ( $order->get_order_item_totals() ) {
?>
<div class="wc-booking-summary-actions" style="margin-bottom: 30px;">
<a href="<?php echo esc_url( $order_url ); ?>"><?php esc_html_e( 'View order →', 'dokan' ); ?></a>
<br/>
<a href="<?php echo esc_url( dokan_get_navigation_url( 'orders' ) ); ?>"><?php esc_html_e( 'View all orders →', 'dokan' ); ?></a>
</div>
<?php
}
}
/**
* Remove product type filter from booking product list
*
* @since 3.7.25
*
* @param array $args
*
* @return array
*/
public function remove_product_type_filter( $args ) {
global $wp;
if ( dokan_is_seller_dashboard() && isset( $wp->query_vars['booking'] ) ) {
$args['product_types'] = '';
}
return $args;
}
/**
* Render linked product content.
*
* @since 3.9.4
*
* @return void
*/
public function load_linked_product_content( $post, $post_id ) {
global $wp;
if ( ! ( ( isset( $wp->query_vars['booking'] ) && $wp->query_vars['booking'] === 'new-product' ) || ( isset( $wp->query_vars['booking'] ) && $wp->query_vars['booking'] === 'edit' ) ) ) {
return;
}
$upsells_ids = get_post_meta( $post_id, '_upsell_ids', true );
$crosssells_ids = get_post_meta( $post_id, '_crosssell_ids', true );
dokan_get_template_part(
'booking/linked-product-content',
'',
array(
'pro' => true,
'is_booking' => true,
'post' => $post,
'post_id' => $post_id,
'upsells_ids' => $upsells_ids,
'crosssells_ids' => $crosssells_ids,
)
);
}
/**
* Disable inventory template for booking products
*
* @since 4.0.3
*
* @param bool $skip
* @param int $post_id
* @return bool
*/
public function maybe_disable_inventory_template_for_booking( $skip, $post_id ) {
$product = wc_get_product( $post_id );
if ( $product && $product->get_type() === 'booking' ) {
return true;
}
return $skip;
}
/**
* Validate coupon for booking person product.
*
* @since 4.1.2
*
* @param bool $should_validate
* @param \WC_Coupon $coupon
* @param array $item
* @param \WC_Discounts $discounts
*
* @return false|mixed
*/
public function should_validate_coupon( $should_validate, $coupon, $item, \WC_Discounts $discounts ) {
if ( ! $should_validate ) {
return $should_validate;
}
// Check if the coupon is for booking person product.
$discount_object = $discounts->get_object();
if ( ! is_a( $discount_object, 'WC_Order' ) ) {
return $should_validate;
}
// Check if the coupon is for booking person product.
if ( did_filter( 'woocommerce_order_recalculate_coupons_coupon_object' ) && ! did_action( 'woocommerce_order_applied_coupon' ) ) {
return false;
}
return $should_validate;
}
/**
* Cancels any "unpaid" bookings linked to the current checkout session.
*
* When a payment attempt fails, WooCommerce may leave bookings in the
* "unpaid" state under the session's `order_awaiting_payment` order.
* These unpaid bookings continue blocking the selected time slot and
* prevent new checkout attempts from creating a fresh booking.
*
* This method checks the existing session order and cancels all
* associated bookings still marked as "unpaid", allowing the customer
* to retry the checkout without availability errors.
*
* @see https://github.com/woocommerce/woocommerce/blob/f5abdd39bef881b1481d8c613a7744fe194f2ed0/plugins/woocommerce/includes/class-wc-checkout.php#L1077
*
* @since 4.2.1
*
* @return void
*/
public function maybe_cancelled_unpaid_booking_from_checkout() {
$order_id = absint( WC()->session->get( 'order_awaiting_payment', 0 ) ) ?? absint( WC()->session->get( 'store_api_draft_order', 0 ) );
if ( ! $order_id ) {
return;
}
$order = wc_get_order( $order_id );
if ( ! $order ) {
return;
}
$booking_ids = WC_Booking_Data_Store::get_booking_ids_from_order_id( $order_id );
foreach ( $booking_ids as $booking_id ) {
$booking = get_wc_booking( $booking_id );
if ( $booking && $booking->has_status( 'unpaid' ) ) {
$booking->update_status( 'cancelled' );
}
}
}
}