Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : April 26, 2026

CVE-2026-39525: Booking Activities <= 1.16.48.1 – Missing Authorization (booking-activities)

Severity Medium (CVSS 5.3)
CWE 862
Vulnerable Version 1.16.48.1
Patched Version 1.17.0
Disclosed April 12, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-39525:

This vulnerability exposes unauthorized access to booking activity data in the Booking Activities plugin for WordPress, versions up to and including 1.16.48.1. The missing capability check on AJAX actions allows unauthenticated attackers to fetch sensitive booking system data, including event details and booking counts. The CVSS score of 5.3 reflects the moderate severity due to information disclosure.

Root Cause: The plugin registers three AJAX endpoints — `bookactiGetBookingSystemDataByInterval`, `bookactiReloadBookingSystem`, and `bookactiGetBookingNumbers` — with both `wp_ajax_` and `wp_ajax_nopriv_` action hooks. The `nopriv` hooks allow unauthenticated access. In the vulnerable version (controller-booking-system.php, lines 1-127), none of these endpoint functions perform any capability check (e.g., `current_user_can()`) before processing requests. The `bookacti_controller_get_booking_system_data_by_interval()` function (line 8-42) accepts POST parameters `attributes` and `interval`, passes them through sanitization, then calls `bookacti_get_booking_system_data()` which returns event bookings within the specified interval. Similarly, `bookacti_controller_reload_booking_system()` (line 48-74) accepts only `attributes` and returns full booking system data plus HTML. The `bookacti_controller_get_booking_numbers()` function (line 80-100) accepts `template_ids` and `groups_data`, returning booking counts per event and per group of events. None of these functions restrict access based on user roles or authentication status.

Exploitation: An unauthenticated attacker can send a POST request to `/wp-admin/admin-ajax.php` with the `action` parameter set to any of the three vulnerable actions. For example, setting `action=bookactiGetBookingNumbers` with `template_ids[]` populated with event template IDs returns the number of bookings for those events. The attacker can enumerate template IDs (often sequential integers) to collect booking statistics for all events in the system. Similarly, `action=bookactiGetBookingSystemDataByInterval` with crafted `attributes` and `interval` parameters returns the full event schedule and availability. The attack does not require any authentication cookies or nonces because the `wp_ajax_nopriv_` hooks explicitly allow unauthenticated requests.

Patch Analysis: The diff does not show the addition of authorization checks to the existing vulnerable functions. Instead, the patch restructures the controller file. The new version (1.17.0) modifies the `bookacti_controller_get_booking_system_data_by_interval()` function (now lines 29-99 of the patched file) to set `$atts[‘select_first_event’] = 0` and adds a new filter `bookacti_controller_booking_system_select_first_event()`. Critically, the patch does NOT add any `current_user_can()` check to the three AJAX handlers. The registered hooks remain unchanged with both `wp_ajax_` and `wp_ajax_nopriv_` actions. This suggests that the “missing authorization” described in the CVE description may have been addressed elsewhere in the full diff (which was truncated), or the vulnerability may have been classified differently. Based on the diff provided, the core issue — unauthenticated access via `nopriv` hooks — persists in the patched version as well.

Impact: If the vulnerability is exploitable as described, an unauthenticated attacker can obtain sensitive information about event configurations, booking counts, and customer attendance patterns. This information disclosure can aid in reconnaissance for more targeted attacks, such as identifying high-value events or times with low bookings for social engineering. The attacker does not need to interact with any authenticated user; they can directly query the AJAX endpoints.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/booking-activities/booking-activities.php
+++ b/booking-activities/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.16.48.1
+ * Version: 1.17.0
  * Author: Booking Activities Team
  * Author URI: https://booking-activities.fr/en/?utm_source=plugin&utm_medium=plugin&utm_content=header
  * Text Domain: booking-activities
@@ -42,7 +42,7 @@


 // GLOBALS AND CONSTANTS
-if( ! defined( 'BOOKACTI_VERSION' ) )     { define( 'BOOKACTI_VERSION', '1.16.48.1' ); }
+if( ! defined( 'BOOKACTI_VERSION' ) )     { define( 'BOOKACTI_VERSION', '1.17.0' ); }
 if( ! defined( 'BOOKACTI_PLUGIN_NAME' ) ) { define( 'BOOKACTI_PLUGIN_NAME', 'booking-activities' ); }
 if( ! defined( 'BOOKACTI_PATH' ) )        { define( 'BOOKACTI_PATH', __DIR__ ); }

