Browse Source

** Booking Activities 1.7.18 **

* Tweak - Add an option to duplicate booking forms
* Tweak - Activity WooCommerce products are no longer forced to virtual
* Tweak - Reschedule: display events as unavailable if their availability is insufficient
* Tweak - Calendar editor: Automatically fill the calendar settings if the duplicated calendar is the current one
* Tweak - Disambiguation in calendar editor's calendar settings dialog
* Tweak - Highlight "Calendar field settings" button, and "Add new field" button in form editor
* Tweak - Display user names in user selectbox as a fallback (in backend booking list filter)
* Tweak - Fallback to WooCommerce user data to display in user selectbox (in backend booking list filter)
* Tweak - Display WC cart form as block instead of flex with Elementor
* Tweak - Display Pack tooltip is now displayed on unavailable events on mouseover
* Fix - Booking numbers not updated on events after changing booking quantity (needed a page reload)
* Fix - Tooltip disappeared after updating a booking
* Fix - Couldn't bind the same product to different activities in Calendar field, Action tab
* Fix - PHP notice Undefined index: picked_events
develop 1.7.18
yoan_cutillas 2 years ago
parent
commit
f6344f7811
  1. 4
      booking-activities.php
  2. 7
      class/class-forms-list.php
  3. 8
      controller/controller-bookings.php
  4. 180
      controller/controller-forms.php
  5. 30
      controller/controller-templates.php
  6. 13
      controller/controller-woocommerce-backend.php
  7. 132
      controller/controller-woocommerce-bookings.php
  8. 38
      controller/controller-woocommerce-forms.php
  9. 46
      controller/controller-woocommerce-notifications.php
  10. 14
      controller/controller-woocommerce-settings.php
  11. 15
      css/forms.css
  12. 2
      css/forms.min.css
  13. 12
      css/frontend.css
  14. 2
      css/frontend.min.css
  15. 2
      css/global.css
  16. 2
      css/global.min.css
  17. 5
      css/templates.css
  18. 2
      css/templates.min.css
  19. 10
      css/woocommerce.css
  20. 2
      css/woocommerce.min.css
  21. 21
      functions/functions-booking-system.php
  22. 4
      functions/functions-bookings.php
  23. 8
      functions/functions-forms.php
  24. 35
      functions/functions-global.php
  25. 18
      functions/functions-settings.php
  26. 2
      functions/functions-templates.php
  27. 76
      functions/functions-woocommerce.php
  28. 8
      js/booking-method-calendar.js
  29. 2
      js/booking-method-calendar.min.js
  30. 53
      js/booking-system-functions.js
  31. 2
      js/booking-system-functions.min.js
  32. 10
      js/bookings-dialogs.js
  33. 2
      js/bookings-dialogs.min.js
  34. 8
      js/bookings.js
  35. 2
      js/bookings.min.js
  36. 76
      js/templates-dialogs.js
  37. 2
      js/templates-dialogs.min.js
  38. 13
      js/templates-forms-control.js
  39. 2
      js/templates-forms-control.min.js
  40. 21
      js/templates-functions.js
  41. 2
      js/templates-functions.min.js
  42. 4
      js/templates.js
  43. 2
      js/templates.min.js
  44. 51
      js/woocommerce-backend.js
  45. 2
      js/woocommerce-backend.min.js
  46. 1492
      languages/booking-activities.pot
  47. 3
      languages/script-translation.php
  48. 7
      model/model-bookings.php
  49. 26
      model/model-forms.php
  50. 20
      readme.txt
  51. 4
      view/view-bookings.php
  52. 4
      view/view-form-editor.php
  53. 386
      view/view-templates-dialogs.php
  54. 4
      view/view-templates.php

4
booking-activities.php

@ -3,7 +3,7 @@
* Plugin Name: Booking Activities
* Plugin URI: https://booking-activities.fr/en/?utm_source=plugin&utm_medium=plugin&utm_content=header
* Description: Booking system specialized in activities (sports, cultural, leisure, events...). Works great with WooCommerce.
* Version: 1.7.17
* Version: 1.7.18
* Author: Booking Activities Team
* Author URI: https://booking-activities.fr/en/?utm_source=plugin&utm_medium=plugin&utm_content=header
* Text Domain: booking-activities
@ -40,7 +40,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
// GLOBALS AND CONSTANTS
if( ! defined( 'BOOKACTI_VERSION' ) ) { define( 'BOOKACTI_VERSION', '1.7.17' ); }
if( ! defined( 'BOOKACTI_VERSION' ) ) { define( 'BOOKACTI_VERSION', '1.7.18' ); }
if( ! defined( 'BOOKACTI_PLUGIN_NAME' ) ) { define( 'BOOKACTI_PLUGIN_NAME', 'booking-activities' ); }

7
class/class-forms-list.php

