--- a/ameliabooking/ameliabooking.php
+++ b/ameliabooking/ameliabooking.php
@@ -3,7 +3,7 @@
Plugin Name: Amelia
Plugin URI: https://wpamelia.com/
Description: Amelia is a simple yet powerful automated booking specialist, working 24/7 to make sure your customers can make appointments and events even while you sleep!
-Version: 1.2.38
+Version: 2.0
Author: Melograno Ventures
Author URI: https://melograno.io/
Text Domain: ameliabooking
@@ -35,7 +35,6 @@
use AmeliaBookingInfrastructureWPWPMenuSubmenu;
use AmeliaBookingInfrastructureWPWPMenuSubmenuPageHandler;
use Exception;
-use InteropContainerExceptionContainerException;
use SlimApp;
// No direct access
@@ -104,7 +103,7 @@
// Const for Amelia version
if (!defined('AMELIA_VERSION')) {
- define('AMELIA_VERSION', '1.2.38');
+ define('AMELIA_VERSION', '2.0');
}
// Const for site URL
@@ -121,6 +120,7 @@
if (!defined('AMELIA_SMS_API_URL')) {
define('AMELIA_SMS_API_URL', 'https://smsapi.wpamelia.com/');
define('AMELIA_SMS_VENDOR_ID', 36082);
+ define('AMELIA_SMS_IS_SANDBOX', false);
define('AMELIA_SMS_PRODUCT_ID_10', 595657);
define('AMELIA_SMS_PRODUCT_ID_20', 595658);
define('AMELIA_SMS_PRODUCT_ID_50', 595659);
@@ -137,8 +137,16 @@
define('AMELIA_DEV', false);
}
+if (!defined('AMELIA_PRODUCTION')) {
+ define('AMELIA_PRODUCTION', true);
+}
+
if (!defined('AMELIA_NGROK_URL')) {
- define('AMELIA_NGROK_URL', 'ce3ac66a70b5.ngrok-free.app');
+ define('AMELIA_NGROK_URL', 'nonmelodiously-barnlike-anika.ngrok-free.dev');
+}
+
+if (!defined('AMELIA_MIDDLEWARE_URL')) {
+ define('AMELIA_MIDDLEWARE_URL', 'https://middleware.wpamelia.com/');
}
if (!defined('AMELIA_MAILCHIMP_CLIENT_ID')) {
@@ -147,6 +155,7 @@
require_once AMELIA_PATH . '/vendor/autoload.php';
+
/**
* @noinspection AutoloadingIssuesInspection
*
@@ -271,8 +280,8 @@
if (!is_admin()) {
add_filter('learn-press/frontend-default-scripts', array('AmeliaBookingPlugin', 'learnPressConflict'));
- add_shortcode('ameliabooking', array('AmeliaBookingInfrastructureWPShortcodeServiceBookingShortcodeService', 'shortcodeHandler'));
- add_shortcode('ameliacatalog', array('AmeliaBookingInfrastructureWPShortcodeServiceCatalogShortcodeService', 'shortcodeHandler'));
+ add_shortcode('ameliabooking', array('AmeliaBookingInfrastructureWPShortcodeServiceStepBookingShortcodeService', 'shortcodeHandler'));
+ add_shortcode('ameliacatalog', array('AmeliaBookingInfrastructureWPShortcodeServiceCatalogBookingShortcodeService', 'shortcodeHandler'));
add_shortcode('ameliaevents', array('AmeliaBookingInfrastructureWPShortcodeServiceEventsShortcodeService', 'shortcodeHandler'));
add_shortcode('ameliaeventslistbooking', array('AmeliaBookingInfrastructureWPShortcodeServiceEventsListBookingShortcodeService', 'shortcodeHandler'));
add_shortcode('ameliastepbooking', array('AmeliaBookingInfrastructureWPShortcodeServiceStepBookingShortcodeService', 'shortcodeHandler'));
@@ -283,9 +292,28 @@
ElementorBlock::get_instance();
}
- require_once AMELIA_PATH . '/extensions/divi_amelia/divi_amelia.php';
+ $theme = wp_get_theme();
+ if ($theme && strtolower($theme->get('Name')) === 'divi' || strtolower($theme->get_template()) === 'divi') {
+ $version = $theme->get('Version');
+ if (version_compare($version, '5.0', '<')) {
+ // Only enqueue jQuery early in Divi builder to avoid frontend conflicts
+ add_action('wp_head', function() {
+ if (function_exists('et_fb_is_enabled') && et_fb_is_enabled()) {
+ wp_enqueue_script('jquery');
+ wp_print_scripts('jquery');
+ }
+ }, 0);
+ require_once AMELIA_PATH . '/extensions/divi_amelia/divi_amelia.php';
+ } else {
+ require_once AMELIA_PATH . '/extensions/divi_5_amelia/divi-5-amelia.php';
+ }
+ }
+
+ // Load BuddyBoss integration only if feature is enabled
+ if ($settingsService->isFeatureEnabled('buddyboss')) {
+ }
}
/**
@@ -409,8 +437,8 @@
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50500) {
deactivate_plugins(AMELIA_PLUGIN_SLUG);
wp_die(
- BackendStrings::getCommonStrings()['php_version_message'],
- BackendStrings::getCommonStrings()['php_version_title'],
+ BackendStrings::get('php_version_message'),
+ BackendStrings::get('php_version_title'),
array('response' => 200, 'back_link' => TRUE)
);
}
@@ -493,7 +521,7 @@
$_REQUEST['tabs_group'] === 'popup'
) {
echo "<div class='notice notice-warning'>
- <p>" . esc_html__(BackendStrings::getCommonStrings()['elementor_popup_notice']) . "</p>
+ <p>" . esc_html__(BackendStrings::get('elementor_popup_notice')) . "</p>
</div>";
}
}
@@ -559,6 +587,26 @@
return $links;
}
+
+ public static function enqueueAngieMcpServer()
+ {
+ global $wp_version;
+ if (version_compare($wp_version, '6.5', '<')) {
+ return;
+ }
+
+ $mcpServerPath = AMELIA_PATH . '/redesign/dist/amelia-angie.js';
+ if (!file_exists($mcpServerPath)) {
+ return;
+ }
+
+ wp_enqueue_script_module(
+ 'amelia-angie-mcp',
+ AMELIA_URL . 'redesign/dist/amelia-angie.js',
+ array(),
+ AMELIA_VERSION
+ );
+ }
}
add_action('wp_ajax_amelia_remove_wpdt_promo_notice', array('AmeliaBookingPlugin', 'amelia_remove_wpdt_promo_notice'));
@@ -605,27 +653,13 @@
add_filter('script_loader_tag', array('AmeliaBookingInfrastructureWPShortcodeServiceEventsListBookingShortcodeService', 'prepareScripts') , 10, 3);
add_filter('style_loader_tag', array('AmeliaBookingInfrastructureWPShortcodeServiceEventsListBookingShortcodeService', 'prepareStyles') , 10, 3);
-add_filter('submenu_file', function($submenu_file) {
- global $submenu;
-
- if (!empty($submenu['amelia'])) {
- foreach ($submenu['amelia'] as $index => $item) {
- foreach ($item as $key => $value) {
- if ($value === 'wpamelia-customize-new') {
- unset($submenu['amelia'][$index]);
-
- break 2;
- }
- }
- }
- }
-
- return $submenu_file;
-});
-
add_filter('plugin_row_meta', array('AmeliaBookingPlugin', 'addPluginRowMeta'), 10, 4);
add_filter('plugin_action_links_' . AMELIA_PLUGIN_SLUG, array('AmeliaBookingPlugin', 'addPluginActionLinks'));
add_action( 'wp_logout', array('AmeliaBookingInfrastructureWPUserServiceUserService', 'logoutAmeliaUser'));
add_action( 'profile_update', array('AmeliaBookingInfrastructureWPUserServiceUserService', 'updateAmeliaUser'), 10, 3);
add_action( 'deleted_user', array('AmeliaBookingInfrastructureWPUserServiceUserService', 'removeWPUserConnection'), 10, 1);
+
+if (function_exists('is_plugin_active') && is_plugin_active('angie/angie.php')) {
+ add_action('admin_enqueue_scripts', array('AmeliaBookingPlugin', 'enqueueAngieMcpServer'));
+}
--- a/ameliabooking/extensions/divi_5_amelia/divi-5-amelia.php
+++ b/ameliabooking/extensions/divi_5_amelia/divi-5-amelia.php
@@ -0,0 +1,178 @@
+<?php
+
+/*
+Plugin Name: Divi 5 Amelia Booking
+Plugin URI: https://wpamelia.com
+Description: Divi 5 integration for Amelia Booking Plugin
+Version: 1.0.0
+Author: Melograno Ventures
+Author URI: https://wpamelia.com
+License: GPL2
+License URI: https://www.gnu.org/licenses/gpl-2.0.html
+phpcs:disable PSR1.Files.SideEffects
+*/
+
+use AmeliaBookingInfrastructureLicenceLicence;
+use AmeliaBookingInfrastructureWPGutenbergBlockGutenbergBlock;
+use AmeliaBookingInfrastructureWPTranslationsBackendStrings;
+
+if (!defined('ABSPATH')) {
+ die('Direct access forbidden.');
+}
+
+// Setup constants.
+define('DIVI5_AMELIA_PATH', plugin_dir_path(__FILE__));
+define('DIVI5_AMELIA_URL', plugin_dir_url(__FILE__));
+define('DIVI5_AMELIA_VERSION', '1.0.0');
+
+
+/**
+ * Load Divi 5 modules on init
+ * This ensures modules are registered for both Visual Builder and Frontend
+ */
+function divi5_amelia_load_modules()
+{
+ // Only load if Divi 5 is available
+ if (function_exists('et_builder_d5_enabled') && et_builder_d5_enabled()) {
+ // Load Divi 5 modules - this registers them for conversion and rendering
+ require_once DIVI5_AMELIA_PATH . 'server/index.php';
+ }
+}
+
+// Load modules early so they're available for conversion
+add_action('after_setup_theme', 'divi5_amelia_load_modules', 20);
+
+/**
+ * Enqueue Divi 5 Visual Builder Assets
+ */
+function divi5_amelia_enqueue_visual_builder_assets()
+{
+ if (et_core_is_fb_enabled() && function_exists('et_builder_d5_enabled') && et_builder_d5_enabled()) {
+ ETBuilderVisualBuilderAssetsPackageBuildManager::register_package_build(
+ [
+ 'name' => 'divi-5-amelia-visual-builder',
+ 'version' => DIVI5_AMELIA_VERSION,
+ 'script' => [
+ 'src' => DIVI5_AMELIA_URL . 'visual-builder/build/divi-5-amelia.js',
+ 'deps' => [
+ 'react',
+ 'jquery',
+ 'divi-module-library',
+ 'wp-hooks',
+ 'divi-rest',
+ ],
+ 'enqueue_top_window' => false,
+ 'enqueue_app_window' => true,
+ ],
+ ]
+ );
+ }
+}
+
+add_action('divi_visual_builder_assets_before_enqueue_scripts', 'divi5_amelia_enqueue_visual_builder_assets');
+
+/**
+ * Add Amelia data to Visual Builder window
+ */
+function divi5_amelia_add_inline_data()
+{
+ if (et_core_is_fb_enabled() && function_exists('et_builder_d5_enabled') && et_builder_d5_enabled()) {
+ // Get Amelia entities data
+ $ameliaData = GutenbergBlock::getEntitiesData();
+ $entitiesData = isset($ameliaData['data']) ? $ameliaData['data'] : [];
+
+ // Prepare options for the Visual Builder
+ $ameliaOptions = [
+ 'categories' => [['value' => '0', 'label' => 'Show All Categories']],
+ 'services' => [['value' => '0', 'label' => 'Show All Services']],
+ 'employees' => [['value' => '0', 'label' => 'Show All Employees']],
+ 'locations' => [['value' => '0', 'label' => 'Show All Locations']],
+ 'packages' => [['value' => '0', 'label' => 'Show All Packages']],
+ 'events' => [['value' => '0', 'label' => 'Show All Events']],
+ 'tags' => [['value' => '0', 'label' => 'Show All Tags']],
+ ];
+
+ // Add categories
+ if (!empty($entitiesData['categories'])) {
+ foreach ($entitiesData['categories'] as $category) {
+ $ameliaOptions['categories'][] = [
+ 'value' => (string)$category['id'],
+ 'label' => $category['name'] . ' (id: ' . $category['id'] . ')'
+ ];
+ }
+ }
+
+ // Add services
+ if (!empty($entitiesData['servicesList'])) {
+ foreach ($entitiesData['servicesList'] as $service) {
+ if ($service) {
+ $ameliaOptions['services'][] = [
+ 'value' => (string)$service['id'],
+ 'label' => $service['name'] . ' (id: ' . $service['id'] . ')'
+ ];
+ }
+ }
+ }
+
+ // Add employees
+ if (!empty($entitiesData['employees'])) {
+ foreach ($entitiesData['employees'] as $employee) {
+ $ameliaOptions['employees'][] = [
+ 'value' => (string)$employee['id'],
+ 'label' => $employee['firstName'] . ' ' . $employee['lastName'] . ' (id: ' . $employee['id'] . ')'
+ ];
+ }
+ }
+
+ // Add locations
+ if (!empty($entitiesData['locations'])) {
+ foreach ($entitiesData['locations'] as $location) {
+ $ameliaOptions['locations'][] = [
+ 'value' => (string)$location['id'],
+ 'label' => $location['name'] . ' (id: ' . $location['id'] . ')'
+ ];
+ }
+ }
+
+ // Add packages
+ if (!empty($entitiesData['packages'])) {
+ foreach ($entitiesData['packages'] as $package) {
+ $ameliaOptions['packages'][] = [
+ 'value' => (string)$package['id'],
+ 'label' => $package['name'] . ' (id: ' . $package['id'] . ')'
+ ];
+ }
+ }
+
+ // Add events
+ if (!empty($entitiesData['events'])) {
+ foreach ($entitiesData['events'] as $event) {
+ $ameliaOptions['events'][] = [
+ 'value' => (string)$event['id'],
+ 'label' => $event['name'] . ' (id: ' . $event['id'] . ') - ' . $event['formattedPeriodStart']
+ ];
+ }
+ }
+
+ // Add tags
+ if (!empty($entitiesData['tags'])) {
+ foreach ($entitiesData['tags'] as $tag) {
+ $ameliaOptions['tags'][] = [
+ 'value' => $tag['name'],
+ 'label' => $tag['name']
+ ];
+ }
+ }
+
+ // Output inline script that will run in the Visual Builder iframe
+ ?>
+ <script type="text/javascript">
+ window.ameliaDivi5Data = <?php echo wp_json_encode($ameliaOptions); ?>;
+ window.wpAmeliaLabels = <?php echo wp_json_encode(BackendStrings::getAllStrings()); ?>;
+ window.isAmeliaLite = <?php echo wp_json_encode(!Licence::$premium); ?>;
+ </script>
+ <?php
+ }
+}
+
+add_action('et_fb_framework_loaded', 'divi5_amelia_add_inline_data');
--- a/ameliabooking/extensions/divi_5_amelia/server/AmeliaBookingModule.php
+++ b/ameliabooking/extensions/divi_5_amelia/server/AmeliaBookingModule.php
@@ -0,0 +1,99 @@
+<?php
+
+namespace Divi5Amelia;
+
+use ETBuilderFrameworkDependencyManagementInterfacesDependencyInterface;
+use ETBuilderPackagesModuleLibraryModuleRegistration;
+
+/**
+ * Class that handle "Amelia Booking" module output in frontend.
+ */
+class AmeliaBookingModule implements DependencyInterface
+{
+ /**
+ * Register module.
+ * DependencyInterface interface ensures class method name `load()` is executed for initialization.
+ */
+ public function load()
+ {
+ // Register module.
+ add_action('init', [AmeliaBookingModule::class, 'registerModule']);
+ }
+
+ public static function registerModule()
+ {
+ // Path to module metadata that is shared between Frontend and Visual Builder.
+ $module_json_folder_path = dirname(__DIR__, 1) . '/visual-builder/src/modules/Booking';
+
+ ModuleRegistration::register_module(
+ $module_json_folder_path,
+ [
+ 'render_callback' => [AmeliaBookingModule::class, 'renderCallback'],
+ ]
+ );
+ }
+
+ /**
+ * Render module HTML output.
+ */
+ public static function renderCallback($attrs, $content, $block, $elements)
+ {
+ $shortcode = '[ameliastepbooking';
+
+ $show_all = $attrs['type']['innerContent']['desktop']['value'] ?? null;
+ if ($show_all !== null && $show_all !== '0') {
+ $shortcode .= ' show=' . $show_all;
+ }
+
+ $trigger = $attrs['trigger']['innerContent']['desktop']['value'] ?? null;
+ if ($trigger !== null && $trigger !== '') {
+ $shortcode .= ' trigger=' . esc_attr($trigger);
+ }
+
+ // Layout
+ $layout = $attrs['layout']['innerContent']['desktop']['value'] ?? null;
+ if ($layout !== null && $layout !== '') {
+ $shortcode .= ' layout=' . $layout;
+ }
+
+ // Trigger Type
+ $trigger_type = $attrs['trigger_type']['innerContent']['desktop']['value'] ?? null;
+ if ($trigger && $trigger_type !== null && $trigger_type !== '') {
+ $shortcode .= ' trigger_type=' . $trigger_type;
+ }
+
+ // In Dialog
+ $in_dialog = $attrs['in_dialog']['innerContent']['desktop']['value'] ?? false;
+ if ($in_dialog === 'on') {
+ $shortcode .= ' in_dialog=1';
+ }
+
+ $preselect = $attrs['parameters']['innerContent']['desktop']['value'] ?? false;
+ if ($preselect === 'on') {
+ $category = $attrs['categories']['innerContent']['desktop']['value'] ?? [];
+ $service = $attrs['services']['innerContent']['desktop']['value'] ?? [];
+ $employee = $attrs['employees']['innerContent']['desktop']['value'] ?? [];
+ $location = $attrs['locations']['innerContent']['desktop']['value'] ?? [];
+ $package = $attrs['packages']['innerContent']['desktop']['value'] ?? [];
+
+ if ($service && count($service) > 0) {
+ $shortcode .= ' service=' . implode(',', $service);
+ } elseif ($category && count($category) > 0) {
+ $shortcode .= ' category=' . implode(',', $category);
+ }
+ if ($employee && count($employee) > 0) {
+ $shortcode .= ' employee=' . implode(',', $employee);
+ }
+ if ($location && count($location) > 0) {
+ $shortcode .= ' location=' . implode(',', $location);
+ }
+ if ($package && count($package) > 0) {
+ $shortcode .= ' package=' . implode(',', $package);
+ }
+ }
+
+ $shortcode .= ']';
+
+ return do_shortcode($shortcode);
+ }
+}
--- a/ameliabooking/extensions/divi_5_amelia/server/AmeliaCatalogBookingModule.php
+++ b/ameliabooking/extensions/divi_5_amelia/server/AmeliaCatalogBookingModule.php
@@ -0,0 +1,101 @@
+<?php
+
+namespace Divi5Amelia;
+
+use ETBuilderFrameworkDependencyManagementInterfacesDependencyInterface;
+use ETBuilderPackagesModuleLibraryModuleRegistration;
+
+/**
+ * Class that handle "Amelia Catalog Booking" module output in frontend.
+ */
+class AmeliaCatalogBookingModule implements DependencyInterface
+{
+ /**
+ * Register module.
+ */
+ public function load()
+ {
+ add_action('init', [AmeliaCatalogBookingModule::class, 'registerModule']);
+ }
+
+ /**
+ * Register module.
+ */
+ public static function registerModule()
+ {
+ $module_json_folder_path = dirname(__DIR__, 1) . '/visual-builder/src/modules/CatalogBooking';
+
+ ModuleRegistration::register_module(
+ $module_json_folder_path,
+ [
+ 'render_callback' => [AmeliaCatalogBookingModule::class, 'renderCallback'],
+ ]
+ );
+ }
+
+ /**
+ * Render module HTML output.
+ */
+ public static function renderCallback($attrs, $content, $block, $elements)
+ {
+ $shortcode = '[ameliacatalogbooking';
+
+ $type_value = $attrs['type']['innerContent']['desktop']['value'] ?? '0';
+ if ($type_value !== null && $type_value !== '0') {
+ $shortcode .= ' show=' . $type_value;
+ }
+
+ $trigger = $attrs['trigger']['innerContent']['desktop']['value'] ?? null;
+ if ($trigger !== null && $trigger !== '') {
+ $shortcode .= ' trigger=' . esc_attr($trigger);
+ }
+
+ $trigger_type = $attrs['trigger_type']['innerContent']['desktop']['value'] ?? null;
+ if ($trigger !== null && $trigger !== '' && $trigger_type !== null) {
+ $shortcode .= ' trigger_type=' . $trigger_type;
+ }
+
+ $in_dialog = $attrs['in_dialog']['innerContent']['desktop']['value'] ?? false;
+ if ($in_dialog === 'on') {
+ $shortcode .= ' in_dialog=1';
+ }
+
+ $catalog_view = $attrs['catalog_view']['innerContent']['desktop']['value'] ?? '0';
+
+ if ($catalog_view !== '0') {
+ $category = $attrs['categories_catalog']['innerContent']['desktop']['value'] ?? [];
+ $service = $attrs['services_catalog']['innerContent']['desktop']['value'] ?? [];
+ $package = $attrs['packages_catalog']['innerContent']['desktop']['value'] ?? [];
+
+ if ($category && count($category) > 0 && $catalog_view === 'category') {
+ $shortcode .= ' category=' . implode(',', $category);
+ } elseif ($service && count($service) > 0 && $catalog_view === 'service') {
+ $shortcode .= ' service=' . implode(',', $service);
+ } elseif ($package && count($package) > 0 && $catalog_view === 'package') {
+ $shortcode .= ' package=' . implode(',', $package);
+ }
+ }
+
+ $filter_params = $attrs['filter_params']['innerContent']['desktop']['value'] ?? false;
+ if ($filter_params === 'on') {
+ $employee = $attrs['employees']['innerContent']['desktop']['value'] ?? [];
+ $location = $attrs['locations']['innerContent']['desktop']['value'] ?? [];
+
+ if ($employee && count($employee) > 0) {
+ $shortcode .= ' employee=' . implode(',', $employee);
+ }
+ if ($location && count($location) > 0) {
+ $shortcode .= ' location=' . implode(',', $location);
+ }
+
+ $skip_categories = $attrs['skip_categories']['innerContent']['desktop']['value'] ?? false;
+ if ($skip_categories === 'on') {
+ $shortcode .= ' categories_hidden=1';
+ }
+ }
+
+ $shortcode .= ']';
+
+ return do_shortcode($shortcode);
+ }
+}
--- a/ameliabooking/extensions/divi_5_amelia/server/AmeliaCatalogModule.php
+++ b/ameliabooking/extensions/divi_5_amelia/server/AmeliaCatalogModule.php
@@ -0,0 +1,83 @@
+<?php
+
+namespace Divi5Amelia;
+
+use ETBuilderFrameworkDependencyManagementInterfacesDependencyInterface;
+use ETBuilderPackagesModuleLibraryModuleRegistration;
+
+/**
+ * Class that handle "Amelia Catalog" (legacy) module output in frontend.
+ */
+class AmeliaCatalogModule implements DependencyInterface
+{
+ /**
+ * Register module.
+ * DependencyInterface interface ensures class method name `load()` is executed for initialization.
+ */
+ public function load()
+ {
+ // Register module.
+ add_action('init', [AmeliaCatalogModule::class, 'registerModule']);
+ }
+
+ public static function registerModule()
+ {
+ // Path to module metadata that is shared between Frontend and Visual Builder.
+ $module_json_folder_path = dirname(__DIR__, 1) . '/visual-builder/src/modules/Catalog';
+
+ ModuleRegistration::register_module(
+ $module_json_folder_path,
+ [
+ 'render_callback' => [AmeliaCatalogModule::class, 'renderCallback'],
+ ]
+ );
+ }
+
+ /**
+ * Render module HTML output.
+ * This converts old divi_catalog to ameliacatalogbooking shortcode.
+ */
+ public static function renderCallback($attrs, $content, $block, $elements)
+ {
+ $shortcode = '[ameliacatalogbooking';
+
+ $catalogView = $attrs['catalog_view']['innerContent']['desktop']['value'] ?? '0';
+
+ // Handle catalog view
+ if ($catalogView && $catalogView !== '0') {
+ // Map the categories/services/packages based on view
+ if ($catalogView === 'category') {
+ $categories = $attrs['categories_catalog']['innerContent']['desktop']['value'] ?? [];
+ if ($categories && count($categories) > 0) {
+ $shortcode .= ' category=' . implode(',', $categories);
+ }
+ } elseif ($catalogView === 'service') {
+ $services = $attrs['services_catalog']['innerContent']['desktop']['value'] ?? [];
+ if ($services && count($services) > 0) {
+ $shortcode .= ' service=' . implode(',', $services);
+ }
+ } elseif ($catalogView === 'package') {
+ $packages = $attrs['packages_catalog']['innerContent']['desktop']['value'] ?? [];
+ if ($packages && count($packages) > 0) {
+ $shortcode .= ' package=' . implode(',', $packages);
+ }
+ }
+ }
+
+ // Type
+ $type = $attrs['type']['innerContent']['desktop']['value'] ?? null;
+ if ($type !== null && $type !== '0') {
+ $shortcode .= ' show=' . $type;
+ }
+
+ // Trigger
+ $trigger = $attrs['trigger']['innerContent']['desktop']['value'] ?? null;
+ if ($trigger !== null && $trigger !== '') {
+ $shortcode .= ' trigger=' . esc_attr($trigger);
+ }
+
+ $shortcode .= ']';
+
+ return do_shortcode($shortcode);
+ }
+}
--- a/ameliabooking/extensions/divi_5_amelia/server/AmeliaCustomerPanelModule.php
+++ b/ameliabooking/extensions/divi_5_amelia/server/AmeliaCustomerPanelModule.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Divi5Amelia;
+
+use ETBuilderFrameworkDependencyManagementInterfacesDependencyInterface;
+use ETBuilderPackagesModuleLibraryModuleRegistration;
+
+/**
+ * Class that handle "Amelia Customer Panel" module output in frontend.
+ */
+class AmeliaCustomerPanelModule implements DependencyInterface
+{
+ /**
+ * Register module.
+ * DependencyInterface interface ensures class method name `load()` is executed for initialization.
+ */
+ public function load()
+ {
+ // Register module.
+ add_action('init', [AmeliaCustomerPanelModule::class, 'registerModule']);
+ }
+
+ /**
+ * Register module.
+ */
+ public static function registerModule()
+ {
+ // Path to module metadata that is shared between Frontend and Visual Builder.
+ $module_json_folder_path = dirname(__DIR__, 1) . '/visual-builder/src/modules/CustomerPanel';
+
+ ModuleRegistration::register_module(
+ $module_json_folder_path,
+ [
+ 'render_callback' => [AmeliaCustomerPanelModule::class, 'renderCallback'],
+ ]
+ );
+ }
+
+ /**
+ * Render callback for the module
+ *
+ * @param array $attrs Module attributes from Visual Builder
+ * @return string Rendered HTML output
+ */
+ public static function renderCallback(array $attrs): string
+ {
+ $shortcode = '[ameliacustomerpanel version=2';
+
+ $trigger = $attrs['trigger']['innerContent']['desktop']['value'] ?? '';
+ if ($trigger) {
+ $shortcode .= ' trigger=' . esc_attr($trigger);
+ }
+
+ $appointments = $attrs['appointments']['innerContent']['desktop']['value'] ?? true;
+ if ($appointments === true || $appointments === 'true' || $appointments === 'on' || $appointments === 1 || $appointments === '1') {
+ $shortcode .= ' appointments=1';
+ }
+
+ $events = $attrs['events']['innerContent']['desktop']['value'] ?? true;
+ if ($events === true || $events === 'true' || $events === 'on' || $events === 1 || $events === '1') {
+ $shortcode .= ' events=1';
+ }
+
+ $shortcode .= ']';
+
+ return do_shortcode($shortcode);
+ }
+}
--- a/ameliabooking/extensions/divi_5_amelia/server/AmeliaEmployeePanelModule.php
+++ b/ameliabooking/extensions/divi_5_amelia/server/AmeliaEmployeePanelModule.php
@@ -0,0 +1,82 @@
+<?php
+
+namespace Divi5Amelia;
+
+use ETBuilderFrameworkDependencyManagementInterfacesDependencyInterface;
+use ETBuilderPackagesModuleLibraryModuleRegistration;
+
+/**
+ * Class that handle "Amelia Employee Panel" module output in frontend.
+ */
+class AmeliaEmployeePanelModule implements DependencyInterface
+{
+ /**
+ * Register module.
+ * DependencyInterface interface ensures class method name `load()` is executed for initialization.
+ */
+ public function load()
+ {
+ // Register module.
+ add_action('init', [AmeliaEmployeePanelModule::class, 'registerModule']);
+ }
+
+ /**
+ * Register module.
+ */
+ public static function registerModule()
+ {
+ // Path to module metadata that is shared between Frontend and Visual Builder.
+ $module_json_folder_path = dirname(__DIR__, 1) . '/visual-builder/src/modules/EmployeePanel';
+
+ ModuleRegistration::register_module(
+ $module_json_folder_path,
+ [
+ 'render_callback' => [AmeliaEmployeePanelModule::class, 'renderCallback'],
+ ]
+ );
+ }
+
+ /**
+ * @param mixed $value
+ * @return bool
+ */
+ private static function checkValue($value): bool
+ {
+ return isset($value) && $value !== '';
+ }
+
+ /**
+ * Render callback for the module
+ *
+ * @param array $attrs Module attributes from Visual Builder
+ * @return string Rendered HTML output
+ */
+ public static function renderCallback(array $attrs): string
+ {
+ $shortcode = '[ameliaemployeepanel version=2';
+
+ $trigger = $attrs['trigger']['innerContent']['desktop']['value'] ?? '';
+ if (self::checkValue($trigger)) {
+ $shortcode .= ' trigger=' . esc_attr($trigger);
+ }
+
+ $appointments = $attrs['appointments']['innerContent']['desktop']['value'] ?? true;
+ if ($appointments === true || $appointments === 'true' || $appointments === 'on' || $appointments === 1 || $appointments === '1') {
+ $shortcode .= ' appointments=1';
+ }
+
+ $events = $attrs['events']['innerContent']['desktop']['value'] ?? true;
+ if ($events === true || $events === 'true' || $events === 'on' || $events === 1 || $events === '1') {
+ $shortcode .= ' events=1';
+ }
+
+ $profile = $attrs['profile']['innerContent']['desktop']['value'] ?? false;
+ if ($profile === true || $profile === 'true' || $profile === 'on' || $profile === 1 || $profile === '1') {
+ $shortcode .= ' profile-hidden=1';
+ }
+
+ $shortcode .= ']';
+
+ return do_shortcode($shortcode);
+ }
+}
--- a/ameliabooking/extensions/divi_5_amelia/server/AmeliaEventsCalendarModule.php
+++ b/ameliabooking/extensions/divi_5_amelia/server/AmeliaEventsCalendarModule.php
@@ -0,0 +1,87 @@
+<?php
+
+namespace Divi5Amelia;
+
+use ETBuilderFrameworkDependencyManagementInterfacesDependencyInterface;
+use ETBuilderPackagesModuleLibraryModuleRegistration;
+
+/**
+ * Class that handle "Amelia Events Calendar" module output in frontend.
+ */
+class AmeliaEventsCalendarModule implements DependencyInterface
+{
+ /**
+ * Register module.
+ * DependencyInterface interface ensures class method name `load()` is executed for initialization.
+ */
+ public function load()
+ {
+ // Register module.
+ add_action('init', [AmeliaEventsCalendarModule::class, 'registerModule']);
+ }
+
+ public static function registerModule()
+ {
+ // Path to module metadata that is shared between Frontend and Visual Builder.
+ $module_json_folder_path = dirname(__DIR__, 1) . '/visual-builder/src/modules/EventsCalendar';
+
+ ModuleRegistration::register_module(
+ $module_json_folder_path,
+ [
+ 'render_callback' => [AmeliaEventsCalendarModule::class, 'renderCallback'],
+ ]
+ );
+ }
+
+ /**
+ * Render module HTML output.
+ */
+ public static function renderCallback($attrs, $content, $block, $elements)
+ {
+ $shortcode = '[ameliaeventscalendarbooking';
+
+ $trigger = $attrs['trigger']['innerContent']['desktop']['value'] ?? null;
+ if ($trigger !== null && $trigger !== '') {
+ $shortcode .= ' trigger=' . esc_attr($trigger);
+ }
+
+ $trigger_type = $attrs['trigger_type']['innerContent']['desktop']['value'] ?? null;
+ if ($trigger && $trigger_type !== null && $trigger_type !== '') {
+ $shortcode .= ' trigger_type=' . $trigger_type;
+ }
+
+ $in_dialog = $attrs['in_dialog']['innerContent']['desktop']['value'] ?? false;
+ if ($trigger && $in_dialog === 'on') {
+ $shortcode .= ' in_dialog=1';
+ }
+
+ $booking_params = $attrs['booking_params']['innerContent']['desktop']['value'] ?? false;
+ if ($booking_params === 'on') {
+ $event = $attrs['events']['innerContent']['desktop']['value'] ?? [];
+ if ($event && count($event) > 0) {
+ $shortcode .= ' event=' . implode(',', $event);
+ }
+
+ $tag = $attrs['tags']['innerContent']['desktop']['value'] ?? [];
+ if ($tag && count($tag) > 0) {
+ $shortcode .= ' tag="' . implode(',', array_map(function ($t) {
+ return '{' . $t . '}';
+ }, $tag)) . '"';
+ }
+
+ $recurring = $attrs['recurring']['innerContent']['desktop']['value'] ?? false;
+ if ($recurring === 'on') {
+ $shortcode .= ' recurring=1';
+ }
+
+ $locations = $attrs['locations']['innerContent']['desktop']['value'] ?? [];
+ if ($locations && count($locations) > 0) {
+ $shortcode .= ' location=' . implode(',', $locations);
+ }
+ }
+
+ $shortcode .= ']';
+
+ return do_shortcode($shortcode);
+ }
+}
--- a/ameliabooking/extensions/divi_5_amelia/server/AmeliaEventsListModule.php
+++ b/ameliabooking/extensions/divi_5_amelia/server/AmeliaEventsListModule.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace Divi5Amelia;
+
+use ETBuilderFrameworkDependencyManagementInterfacesDependencyInterface;
+use ETBuilderPackagesModuleLibraryModuleRegistration;
+
+/**
+ * Class that handle "Amelia Events List" module output in frontend.
+ */
+class AmeliaEventsListModule implements DependencyInterface
+{
+ /**
+ * Register module.
+ * DependencyInterface interface ensures class method name `load()` is executed for initialization.
+ */
+ public function load()
+ {
+ // Register module.
+ add_action('init', [AmeliaEventsListModule::class, 'registerModule']);
+ }
+
+ public static function registerModule()
+ {
+ // Path to module metadata that is shared between Frontend and Visual Builder.
+ $module_json_folder_path = dirname(__DIR__, 1) . '/visual-builder/src/modules/EventsList';
+
+ ModuleRegistration::register_module(
+ $module_json_folder_path,
+ [
+ 'render_callback' => [AmeliaEventsListModule::class, 'renderCallback'],
+ ]
+ );
+ }
+
+ /**
+ * Render module HTML output.
+ */
+ public static function renderCallback($attrs, $content, $block, $elements)
+ {
+ $shortcode = '[ameliaeventslistbooking';
+
+ $trigger = $attrs['trigger']['innerContent']['desktop']['value'] ?? null;
+ if ($trigger !== null && $trigger !== '') {
+ $shortcode .= ' trigger=' . esc_attr($trigger);
+ }
+
+ $trigger_type = $attrs['trigger_type']['innerContent']['desktop']['value'] ?? null;
+ if ($trigger && $trigger_type !== null && $trigger_type !== '') {
+ $shortcode .= ' trigger_type=' . $trigger_type;
+ }
+
+ $in_dialog = $attrs['in_dialog']['innerContent']['desktop']['value'] ?? false;
+ if ($trigger && $in_dialog === 'on') {
+ $shortcode .= ' in_dialog=1';
+ }
+
+ // Preselect/filter parameters
+ $booking_params = $attrs['booking_params']['innerContent']['desktop']['value'] ?? false;
+ if ($booking_params === 'on') {
+ $event = $attrs['events']['innerContent']['desktop']['value'] ?? [];
+ if ($event && count($event) > 0) {
+ $shortcode .= ' event=' . implode(',', $event);
+ }
+
+ $tag = $attrs['tags']['innerContent']['desktop']['value'] ?? [];
+ if ($tag && count($tag) > 0) {
+ $shortcode .= ' tag="' . implode(',', array_map(function ($t) {
+ return '{' . $t . '}';
+ }, $tag)) . '"';
+ }
+
+ $recurring = $attrs['recurring']['innerContent']['desktop']['value'] ?? false;
+ if ($recurring === 'on') {
+ $shortcode .= ' recurring=1';
+ }
+
+ $locations = $attrs['locations']['innerContent']['desktop']['value'] ?? [];
+ if ($locations && count($locations) > 0) {
+ $shortcode .= ' location=' . implode(',', $locations);
+ }
+ }
+
+ $shortcode .= ']';
+
+ return do_shortcode($shortcode);
+ }
+}
--- a/ameliabooking/extensions/divi_5_amelia/server/AmeliaEventsModule.php
+++ b/ameliabooking/extensions/divi_5_amelia/server/AmeliaEventsModule.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace Divi5Amelia;
+
+use ETBuilderFrameworkDependencyManagementInterfacesDependencyInterface;
+use ETBuilderPackagesModuleLibraryModuleRegistration;
+
+/**
+ * Class that handle "Amelia Events" (legacy) module output in frontend.
+ */
+class AmeliaEventsModule implements DependencyInterface
+{
+ /**
+ * Register module.
+ * DependencyInterface interface ensures class method name `load()` is executed for initialization.
+ */
+ public function load()
+ {
+ // Register module.
+ add_action('init', [AmeliaEventsModule::class, 'registerModule']);
+ }
+
+ public static function registerModule()
+ {
+ // Path to module metadata that is shared between Frontend and Visual Builder.
+ $module_json_folder_path = dirname(__DIR__, 1) . '/visual-builder/src/modules/Events';
+
+ ModuleRegistration::register_module(
+ $module_json_folder_path,
+ [
+ 'render_callback' => [AmeliaEventsModule::class, 'renderCallback'],
+ ]
+ );
+ }
+
+ /**
+ * Render module HTML output.
+ */
+ public static function renderCallback($attrs, $content, $block, $elements)
+ {
+ $shortcode = '[ameliaevents';
+
+ $type = $attrs['type']['innerContent']['desktop']['value'] ?? null;
+ if ($type !== null && $type !== '') {
+ $shortcode .= ' type=' . $type;
+ } else {
+ $shortcode .= ' type=list';
+ }
+
+ $trigger = $attrs['trigger']['innerContent']['desktop']['value'] ?? null;
+ if ($trigger !== null && $trigger !== '') {
+ $shortcode .= ' trigger=' . esc_attr($trigger);
+ }
+
+ $bookingParams = $attrs['booking_params']['innerContent']['desktop']['value'] ?? 'off';
+ if ($bookingParams === 'on') {
+ $event = $attrs['events']['innerContent']['desktop']['value'] ?? '0';
+ if ($event !== '0') {
+ $shortcode .= ' event=' . $event;
+ }
+
+ $tag = $attrs['tags']['innerContent']['desktop']['value'] ?? '0';
+ if ($tag !== null && $tag !== '' && $tag !== '0') {
+ $shortcode .= ' tag="' . esc_attr($tag) . '"';
+ }
+
+ $recurring = $attrs['recurring']['innerContent']['desktop']['value'] ?? 'off';
+ if ($recurring === 'on') {
+ $shortcode .= ' recurring=1';
+ }
+ }
+
+ $shortcode .= ']';
+
+ return do_shortcode($shortcode);
+ }
+}
--- a/ameliabooking/extensions/divi_5_amelia/server/AmeliaSearchModule.php
+++ b/ameliabooking/extensions/divi_5_amelia/server/AmeliaSearchModule.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace Divi5Amelia;
+
+use ETBuilderFrameworkDependencyManagementInterfacesDependencyInterface;
+use ETBuilderPackagesModuleLibraryModuleRegistration;
+
+/**
+ * Class that handle "Amelia Search" module output in frontend.
+ */
+class AmeliaSearchModule implements DependencyInterface
+{
+ /**
+ * Register module.
+ * DependencyInterface interface ensures class method name `load()` is executed for initialization.
+ */
+ public function load()
+ {
+ // Register module.
+ add_action('init', [AmeliaSearchModule::class, 'registerModule']);
+ }
+
+ public static function registerModule()
+ {
+ // Path to module metadata that is shared between Frontend and Visual Builder.
+ $module_json_folder_path = dirname(__DIR__, 1) . '/visual-builder/src/modules/Search';
+
+ ModuleRegistration::register_module(
+ $module_json_folder_path,
+ [
+ 'render_callback' => [AmeliaSearchModule::class, 'renderCallback'],
+ ]
+ );
+ }
+
+ /**
+ * Render module HTML output.
+ */
+ public static function renderCallback($attrs, $content, $block, $elements)
+ {
+ $shortcode = '[ameliasearch';
+
+ $trigger = $attrs['trigger']['innerContent']['desktop']['value'] ?? null;
+ if ($trigger !== null && $trigger !== '') {
+ $shortcode .= ' trigger=' . esc_attr($trigger);
+ }
+
+ $bookingParams = $attrs['booking_params']['innerContent']['desktop']['value'] ?? 'off';
+ if ($bookingParams === 'on') {
+ $showAll = $attrs['type']['innerContent']['desktop']['value'] ?? '0';
+ if ($showAll !== null && $showAll !== '' && $showAll !== '0') {
+ $shortcode .= ' show=' . $showAll;
+ }
+ $shortcode .= ' today=1';
+ }
+
+ $shortcode .= ']';
+
+ return do_shortcode($shortcode);
+ }
+}
--- a/ameliabooking/extensions/divi_5_amelia/server/AmeliaStepBookingModule.php
+++ b/ameliabooking/extensions/divi_5_amelia/server/AmeliaStepBookingModule.php
@@ -0,0 +1,99 @@
+<?php
+
+namespace Divi5Amelia;
+
+use ETBuilderFrameworkDependencyManagementInterfacesDependencyInterface;
+use ETBuilderPackagesModuleLibraryModuleRegistration;
+
+/**
+ * Class that handle "Amelia Step Booking" module output in frontend.
+ */
+class AmeliaStepBookingModule implements DependencyInterface
+{
+ /**
+ * Register module.
+ * DependencyInterface interface ensures class method name `load()` is executed for initialization.
+ */
+ public function load()
+ {
+ // Register module.
+ add_action('init', [AmeliaStepBookingModule::class, 'registerModule']);
+ }
+
+ public static function registerModule()
+ {
+ // Path to module metadata that is shared between Frontend and Visual Builder.
+ $module_json_folder_path = dirname(__DIR__, 1) . '/visual-builder/src/modules/StepBooking';
+
+ ModuleRegistration::register_module(
+ $module_json_folder_path,
+ [
+ 'render_callback' => [AmeliaStepBookingModule::class, 'renderCallback'],
+ ]
+ );
+ }
+
+ /**
+ * Render module HTML output.
+ */
+ public static function renderCallback($attrs, $content, $block, $elements)
+ {
+ $shortcode = '[ameliastepbooking';
+
+ $show_all = $attrs['type']['innerContent']['desktop']['value'] ?? null;
+ if ($show_all !== null && $show_all !== '0') {
+ $shortcode .= ' show=' . $show_all;
+ }
+
+ $trigger = $attrs['trigger']['innerContent']['desktop']['value'] ?? null;
+ if ($trigger !== null && $trigger !== '') {
+ $shortcode .= ' trigger=' . esc_attr($trigger);
+ }
+
+ // Layout
+ $layout = $attrs['layout']['innerContent']['desktop']['value'] ?? null;
+ if ($layout !== null && $layout !== '') {
+ $shortcode .= ' layout=' . $layout;
+ }
+
+ // Trigger Type
+ $trigger_type = $attrs['trigger_type']['innerContent']['desktop']['value'] ?? null;
+ if ($trigger && $trigger_type !== null && $trigger_type !== '') {
+ $shortcode .= ' trigger_type=' . $trigger_type;
+ }
+
+ // In Dialog
+ $in_dialog = $attrs['in_dialog']['innerContent']['desktop']['value'] ?? false;
+ if ($in_dialog === 'on') {
+ $shortcode .= ' in_dialog=1';
+ }
+
+ $preselect = $attrs['parameters']['innerContent']['desktop']['value'] ?? false;
+ if ($preselect === 'on') {
+ $category = $attrs['categories']['innerContent']['desktop']['value'] ?? [];
+ $service = $attrs['services']['innerContent']['desktop']['value'] ?? [];
+ $employee = $attrs['employees']['innerContent']['desktop']['value'] ?? [];
+ $location = $attrs['locations']['innerContent']['desktop']['value'] ?? [];
+ $package = $attrs['packages']['innerContent']['desktop']['value'] ?? [];
+
+ if ($service && count($service) > 0) {
+ $shortcode .= ' service=' . implode(',', $service);
+ } elseif ($category && count($category) > 0) {
+ $shortcode .= ' category=' . implode(',', $category);
+ }
+ if ($employee && count($employee) > 0) {
+ $shortcode .= ' employee=' . implode(',', $employee);
+ }
+ if ($location && count($location) > 0) {
+ $shortcode .= ' location=' . implode(',', $location);
+ }
+ if ($package && count($package) > 0) {
+ $shortcode .= ' package=' . implode(',', $package);
+ }
+ }
+
+ $shortcode .= ']';
+
+ return do_shortcode($shortcode);
+ }
+}
--- a/ameliabooking/extensions/divi_5_amelia/server/index.php
+++ b/ameliabooking/extensions/divi_5_amelia/server/index.php
@@ -0,0 +1,212 @@
+<?php
+
+/**
+ * Divi 5 Amelia Modules Bootstrap
+ *
+ * This file loads and registers all Divi 5 Amelia modules.
+ * phpcs:disable PSR1.Files.SideEffects
+ */
+
+namespace Divi5Amelia;
+
+use AmeliaBookingInfrastructureLicenceLicence;
+
+if (!defined('ABSPATH')) {
+ die('Direct access forbidden.');
+}
+
+// Check if Divi 5 is active before loading modules
+function is_divi_5_active()
+{
+ $theme = wp_get_theme();
+ $is_divi_theme = 'Divi' === $theme->name || 'Divi' === $theme->parent_theme;
+
+ return $is_divi_theme;
+}
+
+/**
+ * Custom value expansion function for converting comma-separated strings to arrays
+ * Used during Divi 4 to Divi 5 conversion for multi-select fields
+ */
+function ameliaConvertParams($value, $context = [])
+{
+ if (is_string($value) && $value !== '') {
+ $items = array_map('trim', explode(',', $value));
+ return array_filter($items, function ($item) {
+ return $item !== '';
+ });
+ }
+
+ if (is_array($value)) {
+ return $value;
+ }
+
+ return [];
+}
+
+/**
+ * Convert Divi 4 yes_no_button values to Divi 5 toggle string values
+ * Keep as 'on'/'off' strings since that's what Divi Toggle component expects
+ */
+function ameliaConvertToggle($value, $context = [])
+{
+ // Handle empty/null/undefined - default to 'on' (Divi 4 defaults were 'on')
+ if ($value === null || $value === '') {
+ return 'on';
+ }
+
+ // Already correct string format
+ if ($value === 'on' || $value === '1' || $value === 1 || $value === true || $value === 'true') {
+ return 'on';
+ }
+
+ if ($value === 'off' || $value === '0' || $value === 0 || $value === false || $value === 'false') {
+ return 'off';
+ }
+
+ // Default to 'on' for Customer Panel (matches D4 behavior)
+ return 'on';
+}
+
+/**
+ * Convert catalog items (categories/services/packages) and automatically set catalog_view
+ *
+ * @param mixed $value The value to convert (comma-separated string or array)
+ * @param array $context Context information including field name and attributes
+ * @return array Converted array of items
+ */
+function ameliaConvertCatalogItems($value, $context = [])
+{
+ $result = ameliaConvertParams($value, $context);
+
+ // If items were selected, also update the catalog_view based on field name
+ if (!empty($result) && isset($context['attrs']) && isset($context['fieldName'])) {
+ // Determine catalog view type from field name
+ $catalogViewMap = [
+ 'categories' => 'category',
+ 'services' => 'service',
+ 'packages' => 'package',
+ ];
+
+ $fieldName = $context['fieldName'];
+ if (isset($catalogViewMap[$fieldName])) {
+ if (!isset($context['attrs']['catalog_view'])) {
+ $context['attrs']['catalog_view'] = [];
+ }
+ $context['attrs']['catalog_view']['innerContent'] = [
+ 'desktop' => ['value' => $catalogViewMap[$fieldName]]
+ ];
+ }
+ }
+
+ return $result;
+}
+
+/**
+ * Register custom value expansion functions for Divi conversion system
+ */
+add_filter('divi.moduleLibrary.conversion.valueExpansionFunctionMap', function ($functionMap) {
+ $functionMap['ameliaConvertParams'] = 'Divi5AmeliaameliaConvertParams';
+ $functionMap['ameliaConvertToggle'] = 'Divi5AmeliaameliaConvertToggle';
+ $functionMap['ameliaConvertCatalogItems'] = 'Divi5AmeliaameliaConvertCatalogItems';
+
+ return $functionMap;
+});
+
+if (is_divi_5_active()) {
+ // Load Divi dependency interface before loading modules
+ $divi_dependency_interface = get_template_directory() . '/includes/builder-5/server/Framework/DependencyManagement/Interfaces/DependencyInterface.php';
+
+ if (!file_exists($divi_dependency_interface)) {
+ return;
+ }
+
+ require_once $divi_dependency_interface;
+
+ require_once __DIR__ . '/AmeliaStepBookingModule.php';
+ require_once __DIR__ . '/AmeliaBookingModule.php';
+ require_once __DIR__ . '/AmeliaCatalogBookingModule.php';
+ require_once __DIR__ . '/AmeliaCatalogModule.php';
+ require_once __DIR__ . '/AmeliaEventsListModule.php';
+ require_once __DIR__ . '/AmeliaEventsModule.php';
+ require_once __DIR__ . '/AmeliaSearchModule.php';
+
+ if (Licence::$premium) {
+ require_once __DIR__ . '/AmeliaEventsCalendarModule.php';
+ require_once __DIR__ . '/AmeliaCustomerPanelModule.php';
+ require_once __DIR__ . '/AmeliaEmployeePanelModule.php';
+ }
+
+ add_action(
+ 'divi_module_library_modules_dependency_tree',
+ function ($dependency_tree) {
+ $dependency_tree->add_dependency(new AmeliaStepBookingModule());
+ }
+ );
+
+ add_action(
+ 'divi_module_library_modules_dependency_tree',
+ function ($dependency_tree) {
+ $dependency_tree->add_dependency(new AmeliaBookingModule());
+ }
+ );
+
+ add_action(
+ 'divi_module_library_modules_dependency_tree',
+ function ($dependency_tree) {
+ $dependency_tree->add_dependency(new AmeliaCatalogBookingModule());
+ }
+ );
+
+ add_action(
+ 'divi_module_library_modules_dependency_tree',
+ function ($dependency_tree) {
+ $dependency_tree->add_dependency(new AmeliaCatalogModule());
+ }
+ );
+
+ add_action(
+ 'divi_module_library_modules_dependency_tree',
+ function ($dependency_tree) {
+ $dependency_tree->add_dependency(new AmeliaEventsListModule());
+ }
+ );
+
+ add_action(
+ 'divi_module_library_modules_dependency_tree',
+ function ($dependency_tree) {
+ $dependency_tree->add_dependency(new AmeliaEventsModule());
+ }
+ );
+
+ add_action(
+ 'divi_module_library_modules_dependency_tree',
+ function ($dependency_tree) {
+ $dependency_tree->add_dependency(new AmeliaSearchModule());
+ }
+ );
+
+ // Register premium modules only if license is premium
+ if (Licence::$premium) {
+ add_action(
+ 'divi_module_library_modules_dependency_tree',
+ function ($dependency_tree) {
+ $dependency_tree->add_dependency(new AmeliaEventsCalendarModule());
+ }
+ );
+
+ add_action(
+ 'divi_module_library_modules_dependency_tree',
+ function ($dependency_tree) {
+ $dependency_tree->add_dependency(new AmeliaCustomerPanelModule());
+ }
+ );
+
+ add_action(
+ 'divi_module_library_modules_dependency_tree',
+ function ($dependency_tree) {
+ $dependency_tree->add_dependency(new AmeliaEmployeePanelModule());
+ }
+ );
+ }
+}
--- a/ameliabooking/extensions/divi_amelia/includes/loader.php
+++ b/ameliabooking/extensions/divi_amelia/includes/loader.php
@@ -6,9 +6,19 @@
$module_files = glob(__DIR__ . '/modules/*/*.php');
-// Load custom Divi Builder modules
+$hidden_modules = ['Search', 'Events', 'Booking', 'Catalog'];
+
+// Check if we're in Divi builder context (admin or visual builder)
+$is_builder = is_admin()
+ || isset($_GET['et_fb'])
+ || (function_exists('et_core_is_fb_enabled') && et_core_is_fb_enabled());
+
foreach ((array) $module_files as $module_file) {
- if ($module_file && preg_match("//modules/b([^/]+)/\1.php$/", $module_file)) {
+ if ($module_file && preg_match("//modules/b([^/]+)/\1.php$/", $module_file, $matches)) {
+ // Skip hidden modules in builder, but load them on frontend for existing pages
+ if (in_array($matches[1], $hidden_modules) && $is_builder) {
+ continue;
+ }
require_once $module_file;
}
}
--- a/ameliabooking/extensions/divi_amelia/includes/modules/Booking/Booking.php
+++ b/ameliabooking/extensions/divi_amelia/includes/modules/Booking/Booking.php
@@ -26,11 +26,11 @@
public function init()
{
- $this->name = esc_html__(BackendStrings::getWordPressStrings()['booking_divi'], 'divi-divi_amelia');
+ $this->name = esc_html__(BackendStrings::get('booking_divi'), 'divi-divi_amelia');
- $this->type['0'] = BackendStrings::getWordPressStrings()['show_all'];
- $this->type['services'] = BackendStrings::getCommonStrings()['services'];
- $this->type['packages'] = BackendStrings::getCommonStrings()['packages'];
+ $this->type['0'] = BackendStrings::get('show_all');
+ $this->type['services'] = BackendStrings::get('services');
+ $this->type['packages'] = BackendStrings::get('packages');
if (!is_admin()) {
return;
@@ -39,21 +39,21 @@
$data = GutenbergBlock::getEntitiesData()['data'];
$this->showPackages = !empty($data['packages']);
- $this->categories['0'] = BackendStrings::getWordPressStrings()['show_all_categories'];
+ $this->categories['0'] = BackendStrings::get('show_all_categories');
foreach ($data['categories'] as $category) {
$this->categories[$category['id']] = $category['name']. ' (id: ' . $category['id'] . ')';
}
- $this->services['0'] = BackendStrings::getWordPressStrings()['show_all_services'];
+ $this->services['0'] = BackendStrings::get('show_all_services');
foreach ($data['servicesList'] as $service) {
if ($service) {
$this->services[$service['id']] = $service['name']. ' (id: ' . $service['id'] . ')';
}
}
- $this->employees['0'] = BackendStrings::getWordPressStrings()['show_all_employees'];
+ $this->employees['0'] = BackendStrings::get('show_all_employees');
foreach ($data['employees'] as $employee) {
$this->employees[$employee['id']] = $employee['firstName'] . ' ' . $employee['lastName'] . ' (id: ' . $employee['id'] . ')';
}
- $this->locations['0'] = BackendStrings::getWordPressStrings()['show_all_locations'];
+ $this->locations['0'] = BackendStrings::get('show_all_locations');
foreach ($data['locations'] as $location) {
$this->locations[$location['id']] = $location['name']. ' (id: ' . $location['id'] . ')';
}
@@ -76,17 +76,17 @@
{
$array = array(
'booking_params' => array(
- 'label' => esc_html__(BackendStrings::getWordPressStrings()['filter'], 'divi-divi_amelia'),
+ 'label' => esc_html__(BackendStrings::get('filter'), 'divi-divi_amelia'),
'type' => 'yes_no_button',
'options' => array(
- 'on' => esc_html__(BackendStrings::getCommonStrings()['yes'], 'divi-divi_amelia'),
- 'off' => esc_html__(BackendStrings::getCommonStrings()['no'], 'divi-divi_amelia'),
+ 'on' => esc_html__(BackendStrings::get('yes'), 'divi-divi_amelia'),
+ 'off' => esc_html__(BackendStrings::get('no'), 'divi-divi_amelia'),
),
'toggle_slug' => 'main_content',
'option_category' => 'basic_option',
),
'categories' => array(
- 'label' => esc_html__(BackendStrings::getWordPressStrings()['select_category'], 'divi-divi_amelia'),
+ 'label' => esc_html__(BackendStrings::get('select_category'), 'divi-divi_amelia'),
'type' => 'select',
'options' => $this->categories,
'toggle_slug' => 'main_content',
@@ -96,7 +96,7 @@
),
),
'services' => array(
- 'label' => esc_html__(BackendStrings::getWordPressStrings()['select_service'], 'divi-divi_amelia'),
+ 'label' => esc_html__(BackendStrings::get('select_service'), 'divi-divi_amelia'),
'type' => 'select',
'toggle_slug' => 'main_content',
'options' => $this->services,
@@ -106,7 +106,7 @@
),
),
'employees' => array(
- 'label' => esc_html__(BackendStrings::getWordPressStrings()['select_employee'], 'divi-divi_amelia'),
+ 'label' => esc_html__(BackendStrings::get('select_employee'), 'divi-divi_amelia'),
'type' => 'select',
'options' => $this->employees,
'toggle_slug' => 'main_content',
@@ -116,7 +116,7 @@
),
),
'locations' => array(
- 'label' => esc_html__(BackendStrings::getWordPressStrings()['select_location'], 'divi-divi_amelia'),
+ 'label' => esc_html__(BackendStrings::get('select_location'), 'divi-divi_amelia'),
'type' => 'select',
'options' => $this->locations,
'toggle_slug' => 'main_content',
@@ -129,7 +129,7 @@
if ($this->showPackages) {
$array['type'] = array(
- 'label' => esc_html__(BackendStrings::getWordPressStrings()['show_all'], 'divi-divi_amelia'),
+ 'label' => esc_html__(BackendStrings::get('show_all'), 'divi-divi_amelia'),
'type' => 'select',
'options' => $this->type,
'toggle_slug' => 'main_content',
@@ -140,11 +140,11 @@
}
$array['trigger'] = array(
- 'label' => esc_html__(BackendStrings::getWordPressStrings()['manually_loading'], 'divi-divi_amelia'),
+ 'label' => esc_html__(BackendStr