--- a/booking-activities/controller/controller-booking-system.php
+++ b/booking-activities/controller/controller-booking-system.php
@@ -1,127 +1,158 @@
-<?php
-// Exit if accessed directly
-if ( ! defined( 'ABSPATH' ) ) { exit; }
-
-/**
- * AJAX Controller - Get booking system data by interval (events, groups, and bookings)
- * @since 1.12.0 (was bookacti_controller_fetch_events)
- * @version 1.16.1
- */
-function bookacti_controller_get_booking_system_data_by_interval() {
-	$atts     = isset( $_POST[ 'attributes' ] ) ? ( is_array( $_POST[ 'attributes' ] ) ? $_POST[ 'attributes' ] : ( is_string( $_POST[ 'attributes' ] ) ? bookacti_maybe_decode_json( stripslashes( $_POST[ 'attributes' ] ), true ) : array() ) ) : array();
-	$atts     = bookacti_format_booking_system_attributes( $atts );
-	$interval = isset( $_POST[ 'interval' ] ) ? ( is_array( $_POST[ 'interval' ] ) ? $_POST[ 'interval' ] : ( is_string( $_POST[ 'interval' ] ) ? bookacti_maybe_decode_json( stripslashes( $_POST[ 'interval' ] ), true ) : array() ) ) : array();
-	$interval = $interval ? bookacti_sanitize_events_interval( $interval ) : array();
-
-	$start_dt = $atts[ 'start' ] ? new DateTime( $atts[ 'start' ] ) : '';
-	$end_dt   = $atts[ 'end' ] ? new DateTime( $atts[ 'end' ] ) : '';
-
-	$atts[ 'start' ]               = ! empty( $interval[ 'start' ] ) ? $interval[ 'start' ] : '';
-	$atts[ 'end' ]                 = ! empty( $interval[ 'end' ] ) ? $interval[ 'end' ] : '';
-	$atts[ 'events_min_interval' ] = $atts[ 'start' ] || $atts[ 'end' ] ? array( 'start' => $atts[ 'start' ], 'end' => $atts[ 'end' ] ) : array();
-	$atts[ 'auto_load' ]           = 1;
-
-	$booking_system_data = bookacti_get_booking_system_data( $atts );
-
-	// Trim the availability period
-	$trimmed_period = array();
-	if( $booking_system_data[ 'trim' ] ) {
-		$interval_start_dt    = new DateTime( $interval[ 'start' ] );
-		$interval_end_dt      = new DateTime( $interval[ 'end' ] );
-		$is_first_interval    = $start_dt && $interval_start_dt <= $start_dt;
-		$is_last_interval     = $end_dt && $interval_end_dt >= $end_dt;
-
-		$events_by_start_date = bookacti_sort_events_array_by_dates( $booking_system_data[ 'events' ] );
-		$events_by_end_date   = bookacti_sort_events_array_by_dates( $booking_system_data[ 'events' ], true, true );
-		$first_event_dt       = ! empty( $events_by_start_date[ 0 ][ 'start' ] ) ? new DateTime( $events_by_start_date[ 0 ][ 'start' ] ) : null;
-		$last_event_dt        = ! empty( $events_by_end_date[ 0 ][ 'end' ] ) ? new DateTime( $events_by_end_date[ 0 ][ 'end' ] ) : null;
-
-		if( $is_first_interval && $first_event_dt && $first_event_dt > $start_dt ) {
-			$trimmed_period[ 'start' ] = $first_event_dt->format( 'Y-m-d H:i:s' );
-		}
-
-		if( $is_last_interval && $last_event_dt && $last_event_dt < $end_dt ) {
-			$trimmed_period[ 'end' ] = $last_event_dt->format( 'Y-m-d H:i:s' );
-		}
-	}
-
-	// Encrypt user_id
-	$public_user_ids = array();
-	if( ! empty( $atts[ 'user_id' ] ) ) {
-		foreach( $atts[ 'user_id' ] as $user_id ) {
-			if( $user_id && ( ( is_numeric( $user_id ) && strlen( (string) $user_id ) < 16 ) || is_email( $user_id ) ) ) {
-				$public_user_ids[] = bookacti_encrypt( $user_id );
-			}
-		}
-	}
-
-	// Let plugins define what data should be passed to JS
-	$public_booking_system_data = apply_filters( 'bookacti_public_booking_system_data', array_merge( $booking_system_data, array( 'user_id' => $public_user_ids ) ), $atts );
-
-	bookacti_send_json( array(
-		'status'              => 'success',
-		'booking_system_data' => $public_booking_system_data,
-		'trimmed_period'      => $trimmed_period
-	), 'get_booking_system_data_by_interval' );
-}
-add_action( 'wp_ajax_bookactiGetBookingSystemDataByInterval', 'bookacti_controller_get_booking_system_data_by_interval' );
-add_action( 'wp_ajax_nopriv_bookactiGetBookingSystemDataByInterval', 'bookacti_controller_get_booking_system_data_by_interval' );
-
-
-/**
- * Reload booking system with new attributes via AJAX
- * @since 1.1.0
- * @version 1.16.0
- */
-function bookacti_controller_reload_booking_system() {
-	$atts = isset( $_POST[ 'attributes' ] ) ? ( is_array( $_POST[ 'attributes' ] ) ? $_POST[ 'attributes' ] : ( is_string( $_POST[ 'attributes' ] ) ? bookacti_maybe_decode_json( stripslashes( $_POST[ 'attributes' ] ), true ) : array() ) ) : array();
-	$atts = bookacti_format_booking_system_attributes( $atts );
-
-	$atts[ 'auto_load' ] = 1;
-	$booking_system_data = bookacti_get_booking_system_data( $atts );
-
-	// Get HTML elements used by the booking method
-	$html_elements = bookacti_get_booking_method_html( $booking_system_data[ 'method' ], $booking_system_data );
-
-	// Encrypt user_id
-	$public_user_ids = array();
-	if( ! empty( $atts[ 'user_id' ] ) ) {
-		foreach( $atts[ 'user_id' ] as $user_id ) {
-			if( $user_id && ( ( is_numeric( $user_id ) && strlen( (string) $user_id ) < 16 ) || is_email( $user_id ) ) ) {
-				$public_user_ids[] = bookacti_encrypt( $user_id );
-			}
-		}
-	}
-
-	// Let plugins define what data should be passed to JS
-	$public_booking_system_data = apply_filters( 'bookacti_public_booking_system_data', array_merge( $booking_system_data, array( 'user_id' => $public_user_ids ) ), $atts );
-
-	bookacti_send_json( array(
-		'status'              => 'success',
-		'html_elements'       => $html_elements,
-		'booking_system_data' => $public_booking_system_data
-	), 'reload_booking_system' );
-}
-add_action( 'wp_ajax_bookactiReloadBookingSystem', 'bookacti_controller_reload_booking_system' );
-add_action( 'wp_ajax_nopriv_bookactiReloadBookingSystem', 'bookacti_controller_reload_booking_system' );
-
-
-/**
- * AJAX Controller - Get booking numbers for a given template and / or event
- * @version 1.12.0
- */
-function bookacti_controller_get_booking_numbers() {
-	$template_ids  = isset( $_POST[ 'template_ids' ] ) ? bookacti_ids_to_array( $_POST[ 'template_ids' ] ) : array();
-	$groups_data   = isset( $_POST[ 'groups_data' ] ) && is_array( $_POST[ 'groups_data' ] ) ? $_POST[ 'groups_data' ] : array();
-	$groups_events = isset( $_POST[ 'groups_events' ] ) && is_array( $_POST[ 'groups_events' ] ) ? $_POST[ 'groups_events' ] : array();
-	$groups        = array( 'data' => $groups_data, 'groups' => $groups_events );
-
-	$bookings_nb_per_event = bookacti_get_number_of_bookings_per_event( array( 'templates' => $template_ids ) );
-	if( ! $bookings_nb_per_event ) { bookacti_send_json( array( 'status' => 'no_bookings' ), 'get_booking_numbers' ); }
-
-	$bookings_nb_per_group = bookacti_get_number_of_bookings_per_group_of_events( $groups );
-
-	bookacti_send_json( array( 'status' => 'success', 'bookings' => $bookings_nb_per_event, 'groups_bookings' => $bookings_nb_per_group ), 'get_booking_numbers' );
-}
-add_action( 'wp_ajax_bookactiGetBookingNumbers', 'bookacti_controller_get_booking_numbers' );
+<?php
+// Exit if accessed directly
+if ( ! defined( 'ABSPATH' ) ) { exit; }
+
+/**
+ * Automatically select the first (group of) event(s) available
+ * @since 1.17.0
+ * @param array $booking_system_data
+ * @param array $atts
+ * @return array
+ */
+function bookacti_controller_booking_system_select_first_event( $booking_system_data, $atts ) {
+	// Maybe select the first available event
+	if( $booking_system_data[ 'select_first_event' ] && ! $booking_system_data[ 'picked_events' ] ) {
+		$booking_system_data[ 'picked_events' ] = bookacti_get_booking_system_first_available_picked_events( $booking_system_data );
+	}
+
+	return $booking_system_data;
+}
+add_filter( 'bookacti_booking_system_data', 'bookacti_controller_booking_system_select_first_event', 100, 2 );
+
+
+/**
+ * AJAX Controller - Get booking system data by interval (events, groups, and bookings)
+ * @since 1.12.0 (was bookacti_controller_fetch_events)
+ * @version 1.17.0
+ */
+function bookacti_controller_get_booking_system_data_by_interval() {
+	$atts           = isset( $_POST[ 'attributes' ] ) ? ( is_array( $_POST[ 'attributes' ] ) ? $_POST[ 'attributes' ] : ( is_string( $_POST[ 'attributes' ] ) ? bookacti_maybe_decode_json( stripslashes( $_POST[ 'attributes' ] ), true ) : array() ) ) : array();
+	$atts           = bookacti_format_booking_system_attributes( $atts );
+	$interval       = isset( $_POST[ 'interval' ] ) ? ( is_array( $_POST[ 'interval' ] ) ? $_POST[ 'interval' ] : ( is_string( $_POST[ 'interval' ] ) ? bookacti_maybe_decode_json( stripslashes( $_POST[ 'interval' ] ), true ) : array() ) ) : array();
+	$interval       = $interval ? bookacti_sanitize_events_interval( $interval ) : array();
+
+	// Save initial start and end
+	$start_dt = $atts[ 'start' ] ? new DateTime( $atts[ 'start' ] ) : null;
+	$end_dt   = $atts[ 'end' ] ? new DateTime( $atts[ 'end' ] ) : null;
+
+	// Limit the display period to the desired interval
+	$interval_start_dt = ! empty( $interval[ 'start' ] ) ? new DateTime( $interval[ 'start' ] ) : null;
+	$interval_end_dt   = ! empty( $interval[ 'end' ] ) ? new DateTime( $interval[ 'end' ] ) : null;
+	$period_start_dt   = ! empty( $atts[ 'display_period' ][ 'start' ] ) ? new DateTime( $atts[ 'display_period' ][ 'start' ] ) : null;
+	$period_end_dt     = ! empty( $atts[ 'display_period' ][ 'end' ] ) ? new DateTime( $atts[ 'display_period' ][ 'end' ] ) : null;
+	if( ! $period_start_dt || ( $interval_start_dt && $period_start_dt && $interval_start_dt > $period_start_dt ) ) {
+		$atts[ 'display_period' ][ 'start' ] = $interval[ 'start' ];
+	}
+	if( ! $period_end_dt || ( $interval_end_dt && $period_end_dt && $interval_end_dt < $period_end_dt ) ) {
+		$atts[ 'display_period' ][ 'end' ] = $interval[ 'end' ];
+	}
+
+	$atts[ 'start' ]               = ! empty( $interval[ 'start' ] ) ? $interval[ 'start' ] : '';
+	$atts[ 'end' ]                 = ! empty( $interval[ 'end' ] ) ? $interval[ 'end' ] : '';
+	$atts[ 'events_min_interval' ] = $atts[ 'start' ] || $atts[ 'end' ] ? array( 'start' => $atts[ 'start' ], 'end' => $atts[ 'end' ] ) : array();
+	$atts[ 'select_first_event' ]  = 0;
+	$atts[ 'auto_load' ]           = 1;
+
+	$booking_system_data = bookacti_get_booking_system_data( $atts );
+
+	// Trim the availability period
+	$trimmed_period = array();
+	if( $booking_system_data[ 'trim' ] ) {
+		$is_first_interval   = $start_dt && $interval_start_dt && $interval_start_dt <= $start_dt;
+		$is_last_interval    = $end_dt && $interval_end_dt && $interval_end_dt >= $end_dt;
+		$ordered_events      = bookacti_sort_events_array_by_dates( $booking_system_data[ 'events' ] );
+		$ordered_events_keys = array_keys( $ordered_events );
+		$last_key            = end( $ordered_events_keys );
+		$first_key           = reset( $ordered_events_keys );
+		$first_event_dt      = ! empty( $ordered_events[ $first_key ][ 'start' ] ) ? new DateTime( $ordered_events[ $first_key ][ 'start' ] ) : null;
+		$last_event_dt       = ! empty( $ordered_events[ $last_key ][ 'start' ] ) ? new DateTime( $ordered_events[ $last_key ][ 'start' ] ) : null;
+
+		if( $is_first_interval && $first_event_dt && $first_event_dt > $start_dt ) {
+			$trimmed_period[ 'start' ] = $first_event_dt->format( 'Y-m-d' ) . ' 00:00:00';
+		}
+
+		if( $is_last_interval && $last_event_dt && $last_event_dt < $end_dt ) {
+			$trimmed_period[ 'end' ] = $last_event_dt->format( 'Y-m-d' ) . ' 23:59:59';
+		}
+	}
+
+	// Encrypt user_id
+	$public_user_ids = array();
+	if( ! empty( $atts[ 'user_id' ] ) ) {
+		foreach( $atts[ 'user_id' ] as $user_id ) {
+			if( $user_id && ( ( is_numeric( $user_id ) && strlen( (string) $user_id ) < 16 ) || is_email( $user_id ) ) ) {
+				$public_user_ids[] = bookacti_encrypt( $user_id );
+			}
+		}
+	}
+
+	// Let plugins define what data should be passed to JS
+	$public_booking_system_data = apply_filters( 'bookacti_public_booking_system_data', array_merge( $booking_system_data, array( 'user_id' => $public_user_ids ) ), $atts );
+
+	bookacti_send_json( array(
+		'status'              => 'success',
+		'booking_system_data' => $public_booking_system_data,
+		'trimmed_period'      => $trimmed_period
+	), 'get_booking_system_data_by_interval' );
+}
+add_action( 'wp_ajax_bookactiGetBookingSystemDataByInterval', 'bookacti_controller_get_booking_system_data_by_interval' );
+add_action( 'wp_ajax_nopriv_bookactiGetBookingSystemDataByInterval', 'bookacti_controller_get_booking_system_data_by_interval' );
+
+
+/**
+ * Reload booking system with new attributes via AJAX
+ * @since 1.1.0
+ * @version 1.16.0
+ */
+function bookacti_controller_reload_booking_system() {
+	$atts = isset( $_POST[ 'attributes' ] ) ? ( is_array( $_POST[ 'attributes' ] ) ? $_POST[ 'attributes' ] : ( is_string( $_POST[ 'attributes' ] ) ? bookacti_maybe_decode_json( stripslashes( $_POST[ 'attributes' ] ), true ) : array() ) ) : array();
+	$atts = bookacti_format_booking_system_attributes( $atts );
+
+	$atts[ 'auto_load' ] = 1;
+	$booking_system_data = bookacti_get_booking_system_data( $atts );
+
+	// Get HTML elements used by the booking method
+	$html_elements = bookacti_get_booking_method_html( $booking_system_data[ 'method' ], $booking_system_data );
+
+	// Encrypt user_id
+	$public_user_ids = array();
+	if( ! empty( $atts[ 'user_id' ] ) ) {
+		foreach( $atts[ 'user_id' ] as $user_id ) {
+			if( $user_id && ( ( is_numeric( $user_id ) && strlen( (string) $user_id ) < 16 ) || is_email( $user_id ) ) ) {
+				$public_user_ids[] = bookacti_encrypt( $user_id );
+			}
+		}
+	}
+
+	// Let plugins define what data should be passed to JS
+	$public_booking_system_data = apply_filters( 'bookacti_public_booking_system_data', array_merge( $booking_system_data, array( 'user_id' => $public_user_ids ) ), $atts );
+
+	bookacti_send_json( array(
+		'status'              => 'success',
+		'html_elements'       => $html_elements,
+		'booking_system_data' => $public_booking_system_data
+	), 'reload_booking_system' );
+}
+add_action( 'wp_ajax_bookactiReloadBookingSystem', 'bookacti_controller_reload_booking_system' );
+add_action( 'wp_ajax_nopriv_bookactiReloadBookingSystem', 'bookacti_controller_reload_booking_system' );
+
+
+/**
+ * AJAX Controller - Get booking numbers for a given template and / or event
+ * @version 1.12.0
+ */
+function bookacti_controller_get_booking_numbers() {
+	$template_ids  = isset( $_POST[ 'template_ids' ] ) ? bookacti_ids_to_array( $_POST[ 'template_ids' ] ) : array();
+	$groups_data   = isset( $_POST[ 'groups_data' ] ) && is_array( $_POST[ 'groups_data' ] ) ? $_POST[ 'groups_data' ] : array();
+	$groups_events = isset( $_POST[ 'groups_events' ] ) && is_array( $_POST[ 'groups_events' ] ) ? $_POST[ 'groups_events' ] : array();
+	$groups        = array( 'data' => $groups_data, 'groups' => $groups_events );
+
+	$bookings_nb_per_event = bookacti_get_number_of_bookings_per_event( array( 'templates' => $template_ids ) );
+	if( ! $bookings_nb_per_event ) { bookacti_send_json( array( 'status' => 'no_bookings' ), 'get_booking_numbers' ); }
+
+	$bookings_nb_per_group = bookacti_get_number_of_bookings_per_group_of_events( $groups );
+
+	bookacti_send_json( array( 'status' => 'success', 'bookings' => $bookings_nb_per_event, 'groups_bookings' => $bookings_nb_per_group ), 'get_booking_numbers' );
+}
+add_action( 'wp_ajax_bookactiGetBookingNumbers', 'bookacti_controller_get_booking_numbers' );
 add_action( 'wp_ajax_nopriv_bookactiGetBookingNumbers', 'bookacti_controller_get_booking_numbers' );
 No newline at end of file