@ -210,7 +210,7 @@ if( ! class_exists( 'Forms_List_Table' ) ) {
/**
* Fill "Title" column and add action buttons
* @version 1.7.12
* @version 1.7.18
* @access public
* @param array $item
* @return string
@ -221,11 +221,14 @@ if( ! class_exists( 'Forms_List_Table' ) ) {
if( current_user_can( 'bookacti_edit_forms' ) ) {
// Add the 'edit' action
// Add the 'edit' and the 'duplicate' actions
if( $item[ 'active_raw' ] ) {
$actions[ 'edit' ] = '<a href="' . esc_url( admin_url( 'admin.php?page=bookacti_forms&action=edit&form_id=' . $form_id ) ) . '" >'
. esc_html_x( 'Edit', 'forms', 'booking-activities' )
. '</a>';
$actions[ 'duplicate' ] = '<a href="' . esc_url( wp_nonce_url( admin_url( 'admin.php?page=bookacti_forms&action=duplicate&form_id=' . $form_id ), 'duplicate-form_' . $form_id ) ) . '" >'
. esc_html_x( 'duplicate', 'forms', 'booking-activities' )
. '</a>';
}
if( current_user_can( 'bookacti_delete_forms' ) ) {

8
controller/controller-bookings.php

@ -263,7 +263,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* AJAX Controller - Get booking system data by booking ID
* @version 1.7.4
* @version 1.7.18
*/
function bookacti_controller_get_booking_data() {
// Check nonce, no need to check capabilities
@ -273,9 +273,11 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
$booking_id = intval( $_POST[ 'booking_id' ] );
$booking_data = bookacti_get_booking_data( $booking_id );
if( ! empty( $booking_data ) && is_array( $booking_data ) ) {
bookacti_send_json( array( 'status' => 'success', 'booking_data' => $booking_data ), 'get_booking_data' );
$calendar_field_data = ! empty( $booking_data[ 'form_id' ] ) ? bookacti_get_form_field_data_by_name( $booking_data[ 'form_id' ], 'calendar' ) : bookacti_get_default_form_fields_data( 'calendar' );
bookacti_send_json( array( 'status' => 'success', 'booking_data' => $booking_data, 'calendar_field_data' => $calendar_field_data ), 'get_booking_data' );
} else {
bookacti_send_json( array( 'status' => 'failed', 'error' => 'empty_data' ), 'get_booking_data' );
}

180
controller/controller-forms.php

@ -7,7 +7,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* Display the form field 'calendar'
* @since 1.5.0
* @version 1.7.17
* @version 1.7.18
* @param array $field
* @param string $instance_id
* @param string $context
@ -17,18 +17,6 @@ function bookacti_display_form_field_calendar( $field, $instance_id, $context )
$field[ 'id' ] = $instance_id;
$field[ 'class' ] = '';
// Check if an event / group of events is picked by default
if( isset( $_REQUEST[ 'bookacti_event_id' ] ) ) { $field[ 'picked_events' ][ 'event_id' ] = is_numeric( $_REQUEST[ 'bookacti_event_id' ] ) ? intval( $_REQUEST[ 'bookacti_event_id' ] ) : ''; }
if( isset( $_REQUEST[ 'event_id' ] ) ) { $field[ 'picked_events' ][ 'event_id' ] = is_numeric( $_REQUEST[ 'event_id' ] ) ? intval( $_REQUEST[ 'event_id' ] ) : ''; }
if( isset( $_REQUEST[ 'bookacti_event_start' ] ) ) { $field[ 'picked_events' ][ 'event_start' ] = bookacti_sanitize_datetime( $_REQUEST[ 'bookacti_event_start' ] ); }
if( isset( $_REQUEST[ 'event_start' ] ) ) { $field[ 'picked_events' ][ 'event_start' ] = bookacti_sanitize_datetime( $_REQUEST[ 'event_start' ] ); }
if( isset( $_REQUEST[ 'bookacti_event_end' ] ) ) { $field[ 'picked_events' ][ 'event_end' ] = bookacti_sanitize_datetime( $_REQUEST[ 'bookacti_event_end' ] ); }
if( isset( $_REQUEST[ 'event_end' ] ) ) { $field[ 'picked_events' ][ 'event_end' ] = bookacti_sanitize_datetime( $_REQUEST[ 'event_end' ] ); }
if( isset( $_REQUEST[ 'bookacti_group_id' ] ) ) { $field[ 'picked_events' ][ 'group_id' ] = is_numeric( $_REQUEST[ 'bookacti_group_id' ] ) ? intval( $_REQUEST[ 'bookacti_group_id' ] ) : ''; }
if( isset( $_REQUEST[ 'event_group_id' ] ) ) { $field[ 'picked_events' ][ 'group_id' ] = is_numeric( $_REQUEST[ 'event_group_id' ] ) ? intval( $_REQUEST[ 'event_group_id' ] ) : ''; }
if( is_numeric( $field[ 'picked_events' ][ 'event_id' ] )
&& ! is_numeric( $field[ 'picked_events' ][ 'group_id' ] ) ) { $field[ 'picked_events' ][ 'group_id' ] = 'single'; }
// Do not auto load on form editor
// So that if a JS error occurs, you can still change the calendar settings and try to fix it
if( $context === 'edit' ) { $field[ 'auto_load' ] = 0; }
@ -962,9 +950,96 @@ function bookacti_controller_update_form() {
add_action( 'wp_ajax_bookactiUpdateForm', 'bookacti_controller_update_form' );
/**
* Duplicate a booking form
* @since 1.7.18
*/
function bookacti_controller_duplicate_form() {
if( empty( $_REQUEST[ 'form_id' ] ) || empty( $_REQUEST[ 'action' ] ) || empty( $_REQUEST[ 'page' ] )
|| $_REQUEST[ 'page' ] !== 'bookacti_forms'
|| ! is_numeric( $_REQUEST[ 'form_id' ] )
|| $_REQUEST[ 'action' ] !== 'duplicate' ) { return; }
$notice = array( 'type' => 'error', 'message' => '' );
$original_form_id = intval( $_REQUEST[ 'form_id' ] );
// Check nonces
if( ! wp_verify_nonce( $_REQUEST[ '_wpnonce' ], 'duplicate-form_' . $original_form_id ) ) {
$notice[ 'message' ] = esc_html__( 'You are not allowed to do that.', 'booking-activities' );
bookacti_display_admin_notice( $notice, 'duplicate_form' );
return;
}
// Check permissions
if( ! current_user_can( 'bookacti_create_forms' ) || ! current_user_can( 'bookacti_edit_forms' ) || ! bookacti_user_can_manage_form( $original_form_id ) ) {
$notice[ 'message' ] = esc_html__( 'You are not allowed to do that.', 'booking-activities' );
bookacti_display_admin_notice( $notice, 'duplicate_form' );
return;
}
// Gget original form data
$original_form_data = bookacti_get_form_data( $original_form_id );
if( ! $original_form_data ) {
$notice[ 'message' ] = esc_html__( 'An error occured while trying to duplicate a booking form.', 'booking-activities' );
bookacti_display_admin_notice( $notice, 'duplicate_form' );
return;
}
// Duplicate the form
/* translators: %s is the original title */
$form_title = sprintf( esc_html__( '%s - Copy', 'booking-activities' ), $original_form_data[ 'title' ] );
$form_id = bookacti_create_form( $form_title, 'publish', 1, array( 'none' ) );
if( ! $form_id ) {
$notice[ 'message' ] = esc_html__( 'Error occurs when trying to create the form.', 'booking-activities' );
bookacti_display_admin_notice( $notice, 'duplicate_form' );
return;
}
// Update form managers
$original_form_managers = bookacti_get_managers( 'form', $original_form_id );
bookacti_update_managers( 'form', $form_id, $original_form_managers );
// Duplicate the fields
$field_order = array();
$original_fields = bookacti_get_form_fields_data( $original_form_id );
$default_form_fields_meta = bookacti_get_default_form_fields_meta();
if( $original_fields ) {
$original_fields_ordered = bookacti_sort_form_fields_array( $original_form_id, $original_fields );
foreach( $original_fields_ordered as $original_field ) {
// Duplicate field
$sanitized_data = bookacti_sanitize_form_field_data( $original_field );
$field_id = bookacti_insert_form_field( $form_id, $sanitized_data );
if( ! $field_id ) { continue; }
$field_order[] = $field_id;
// Duplicate field meta
$field_meta = ! empty( $default_form_fields_meta[ $original_field[ 'name' ] ] ) ? array_intersect_key( $sanitized_data, $default_form_fields_meta[ $original_field[ 'name' ] ] ) : array();
if( ! $field_meta ) { continue; }
bookacti_update_metadata( 'form_field', $field_id, $field_meta );
}
}
// Duplicate form meta
$sanitized_data = bookacti_sanitize_form_data( $original_form_data );
$form_meta = array_intersect_key( $sanitized_data, bookacti_get_default_form_meta() );
if( $field_order ) { $form_meta[ 'field_order' ] = $field_order; }
bookacti_update_metadata( 'form', $form_id, $form_meta );
// Allow plugins to hook here
do_action( 'bookacti_form_duplicated', $form_id, $original_form_id );
// Feedback success
$notice[ 'type' ] = 'success';
$notice[ 'message' ] = esc_html__( 'The booking form has been duplicated.', 'booking-activities' );
bookacti_display_admin_notice( $notice, 'duplicate_form' );
}
add_action( 'all_admin_notices', 'bookacti_controller_duplicate_form', 10 );
/**
* Trash / Remove / Restore a booking form according to URL parameters and display an admin notice to feedback
* @since 1.5.0
* @version 1.7.18
*/
function bookacti_controller_remove_form() {
if( empty( $_REQUEST[ 'form_id' ] ) || empty( $_REQUEST[ 'action' ] ) || empty( $_REQUEST[ 'page' ] )
@ -972,33 +1047,24 @@ function bookacti_controller_remove_form() {
|| ! is_numeric( $_REQUEST[ 'form_id' ] )
|| ! in_array( $_REQUEST[ 'action' ], array( 'trash', 'restore', 'delete' ), true ) ) { return; }
$notice = array( 'type' => 'error', 'message' => '' );
$form_id = intval( $_REQUEST[ 'form_id' ] );
$action = $_REQUEST[ 'action' ] . '_form';
// Check nonces
if( ! wp_verify_nonce( $_REQUEST[ '_wpnonce' ], $_REQUEST[ 'action' ] . '-form_' . $form_id ) ) {
?>
<div class='notice notice-error is-dismissible bookacti-form-notice' >
<p>
<?php _e( 'You are not allowed to do that.', 'booking-activities' ); ?>
</p>
</div>
<?php
$notice[ 'message' ] = esc_html__( 'You are not allowed to do that.', 'booking-activities' );
bookacti_display_admin_notice( $notice, $action );
return;
}
// Remove a booking form
if( $_REQUEST[ 'action' ] === 'trash' || $_REQUEST[ 'action' ] === 'delete' ) {
// Check if current user is allowed to remove the booking form
$can_delete_form = current_user_can( 'bookacti_delete_forms' ) && bookacti_user_can_manage_form( $form_id );
if( ! $can_delete_form ) {
?>
<div class='notice notice-error is-dismissible bookacti-form-notice' >
<p>
<?php _e( 'You are not allowed to remove a booking form.', 'booking-activities' ); ?>
</p>
</div>
<?php
$notice[ 'message' ] = esc_html__( 'You are not allowed to remove a booking form.', 'booking-activities' );
bookacti_display_admin_notice( $notice, $action );
return;
}
@ -1011,69 +1077,41 @@ function bookacti_controller_remove_form() {
$removed = bookacti_delete_form( $form_id );
}
// Feedback success
if( $removed ) {
do_action( 'bookacti_form_removed', $form_id );
?>
<div class='notice notice-success is-dismissible bookacti-form-notice' >
<p>
<?php _e( 'The booking form has been removed.', 'booking-activities' ); ?>
</p>
</div>
<?php
// Feedback failure
$notice[ 'type' ] = 'success';
$notice[ 'message' ] = esc_html__( 'The booking form has been removed.', 'booking-activities' );
} else {
?>
<div class='notice notice-error is-dismissible bookacti-form-notice' >
<p>
<?php _e( 'An error occured while trying to delete a booking form.', 'booking-activities' ); ?>
</p>
</div>
<?php
$notice[ 'message' ] = esc_html__( 'An error occured while trying to delete a booking form.', 'booking-activities' );
}
}
// Restore a booking form
else if( $_REQUEST[ 'action' ] === 'restore' ) {
// Check if current user is allowed to restore the booking form
$can_edit_form = current_user_can( 'bookacti_edit_forms' );
if( ! $can_edit_form ) {
?>
<div class='notice notice-error is-dismissible bookacti-form-notice' >
<p>
<?php _e( 'You are not allowed to restore a booking form.', 'booking-activities' ); ?>
</p>
</div>
<?php
$notice[ 'message' ] = esc_html__( 'You are not allowed to restore a booking form.', 'booking-activities' );
bookacti_display_admin_notice( $notice, $action );
return;
}
$restored = bookacti_activate_form( $form_id );
// Feedback success
if( $restored ) {
do_action( 'bookacti_form_restored', $form_id );
?>
<div class='notice notice-success is-dismissible bookacti-form-notice' >
<p>
<?php _e( 'The booking form has been restored.', 'booking-activities' ); ?>
</p>
</div>
<?php
$notice[ 'type' ] = 'success';
$notice[ 'message' ] = esc_html__( 'The booking form has been restored.', 'booking-activities' );
// Feedback failure
} else {
?>
<div class='notice notice-error is-dismissible bookacti-form-notice' >
<p>
<?php _e( 'An error occured while trying to restore a booking form.', 'booking-activities' ); ?>
</p>
</div>
<?php
$notice[ 'message' ] = esc_html__( 'An error occured while trying to restore a booking form.', 'booking-activities' );
}
}
// Feedback
bookacti_display_admin_notice( $notice, $action );
}
add_action( 'all_admin_notices', 'bookacti_controller_remove_form', 10 );
@ -1427,13 +1465,13 @@ add_filter( 'bookacti_send_json_reset_form_field', 'bookacti_send_booking_system
/**
* Add the "Export" action to the "Calendar" field in form editor
* @version 1.6.0
* @version 1.7.18
* @param array $field
*/
function bookacti_add_export_action_to_calendar_field( $field ) {
if( $field[ 'name' ] !== 'calendar' ) { return; }
?>
<div class='bookacti-form-editor-field-action bookacti-export-events dashicons dashicons-external' title='<?php esc_attr_e( 'Export events', 'booking-activities' ); ?>'></div>
<div id='bookacti-export-events-form-field-<?php echo esc_attr( $field[ 'field_id' ] ); ?>' class='bookacti-form-editor-field-action bookacti-export-events dashicons dashicons-external' title='<?php esc_attr_e( 'Export events', 'booking-activities' ); ?>'></div>
<?php
}
add_action( 'bookacti_form_editor_field_actions_after', 'bookacti_add_export_action_to_calendar_field', 10, 1 );

30
controller/controller-templates.php

@ -705,7 +705,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* AJAX Controller - Create a new template
* @version 1.7.10
* @version 1.7.18
*/
function bookacti_controller_insert_template() {
// Check nonce and capabilities
@ -716,10 +716,10 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
bookacti_send_json_not_allowed( 'insert_template' );
}
$template_title = sanitize_text_field( stripslashes( $_POST['template-title'] ) );
$template_start = bookacti_sanitize_date( $_POST['template-opening'] );
$template_end = bookacti_sanitize_date( $_POST['template-closing'] );
$template_title = sanitize_text_field( stripslashes( $_POST[ 'template-title' ] ) );
$template_start = bookacti_sanitize_date( $_POST[ 'template-opening' ] ) ? bookacti_sanitize_date( $_POST[ 'template-opening' ] ) : date( 'Y-m-d' );
$template_end = bookacti_sanitize_date( $_POST[ 'template-closing' ] ) ? bookacti_sanitize_date( $_POST[ 'template-closing' ] ) : '2037-12-31';
$is_template_valid = bookacti_validate_template_data( $template_title, $template_start, $template_end );
// Create template only if its data are consistent
@ -727,9 +727,9 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
bookacti_send_json( array( 'status' => 'failed' ), 'insert_template' );
}
$duplicated_template_id = intval( $_POST['duplicated-template-id'] );
$managers_array = isset( $_POST['template-managers'] ) ? bookacti_ids_to_array( $_POST['template-managers'] ) : array();
$options_array = isset( $_POST['templateOptions'] ) && is_array( $_POST['templateOptions'] ) ? $_POST['templateOptions'] : array();
$duplicated_template_id = intval( $_POST[ 'duplicated-template-id' ] );
$managers_array = isset( $_POST[ 'template-managers' ] ) ? bookacti_ids_to_array( $_POST[ 'template-managers' ] ) : array();
$options_array = isset( $_POST[ 'templateOptions' ] ) && is_array( $_POST[ 'templateOptions' ] ) ? $_POST[ 'templateOptions' ] : array();
$template_managers = bookacti_format_template_managers( $managers_array );
$template_settings = bookacti_format_template_settings( $options_array );
@ -749,7 +749,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* AJAX Controller - Update template
* @version 1.7.17
* @version 1.7.18
*/
function bookacti_controller_update_template() {
$template_id = intval( $_POST['template-id'] );
@ -762,10 +762,10 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
bookacti_send_json_not_allowed( 'update_template' );
}
$template_title = sanitize_text_field( stripslashes( $_POST['template-title'] ) );
$template_start = bookacti_sanitize_date( $_POST['template-opening'] );
$template_end = bookacti_sanitize_date( $_POST['template-closing'] );
$template_title = sanitize_text_field( stripslashes( $_POST[ 'template-title' ] ) );
$template_start = bookacti_sanitize_date( $_POST[ 'template-opening' ] ) ? bookacti_sanitize_date( $_POST[ 'template-opening' ] ) : date( 'Y-m-d' );
$template_end = bookacti_sanitize_date( $_POST[ 'template-closing' ] ) ? bookacti_sanitize_date( $_POST[ 'template-closing' ] ) : '2037-12-31';
$is_template_valid = bookacti_validate_template_data( $template_title, $template_start, $template_end );
// Update template only if its data are consistent
@ -776,8 +776,8 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
$updated_template = bookacti_update_template( $template_id, $template_title, $template_start, $template_end );
$updated_metadata = 0;
if( isset( $_POST['templateOptions'] ) ) {
$template_settings = bookacti_format_template_settings( $_POST['templateOptions'] );
if( isset( $_POST[ 'templateOptions' ] ) ) {
$template_settings = bookacti_format_template_settings( $_POST[ 'templateOptions' ] );
$updated_metadata = bookacti_update_metadata( 'template', $template_id, $template_settings );
}

13
controller/controller-woocommerce-backend.php

@ -829,17 +829,13 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* Save custom activity product type and activity tab content
* @version 1.5.0
* @version 1.7.18
* @param int $post_id
*/
function bookacti_save_custom_product_type_and_tab_content( $post_id ) {
if( ! empty( $_POST['_bookacti_is_activity'] ) ) {
update_post_meta( $post_id, '_bookacti_is_activity', sanitize_text_field( 'yes' ) );
//Force the product to be flagged as virtual if it is an activity
if( empty( $_POST['_virtual'] ) ) {
update_post_meta( $post_id, '_virtual', wc_clean( 'yes' ) );
}
} else {
update_post_meta( $post_id, '_bookacti_is_activity', sanitize_text_field( 'no' ) );
}
@ -1282,7 +1278,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* Save custom variation product
* @version 1.7.16
* @version 1.7.18
* @param int $post_id
*/
function bookacti_save_variation_option( $post_id ) {
@ -1298,11 +1294,6 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
if ( isset( $_POST[ 'bookacti_variable_is_activity' ][ $key ] ) ) {
$variable_is_activity = $_POST[ 'bookacti_variable_is_activity' ][ $key ] === 'yes' ? 'yes' : 'no';
update_post_meta( $variation_id, 'bookacti_variable_is_activity', $variable_is_activity );
// Force the variation to be flagged as virtual if it is an activity
if( $variable_is_activity === 'yes' ) {
update_post_meta( $variation_id, '_virtual', 'yes' );
}
}
// Save form

132
controller/controller-woocommerce-bookings.php

@ -237,16 +237,14 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* Turn paid order status to complete if the order has only activities
*
* @version 1.5.8
* Turn paid order status to complete if the order has only virtual activities
* @version 1.7.18
* @param string $order_status
* @param int $order_id
* @return string
*/
function bookacti_set_order_status_to_completed_after_payment( $order_status, $order_id ) {
if( ! in_array( $order_status, array( 'processing', 'pending' ), true ) ) { return $order_status; }
if( ! in_array( $order_status, array( 'completed', 'processing', 'pending' ), true ) ) { return $order_status; }
$order = wc_get_order( $order_id );
if( empty( $order ) ) { return $order_status; }
@ -262,21 +260,33 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
break;
}
}
// Check if the order is only composed of activities
// Check if the order is only composed of (virtual) activities
$are_activities = true;
$are_virtual_activities = true;
foreach( $items as $item ) {
// Is activity
if( ! isset( $item[ 'bookacti_booking_id' ] ) && ! isset( $item[ 'bookacti_booking_group_id' ] ) ) {
$are_activities = false;
break;
}
// Is virtual
$product = $item[ 'variation_id' ] ? wc_get_product( $item[ 'variation_id' ] ) : wc_get_product( $item[ 'product_id' ] );
if( $product && ! $product->is_virtual() ) {
$are_virtual_activities = false;
}
}
// If there are only activities, mark the order as 'completed' and
// If there are only virtual activities, mark the order as 'completed' and
// a function hooked to woocommerce_order_status_completed will mark the activities as 'booked'
if( $are_activities ) {
if( $are_activities && $are_virtual_activities ) {
$order_status = 'completed';
// If there are only virtual activities, but not virtuals, mark the order as 'processing' and
// mark the activities as 'booked'
} else if( $are_activities ) {
$order_status = 'processing';
// If there are at least one activity in the middle of other products,
// we won't mark the order as 'completed', but we still need to mark the bookings as 'pending' and 'owed'
// until the order changes state. At that time the bookings state will be redefined by other hooks
@ -291,13 +301,12 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* Turn bookings of a paid order containing non-activity products to booked
* @version 1.6.0
* Turn the bookings bound to order items of a paid order to booked
* @since 1.7.18 (was bookacti_turn_non_activity_order_bookings_to_permanent)
* @param int $order_id
* @param WC_Order $order
*/
function bookacti_turn_non_activity_order_bookings_to_permanent( $order_id, $order = null ) {
function bookacti_turn_paid_order_item_bookings_to_permanent( $order_id, $order = null ) {
if( ! $order ) { $order = wc_get_order( $order_id ); }
if( ! $order ) { return false; }
@ -312,31 +321,59 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
// Retrieve bought items
$items = $order->get_items();
// Check if the order has at least 1 activity
$has_activities = false;
foreach( $items as $item ) {
if( isset( $item[ 'bookacti_booking_id' ] ) || isset( $item[ 'bookacti_booking_group_id' ] ) ) {
$has_activities = true;
break;
}
}
// Check if the order is only composed of activities
$are_activities = true;
// Get virtual order item booking ids
$virtual_item_booking_ids = array();
$virtual_item_booking_group_ids = array();
$non_virtual_item_booking_ids = array();
$non_virtual_item_booking_group_ids = array();
foreach( $items as $item ) {
if( ! isset( $item[ 'bookacti_booking_id' ] ) && ! isset( $item[ 'bookacti_booking_group_id' ] ) ) {
$are_activities = false;
break;
// Is activity
if( ! isset( $item[ 'bookacti_booking_id' ] ) && ! isset( $item[ 'bookacti_booking_group_id' ] ) ) { continue; }
// Is virtual
$product = $item[ 'variation_id' ] ? wc_get_product( $item[ 'variation_id' ] ) : wc_get_product( $item[ 'product_id' ] );
if( ! $product ) { continue; }
if( $product->is_virtual() ) {
if( isset( $item[ 'bookacti_booking_id' ] ) ) { $virtual_item_booking_ids[] = $item[ 'bookacti_booking_id' ]; }
if( isset( $item[ 'bookacti_booking_group_id' ] ) ) { $virtual_item_booking_group_ids[] = $item[ 'bookacti_booking_group_id' ]; }
} else {
if( isset( $item[ 'bookacti_booking_id' ] ) ) { $non_virtual_item_booking_ids[] = $item[ 'bookacti_booking_id' ]; }
if( isset( $item[ 'bookacti_booking_group_id' ] ) ) { $non_virtual_item_booking_group_ids[] = $item[ 'bookacti_booking_group_id' ]; }
}
}
// If there are at least one activity in the middle of other products,
// mark the bookings as 'booked' and 'paid'
if( ! $are_activities && $has_activities ) {
// Allow plugins to change the default booking status of paid non virtual bookings
$non_virtual_booking_status = apply_filters( 'bookacti_paid_non_virtual_booking_status', 'booked' );
// Turn all order bookings to booked
if( $non_virtual_booking_status === 'booked' ) {
bookacti_turn_temporary_booking_to_permanent( $order_id, $order, 'booked', 'paid' );
} else {
$updated_bookings = array( 'booking_ids' => array(), 'booking_group_ids' => array() );
// Turn non virtual activities to their permanent booking status
if( $non_virtual_item_booking_ids || $non_virtual_item_booking_group_ids ) {
$updated_bookings = bookacti_turn_order_bookings_to( $order, $non_virtual_booking_status, 'paid', true, array( 'states_in' => array( 'in_cart', 'pending' ), 'in__booking_id' => $non_virtual_item_booking_ids, 'in__booking_group_id' => $non_virtual_item_booking_group_ids, 'is_new_order' => true ) );
if( $updated_bookings && is_numeric( $updated_bookings[ 'updated' ] ) && intval( $updated_bookings[ 'updated' ] ) === 0 ) {
$notification_args = array_merge( $updated_bookings, array( 'is_new_order' => true ) );
bookacti_send_notification_when_order_status_changes( $order_id, $non_virtual_booking_status, $notification_args );
}
}
// Turn virtual activities to booked in any case
if( $virtual_item_booking_ids || $virtual_item_booking_group_ids ) {
$updated_virtual_bookings = bookacti_turn_order_bookings_to( $order, 'booked', 'paid', true, array( 'states_in' => array( 'in_cart', 'pending' ), 'in__booking_id' => $virtual_item_booking_ids, 'in__booking_group_id' => $virtual_item_booking_group_ids ) );
if( $updated_virtual_bookings ) {
$updated_bookings[ 'booking_ids' ] = array_merge( $updated_bookings[ 'booking_ids' ], $updated_virtual_bookings[ 'booking_ids' ] );
$updated_bookings[ 'booking_group_ids' ]= array_merge( $updated_bookings[ 'booking_group_ids' ], $updated_virtual_bookings[ 'booking_group_ids' ] );
}
}
// Remove remaining undesired bookings
bookacti_cancel_order_pending_bookings( $order_id, $updated_bookings[ 'booking_ids' ], $updated_bookings[ 'booking_group_ids' ] );
}
}
add_action( 'woocommerce_order_status_pending_to_processing', 'bookacti_turn_non_activity_order_bookings_to_permanent', 5, 2 );
add_action( 'woocommerce_order_status_pending_to_processing', 'bookacti_turn_paid_order_item_bookings_to_permanent', 5, 2 );
add_action( 'woocommerce_order_status_pending_to_on-hold', 'bookacti_turn_paid_order_item_bookings_to_permanent', 5, 2 );
@ -925,31 +962,32 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* Turn order items booking status meta to new status
*
* @since 1.2.0
* @version 1.5.6
*
* @version 1.7.18
* @param WC_Order $order
* @param string $new_state
* @param array $args
*/
function bookacti_update_order_items_booking_status_by_order_id( $order, $new_state, $args ) {
if( is_numeric( $order ) ) {
$order = wc_get_order( $order );
}
if( is_numeric( $order ) ) { $order = wc_get_order( $order ); }
if( ! $order ) { return; }
$order_items = $order->get_items();
if( ! $order_items ) { return; }
foreach( $order_items as $order_item_id => $order_item ) {
$item = $order_item;
if( version_compare( WC_VERSION, '3.0.0', '<' ) ) {
$item[ 'id' ] = $order_item_id;
}
$in__booking_id = ! empty( $args[ 'booking_ids' ] ) ? $args[ 'booking_ids' ] : array();
$in__booking_group_id = ! empty( $args[ 'booking_group_ids' ] ) ? $args[ 'booking_group_ids' ] : array();
foreach( $order_items as $item_id => $item ) {
// Make sure the order item has a booking
if( ! isset( $item[ 'bookacti_booking_id' ] ) && ! isset( $item[ 'bookacti_booking_group_id' ] ) ) { continue; }
// Make sure the booking is part of those updated
if( isset( $item[ 'bookacti_booking_id' ] ) && ( $in__booking_id || $in__booking_group_id ) && ! in_array( $item[ 'bookacti_booking_id' ], $in__booking_id ) ) { continue; }
if( isset( $item[ 'bookacti_booking_group_id' ] ) && ( $in__booking_id || $in__booking_group_id ) && ! in_array( $item[ 'bookacti_booking_group_id' ], $in__booking_group_id ) ) { continue; }
if( version_compare( WC_VERSION, '3.0.0', '<' ) ) { $item[ 'id' ] = $item_id; }
// Do not allow to update order status based on new bookings status
// because this function is actually triggered after order status changed

38
controller/controller-woocommerce-forms.php

@ -168,6 +168,7 @@ add_filter( 'bookacti_formatted_booking_system_attributes', 'bookacti_format_wc_
/**
* Sanitize WC booking system attributes
* @since 1.7.17
* @version 1.7.18
* @param array $field_data
* @param array $raw_field_data
* @return array
@ -175,8 +176,8 @@ add_filter( 'bookacti_formatted_booking_system_attributes', 'bookacti_format_wc_
function bookacti_format_wc_field_data( $field_data, $raw_field_data ) {
if( $raw_field_data[ 'name' ] === 'calendar' ) {
$default_meta = bookacti_default_wc_calendar_form_field_meta( array() );
$field_data[ 'product_by_activity' ] = isset( $raw_field_data[ 'product_by_activity' ] ) && is_array( $raw_field_data[ 'product_by_activity' ] ) ? bookacti_ids_to_array( $raw_field_data[ 'product_by_activity' ] ) : $default_meta[ 'product_by_activity' ];
$field_data[ 'product_by_group_category' ] = isset( $raw_field_data[ 'product_by_group_category' ] ) && is_array( $raw_field_data[ 'product_by_group_category' ] ) ? bookacti_ids_to_array( $raw_field_data[ 'product_by_group_category' ] ) : $default_meta[ 'product_by_group_category' ];
$field_data[ 'product_by_activity' ] = isset( $raw_field_data[ 'product_by_activity' ] ) && is_array( $raw_field_data[ 'product_by_activity' ] ) ? array_filter( array_map( 'intval', $raw_field_data[ 'product_by_activity' ] ) ) : $default_meta[ 'product_by_activity' ];
$field_data[ 'product_by_group_category' ] = isset( $raw_field_data[ 'product_by_group_category' ] ) && is_array( $raw_field_data[ 'product_by_group_category' ] ) ? array_filter( array_map( 'intval', $raw_field_data[ 'product_by_group_category' ] ) ) : $default_meta[ 'product_by_group_category' ];
}
return $field_data;
}
@ -186,7 +187,7 @@ add_filter( 'bookacti_formatted_field_data', 'bookacti_format_wc_field_data', 10
/**
* Sanitize WC booking system attributes
* @since 1.7.0
* @version 1.7.17
* @version 1.7.18
* @param array $field_data
* @param array $raw_field_data
* @return array
@ -194,8 +195,8 @@ add_filter( 'bookacti_formatted_field_data', 'bookacti_format_wc_field_data', 10
function bookacti_sanitize_wc_field_data( $field_data, $raw_field_data ) {
if( $raw_field_data[ 'name' ] === 'calendar' ) {
$default_meta = bookacti_default_wc_calendar_form_field_meta( array() );
$field_data[ 'product_by_activity' ] = isset( $raw_field_data[ 'product_by_activity' ] ) && is_array( $raw_field_data[ 'product_by_activity' ] ) ? bookacti_ids_to_array( $raw_field_data[ 'product_by_activity' ] ) : $default_meta[ 'product_by_activity' ];
$field_data[ 'product_by_group_category' ] = isset( $raw_field_data[ 'product_by_group_category' ] ) && is_array( $raw_field_data[ 'product_by_group_category' ] ) ? bookacti_ids_to_array( $raw_field_data[ 'product_by_group_category' ] ) : $default_meta[ 'product_by_group_category' ];
$field_data[ 'product_by_activity' ] = isset( $raw_field_data[ 'product_by_activity' ] ) && is_array( $raw_field_data[ 'product_by_activity' ] ) ? array_filter( array_map( 'intval', $raw_field_data[ 'product_by_activity' ] ) ) : $default_meta[ 'product_by_activity' ];
$field_data[ 'product_by_group_category' ] = isset( $raw_field_data[ 'product_by_group_category' ] ) && is_array( $raw_field_data[ 'product_by_group_category' ] ) ? array_filter( array_map( 'intval', $raw_field_data[ 'product_by_group_category' ] ) ) : $default_meta[ 'product_by_group_category' ];
}
return $field_data;
}
@ -468,4 +469,29 @@ function bookacti_change_product_form_id_if_added_to_cart_via_booking_form( $for
}
return $form_id;
}
add_filter( 'bookacti_product_booking_form_id', 'bookacti_change_product_form_id_if_added_to_cart_via_booking_form', 10, 3 );
add_filter( 'bookacti_product_booking_form_id', 'bookacti_change_product_form_id_if_added_to_cart_via_booking_form', 10, 3 );
/**
* Display WC user meta corresponding to the desired meta if it is empty
* @since 1.7.18
* @param array $args
* @param array $raw_args
* @return array
*/
function bookacti_display_wc_user_meta_in_user_selectbox( $args, $raw_args ) {
$wc_additional_option_labels = array(
'user_email'=> 'billing_email',
'first_name'=> 'billing_first_name||shipping_first_name',
'last_name' => 'billing_last_name||shipping_last_name',
'phone' => 'billing_phone'
);
$wc_additional_option_labels_keys = array_keys( $wc_additional_option_labels );
foreach( $args[ 'option_label' ] as $i => $show ) {
if( in_array( $show, $wc_additional_option_labels_keys, true ) ) {
$args[ 'option_label' ][ $i ] .= '||' . $wc_additional_option_labels[ $show ];
}
}
return $args;
}
add_filter( 'bookacti_user_selectbox_args', 'bookacti_display_wc_user_meta_in_user_selectbox', 10, 2 );

46
controller/controller-woocommerce-notifications.php

@ -4,19 +4,14 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* Send one notification per booking to admin and customer when an order contining bookings is made or when its status changes
*
* @since 1.2.2
* @version 1.7.0
* @version 1.7.18
* @param WC_Order $order
* @param string $new_status
* @param array $args
*/
function bookacti_send_notification_when_order_status_changes( $order, $new_status, $args = array() ) {
if( is_numeric( $order ) ) {
$order = wc_get_order( $order );
}
if( is_numeric( $order ) ) { $order = wc_get_order( $order ); }
if( ! $order ) { return; }
$action = isset( $_REQUEST[ 'action' ] ) ? $_REQUEST[ 'action' ] : '';
@ -42,28 +37,29 @@ function bookacti_send_notification_when_order_status_changes( $order, $new_stat
$order_status = $order->get_status();
if( ( $order_status === 'pending' && $new_status === 'pending' )
|| ( $order_status === 'failed' && $new_status === 'cancelled' ) ) { return; }
$order_items = $order->get_items();
if( ! $order_items ) { return; }
$in__booking_id = ! empty( $args[ 'booking_ids' ] ) ? $args[ 'booking_ids' ] : array();
$in__booking_group_id = ! empty( $args[ 'booking_group_ids' ] ) ? $args[ 'booking_group_ids' ] : array();
foreach( $order_items as $order_item_id => $item ) {
// Check if the order item is a booking, or skip it
if( ! $item || ( ! isset( $item[ 'bookacti_booking_id' ] ) && ! isset( $item[ 'bookacti_booking_group_id' ] ) ) ) { continue; }
// Make sure the booking is part of those updated
if( isset( $item[ 'bookacti_booking_id' ] ) && ( $in__booking_id || $in__booking_group_id ) && ! in_array( $item[ 'bookacti_booking_id' ], $in__booking_id ) ) { continue; }
if( isset( $item[ 'bookacti_booking_group_id' ] ) && ( $in__booking_id || $in__booking_group_id ) && ! in_array( $item[ 'bookacti_booking_group_id' ], $in__booking_group_id ) ) { continue; }
// If the state hasn't changed, do not send the notifications, unless it is a new order
$old_status = isset( $args[ 'old_status' ] ) && $args[ 'old_status' ] ? $args[ 'old_status' ] : wc_get_order_item_meta( $order_item_id, 'bookacti_state', true );
if( $old_status === $new_status && empty( $args[ 'is_new_order' ] ) ) { continue; }
// Get booking ID and booking type ('single' or 'group')
if( isset( $item[ 'bookacti_booking_id' ] ) ) {
$booking_id = $item[ 'bookacti_booking_id' ];
$booking_type = 'single';
}
else if( isset( $item[ 'bookacti_booking_group_id' ] ) ) {
$booking_id = $item[ 'bookacti_booking_group_id' ];
$booking_type = 'group';
}
$booking_id = isset( $item[ 'bookacti_booking_id' ] ) ? $item[ 'bookacti_booking_id' ] : ( isset( $item[ 'bookacti_booking_group_id' ] ) ? $item[ 'bookacti_booking_group_id' ] : 0 );
$booking_type = isset( $item[ 'bookacti_booking_id' ] ) ? 'single' : ( isset( $item[ 'bookacti_booking_group_id' ] ) ? 'group' : '' );
if( ! $booking_id || ! $booking_type ) { continue; }
// Send a booking confirmation to the customer
if( $notify_customer ) {
@ -79,20 +75,6 @@ function bookacti_send_notification_when_order_status_changes( $order, $new_stat
add_action( 'bookacti_order_bookings_state_changed', 'bookacti_send_notification_when_order_status_changes', 10, 3 );
/**
* Send notifications when a new order is made but stays in a pending state
*
* @since 1.2.2
* @param int $order_id
* @param WC_Order $order
*/
function bookacti_send_notification_when_new_order_is_pending( $order_id, $order = null ) {
bookacti_send_notification_when_order_status_changes( $order_id, 'pending', array( 'is_new_order' => true ) );
}
add_action( 'woocommerce_order_status_pending_to_processing', 'bookacti_send_notification_when_new_order_is_pending', 20, 2 );
add_action( 'woocommerce_order_status_pending_to_on-hold', 'bookacti_send_notification_when_new_order_is_pending', 20, 2 );
/**
* Add a mention to notifications
*

14
controller/controller-woocommerce-settings.php

@ -155,20 +155,6 @@ function bookacti_delete_woocommerce_settings() {
add_action( 'bookacti_delete_settings', 'bookacti_delete_woocommerce_settings' );
/**
* Add a mention to booking method tip
*
* @param string $tip
* @return string
*/
function bookacti_add_wc_mention_to_booking_method_tip( $tip ) {
$tip .= '<br/>';
$tip .= esc_html__( 'This parameter can be overriden by products settings in woocommerce.', 'booking-activities' );
return $tip;
}
add_filter( 'bookacti_booking_methods_tip', 'bookacti_add_wc_mention_to_booking_method_tip', 20, 1 );
/**
* Add notification global settings
*

15
css/forms.css

@ -41,16 +41,15 @@ body.booking-activities_page_bookacti_forms label[for='bookacti_form_publish-hid
.bookacti-form-editor-field-header { display: flex; justify-content: space-between; border-bottom: 1px solid #e5e5e5; transition: max-height 0.2s; }
.bookacti-form-editor-field-title { cursor: move; margin: 1em; margin-right: 0; width: 100%; text-align: left; }
.bookacti-form-editor-field-header h3 { display: inline-block; vertical-align: middle; margin: 0; padding: 0; }
.bookacti-form-editor-field-actions { margin: 1em; white-space: nowrap; }
.bookacti-form-editor-field-actions { margin: 1em; white-space: nowrap; position: relative; }
.bookacti-form-editor-field-body { padding: 1em; }
.bookacti-form-editor-field-placeholder { display: block; min-height: 47px; width: 100%; border: 1px dashed #b4b9be; margin: 1em 0; }
#bookacti-form-editor-actions > *,
.bookacti-form-editor-field-actions > * { display: inline-block; vertical-align: middle; color: #565d61; cursor: pointer; }
#bookacti-form-editor-actions > *:hover,
.bookacti-form-editor-field-actions > *:hover,
#bookacti-form-editor-container .dashicons-plus-alt { color: #418fb6; }
#bookacti-form-editor-container .dashicons-plus-alt { transition: all 0.2s; }
#bookacti-insert-form-field:hover { font-size: 32px; height: 32px; width: 32px; margin-right: -6px; transition: all 0.2s; }
#bookacti-form-editor-actions > .button,
.bookacti-form-editor-field-actions > .button { vertical-align: middle; }
#bookacti-form-editor-actions > .button-secondary,
.bookacti-form-editor-field-actions > .button-secondary { color: #0071a1; }
.bookacti-form-editor-field-header .bookacti-wc-icon-not-supported { display: inline-block; vertical-align: middle; margin-right: 20px; font-weight: normal; }
#bookacti-form-editor .bookacti-addon-promo { text-align: left; }
@ -58,6 +57,10 @@ body.booking-activities_page_bookacti_forms label[for='bookacti_form_publish-hid
.bookacti-form-action-wc-notice { color: #f89b2f; }
.bookacti-form-action-wc-notice:before { content: '\26A0 '; }
#bookacti-insert-form-field { padding-left: 6px; }
#bookacti-insert-form-field:before { content: '\f132'; font: 400 20px dashicons; margin-right: 4px; vertical-align: middle; }
.bookacti-form-field-name-calendar .bookacti-edit-form-field:before { content: '\f111'; font: 400 20px dashicons; margin-right: 4px; vertical-align: sub; }
/* Dialogs */
.bookacti-form-dialog form div > fieldset > label:not(.bookacti-onoffswitch-label),

2
css/forms.min.css

File diff suppressed because one or more lines are too long

12
css/frontend.css

@ -7,5 +7,13 @@
.bookacti-booking-system-calendar-only .bookacti-booking-system-title,
.bookacti-booking-system-calendar-only .bookacti-picked-events { display: none !important; }
.bookacti-user-booking-list-previous-page { margin-right: 10px }
.bookacti-user-booking-list-next-page { margin-left: 10px }
.bookacti-user-booking-list-previous-page,
.bookacti-user-booking-list-current-page,
.bookacti-user-booking-list-next-page { display: inline-block; vertical-align: middle; line-height: 1em; }
.bookacti-user-booking-list-previous-page { margin-right: 10px; }
.bookacti-user-booking-list-next-page { margin-left: 10px; }
.bookacti-user-booking-list-page-counter,
.bookacti-user-booking-list-total-bookings { display: block; text-align: center; }
.bookacti-user-booking-list-total-bookings { font-size: 0.7em; margin-top: 3px; }
.bookacti-user-booking-list-total-bookings:before { content: '('; }
.bookacti-user-booking-list-total-bookings:after { content: ')'; }

2
css/frontend.min.css

@ -1 +1 @@
.bookacti-frontend-dialog{display:none}.bookacti-picked-events{display:none}.bookacti-booking-events-list{margin-left:18px}.bookacti-booking-system-calendar-only .bookacti-booking-system-title,.bookacti-booking-system-calendar-only .bookacti-picked-events{display:none!important}.bookacti-user-booking-list-previous-page{margin-right:10px}.bookacti-user-booking-list-next-page{margin-left:10px}
.bookacti-frontend-dialog{display:none}.bookacti-picked-events{display:none}.bookacti-booking-events-list{margin-left:18px}.bookacti-booking-system-calendar-only .bookacti-booking-system-title,.bookacti-booking-system-calendar-only .bookacti-picked-events{display:none!important}.bookacti-user-booking-list-previous-page,.bookacti-user-booking-list-current-page,.bookacti-user-booking-list-next-page{display:inline-block;vertical-align:middle;line-height:1em}.bookacti-user-booking-list-previous-page{margin-right:10px}.bookacti-user-booking-list-next-page{margin-left:10px}.bookacti-user-booking-list-page-counter,.bookacti-user-booking-list-total-bookings{display:block;text-align:center}.bookacti-user-booking-list-total-bookings{font-size:.7em;margin-top:3px}.bookacti-user-booking-list-total-bookings:before{content:'('}.bookacti-user-booking-list-total-bookings:after{content:')'}

2
css/global.css

@ -103,7 +103,7 @@
/* Events */
.bookacti-calendar .fc-event { overflow: hidden; }
.bookacti-calendar .fc-event:not(.bookacti-event-unavailable) { cursor: pointer; }
.bookacti-event-unavailable { opacity: 0.5; pointer-events: none; z-index: -1 !important; }
.bookacti-event-unavailable { opacity: 0.5; z-index: -1 !important; }
.bookacti-picked-event .fc-bg { opacity: 0.5; transition: opacity 0.2s; }
.bookacti-picked-event { border-width: 2px; z-index: 15 !important; transition: border 0.2s; }

2
css/global.min.css

File diff suppressed because one or more lines are too long

5
css/templates.css

@ -128,6 +128,11 @@
.bookacti-tabs .bookacti-tab-content .bookacti-promo-events-examples div { margin-bottom: 0; }
.bookacti-tabs .bookacti-tab-content .bookacti-promo-events-examples { margin: 10px 0 0 0; }
/* Calendar dialog */
.bookacti-editor-settings-only-notice { color: #f89b2f; }
.bookacti-editor-settings-only-notice a { color: #d47408; }
.bookacti-editor-settings-only-notice:before { content: '\26A0 '; }
/* Activity dialog */
#bookacti-activity-import-dialog label { display: inline-block; width: 150px; font-weight: bold; }
#bookacti-activity-import-dialog div { margin-bottom: 10px; }

2
css/templates.min.css

File diff suppressed because one or more lines are too long

10
css/woocommerce.css

@ -36,11 +36,15 @@ table.woocommerce_order_items ul.bookacti-booking-events-list { margin: 0; }
/* Booking forms */
.bookacti-success-list.woocommerce a.button,
.woocommerce div.product form.cart .bookacti-success-list.woocommerce .button { float: right; }
.woocommerce div.product.bookacti-activity form.cart .bookacti-success-list.woocommerce .button { float: right; }
/* Single product page */
.woocommerce div.product form.cart table td.fc-axis { padding-left: 4px; }
.woocommerce.single.single-product div.product.bookacti-activity form.cart { width: 100%; }
.woocommerce div.product.bookacti-activity form.cart table td.fc-axis { padding-left: 4px; }
.woocommerce.single.single-product div.product.bookacti-activity form.cart { width: 100%; }
/* Elementor support */
.woocommerce div.product.bookacti-activity.elementor form.cart.variations_form .woocommerce-variation-add-to-cart,
.woocommerce div.product.bookacti-activity.elementor form.cart:not(.grouped_form):not(.variations_form) { display: block; }
/* Cart, Checkout */
.bookacti-order-item-activity td.product-name .wc-item-meta .wc-item-meta-bookacti_booked_events,

2
css/woocommerce.min.css

@ -1 +1 @@
#woocommerce-product-data .bookacti-loading-alt{display:inline-block;margin:10px;max-width:120px}#woocommerce-product-data ul.product_data_tabs li.activity_tab a::before{font-family:dashicons;content:'\f508'}.bookacti-woo-title{padding:1em 0 .5em 0}p.form-field._bookacti_groups_field{margin-bottom:0}.bookacti-groups-options{margin-top:0}.bookacti-groups-options label,.form-row.bookacti-groups-options label{float:none;width:auto;margin:0 0 0 7px;font-size:12px}.bookacti-groups-options>span,.form-row.bookacti-groups-options>span{display:block;clear:both}.bookacti-groups-options>span>*,.form-row.bookacti-groups-options>span>*{display:table-cell;padding-right:8px}.bookacti-groups-options .woocommerce-help-tip,.form-row.bookacti-groups-options .woocommerce-help-tip{float:none}.woocommerce_options_panel .bookacti-multiple-select-container{white-space:nowrap;display:inline-block}.woocommerce_options_panel .bookacti-multiple-select-container label{float:none;width:auto;margin:0;display:inline-block}.bookacti-empty-product-price-notice{clear:both;color:#f89b2f}.bookacti-empty-product-price-notice:before{content:'\26A0 '}table.woocommerce_order_items ul.bookacti-booking-events-list{margin:0}.bookacti-deprecated-hidden{display:none}.woocommerce_options_panel .bookacti-wc-deprecated-note p.form-field{padding-left:12px!important}.woocommerce_order_items .display_meta .bookacti-booking-events-list{margin:0}.bookacti-order-item-action-buttons>div{display:inline-block;vertical-align:middle}.bookacti-order-item-action-buttons>div:after{content:' | ';vertical-align:middle}.bookacti-order-item-action-buttons>div:last-child:after{content:''}.bookacti-success-list.woocommerce a.button,.woocommerce div.product form.cart .bookacti-success-list.woocommerce .button{float:right}.woocommerce div.product form.cart table td.fc-axis{padding-left:4px}.woocommerce.single.single-product div.product.bookacti-activity form.cart{width:100%}.bookacti-order-item-activity td.product-name .wc-item-meta .wc-item-meta-bookacti_booked_events,.bookacti-cart-item-activity td.product-name dl.variation dt{float:none;display:block}.woocommerce a.button.bookacti-booking-group-action,.woocommerce a.button.bookacti-booking-action{margin:5px}
#woocommerce-product-data .bookacti-loading-alt{display:inline-block;margin:10px;max-width:120px}#woocommerce-product-data ul.product_data_tabs li.activity_tab a::before{font-family:dashicons;content:'\f508'}.bookacti-woo-title{padding:1em 0 .5em 0}p.form-field._bookacti_groups_field{margin-bottom:0}.bookacti-groups-options{margin-top:0}.bookacti-groups-options label,.form-row.bookacti-groups-options label{float:none;width:auto;margin:0 0 0 7px;font-size:12px}.bookacti-groups-options>span,.form-row.bookacti-groups-options>span{display:block;clear:both}.bookacti-groups-options>span>*,.form-row.bookacti-groups-options>span>*{display:table-cell;padding-right:8px}.bookacti-groups-options .woocommerce-help-tip,.form-row.bookacti-groups-options .woocommerce-help-tip{float:none}.woocommerce_options_panel .bookacti-multiple-select-container{white-space:nowrap;display:inline-block}.woocommerce_options_panel .bookacti-multiple-select-container label{float:none;width:auto;margin:0;display:inline-block}.bookacti-empty-product-price-notice{clear:both;color:#f89b2f}.bookacti-empty-product-price-notice:before{content:'\26A0 '}table.woocommerce_order_items ul.bookacti-booking-events-list{margin:0}.bookacti-deprecated-hidden{display:none}.woocommerce_options_panel .bookacti-wc-deprecated-note p.form-field{padding-left:12px!important}.woocommerce_order_items .display_meta .bookacti-booking-events-list{margin:0}.bookacti-order-item-action-buttons>div{display:inline-block;vertical-align:middle}.bookacti-order-item-action-buttons>div:after{content:' | ';vertical-align:middle}.bookacti-order-item-action-buttons>div:last-child:after{content:''}.bookacti-success-list.woocommerce a.button,.woocommerce div.product.bookacti-activity form.cart .bookacti-success-list.woocommerce .button{float:right}.woocommerce div.product.bookacti-activity form.cart table td.fc-axis{padding-left:4px}.woocommerce.single.single-product div.product.bookacti-activity form.cart{width:100%}.woocommerce div.product.bookacti-activity.elementor form.cart.variations_form .woocommerce-variation-add-to-cart,.woocommerce div.product.bookacti-activity.elementor form.cart:not(.grouped_form):not(.variations_form){display:block}.bookacti-order-item-activity td.product-name .wc-item-meta .wc-item-meta-bookacti_booked_events,.bookacti-cart-item-activity td.product-name dl.variation dt{float:none;display:block}.woocommerce a.button.bookacti-booking-group-action,.woocommerce a.button.bookacti-booking-action{margin:5px}

21
functions/functions-booking-system.php

@ -198,12 +198,12 @@ function bookacti_display_booking_system_dialogs( $booking_system_id ) {
/**
* Get available booking methods
*
* @version 1.7.18
* @return string
*/
function bookacti_get_available_booking_methods(){
$available_booking_methods = array(
'calendar' => __( 'Calendar', 'booking-activities' )
'calendar' => esc_html__( 'Calendar', 'booking-activities' )
);
return apply_filters( 'bookacti_available_booking_methods', $available_booking_methods );
}
@ -211,9 +211,7 @@ function bookacti_get_available_booking_methods(){
/**
* Get booking method HTML elemnts
*
* @since 1.1.0
*
* @param string $method
* @param array $booking_system_attributes
* @return string $html_elements
@ -483,6 +481,7 @@ function bookacti_format_booking_system_attributes( $raw_atts = array() ) {
/**
* Get booking system attributes from calendar field data
* @since 1.7.17
* @version 1.7.18
* @param array|int $calendar_field
* @return array
*/
@ -490,6 +489,18 @@ function bookacti_get_calendar_field_booking_system_attributes( $calendar_field
if( is_numeric( $calendar_field ) ) { $calendar_field = bookacti_get_form_field_data( $calendar_field ); }
if( ! is_array( $calendar_field ) ) { $calendar_field = array(); }
// Check if an event / group of events is picked by default
$picked_events = array( 'group_id' => '', 'event_id' => '', 'event_start' => '', 'event_end' => '' );
if( isset( $_REQUEST[ 'bookacti_event_id' ] ) ) { $picked_events[ 'event_id' ] = is_numeric( $_REQUEST[ 'bookacti_event_id' ] ) ? intval( $_REQUEST[ 'bookacti_event_id' ] ) : ''; }
if( isset( $_REQUEST[ 'event_id' ] ) ) { $picked_events[ 'event_id' ] = is_numeric( $_REQUEST[ 'event_id' ] ) ? intval( $_REQUEST[ 'event_id' ] ) : ''; }
if( isset( $_REQUEST[ 'bookacti_event_start' ] ) ) { $picked_events[ 'event_start' ] = bookacti_sanitize_datetime( $_REQUEST[ 'bookacti_event_start' ] ); }
if( isset( $_REQUEST[ 'event_start' ] ) ) { $picked_events[ 'event_start' ] = bookacti_sanitize_datetime( $_REQUEST[ 'event_start' ] ); }
if( isset( $_REQUEST[ 'bookacti_event_end' ] ) ) { $picked_events[ 'event_end' ] = bookacti_sanitize_datetime( $_REQUEST[ 'bookacti_event_end' ] ); }
if( isset( $_REQUEST[ 'event_end' ] ) ) { $picked_events[ 'event_end' ] = bookacti_sanitize_datetime( $_REQUEST[ 'event_end' ] ); }
if( isset( $_REQUEST[ 'bookacti_group_id' ] ) ) { $picked_events[ 'group_id' ] = is_numeric( $_REQUEST[ 'bookacti_group_id' ] ) ? intval( $_REQUEST[ 'bookacti_group_id' ] ) : ''; }
if( isset( $_REQUEST[ 'event_group_id' ] ) ) { $picked_events[ 'group_id' ] = is_numeric( $_REQUEST[ 'event_group_id' ] ) ? intval( $_REQUEST[ 'event_group_id' ] ) : ''; }
if( is_numeric( $picked_events[ 'event_id' ] ) && ! is_numeric( $picked_events[ 'group_id' ] ) ) { $picked_events[ 'group_id' ] = 'single'; }
// Compute availability period
$availability_period = bookacti_get_calendar_field_availability_period( $calendar_field );
@ -497,7 +508,7 @@ function bookacti_get_calendar_field_booking_system_attributes( $calendar_field
$display_data = array_intersect_key( $calendar_field, bookacti_get_booking_system_default_display_data() );
// Transform the Calendar field settings to Booking system attributes
$booking_system_atts_raw= array_merge( $calendar_field, $availability_period, array( 'display_data' => $display_data ) );
$booking_system_atts_raw= array_merge( $calendar_field, $availability_period, array( 'picked_events' => $picked_events, 'display_data' => $display_data ) );
$booking_system_atts = bookacti_format_booking_system_attributes( $booking_system_atts_raw );
return apply_filters( 'bookacti_calendar_field_booking_system_attributes', $booking_system_atts, $calendar_field );

4
functions/functions-bookings.php

@ -1895,6 +1895,7 @@ function bookacti_get_user_booking_list_items( $filters, $columns = array() ) {
/**
* Display a booking list
* @since 1.7.6
* @version 1.7.18
* @param array $filters
* @param array $columns
* @param int $per_page
@ -1959,7 +1960,8 @@ function bookacti_get_user_booking_list( $filters, $columns = array(), $per_page
}
?>
<span class='bookacti-user-booking-list-current-page'>
<strong><?php echo $page_nb; ?></strong> / <em><?php echo $page_max; ?></em>
<span class='bookacti-user-booking-list-page-counter'><strong><?php echo $page_nb; ?></strong><span> / </span><em><?php echo $page_max; ?></em></span>
<span class='bookacti-user-booking-list-total-bookings'><?php /* translators: %s is the number of bookings */ echo esc_html( sprintf( _n( '%s booking', '%s bookings', $bookings_nb ), $bookings_nb ) ); ?></span>
</span>
<?php
if( $page_nb < $page_max ) {

8
functions/functions-forms.php

@ -1023,7 +1023,7 @@ function bookacti_display_form_field( $field, $instance_id = '', $context = 'dis
/**
* Display a form field for the form editor
* @since 1.5.0
* @version 1.5.4
* @version 1.7.18
* @param array $field
* @param boolean $echo
* @return string|void
@ -1048,13 +1048,13 @@ function bookacti_display_form_field_for_editor( $field, $echo = true ) {
<?php
do_action( 'bookacti_form_editor_field_actions_before', $field );
?>
<div class='bookacti-form-editor-field-action bookacti-edit-form-field dashicons dashicons-admin-generic' title='<?php esc_attr_e( 'Change field settings', 'booking-activities' ); ?>'></div>
<div id='bookacti-edit-form-field-<?php echo esc_attr( $field[ 'field_id' ] ); ?>' class='bookacti-form-editor-field-action bookacti-edit-form-field <?php echo $field_name === 'calendar' ? 'button button-secondary' : 'dashicons dashicons-admin-generic'; ?>' title='<?php esc_attr_e( 'Change field settings', 'booking-activities' ); ?>'><?php if( $field_name === 'calendar' ) { esc_attr_e( 'Calendar settings', 'booking-activities' ); } ?></div>
<?php if( ! $field[ 'compulsory' ] ) { ?>
<div class='bookacti-form-editor-field-action bookacti-remove-form-field dashicons dashicons-trash' title='<?php esc_attr_e( 'Remove this field', 'booking-activities' ); ?>'></div>
<div id='bookacti-remove-form-field-<?php echo esc_attr( $field[ 'field_id' ] ); ?>' class='bookacti-form-editor-field-action bookacti-remove-form-field dashicons dashicons-trash' title='<?php esc_attr_e( 'Remove this field', 'booking-activities' ); ?>'></div>
<?php }
do_action( 'bookacti_form_editor_field_actions_after', $field );
?>
<div class='bookacti-field-toggle dashicons <?php echo $field_name === 'calendar' ? 'dashicons-arrow-up' :'dashicons-arrow-down'; ?>' title='<?php esc_attr_e( 'Show / Hide', 'booking-activities' ); ?>'></div>
<div id='bookacti-toggle-form-field-<?php echo esc_attr( $field[ 'field_id' ] ); ?>' class='bookacti-field-toggle dashicons <?php echo $field_name === 'calendar' ? 'dashicons-arrow-up' :'dashicons-arrow-down'; ?>' title='<?php esc_attr_e( 'Show / Hide', 'booking-activities' ); ?>'></div>
</div>
</div>
<div class='bookacti-form-editor-field-body' style='<?php echo $field_name === 'calendar' ? '' : 'display:none;'; ?>' >

35
functions/functions-global.php

@ -18,6 +18,22 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
}
/**
* Display an admin notice
* @since 1.7.18
* @param array $array composed of a type and a message
* @param string $action Name of the filter to allow third-party modifications
*/
function bookacti_display_admin_notice( $array, $action = '' ) {
if( empty( $array[ 'type' ] ) ) { $array[ 'type' ] = 'error'; }
if( empty( $array[ 'message' ] ) ) { $array[ 'message' ] = esc_html__( 'An error occurred, please try again.', 'booking-activities' ); }
$notice = apply_filters( 'bookacti_display_admin_notice_' . $action, $array );
?>
<div class='notice is-dismissible bookacti-form-notice notice-<?php echo $notice[ 'type' ]; ?>' ><p><?php echo $notice[ 'message' ]; ?></p></div>
<?php
}
/**
* Send a filtered array via json during an ajax process
* @since 1.5.0
@ -1057,12 +1073,11 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* Create a user selectbox
* @since 1.3.0
* @version 1.7.1
* @param array $args
* @version 1.7.18
* @param array $raw_args
* @return string|void
*/
function bookacti_display_user_selectbox( $args ) {
function bookacti_display_user_selectbox( $raw_args ) {
$defaults = array(
'show_option_all' => '',
'show_option_none' => '', 'option_none_value' => -1,
@ -1075,7 +1090,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
'orderby' => 'display_name', 'order' => 'ASC'
);
$args = apply_filters( 'bookacti_user_selectbox_args', wp_parse_args( $args, $defaults ), $args );
$args = apply_filters( 'bookacti_user_selectbox_args', wp_parse_args( $raw_args, $defaults ), $raw_args );
$users = bookacti_get_users_data( $args );
ob_start();
@ -1113,6 +1128,16 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
// Build the option label based on the array
$label = '';
foreach( $args[ 'option_label' ] as $show ) {
// If the key contain "||" display the first not empty value
if( strpos( $show, '||' ) !== false ) {
$keys = explode( '||', $show );
$show = $keys[ 0 ];
foreach( $keys as $key ) {
if( ! empty( $user->{ $key } ) ) { $show = $key; break; }
}
}
// Display the value if the key exists, else display the key as is, as a separator
if( isset( $user->{ $show } ) ) {
$label .= $user->{ $show };
} else {

18
functions/functions-settings.php

@ -253,28 +253,24 @@ function bookacti_settings_section_licenses_callback() { }
/**
* Display "default payment status" setting
*
* @since 1.3.0
* @version 1.7.18
*/
function bookacti_settings_field_default_payment_status_callback() {
$payment_status = bookacti_get_payment_status_labels();
$payment_status_array = array();
foreach( $payment_status as $payment_status_id => $payment_status_data ) {
$payment_status_array[ esc_attr( $payment_status_id ) ] = esc_html( $payment_status_data[ 'label' ] );
}
$args = array(
bookacti_display_field( array(
'type' => 'select',
'name' => 'bookacti_general_settings[default_payment_status]',
'id' => 'default_payment_status',
'options' => $payment_status_array,
'value' => bookacti_get_setting_value( 'bookacti_general_settings', 'default_payment_status' ),
/* translators: The word 'Calendar' refers to a booking method you have to translate too. Make sure you use the same word for both translation. */
'tip' => __( 'Choose what payment status a booking should have when a customer complete the booking form.', 'booking-activities' )
. '<br/>' . __( 'This option has no effect on bookings made with WooCommerce.', 'booking-activities' )
);
bookacti_display_field( $args );
'tip' => esc_html__( 'Choose what payment status a booking should have when a customer complete the booking form.', 'booking-activities' )
. '<br/>' . esc_html__( 'This option has no effect on bookings made with WooCommerce.', 'booking-activities' )
));
}
@ -1424,7 +1420,7 @@ function bookacti_settings_section_licenses_callback() { }
// PRIVACY OPTIONS
/**
* Export additionnal user metadata with WP privacy export tool
* Export additional user metadata with WP privacy export tool
* @since 1.7.0
* @version 1.7.8
* @param string $email_address
@ -1606,7 +1602,7 @@ function bookacti_privacy_exporter_bookings_data( $email_address, $page = 1 ) {
/**
* Erase additionnal user metadata with WP privacy export tool
* Erase additional user metadata with WP privacy export tool
* @since 1.7.0
* @version 1.7.8
* @param string $email_address

2
functions/functions-templates.php

@ -184,7 +184,7 @@ function bookacti_get_editor_booking_system_data( $atts, $template_id ) {
/**
* Get additionnal calendar fields default data
* Get additional calendar fields default data
* @since 1.5.0
* @param array $fields
* @return array

76
functions/functions-woocommerce.php

@ -1070,8 +1070,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* Turn all bookings of an order to the desired status.
* Also make sure that bookings are bound to the order and the associated user.
*
* @version 1.7.0
* @version 1.7.18
* @param WC_Order $order
* @param string $state
* @param string $payment_status
@ -1080,12 +1079,8 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
* @return int|false
*/
function bookacti_turn_order_bookings_to( $order, $state = 'booked', $payment_status = NULL, $alert_if_fails = false, $args = array() ) {
// Retrieve order data
if( is_numeric( $order ) ) {
$order = wc_get_order( $order );
}
if( is_numeric( $order ) ) { $order = wc_get_order( $order ); }
if( ! $order ) { return false; }
$states_in = ! empty( $args[ 'states_in' ] ) ? $args[ 'states_in' ] : array();
@ -1093,15 +1088,13 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
// Retrieve bought items and user id
$items = $order->get_items();
$user_id = $order->get_user_id();
if( version_compare( WC_VERSION, '3.0.0', '>=' ) ) {
$order_id = $order->get_id();
} else {
$order_id = $order->id;
}
$order_id = version_compare( WC_VERSION, '3.0.0', '>=' ) ? $order->get_id() : $order->id;
// Create an array with order booking ids
$booking_id_array = array();
$booking_group_id_array = array();
$in__booking_id = ! empty( $args[ 'in__booking_id' ] ) ? $args[ 'in__booking_id' ] : array();
$in__booking_group_id = ! empty( $args[ 'in__booking_group_id' ] ) ? $args[ 'in__booking_group_id' ] : array();
foreach( $items as $key => $item ) {
// Reset item booking id
$booking_id = 0;
@ -1122,12 +1115,12 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
}
// Single event
if( ! empty( $booking_id ) ) {
if( $booking_id && ( ! $in__booking_id || in_array( $booking_id, $in__booking_id ) ) ) {
// Add the booking id to the bookings array to change state
array_push( $booking_id_array, $booking_id );
$booking_id_array[] = $booking_id;
// Group of events
} else if( ! empty( $booking_group_id ) ) {
} else if( $booking_group_id && ( ! $in__booking_group_id || in_array( $booking_group_id, $in__booking_group_id ) ) ) {
// Add the group booking ids to the bookings array to change state
$booking_group_id_array[] = $booking_group_id;
@ -1154,14 +1147,14 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
$updated = bookacti_change_order_bookings_state( $user_id, $order_id, $booking_id_array, $state, $payment_status, $states_in );
$response[ 'status' ] = 'success';
$response[ 'errors' ] = array();
$response[ 'updated' ] = $updated;
$response[ 'status' ] = 'success';
$response[ 'errors' ] = array();
$response[ 'updated' ] = $updated;
// Check if an error occured during booking state update
if( $updated === false ) {
$response[ 'status' ] = 'failed';
array_push( $response[ 'errors' ], 'update_failed' );
$response[ 'errors' ][] = 'update_failed';
}
// If bookings have not updated correctly, send an e-mail to alert the administrator
@ -1195,7 +1188,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
}
if( is_numeric( $response[ 'updated' ] ) && intval( $response[ 'updated' ] ) > 0 ) {
do_action( 'bookacti_order_bookings_state_changed', $order, $state, $args );
do_action( 'bookacti_order_bookings_state_changed', $order, $state, array_merge( $args, $response ) );
}
return $response;
@ -1204,16 +1197,14 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* Update order item booking status meta to new status
*
* @since 1.2.0
* @version 1.7.0
* @version 1.7.18
* @param int $item
* @param string $new_state
* @param WC_Order $order
* @param array $args
*/
function bookacti_update_order_item_booking_status( $item, $new_state, $order, $args ) {
if( ! $item || ( ! isset( $item[ 'bookacti_booking_id' ] ) && ! isset( $item[ 'bookacti_booking_group_id' ] ) ) ) { return; }
// WOOCOMMERCE 3.0.0 backward compatibility
@ -1223,9 +1214,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
$old_state = wc_get_order_item_meta( $order_item_id, 'bookacti_state', true );
$states_in = ! empty( $args[ 'states_in' ] ) ? $args[ 'states_in' ] : array();
if( $states_in ) {
if( ! in_array( $old_state, $states_in, true ) ) { return; }
}
if( $states_in && ! in_array( $old_state, $states_in, true ) ) { return; }
// Turn meta state to new state
wc_update_order_item_meta( $order_item_id, 'bookacti_state', $new_state );
@ -1236,27 +1225,24 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
wc_update_order_item_meta( $order_item_id, '_bookacti_refund_method', $refund_action );
}
if( is_numeric( $order ) ) {
$order = wc_get_order( $order );
}
if( is_numeric( $order ) ) { $order = wc_get_order( $order ); }
if( ! $order ) { return; }
// Log booking state change
if( $old_state !== $new_state ) {
// Single event
if( isset( $item[ 'bookacti_booking_id' ] ) && $item[ 'bookacti_booking_id' ] ) {
$booking_id = $item[ 'bookacti_booking_id' ];
$booking_owner = bookacti_get_booking_owner( $booking_id );
/* translators: %1$s is booking id, %2$s is old state, %3$s is new state */
$message = __( 'Booking #%1$s state has been updated from %2$s to %3$s.', 'booking-activities' );
$message = esc_html__( 'Booking #%1$s state has been updated from %2$s to %3$s.', 'booking-activities' );
// Group of events
} else if( isset( $item[ 'bookacti_booking_group_id' ] ) && $item[ 'bookacti_booking_group_id' ] ) {
$booking_id = $item[ 'bookacti_booking_group_id' ];
$booking_owner = bookacti_get_booking_group_owner( $booking_id );
/* translators: %1$s is booking group id, %2$s is old state, %3$s is new state */
$message = __( 'Booking group #%1$s state has been updated from %2$s to %3$s.', 'booking-activities' );
$message = esc_html__( 'Booking group #%1$s state has been updated from %2$s to %3$s.', 'booking-activities' );
}
$status_labels = bookacti_get_booking_state_labels();
@ -1274,7 +1260,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
}
// Turn the order state if it is composed of inactive / pending / booked bookings only
if( ! isset( $args[ 'update_order_status' ] ) || $args[ 'update_order_status' ] ) {
if( ! empty( $args[ 'update_order_status' ] ) ) {
bookacti_change_order_state_based_on_its_bookings_state( $order->get_id() );
}
}
@ -1283,11 +1269,10 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* Turn the order state if it is composed of inactive / pending / booked bookings only
* @since 1.1.0
* @version 1.7.1
* @version 1.7.18
* @param int $order_id
*/
function bookacti_change_order_state_based_on_its_bookings_state( $order_id ) {
// Get a fresh instance of WC_Order because some of its items may have changed
$order = wc_get_order( $order_id );
@ -1304,14 +1289,22 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
// Determine if the order is only composed of activities
$states = array();
$only_activities = true;
$only_virtual_activities = true;
foreach( $items as $item ) {
// Is activity
if( ! isset( $item[ 'bookacti_booking_id' ] ) && ! isset( $item[ 'bookacti_booking_group_id' ] ) ) {
$only_activities = false;
break;
$only_activities = false; break;
}
// Is virtual
$product = $item[ 'variation_id' ] ? wc_get_product( $item[ 'variation_id' ] ) : wc_get_product( $item[ 'product_id' ] );
if( $product && ! $product->is_virtual() ) {
$only_virtual_activities = false;
}
$states[] = $item[ 'bookacti_state' ];
}
if( ! $only_activities || empty( $states ) || in_array( 'in_cart', $states, true ) ) { return; }
sort( $states );
@ -1326,9 +1319,10 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
if( $order_status !== 'cancelled' && in_array( 'pending', $states, true ) ) {
// Turn order status to processing (or let it on on-hold)
$new_order_status = $order_status === 'on-hold' ? 'on-hold' : 'processing';
} else if( $order_status !== 'cancelled' && ! empty( $has_completed_booking_states ) ) {
} else if( $order_status !== 'cancelled' && $order_status !== 'completed' && ! empty( $has_completed_booking_states ) ) {
// Turn order status to completed
$new_order_status = 'completed';
$non_virtual_bookings_order_status = apply_filters( 'bookacti_completed_non_virtual_bookings_order_status', 'processing' );
$new_order_status = $only_virtual_activities ? 'completed' : $non_virtual_bookings_order_status;
} else if( ! empty( $has_cancelled_booking_states ) ) {
// Turn order status to cancelled
$new_order_status = 'cancelled';

8
js/booking-method-calendar.js

@ -1,6 +1,6 @@
/**
* Initialize the calendar
* @version 1.7.17
* @version 1.7.18
* @param {dom_element} booking_system
* @param {boolean} reload_events
*/
@ -133,7 +133,11 @@ function bookacti_set_calendar_up( booking_system, reload_events ) {
},
eventClick: function( event, jsEvent, view ) {
bookacti_event_click( booking_system, event );
// Don't pick the event if it is not available
var is_available = bookacti_is_event_available( booking_system, event );
if( is_available ) {
bookacti_event_click( booking_system, event );
}
},
eventMouseover: function( event, jsEvent, view ) {

2
js/booking-method-calendar.min.js

File diff suppressed because one or more lines are too long

53
js/booking-system-functions.js

@ -66,16 +66,18 @@ function bookacti_fetch_events( booking_system, interval ) {
/**
* Reload a booking system
* @version 1.7.14