--- a/booking-activities/controller/controller-bookings.php
+++ b/booking-activities/controller/controller-bookings.php
@@ -634,7 +634,7 @@
 /**
  * AJAX Controller - Get reschedule booking system data by booking selection
  * @since 1.8.0 (was bookacti_controller_get_booking_data)
- * @version 1.16.24
+ * @version 1.17.0
  */
 function bookacti_controller_get_reschedule_booking_system_data() {
 	$is_admin          = current_user_can( 'bookacti_edit_bookings' ) && ! empty( $_POST[ 'is_admin' ] );
@@ -686,6 +686,8 @@
 	$atts[ 'id' ]                       = 'bookacti-booking-system-reschedule';
 	$atts[ 'form_action' ]              = 'default';
 	$atts[ 'when_perform_form_action' ] = 'on_submit';
+	$atts[ 'select_first_event' ]       = 0;
+	$atts[ 'hide_calendar' ]            = array( 'none' );
 	$atts[ 'multiple_bookings' ]        = 0;
 	$atts[ 'auto_load' ]                = 0;

@@ -840,6 +842,7 @@
 		$atts[ 'start' ]                = '';
 		$atts[ 'end' ]                  = '';
 		$atts[ 'trim' ]                 = 1;
+		$atts[ 'out_of_period_events' ] = 1;
 		$atts[ 'past_events' ]          = 1;
 		$atts[ 'past_events_bookable' ] = 1;
 	}
--- a/booking-activities/controller/controller-forms.php
+++ b/booking-activities/controller/controller-forms.php
@@ -1,1950 +1,1950 @@
-<?php
-// Exit if accessed directly
-if ( ! defined( 'ABSPATH' ) ) { exit; }
-
-// DISPLAY FORM FIELDS
-
-/**
- * Display the form field 'calendar'
- * @since 1.5.0
- * @version 1.8.0
- * @param array $field
- * @param string $instance_id
- * @param string $context
- */
-function bookacti_display_form_field_calendar( $field, $instance_id, $context ) {
-	// Do not keep ID and class (already used for the container)
-	$field[ 'id' ] = $instance_id;
-	$field[ 'class' ] = '';
-
-	// 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; }
-
-	$field = apply_filters( 'bookacti_form_field_calendar_attributes', $field, $instance_id, $context );
-
-	$booking_system_atts = bookacti_get_calendar_field_booking_system_attributes( $field );
-
-	// Display the booking system
-	echo bookacti_get_booking_system( $booking_system_atts );
-}
-add_action( 'bookacti_display_form_field_calendar', 'bookacti_display_form_field_calendar', 10, 3 );
-
-
-/**
- * Display the form field 'login'
- * @since 1.5.0
- * @version 1.16.45
- * @param string $html
- * @param array $field
- * @param string $instance_id
- * @param string $context
- * @return string
- */
-function bookacti_display_form_field_login( $html, $field, $instance_id, $context ) {
-	$field_id       = ! empty( $field[ 'id' ] ) ? $field[ 'id' ] : 'bookacti-form-field-' . $field[ 'type' ] . '-' . $field[ 'field_id' ] . '-' . $instance_id;
-	$field_class    = 'bookacti-form-field-container';
-	$field_css_data = '';
-
-	if( ! empty( $field[ 'name' ] ) )         { $field_class .= ' bookacti-form-field-name-' . sanitize_title_with_dashes( $field[ 'name' ] ); $field_css_data .= ' data-field-name="' . esc_attr( $field[ 'name' ] ) . '"'; }
-	if( ! empty( $field[ 'type' ] ) )         { $field_class .= ' bookacti-form-field-type-' . sanitize_title_with_dashes( $field[ 'type' ] ); $field_css_data .= ' data-field-type="' . esc_attr( $field[ 'type' ] ) . '"'; }
-	if( ! empty( $field[ 'field_id' ] ) )     { $field_class .= ' bookacti-form-field-id-' . $field[ 'field_id' ]; $field_css_data .= ' data-field-id="' . esc_attr( $field[ 'field_id' ] ) . '"'; }
-	if( ! empty( $field[ 'class' ] ) )        { $field_class .= ' ' . $field[ 'class' ]; }
-	if( ! empty( $field[ 'login_button' ] ) ) { $field_class .= ' bookacti-has-login-button'; }
-
-	ob_start();
-	?>
-	<div class='<?php echo esc_attr( $field_class ); ?> bookacti-user-is-not-logged-in' id='<?php echo esc_attr( $field_id ); ?>' <?php echo trim( $field_css_data ); ?>>
-	<?php
-		// Display login types
-		$login_types = bookacti_get_login_type_field_default_options();
-		if( $login_types ) {
-			foreach( $login_types as $login_type_name => $login_type ) {
-				if( empty( $field[ 'displayed_fields' ][ $login_type_name ] ) ) { unset( $login_types[ $login_type_name ] ); }
-			}
-		}
-		if( $login_types ) {
-			$login_types_class = count( $login_types ) === 1 ? 'bookacti-login-types-hidden' : '';
-		?>
-			<div class='bookacti-form-field-login-field-container bookacti-login-field-login-type bookacti-custom-radio-button-container <?php echo $login_types_class; ?>' data-field-name='login_type'>
-		<?php
-			// Set the default login type on the first available by default
-			reset( $login_types );
-			$first_login_type = key( $login_types );
-			$default_login_type = apply_filters( 'bookacti_default_login_type', ! empty( $_REQUEST[ 'login_type' ] ) ? sanitize_title_with_dashes( $_REQUEST[ 'login_type' ] ) : $first_login_type, $field, $instance_id, $context );
-			if( ! in_array( $default_login_type, array_keys( $login_types ), true ) ) { $default_login_type = $first_login_type; }
-
-			foreach( $login_types as $login_type_name => $login_type ) {
-				if( empty( $field[ 'displayed_fields' ][ $login_type_name ] ) ) { continue; }
-				?>
-				<div class='bookacti-login-type-container bookacti-custom-radio-button bookacti-login-type-<?php echo $login_type_name; ?>' data-separator='<?php echo esc_html_x( 'or', 'separator between different options', 'booking-activities' ); ?>'>
-					<input type='radio' name='login_type' value='<?php echo $login_type_name; ?>' id='bookacti-<?php echo $instance_id; ?>-login-type-<?php echo $login_type_name; ?>' required <?php checked( $default_login_type, $login_type_name, true ); ?>/>
-					<label for='bookacti-<?php echo $instance_id; ?>-login-type-<?php echo $login_type_name; ?>'
-						<?php
-							if( ! empty( $field[ 'tip' ][ $login_type_name ] ) ) {
-								echo 'class="bookacti-tip" data-tip="' . esc_attr( $field[ 'tip' ][ $login_type_name ] ) . '"';
-							}
-						?>
-					>
-					<?php
-						echo $field[ 'label' ][ $login_type_name ];
-					?>
-					</label>
-				</div>
-				<?php
-			}
-
-			do_action( 'bookacti_login_field_after_login_type', $field, $instance_id, $context );
-			?>
-			</div>
-		<?php
-		}
-	?>
-		<div class='bookacti-user-data-fields'>
-			<div class='bookacti-log-in-fields'>
-				<?php do_action( 'bookacti_login_fields_before', $field, $instance_id, $context ); ?>
-				<div class='bookacti-form-field-login-field-container bookacti-login-field-email' id='<?php echo esc_attr( $field_id . '-email-container' ); ?>' data-field-name='email' data-field-type='email'>
-					<div class='bookacti-form-field-label' >
-						<label for='<?php echo esc_attr( $field_id . '-email' ); ?>' >
-							<?php echo esc_html( $field[ 'label' ][ 'email' ] ); ?>
-							<span class='bookacti-required-field-indicator' title='<?php esc_html_e( 'Required field', 'booking-activities' ); ?>'></span>
-						</label>
-					<?php if( ! empty( $field[ 'tip' ][ 'email' ] ) ) { bookacti_help_tip( esc_html( $field[ 'tip' ][ 'email' ] ) ); } ?>
-					</div>
-					<div class='bookacti-form-field-content' >
-					<?php
-						$email_args = apply_filters( 'bookacti_form_field_login_email', array(
-							'type'        => 'text',
-							'name'        => 'email',
-							'value'       => ! empty( $_REQUEST[ 'email' ] ) ? sanitize_text_field( $_REQUEST[ 'email' ] ) : '',
-							'id'          => $field_id . '-email',
-							'class'       => 'bookacti-form-field bookacti-email',
-							'placeholder' => $field[ 'placeholder' ][ 'email' ],
-							'required'    => 1
-						), $field, $instance_id, $context );
-						bookacti_display_field( $email_args );
-					?>
-					</div>
-					<?php do_action( 'bookacti_login_field_after_email', $field, $instance_id, $context ); ?>
-				</div>
-				<div class='bookacti-form-field-login-field-container bookacti-login-field-password <?php if( ! empty( $field[ 'generate_password' ] ) ) { echo esc_attr( 'bookacti-generated-password' ); } ?>' id='<?php echo esc_attr( $field_id . '-password-container' ); ?>' data-field-name='password' data-field-type='password'>
-					<div class='bookacti-form-field-label' >
-						<label for='<?php echo esc_attr( $field_id . '-password' ); ?>' >
-							<?php echo esc_html( $field[ 'label' ][ 'password' ] ); ?>
-							<span class='bookacti-required-field-indicator' title='<?php esc_html_e( 'Required field', 'booking-activities' ); ?>'></span>
-						</label>
-					<?php if( ! empty( $field[ 'tip' ][ 'password' ] ) ) { bookacti_help_tip( esc_html( $field[ 'tip' ][ 'password' ] ) ); } ?>
-					</div>
-					<div class='bookacti-form-field-content' >
-					<?php
-						$password_args = apply_filters( 'bookacti_form_field_login_password', array(
-							'type'        => 'password',
-							'name'        => 'password',
-							'value'       => ! empty( $_REQUEST[ 'password' ] ) ? sanitize_text_field( $_REQUEST[ 'password' ] ) : '',
-							'id'          => $field_id . '-password',
-							'class'       => 'bookacti-form-field bookacti-password',
-							'placeholder' => $field[ 'placeholder' ][ 'password' ],
-							'required'    => 1
-						), $field, $instance_id, $context );
-						bookacti_display_field( $password_args );
-
-						if( empty( $field[ 'generate_password' ] ) && $field[ 'min_password_strength' ] > 1 ) {
-							if( wp_script_is( 'password-strength-meter', 'registered' ) ) { wp_enqueue_script( 'password-strength-meter' ); }
-							?>
-							<div class='bookacti-password-strength' style='display:none;'>
-								<span class='bookacti-password-strength-meter'></span>
-								<input type='hidden' name='password_strength' class='bookacti-password_strength' value='0' min='<?php echo $field[ 'min_password_strength' ]; ?>' />
-							</div>
-							<?php
-						}
-
-						if( ! empty( $field[ 'displayed_fields' ][ 'forgotten_password' ] ) ) {
-							$forgotten_password_url = esc_attr( $field[ 'placeholder' ][ 'forgotten_password' ] );
-						?>
-							<div class='bookacti-forgotten-password' >
-								<a href='<?php echo $forgotten_password_url ? $forgotten_password_url : '#'; ?>' class='bookacti-forgotten-password-link' data-field-id='<?php echo esc_attr( $field_id ); ?>'><?php echo esc_html( $field[ 'label' ][ 'forgotten_password' ] ); ?></a>
-							<?php
-								if( ! empty( $field[ 'tip' ][ 'forgotten_password' ] ) ) {
-									bookacti_help_tip( esc_html( $field[ 'tip' ][ 'forgotten_password' ] ) );
-								}
-							?>
-							</div>
-							<?php if( ! $forgotten_password_url ) { ?>
-							<div data-field-id='<?php echo esc_attr( $field_id ); ?>' class='bookacti-backend-dialog bookacti-forgotten-password-dialog bookacti-form-dialog' title='<?php esc_html_e( 'Forgotten password', 'booking-activities' ); ?>' style='display:none;'>
-								<div class='bookacti-forgotten-password-dialog-description' >
-									<p>
-									<?php
-										echo apply_filters( 'bookacti_forgotten_password_description', esc_html__( 'Please enter your email address. You will receive a link to create a new password via email.', 'booking-activities' ), $field, $instance_id, $context );
-									?>
-									</p>
-								</div>
-								<div class='bookacti-forgotten-password-dialog-fields' >
-									<?php
-										$forgotten_pw_fields = apply_filters( 'bookacti_forgotten_password_fields', array(
-											'forgotten_password_email' => array(
-												'type'        => 'email',
-												'name'        => 'forgotten_password_email',
-												'id'          => 'bookacti-forgotten-password-email-' . $field_id,
-												'class'       => 'bookacti-forgotten-password-email',
-												'placeholder' => esc_html__( 'Your email address', 'booking-activities' ),
-											)
-										), $field, $instance_id, $context );
-
-										bookacti_display_fields( $forgotten_pw_fields );
-									?>
-								</div>
-							</div>
-						<?php
-							}
-						}
-						?>
-					</div>
-					<?php do_action( 'bookacti_login_field_after_password', $field, $instance_id, $context ); ?>
-				</div>
-				<?php
-				if( ! empty( $field[ 'displayed_fields' ][ 'remember' ] ) ) {
-				?>
-				<div class='bookacti-form-field-login-field-container bookacti-login-field-remember' id='<?php echo esc_attr( $field_id . '-remember-container' ); ?>' data-field-name='remember' data-field-type='checkbox'>
-					<div class='bookacti-form-field-label' >
-						<label for='<?php echo esc_attr( $field_id . '-remember' ); ?>'>
-							<?php echo esc_html( $field[ 'label' ][ 'remember' ] ); ?>
-						</label>
-					<?php if( ! empty( $field[ 'tip' ][ 'remember' ] ) ) { bookacti_help_tip( esc_html( $field[ 'tip' ][ 'remember' ] ) ); } ?>
-					</div>
-					<div class='bookacti-form-field-content'>
-					<?php
-						$remember_args = apply_filters( 'bookacti_form_field_login_remember', array(
-							'type'	=> 'checkbox',
-							'name'	=> 'remember',
-							'value'	=> ! empty( $_REQUEST[ 'remember' ] ) || ! empty( $field[ 'placeholder' ][ 'remember' ] ) ? 1 : 0,
-							'id'	=> $field_id . '-remember',
-							'class'	=> 'bookacti-form-field bookacti-remember'
-						), $field, $instance_id, $context );
-						bookacti_display_field( $remember_args );
-					?>
-					</div>
-					<?php do_action( 'bookacti_login_field_after_remember', $field, $instance_id, $context ); ?>
-				</div>
-				<?php
-				}
-				do_action( 'bookacti_login_fields_after', $field, $instance_id, $context );
-				?>
-			</div>
-			<?php
-			if( ! empty( $field[ 'displayed_fields' ][ 'new_account' ] ) || ! empty( $field[ 'displayed_fields' ][ 'no_account' ] ) ) {
-				// Display registration fields if any
-				$register_fields_defaults = bookacti_get_register_fields_default_data();
-				$register_fields = apply_filters( 'bookacti_register_fields', $register_fields_defaults );
-
-				if( in_array( 1, array_values( array_intersect_key( $field[ 'displayed_fields' ], $register_fields ) ) ) ) { ?>
-					<div class='bookacti-register-fields' id='<?php echo esc_attr( $field_id . '-register-fields' ); ?>' style='<?php if( $context !== 'edit' ) { echo 'display:none;'; } ?>' >
-						<?php
-						do_action( 'bookacti_register_fields_before', $field, $instance_id, $context );
-
-						foreach( $register_fields as $register_field_name => $register_field ) {
-							if( ! empty( $field[ 'displayed_fields' ][ $register_field_name ] ) ) { ?>
-								<div class='bookacti-form-field-login-field-container bookacti-login-field-<?php echo $register_field_name; ?>' id='<?php echo esc_attr( $field_id . '-' . $register_field_name . '-container' ); ?>' data-field-name='<?php echo esc_attr( $register_field_name ); ?>' data-field-type='<?php echo esc_attr( $register_field[ 'type' ] ); ?>'>
-									<?php if( $register_field[ 'type' ] !== 'checkbox' ) { ?>
-										<div class='bookacti-form-field-label' >
-											<label for='<?php echo esc_attr( $field_id . '-' . $register_field_name ); ?>' >
-											<?php
-												echo esc_html( $field[ 'label' ][ $register_field_name ] );
-												if( $field[ 'required_fields' ][ $register_field_name ] ) {
-													echo '<span class="bookacti-required-field-indicator" title="' . esc_attr__( 'Required field', 'booking-activities' ) . '"></span>';
-												}
-											?>
-											</label>
-										<?php if( ! empty( $field[ 'tip' ][ $register_field_name ] ) ) { bookacti_help_tip( esc_html( $field[ 'tip' ][ $register_field_name ] ) ); } ?>
-										</div>
-									<?php } ?>
-									<div class='bookacti-form-field-content' >
-									<?php
-										$register_field_args = array(
-											'type'        => $register_field[ 'type' ],
-											'name'        => $register_field_name,
-											'value'       => ! empty( $_REQUEST[ $register_field_name ] ) ? sanitize_text_field( $_REQUEST[ $register_field_name ] ) : ( isset( $register_field[ 'value' ] ) ? $register_field[ 'value' ] : '' ),
-											'id'          => $field_id . '-' . $register_field_name,
-											'class'       => 'bookacti-form-field bookacti-' . $register_field_name,
-											'required'    => $field[ 'required_fields' ][ $register_field_name ],
-											'placeholder' => $field[ 'placeholder' ][ $register_field_name ],
-											'required'    => $field[ 'required_fields' ][ $register_field_name ] ? 1 : 0
-										);
-										if( $register_field[ 'type' ] === 'checkbox' ) {
-											$register_field_args[ 'label' ] = esc_html( $field[ 'label' ][ $register_field_name ] );
-											$register_field_args[ 'tip' ]   = esc_html( $field[ 'tip' ][ $register_field_name ] );
-										}
-										$register_field_args = apply_filters( 'bookacti_register_field', $register_field_args, $register_field, $field, $instance_id, $context );
-										bookacti_display_field( $register_field_args );
-									?>
-									</div>
-									<?php do_action( 'bookacti_register_field_after_' . $register_field_name, $register_field, $field, $instance_id, $context ); ?>
-								</div>
-							<?php }
-						}
-
-						do_action( 'bookacti_register_fields_after', $field, $instance_id, $context );
-					?>
-					</div>
-				<?php
-				}
-			}
-
-			if( ! empty( $field[ 'login_button' ] ) ) {
-				$login_button_label    = $field[ 'login_button_label' ];
-				$register_button_label = $field[ 'register_button_label' ];
-				$input_type            = ! is_user_logged_in() && ( ! empty( $field[ 'login_first' ] ) || $context === 'login_form' ) ? 'submit' : 'button';
-			?>
-			<div class='bookacti-form-field-login-field-container bookacti-login-field-submit-button' id='<?php echo esc_attr( $field_id . '-submit-button' ); ?>' style='display:none;'>
-				<input type='<?php echo esc_attr( $input_type ); ?>' value='<?php echo esc_attr( $login_button_label ); ?>' class='bookacti-login-button button' data-login-label='<?php echo esc_attr( $login_button_label ); ?>' data-register-label='<?php echo esc_attr( $register_button_label ); ?>'/>
-			</div>
-			<?php } ?>
-		</div>
-	</div>
-	<?php
-	return ob_get_clean();
-}
-add_filter( 'bookacti_html_form_field_login', 'bookacti_display_form_field_login', 20, 4 );
-
-
-/**
- * Display the form field "Login / Registration" when the user is already logged in
- * @since 1.5.0
- * @version 1.13.0
- * @param string $html
- * @param array $field
- * @param string $instance_id
- * @param string $context
- * @return string
- */
-function bookacti_display_form_field_login_when_logged_in( $html, $field, $instance_id, $context ) {
-	// Display this only if user is already logged in
-	if( $context === 'edit' || ! is_user_logged_in() ) { return $html; }
-
-	// Do not display the Login / Registration fields
-	remove_filter( 'bookacti_html_form_field_login', 'bookacti_display_form_field_login', 20 );
-
-	$user           = get_user_by( 'id', get_current_user_id() );
-	$field_id       = ! empty( $field[ 'id' ] ) ? esc_attr( $field[ 'id' ] ) : esc_attr( 'bookacti-form-field-' . $field[ 'type' ] . '-' . $field[ 'field_id' ] . '-' . $instance_id );
-	$field_class    = 'bookacti-form-field-container';
-	$field_css_data = '';
-	if( ! empty( $field[ 'name' ] ) )     { $field_class .= ' bookacti-form-field-name-' . sanitize_title_with_dashes( esc_attr( $field[ 'name' ] ) ); $field_css_data .= ' data-field-name="' . esc_attr( $field[ 'name' ] ) . '"'; }
-	if( ! empty( $field[ 'type' ] ) )     { $field_class .= ' bookacti-form-field-type-' . sanitize_title_with_dashes( esc_attr( $field[ 'type' ] ) ); $field_css_data .= ' data-field-type="' . esc_attr( $field[ 'type' ] ) . '"'; }
-	if( ! empty( $field[ 'field_id' ] ) ) { $field_class .= ' bookacti-form-field-id-' . esc_attr( $field[ 'field_id' ] ); $field_css_data .= ' data-field-id="' . esc_attr( $field[ 'field_id' ] ) . '"'; }
-	if( ! empty( $field[ 'class' ] ) )    { $field_class .= ' ' . esc_attr( $field[ 'class' ] ); }
-	ob_start();
-	?>
-	<div class='<?php echo $field_class; ?> bookacti-user-is-logged-in' id='<?php echo $field_id; ?>' <?php echo trim( $field_css_data ); ?>>
-		<div class='bookacti-form-field-login-field-container bookacti-login-field-log-out' id='<?php echo $field_id; ?>-email-container' >
-			<div class='bookacti-logout-form-field-container'>
-				<span>
-					<?php
-					/* translators: %1$s = user name. %2$s = user email address */
-					echo sprintf( esc_html__( 'You are currently logged in as %1$s (%2$s).', 'booking-activities' ), $user->display_name, $user->user_email );
-					?>
-				</span>
-				<a href='<?php echo wp_logout_url( apply_filters( 'bookacti_logout_redirect_url', get_permalink(), $field, $instance_id, $context ) ); ?>' class='bookacti-logout-link'>
-					<?php esc_html_e( 'Click here to log out.', 'booking-activities' ); ?>
-				</a>
-			</div>
-			<?php do_action( 'bookacti_login_field_after_log_out', $field, $instance_id, $context ); ?>
-		</div>
-	</div>
-	<?php
-	return ob_get_clean();
-}
-add_filter( 'bookacti_html_form_field_login', 'bookacti_display_form_field_login_when_logged_in', 10, 4 );
-
-
-/**
- * Display the form field 'quantity'
- * @since 1.5.0
- * @version 1.15.13
- * @param array $field
- * @param string $instance_id
- * @param string $context
- */
-function bookacti_display_form_field_quantity( $field, $instance_id, $context ) {
-	$args = apply_filters( 'bookacti_form_field_quantity_args', array(
-		'type'        => 'number',
-		'name'        => 'quantity',
-		'class'       => 'bookacti-form-field bookacti-quantity',
-		'placeholder' => esc_attr( $field[ 'placeholder' ] ),
-		'options'     => array( 'min' => 1 ),
-		'value'       => ! empty( $_REQUEST[ 'quantity' ] ) && is_numeric( $_REQUEST[ 'quantity' ] ) ? intval( $_REQUEST[ 'quantity' ] ) : 1
-	), $field, $instance_id, $context );
-	bookacti_display_field( $args );
-}
-add_action( 'bookacti_display_form_field_quantity', 'bookacti_display_form_field_quantity', 10, 3 );
-
-
-/**
- * Display the form field 'checkbox'
- * @since 1.5.2
- * @version 1.14.0
- * @param string $html
- * @param array $field
- * @param string $instance_id
- * @param string $context
- * @return string
- */
-function bookacti_display_form_field_checkbox( $html, $field, $instance_id, $context ) {
-	$field_id       = ! empty( $field[ 'id' ] ) ? esc_attr( $field[ 'id' ] ) : esc_attr( 'bookacti-form-field-' . $field[ 'type' ] . '-' . $field[ 'field_id' ] . '-' . $instance_id );
-	$field_class    = 'bookacti-form-field-container';
-	$field_css_data = '';
-	if( ! empty( $field[ 'name' ] ) )     { $field_class .= ' bookacti-form-field-name-' . sanitize_title_with_dashes( esc_attr( $field[ 'name' ] ) ); $field_css_data .= ' data-field-name="' . esc_attr( $field[ 'name' ] ) . '"'; }
-	if( ! empty( $field[ 'type' ] ) )     { $field_class .= ' bookacti-form-field-type-' . sanitize_title_with_dashes( esc_attr( $field[ 'type' ] ) ); $field_css_data .= ' data-field-type="' . esc_attr( $field[ 'type' ] ) . '"'; }
-	if( ! empty( $field[ 'field_id' ] ) ) { $field_class .= ' bookacti-form-field-id-' . esc_attr( $field[ 'field_id' ] ); $field_css_data .= ' data-field-id="' . esc_attr( $field[ 'field_id' ] ) . '"'; }
-	if( ! empty( $field[ 'class' ] ) )    { $field_class .= ' ' . esc_attr( $field[ 'class' ] ); }
-	$is_checked = ! empty( $_REQUEST[ $field[ 'name' ] ] ) ? 1 : ( ! empty( $field[ 'value' ] ) ? 1 : 0 );
-
-	$args = apply_filters( 'bookacti_form_field_checkbox_args', array(
-		'type'     => $field[ 'type' ],
-		'name'     => $field[ 'name' ],
-		'id'       => $field_id . '-input',
-		'class'    => 'bookacti-form-field ' . $field[ 'class' ] ,
-		'value'    => $is_checked,
-		'attr'     => '',
-		'required' => $field[ 'required' ]
-	), $field, $instance_id, $context );
-
-	ob_start();
-	?>
-	<div class='<?php echo $field_class; ?>' id='<?php echo $field_id; ?>' <?php echo trim( $field_css_data ); ?>>
-		<div class='bookacti-form-field-checkbox-field-container bookacti-form-field-content' >
-			<div class='bookacti-form-field-checkbox-input' >
-				<input type='hidden' name='<?php echo esc_attr( $args[ 'name' ] ); ?>' value='0'/>
-				<input type='<?php echo esc_attr( $args[ 'type' ] ); ?>'
-					   name='<?php echo esc_attr( $args[ 'name' ] ); ?>'
-					   id='<?php echo esc_attr( $args[ 'id' ] ); ?>'
-					   class='<?php echo esc_attr( $args[ 'class' ] ); ?>'
-					   value='1'
-					   <?php if( $args[ 'attr' ] )        { echo $args[ 'attr' ]; } ?>
-					   <?php if( $args[ 'required' ] )    { echo 'required'; } ?>
-					   <?php if( $args[ 'value' ] === 1 ) { echo 'checked'; } ?> />
-			</div>
-			<div class='bookacti-form-field-checkbox-label' >
-				<label for='<?php echo esc_attr( $args[ 'id' ] ); ?>' >
-				<?php
-					echo $field[ 'label' ];
-					if( $args[ 'required' ] ) {
-						echo '<span class="bookacti-required-field-indicator" title="' . esc_attr__( 'Required field', 'booking-activities' ) . '"></span>';
-					}
-				?>
-				</label>
-			<?php if( ! empty( $field[ 'tip' ] ) ) { bookacti_help_tip( esc_html( $field[ 'tip' ] ) ); } ?>
-			</div>
-			<?php do_action( 'bookacti_form_field_checkbox_after', $field, $instance_id, $context, $args ); ?>
-		</div>
-	</div>
-	<?php
-	return ob_get_clean();
-}
-add_filter( 'bookacti_html_form_field_checkbox', 'bookacti_display_form_field_checkbox', 10, 4 );
-
-
-/**
- * Display the form field 'submit'
- * @since 1.5.0
- * @version 1.14.0
- * @param string $html
- * @param array $field
- * @param string $instance_id
- * @param string $context
- * @return string
- */
-function bookacti_display_form_field_submit( $html, $field, $instance_id, $context ) {
-	$field_id       = ! empty( $field[ 'id' ] ) ? esc_attr( $field[ 'id' ] ) : esc_attr( 'bookacti-form-field-' . $field[ 'type' ] . '-' . $field[ 'field_id' ] . '-' . $instance_id );
-	$field_class    = 'bookacti-form-field-container';
-	$field_css_data = '';
-	if( ! empty( $field[ 'name' ] ) )     { $field_class .= ' bookacti-form-field-name-' . sanitize_title_with_dashes( esc_attr( $field[ 'name' ] ) ); $field_css_data .= ' data-field-name="' . esc_attr( $field[ 'name' ] ) . '"'; }
-	if( ! empty( $field[ 'type' ] ) )     { $field_class .= ' bookacti-form-field-type-' . sanitize_title_with_dashes( esc_attr( $field[ 'type' ] ) ); $field_css_data .= ' data-field-type="' . esc_attr( $field[ 'type' ] ) . '"'; }
-	if( ! empty( $field[ 'field_id' ] ) ) { $field_class .= ' bookacti-form-field-id-' . esc_attr( $field[ 'field_id' ] ); $field_css_data .= ' data-field-id="' . esc_attr( $field[ 'field_id' ] ) . '"'; }
-	if( ! empty( $field[ 'class' ] ) )    { $field_class .= ' ' . esc_attr( $field[ 'class' ] ); }
-	ob_start();
-	?>
-	<div class='<?php echo $field_class; ?>' id='<?php echo $field_id; ?>' <?php echo trim( $field_css_data ); ?>>
-		<input type='<?php echo $context === 'edit' ? 'button' : 'submit'; ?>' class='bookacti-submit-form button' value='<?php echo esc_attr( $field[ 'value' ] ); ?>'/>
-		<input type='button' class='bookacti-new-booking-button button' value='<?php echo bookacti_get_message( 'booking_form_new_booking_button' ); ?>' style='display:none;'/>
-	</div>
-	<?php
-	return ob_get_clean();
-}
-add_filter( 'bookacti_html_form_field_submit', 'bookacti_display_form_field_submit', 10, 4 );
-
-
-/**
- * Display the form field 'free_text'
- * @since 1.5.0
- * @version 1.14.0
- * @param array $field
- * @param string $instance_id
- * @param string $context
- */
-function bookacti_display_form_field_free_text( $field, $instance_id, $context ) {
-	$field_id = ! empty( $field[ 'id' ] ) ? esc_attr( $field[ 'id' ] ) : esc_attr( 'bookacti-form-field-' . $field[ 'type' ] . '-' . $field[ 'field_id' ] . '-' . $instance_id );
-	?>
-	<div id='<?php echo $field_id; ?>' class='bookacti-form-free-text <?php echo esc_attr( $field[ 'class' ] ); ?>' >
-	<?php
-		echo $field[ 'value' ] && $context !== 'edit' ? do_shortcode( $field[ 'value' ] ) : $field[ 'value' ];
-	?>
-	</div>
-	<?php
-}
-add_action( 'bookacti_display_form_field_free_text', 'bookacti_display_form_field_free_text', 10, 3 );
-
-
-/**
- * Add a compulsory quantity input for correct booking form functionning
- * @since 1.5.0
- * @version 1.8.0
- * @param array $fields
- * @param array $form
- * @param string $instance_id
- * @param string $context
- * @return array
- */
-function bookacti_display_compulsory_quantity_form_field( $fields, $form, $instance_id, $context ) {
-	if( $context !== 'display' ) { return $fields; }
-
-	// Get the fields types and the calendar form action trigger
-	$fields_types = array();
-	$form_action_trigger = 'on_submit';
-	foreach( $fields as $field ) {
-		if( ! empty( $field[ 'type' ] ) ) {
-			$fields_types[] = $field[ 'type' ];
-			if( $field[ 'type' ] === 'calendar' && ! empty( $field[ 'when_perform_form_action' ] ) ) {
-				$form_action_trigger = $field[ 'when_perform_form_action' ];
-			}
-		}
-	}
-
-	// If there is no "quantity" input, add a default hidden quantity input
-	if( ! in_array( 'quantity', $fields_types, true ) && ( in_array( 'submit', $fields_types, true ) || $form_action_trigger = 'on_event_click' ) ) {
-		$field = bookacti_get_default_form_fields_data( 'quantity' );
-		$field[ 'id' ]     = 'bookacti-compulsory-quantity-field';
-		$field[ 'class' ] .= ' bookacti-hidden-field';
-		$field[ 'value' ]  = ! empty( $_REQUEST[ 'quantity' ] ) && is_numeric( $_REQUEST[ 'quantity' ] ) ? intval( $_REQUEST[ 'quantity' ] ) : 1;
-		$fields[] = $field;
-	}
-
-	return $fields;
-}
-add_filter( 'bookacti_displayed_form_fields', 'bookacti_display_compulsory_quantity_form_field', 100, 4 );
-
-
-/**
- * Remove the Total Price field by default, since it is only used by third party plugins
- * @since 1.2.14
- * @param array $fields_data
- * @param string $field_name
- * @return array
- */
-function bookacti_remove_unused_total_price_field( $fields_data, $field_name = '' ) {
-	$used = apply_filters( 'bookacti_is_total_price_field_used', false );
-	if( ! $used && isset( $fields_data[ 'total_price' ] ) ) { unset( $fields_data[ 'total_price' ] ); }
-	return $fields_data;
-}
-add_filter( 'bookacti_default_form_fields_data', 'bookacti_remove_unused_total_price_field', 10, 2 );
-add_filter( 'bookacti_default_form_fields_meta', 'bookacti_remove_unused_total_price_field', 10, 2 );
-
-
-/**
- * Display the form field "Total price"
- * @since 1.12.4
- * @version 1.15.15
- * @param string $html
- * @param array $field
- * @param string $instance_id
- * @param string $context
- */
-function bookacti_display_form_field_total_price( $html, $field, $instance_id = '', $context = '' ) {
-	if( ! $instance_id ) { $instance_id = rand(); }
-	$field_id = ! empty( $field[ 'id' ] ) ? esc_attr( $field[ 'id' ] ) : esc_attr( 'bookacti-form-field-' . $field[ 'type' ] . '-' . $field[ 'field_id' ] . '-' . $instance_id );
-
-	$field_class    = 'bookacti-form-field-container';
-	$field_css_data = empty( $field[ 'items' ] ) ? 'style="display:none;"' : '';
-	if( ! empty( $field[ 'name' ] ) )     { $field_class .= ' bookacti-form-field-name-' . sanitize_title_with_dashes( esc_attr( $field[ 'name' ] ) ); $field_css_data .= ' data-field-name="' . esc_attr( $field[ 'name' ] ) . '"'; }
-	if( ! empty( $field[ 'type' ] ) )     { $field_class .= ' bookacti-form-field-type-' . sanitize_title_with_dashes( esc_attr( $field[ 'type' ] ) ); $field_css_data .= ' data-field-type="' . esc_attr( $field[ 'type' ] ) . '"'; }
-	if( ! empty( $field[ 'field_id' ] ) ) { $field_class .= ' bookacti-form-field-id-' . esc_attr( $field[ 'field_id' ] ); $field_css_data .= ' data-field-id="' . esc_attr( $field[ 'field_id' ] ) . '"'; }
-	if( ! empty( $field[ 'class' ] ) )    { $field_class .= ' ' . esc_attr( $field[ 'class' ] ); }
-
-	$tip = esc_attr( $field[ 'tip' ] ) ? bookacti_help_tip( $field[ 'tip' ], false ) : '';
-
-	// Compute grand total
-	$grand_total_item = array(
-		'id'               => 'grand_total',
-		'label'            => esc_html__( 'Total', 'booking-activities' ),
-		'price'            => 0,
-		'price_to_display' => ''
-	);
-
-	if( ! empty( $field[ 'items' ] ) ) {
-		foreach( $field[ 'items' ] as $item ) {
-			$grand_total_item[ 'price' ] += $item[ 'price' ];
-		}
-		$grand_total_item[ 'price_to_display' ] = $grand_total_item[ 'price' ] ? bookacti_format_price( $grand_total_item[ 'price' ], array( 'plain_text' => true ) ) : '';
-
-		$grand_total_item = apply_filters( 'bookacti_total_price_field_grand_total_item', $grand_total_item, $field, $instance_id, $context );
-	}
-
-	ob_start();
-?>
-	<div class='<?php echo $field_class; ?>' id='<?php echo $field_id; ?>' <?php echo trim( $field_css_data ); ?>>
-		<input type='hidden' name='total_price' value='<?php echo $grand_total_item[ 'price' ]; ?>' class='bookacti-total-price-value'/>
-	<?php if( ! empty( $field[ 'label' ] ) ) { ?>
-			<label><?php echo $field[ 'label' ]; ?></label>
-			<?php echo $tip; ?>
-	<?php }
-	if( ! empty( $field[ 'price_breakdown' ] ) ) { ?>
-		<table class='bookacti-total-price-table'>
-			<thead>
-				<tr>
-					<th><?php esc_html_e( 'Items', 'booking-activities' ); ?></th>
-					<th><?php esc_html_e( 'Price', 'booking-activities' ); ?></th>
-				</tr>
-			</thead>
-			<tbody>
-			<?php
-				if( ! empty( $field[ 'items' ] ) ) {
-					foreach( $field[ 'items' ] as $item ) {
-						if( ! ( isset( $item[ 'label' ] ) || isset( $item[ 'id' ] ) )
-						||  ! ( isset( $item[ 'price_to_display' ] ) || isset( $item[ 'price' ] ) ) ) { continue; }
-					?>
-						<tr data-item-id='<?php echo isset( $item[ 'id' ] ) ? $item[ 'id' ] : ''; ?>'>
-							<td><?php echo isset( $item[ 'label' ] ) ? $item[ 'label' ] : $item[ 'id' ]; ?></td>
-							<td><?php echo isset( $item[ 'price_to_display' ] ) ? $item[ 'price_to_display' ] : $item[ 'price' ]; ?></td>
-						</tr>
-					<?php
-					}
-				}
-			?>
-			</tbody>
-			<tfoot>
-				<tr>
-					<th>
-					<?php
-						echo $grand_total_item[ 'label' ];
-						if( empty( $field[ 'label' ] ) ) {
-							echo $tip;
-						}
-					?>
-					</th>
-					<th class='bookacti-grand-total-price-container'>
-					<?php
-						echo $grand_total_item[ 'price_to_display' ];
-					?>
-					</th>
-				</tr>
-			</tfoot>
-		</table>
-	<?php } else { ?>
-		<span class='bookacti-grand-total-price-container'>
-		<?php
-			echo $grand_total_item[ 'price_to_display' ];
-		?>
-		</span>
-	<?php
-		if( empty( $field[ 'label' ] ) ) { echo $tip; }
-	} ?>
-	</div>
-<?php
-	return ob_get_clean();
-}
-add_filter( 'bookacti_html_form_field_total_price', 'bookacti_display_form_field_total_price', 10, 4 );
-
-
-
-
-// FORM
-
-/**
- * AJAX Controller - Get a booking form
- * @since 1.5.0
- * @version 1.8.0
- */
-function bookacti_controller_get_form() {
-	// Sanitize values
-	$form_id     = intval( $_POST[ 'form_id' ] );
-	$instance_id = ! empty( $_POST[ 'instance_id' ] ) ? sanitize_title_with_dashes( $_POST[ 'instance_id' ] ) : '';
-	$context     = ! empty( $_POST[ 'context' ] ) ? sanitize_title_with_dashes( $_POST[ 'context' ] ) : 'display';
-
-	// Get the form
-	$form_html = bookacti_display_form( $form_id, $instance_id, $context, false );
-	if( ! $form_html ) { bookacti_send_json( array( 'status' => 'failed', 'error' => 'no_form' ), 'get_form' ); }
-
-	bookacti_send_json( array( 'status' => 'success', 'form_html' => $form_html ), 'get_form' );
-}
-add_action( 'wp_ajax_bookactiGetForm', 'bookacti_controller_get_form' );
-add_action( 'wp_ajax_nopriv_bookactiGetForm', 'bookacti_controller_get_form' );
-
-
-/**
- * AJAX Controller - Send the forgotten password email
- * @since 1.5.0
- * @version 1.15.5
- */
-function bookacti_controller_forgotten_password() {
-	$user_login   = isset( $_POST[ 'user_login' ] ) ? sanitize_user( wp_unslash( $_POST[ 'user_login' ] ) ) : '';
-	$callback     = apply_filters( 'bookacti_reset_password_notification_callback', 'retrieve_password' );
-	$return_array = array(
-		'status'  => 'failed',
-		'message' => ''
-	);
-
-	$response = false;
-	if( is_callable( $callback ) ) {
-		$response = call_user_func( $callback, $user_login );
-
-		if( $response === true ) {
-			$return_array[ 'status' ] = 'success';
-			/* translators: %s is the user email address or the user login */
-			$return_array[ 'message' ] = sprintf( esc_html__( 'An email has been sent to %s, please check your inbox.', 'booking-activities' ), $user_login );
-		} else {
-			$return_array[ 'status' ] = 'failed';
-			if( is_wp_error( $response ) ) {
-				$return_array[ 'messages' ] = $response->get_error_messages();
-			} else if( is_array( $response ) ) {
-				$return_array[ 'messages' ] = array_filter( $response, 'is_string' );
-			} else if( is_string( $response ) ) {
-				$return_array[ 'message' ] = $response;
-			}
-			if( ! empty( $return_array[ 'messages' ] ) ) {
-				$return_array[ 'message' ] = implode( '</li><li>', $return_array[ 'messages' ] );
-			}
-		}
-	}
-
-	if( $response === true ) {
-		do_action( 'bookacti_reset_password_notification_sent', $user_login );
-	}
-
-	bookacti_send_json( $return_array, 'reset_password' );
-}
-add_action( 'wp_ajax_bookactiForgottenPassword', 'bookacti_controller_forgotten_password' );
-add_action( 'wp_ajax_nopriv_bookactiForgottenPassword', 'bookacti_controller_forgotten_password' );
-
-
-/**
- * AJAX Controller - Check if login form is correct and then register / log the user in
- * @since 1.8.0
- * @version 1.16.45
- */
-function bookacti_controller_validate_login_form() {
-	$return_array = array(
-		'status'			=> '',
-		'error'				=> '',
-		'messages'			=> array(),
-		'message'			=> '',
-		'has_logged_in'		=> false,
-		'has_registered'	=> false,
-		'user_id'			=> 0,
-		'redirect_url'		=> ''
-	);
-
-	// Check if the user is already logged in
-	if( is_user_logged_in() ) {
-		$return_array[ 'error' ] = 'already_logged_in';
-		$return_array[ 'messages' ][ 'already_logged_in' ] = esc_html__( 'You are already logged in.', 'booking-activities' ) . ' ' . esc_html__( 'Please reload the page and try again.', 'booking-activities' );
-		$return_array[ 'message' ] = implode( '</li><li>', $return_array[ 'messages' ] );
-		bookacti_send_json( $return_array, 'submit_login_form' );
-	}
-
-	// Check form
-	$form_id = ! empty( $_POST[ 'form_id' ] ) ? intval( $_POST[ 'form_id' ] ) : 0;
-	$fields_data = $form_id ? bookacti_get_form_fields_data( $form_id, true, true ) : array();
-	if( ! $fields_data ) {
-		$return_array[ 'error' ] = 'invalid_form_id';
-		$return_array[ 'messages' ][ 'invalid_form_id' ] = esc_html__( 'Invalid form ID.', 'booking-activities' ) . ' ' . esc_html__( 'Please reload the page and try again.', 'booking-activities' );
-		$return_array[ 'message' ] = implode( '</li><li>', $return_array[ 'messages' ] );
-		bookacti_send_json( $return_array, 'submit_login_form' );
-	}
-
-	// Retrieve login field data
-	$login_field = ! empty( $fields_data[ 'login' ] ) ? $fields_data[ 'login' ] : array();
-	if( ! $login_field || empty( $_POST[ 'login_type' ] ) ) {
-		$return_array[ 'error' ] = 'invalid_login_field';
-		$return_array[ 'messages' ][ 'invalid_login_field' ] = esc_html__( 'Invalid form ID.', 'booking-activities' ) . ' ' . esc_html__( 'Please reload the page and try again.', 'booking-activities' );
-		$return_array[ 'message' ] = implode( '</li><li>', $return_array[ 'messages' ] );
-		bookacti_send_json( $return_array, 'submit_login_form' );
-	}
-
-	// Check if login / registration is allowed independantly
-	$calendar_field = ! empty( $fields_data[ 'calendar' ] ) ? $fields_data[ 'calendar' ] : array();
-	if( ! $calendar_field ) {
-		$return_array[ 'error' ] = 'invalid_calendar_field';
-		$return_array[ 'messages' ][ 'invalid_calendar_field' ] = esc_html__( 'Invalid form ID.', 'booking-activities' ) . ' ' . esc_html__( 'Please reload the page and try again.', 'booking-activities' );
-		$return_array[ 'message' ] = implode( '</li><li>', $return_array[ 'messages' ] );
-		bookacti_send_json( $return_array, 'submit_login_form' );
-	}
-
-	// Let third party plugins validate their own part of the form
-	$return_array = apply_filters( 'bookacti_validate_login_form_submission', $return_array, $form_id, $login_field );
-	if( $return_array[ 'status' ] ) {
-		if( $return_array[ 'messages' ] ) { $return_array[ 'message' ] = implode( '</li><li>', $return_array[ 'messages' ] ); }
-		bookacti_send_json( $return_array, 'submit_login_form' );
-	}
-
-	// Sanitize values
-	$login_values = bookacti_sanitize_form_field_values( $_POST, 'login' );
-
-	// Check if login / registration is allowed
-	if( ! in_array( $login_values[ 'login_type' ], array( 'my_account', 'new_account' ), true )
-	 || ( $login_values[ 'login_type' ] === 'my_account' && empty( $login_field[ 'displayed_fields' ][ 'my_account' ] ) )
-	 || ( $login_values[ 'login_type' ] === 'new_account' && empty( $login_field[ 'displayed_fields' ][ 'new_account' ] ) )
-	) {
-		$return_array[ 'error' ] = 'action_not_allowed';
-		$return_array[ 'messages' ][ 'action_not_allowed' ] = esc_html__( 'You are not allowed to do that.', 'booking-activities' );
-		$return_array[ 'message' ] = implode( '</li><li>', $return_array[ 'messages' ] );
-		bookacti_send_json( $return_array, 'submit_login_form' );
-	}
-
-	// Register
-	if( $login_values[ 'login_type' ] === 'new_account' ) {
-		// Register the new user
-		$user = bookacti_register_a_new_user( $login_values, $login_field );
-		if( is_a( $user, 'WP_User' ) ) {
-			$return_array[ 'has_registered' ] = true;
-			$return_array[ 'messages' ][ 'registered' ] = esc_html__( 'Your account has been successfully created.', 'booking-activities' );
-
-			do_action( 'bookacti_booking_form_user_registered', $user, $form_id, $login_values );
-		}
-
-	// Login
-	} else if( $login_values[ 'login_type' ] === 'my_account' ) {
-		// Validate login fields
-		$user = bookacti_validate_login( $login_values );
-	}
-
-	// Check if the user exists
-	if( ! is_a( $user, 'WP_User' ) ) {
-		$return_array[ 'error' ]    = $login_values[ 'login_type' ] === 'new_account' ? 'user_registration_failed' : 'user_login_failed';
-		$return_array[ 'messages' ] = ! empty( $user[ 'messages' ] ) ? $user[ 'messages' ] : array();
-		$return_array[ 'message' ]  = implode( '</li><li>', $return_array[ 'messages' ] );
-		bookacti_send_json( $return_array, 'submit_login_form' );
-	}
-
-	// Log the user in
-	$is_logged_in = bookacti_log_user_in( $user->user_login, $login_values[ 'remember' ] );
-	if( ! $is_logged_in ) {
-		$return_array[ 'error' ] = 'cannot_log_in';
-		$return_array[ 'messages' ][ 'cannot_log_in' ] = esc_html__( 'An error occurred while trying to log you in.', 'booking-activities' );
-		$return_array[ 'message' ] = implode( '</li><li>', $return_array[ 'messages' ] );
-		bookacti_send_json( $return_array, 'submit_login_form' );
-	}
-
-	do_action( 'bookacti_login_form_user_logged_in', $user, $login_values, $login_field, $form_id );
-
-	$return_array[ 'status' ] = 'success';
-	$return_array[ 'user_id' ] = $user->ID;
-	$return_array[ 'has_logged_in' ] = true;
-	$return_array[ 'messages' ][ 'logged_in' ] = esc_html__( 'You are now logged into your account.', 'booking-activities' );
-
-	$return_array = apply_filters( 'bookacti_login_form_validated_response', $return_array, $user, $login_values, $login_field, $form_id );
-
-	if( $return_array[ 'messages' ] ) { $return_array[ 'message' ] = implode( '</li><li>', $return_array[ 'messages' ] ); }
-
-	bookacti_send_json( $return_array, 'submit_login_form' );
-}
-add_action( 'wp_ajax_bookactiSubmitLoginForm', 'bookacti_controller_validate_login_form' );
-add_action( 'wp_ajax_nopriv_bookactiSubmitLoginForm', 'bookacti_controller_validate_login_form' );
-
-
-/**
- * AJAX Controller - Check if booking form is correct and then book the event, or send the error message
- * @since 1.5.0
- * @version 1.16.42
- */
-function bookacti_controller_validate_booking_form() {
-	$return_array = array(
-		'has

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School