Published : August 7, 2026

CVE-2026-13344: Essential Addons for Elementor – Popular Elementor Templates & Widgets < 6.6.10 Authenticated (Contributor+) Stored Cross-Site Scripting PoC, Patch Analysis & Rule

Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 6.6.10
Patched Version 6.6.10
Disclosed July 29, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-13344:

This vulnerability allows authenticated users with contributor-level access or higher to execute arbitrary JavaScript in the browser of any user who views an affected page. The flaw is a Stored Cross-Site Scripting (XSS) issue in the Essential Addons for Elementor plugin for WordPress. It carries a CVSS score of 6.4 (Medium) and is classified under CWE-79. The issue was present in plugin versions up to and including 6.6.9, and was addressed in version 6.6.10.

Root Cause: The root cause is insufficient input sanitization and output escaping within widget settings, specifically concerning HTML tag selection. The vulnerable code path is in the `Pricing_Table.php` file within the `render()` method. In the vulnerable version, the code directly echoed the `eael_pricing_table_title_tag` setting into the HTML output without sanitization or validation. Specifically, the line `< class=”title”>` allowed a user to supply an arbitrary HTML tag name. This value is set through Elementor’s widget settings interface, which a contributor can manipulate. The patch replaces this direct output with `HelperClass::eael_validate_html_tag( $settings[‘eael_pricing_table_title_tag’] )`, introducing a validation step that restricts the tag to an allowlist.

Exploitation: An attacker with contributor-level access can exploit this by creating or editing a page, adding the Pricing Table widget, and navigating to its style settings. The ‘eael_pricing_table_title_tag’ setting, which dictates the HTML tag for the pricing plan title, is the attack vector. By injecting a malicious event handler, such as `img src=x onerror=alert(1)`, into this field, the environment allows the XSS payload to be stored. The attacker would then save the page and cause it to be viewed by an administrator or other user. When the page loads, the script payload executes in the context of the victim’s session, allowing the attacker to perform actions like creating a new admin account or exfiltrating sensitive data.

Patch Analysis: The patch in version 6.6.10 introduces a call to `HelperClass::eael_validate_html_tag()` on the `eael_pricing_table_title_tag` setting. This new method validates the user-provided tag against an allowlist of safe HTML tags. If the provided value is not on the allowlist, the function likely returns a default safe value, such as ‘h3’. This prevents the injection of arbitrary tag names or event handler attributes. The before/after behavior is clear: the vulnerable version trusted the input entirely, while the patched version enforces a strict allowlist, neutralizing the XSS vector.

Impact: Successful exploitation of this vulnerability gives an attacker with contributor-level access the ability to execute arbitrary JavaScript in the context of any user who loads the compromised page. If a site administrator views the page, the attacker can potentially take over their account, leading to full admin-level access. The impact is complete technical impact, including the potential for a full site compromise, depending on the actions performed by the injected script.

Differential between vulnerable and patched code

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

Code Diff
--- a/essential-addons-for-elementor-lite/essential_adons_elementor.php
+++ b/essential-addons-for-elementor-lite/essential_adons_elementor.php
@@ -4,7 +4,7 @@
  * Description: The Essential plugin you install after Elementor! Packed with 100+ stunning elements like Data Table, Event Calendar, Filterable Gallery, WooCommerce.
  * Plugin URI: https://essential-addons.com/
  * Author: WPDeveloper
- * Version: 6.6.9
+ * Version: 6.6.10
  * Author URI: https://wpdeveloper.com/
  * Text Domain: essential-addons-for-elementor-lite
  * Domain Path: /languages
@@ -27,7 +27,7 @@
 define( 'EAEL_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
 define( 'EAEL_PLUGIN_PATH', trailingslashit( plugin_dir_path( __FILE__ ) ) );
 define( 'EAEL_PLUGIN_URL', trailingslashit( plugins_url( '/', __FILE__ ) ) );
-define( 'EAEL_PLUGIN_VERSION', '6.6.9' );
+define( 'EAEL_PLUGIN_VERSION', '6.6.10' );
 define( 'EAEL_ASSET_PATH', wp_upload_dir()['basedir'] . '/essential-addons-elementor' );
 define( 'EAEL_ASSET_URL', wp_upload_dir()['baseurl'] . '/essential-addons-elementor' );
 /**
--- a/essential-addons-for-elementor-lite/includes/Classes/Bootstrap.php
+++ b/essential-addons-for-elementor-lite/includes/Classes/Bootstrap.php
@@ -219,9 +219,21 @@
         //rank math support
         add_filter('rank_math/researches/toc_plugins', [$this, 'toc_rank_math_support']);

-//        if(defined('WPML_TM_VERSION')){
-//	        add_filter( 'elementor/documents/get/post_id',[$this, 'eael_wpml_template_translation']);
-//        }
+        // Translate embedded Elementor templates/documents (saved templates used by
+        // Advanced Tabs, Advanced Accordion, Info Box, etc.) to the current language.
+        // eael_wpml_template_translation() handles both WPML and Polylang. Previously
+        // this was disabled and gated to WPML only, so Polylang sites always rendered
+        // the source-language template.
+        if ( defined( 'WPML_TM_VERSION' ) || defined( 'POLYLANG_VERSION' ) || function_exists( 'pll_get_post_language' ) ) {
+            add_filter( 'elementor/documents/get/post_id', [ $this, 'eael_wpml_template_translation' ] );
+        }
+
+        // Polylang has no Elementor integration, so the template library is not
+        // translatable by default. Opt it in so saved templates can be mapped to the
+        // current language (and managed from Polylang's UI).
+        if ( defined( 'POLYLANG_VERSION' ) || function_exists( 'pll_get_post_language' ) ) {
+            add_filter( 'pll_get_post_types', [ $this, 'eael_pll_translate_elementor_library' ], 10, 2 );
+        }

         //templately plugin support
         if( !class_exists('TemplatelyPlugin') && !get_option('eael_templately_promo_hide') ) {
--- a/essential-addons-for-elementor-lite/includes/Classes/Helper.php
+++ b/essential-addons-for-elementor-lite/includes/Classes/Helper.php
@@ -266,9 +266,89 @@
             $args['meta_query'] = array_filter( apply_filters( 'woocommerce_product_query_meta_query', $args['meta_query'], new WC_Query() ) );
         }

+	    // Polylang: pin the query to the language of the page/document the widget is
+	    // on, instead of the ambient (cookie / last-page-load) current language. In
+	    // the editor the ambient language flips on every page load, which made the
+	    // Post Grid show the wrong language's posts. Skip manual ("by_id") selections
+	    // and post types Polylang isn't translating.
+	    if ( function_exists( 'pll_get_post_language' ) && 'by_id' !== $settings['post_type'] ) {
+		    $eael_is_translated = ! function_exists( 'pll_is_translated_post_type' );
+		    if ( ! $eael_is_translated ) {
+			    foreach ( (array) $args['post_type'] as $eael_pt ) {
+				    if ( 'any' !== $eael_pt && pll_is_translated_post_type( $eael_pt ) ) {
+					    $eael_is_translated = true;
+					    break;
+				    }
+			    }
+		    }
+
+		    if ( $eael_is_translated ) {
+			    $eael_lang = self::eael_get_current_language();
+			    // Allow integrators to override the pinned language.
+			    $eael_lang = apply_filters( 'eael/post_grid/query_lang', $eael_lang, $settings, $args );
+			    if ( ! empty( $eael_lang ) ) {
+				    $args['lang'] = $eael_lang;
+			    }
+		    }
+	    }
+
         return $args;
     }

+	/**
+	 * Resolve the Polylang language slug a widget's query/content should be pinned
+	 * to.
+	 *
+	 * The Elementor editor (and admin-ajax) "current language" is ambient global
+	 * state driven by the pll_language cookie, which flips on every page load. That
+	 * made the Post Grid and template widgets follow the last-loaded language rather
+	 * than the language of the page the widget actually lives on. We instead derive
+	 * the language from the current document/page id so it is deterministic.
+	 *
+	 * @param int $post_id Optional page/post id to read the language from.
+	 *
+	 * @return string Language slug, or '' when Polylang is inactive/undeterminable.
+	 */
+	public static function eael_get_current_language( $post_id = 0 ) {
+		if ( ! function_exists( 'pll_get_post_language' ) ) {
+			return '';
+		}
+
+		if ( ! $post_id && class_exists( 'ElementorPlugin' ) ) {
+			$document = ElementorPlugin::$instance->documents->get_current();
+			if ( $document ) {
+				$post_id = $document->get_main_id();
+			}
+		}
+
+		if ( ! $post_id ) {
+			$post_id = get_the_ID();
+		}
+
+		$lang = $post_id ? pll_get_post_language( $post_id ) : '';
+
+		if ( ! $lang && function_exists( 'pll_current_language' ) ) {
+			$lang = pll_current_language();
+		}
+
+		return $lang ? $lang : '';
+	}
+
+	/**
+	 * Build a language-specific cache-key suffix so translated pages that share a
+	 * widget id (e.g. created via Polylang "copy content") don't collide in the
+	 * Post Grid transients.
+	 *
+	 * @param int $post_id Optional page/post id to read the language from.
+	 *
+	 * @return string e.g. "_lang_es", or '' when no language is resolved.
+	 */
+	public static function eael_lang_suffix( $post_id = 0 ) {
+		$lang = self::eael_get_current_language( $post_id );
+
+		return $lang ? '_lang_' . sanitize_key( $lang ) : '';
+	}
+
     /**
      * Go Premium
      *
@@ -2085,4 +2165,32 @@

 		return get_post_status( $template_id ) === 'publish' && get_post_type( $template_id ) === 'elementor_library';
 	}
+
+	/**
+	 * eael_wpml_translate_media
+	 *
+	 * Resolve an Elementor MEDIA control value (image/video) to its
+	 * WPML-translated attachment so the correct media is shown per language.
+	 * Safe to call when WPML / WPML Media Translation is inactive — the
+	 * `wpml_object_id` filter simply returns the original id unchanged.
+	 *
+	 * @param array $media Elementor MEDIA control value (expects 'id' and 'url').
+	 *
+	 * @return array The media array with translated 'id' and 'url' when available.
+	 */
+	public static function eael_wpml_translate_media( $media ) {
+		if ( ! is_array( $media ) || empty( $media['id'] ) ) {
+			return $media;
+		}
+
+		// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
+		$translated_id = apply_filters( 'wpml_object_id', $media['id'], 'attachment', true );
+
+		if ( $translated_id && (int) $translated_id !== (int) $media['id'] ) {
+			$media['id']  = $translated_id;
+			$media['url'] = wp_get_attachment_url( $translated_id );
+		}
+
+		return $media;
+	}
 }
--- a/essential-addons-for-elementor-lite/includes/Elements/Adv_Accordion.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Adv_Accordion.php
@@ -1830,7 +1830,7 @@
 					if ( ! empty( $tab['eael_primary_templates'] ) && Helper::is_elementor_publish_template( $tab['eael_primary_templates'] ) ) {
 						// WPML Compatibility
 						if ( ! is_array( $tab['eael_primary_templates'] ) ) {
-							$tab['eael_primary_templates'] = apply_filters( 'wpml_object_id', $tab['eael_primary_templates'], 'wp_template', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
+							$tab['eael_primary_templates'] = apply_filters( 'wpml_object_id', $tab['eael_primary_templates'], 'elementor_library', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
 						}

 						Helper::eael_onpage_edit_template_markup( get_the_ID(), $tab['eael_primary_templates'] );
--- a/essential-addons-for-elementor-lite/includes/Elements/Adv_Tabs.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Adv_Tabs.php
@@ -1387,7 +1387,8 @@
                                     } else {
                                         echo '<i class="' . esc_attr( $tab['eael_adv_tabs_tab_title_icon'] ) . '"></i>';
                                     } ?>
-                                <?php elseif ($tab['eael_adv_tabs_icon_type'] === 'image') : ?>
+                                <?php elseif ($tab['eael_adv_tabs_icon_type'] === 'image') :
+                                    $tab['eael_adv_tabs_tab_title_image'] = Helper::eael_wpml_translate_media( $tab['eael_adv_tabs_tab_title_image'] ); // WPML Media Translation compatibility ?>
                                     <img src="<?php echo esc_url( $tab['eael_adv_tabs_tab_title_image']['url'] ); ?>" alt="<?php echo esc_attr(get_post_meta($tab['eael_adv_tabs_tab_title_image']['id'], '_wp_attachment_image_alt', true)); ?>">
                                 <?php endif; ?>
                             <?php endif; ?>
@@ -1478,7 +1479,7 @@

 							        // WPML Compatibility
 							        if ( ! is_array( $tab['eael_primary_templates'] ) ) {
-								        $tab['eael_primary_templates'] = apply_filters( 'wpml_object_id', $tab['eael_primary_templates'], 'wp_template', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
+								        $tab['eael_primary_templates'] = apply_filters( 'wpml_object_id', $tab['eael_primary_templates'], 'elementor_library', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
 							        }

 							        Helper::eael_onpage_edit_template_markup( $page_id, $tab['eael_primary_templates'] );
--- a/essential-addons-for-elementor-lite/includes/Elements/Countdown.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Countdown.php
@@ -1343,7 +1343,7 @@
                     if ( ! empty( $settings['countdown_expiry_templates'] ) && Helper::is_elementor_publish_template( $settings['countdown_expiry_templates'] ) ) {
                         // WPML Compatibility
                         if ( ! is_array( $settings['countdown_expiry_templates'] ) ) {
-                            $settings['countdown_expiry_templates'] = apply_filters( 'wpml_object_id', $settings['countdown_expiry_templates'], 'wp_template', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
+                            $settings['countdown_expiry_templates'] = apply_filters( 'wpml_object_id', $settings['countdown_expiry_templates'], 'elementor_library', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
                         }

 	                    Helper::eael_onpage_edit_template_markup( get_the_ID(), $settings['countdown_expiry_templates'] );
@@ -1363,7 +1363,7 @@
                             if ( ! empty( $settings['countdown_expiry_templates'] ) && Helper::is_elementor_publish_template( $settings['countdown_expiry_templates'] ) ) {
                                 // WPML Compatibility
                                 if ( ! is_array( $settings['countdown_expiry_templates'] ) ) {
-                                    $settings['countdown_expiry_templates'] = apply_filters( 'wpml_object_id', $settings['countdown_expiry_templates'], 'wp_template', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
+                                    $settings['countdown_expiry_templates'] = apply_filters( 'wpml_object_id', $settings['countdown_expiry_templates'], 'elementor_library', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
                                 }

 	                            Helper::eael_onpage_edit_template_markup( get_the_ID(), $settings['countdown_expiry_templates'] );
--- a/essential-addons-for-elementor-lite/includes/Elements/Cta_Box.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Cta_Box.php
@@ -2134,7 +2134,7 @@
 		        $eael_template_id = $settings['eael_primary_templates'];
 		        // WPML Compatibility
 		        if ( ! is_array( $eael_template_id ) ) {
-			        $eael_template_id = apply_filters( 'wpml_object_id', $eael_template_id, 'wp_template', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
+			        $eael_template_id = apply_filters( 'wpml_object_id', $eael_template_id, 'elementor_library', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
 		        }

 		        if ( Plugin::$instance->editor->is_edit_mode() ) {
--- a/essential-addons-for-elementor-lite/includes/Elements/Data_Table.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Data_Table.php
@@ -1416,6 +1416,7 @@
 			            	<?php endif; ?>
 							<?php
 								if( $header_title['eael_data_table_header_col_icon_enabled'] == 'true' && $header_title['eael_data_table_header_icon_type'] == 'image' ) :
+									$header_title['eael_data_table_header_col_img'] = Helper::eael_wpml_translate_media( $header_title['eael_data_table_header_col_img'] ); // WPML Media Translation compatibility
 									$this->add_render_attribute('data_table_th_img'.$i, [
 										'src'	=> esc_url( $header_title['eael_data_table_header_col_img']['url'] ),
 										'class'	=> 'eael-data-table-th-img',
@@ -1473,7 +1474,7 @@
 													if ( Helper::is_elementor_publish_template( $table_td[ $j ]['template'] ) ) {
 														// WPML Compatibility
 														if ( ! is_array( $table_td[ $j ]['template'] ) ) {
-															$table_td[ $j ]['template'] = apply_filters( 'wpml_object_id', $table_td[ $j ]['template'], 'wp_template', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
+															$table_td[ $j ]['template'] = apply_filters( 'wpml_object_id', $table_td[ $j ]['template'], 'elementor_library', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
 														}

 														Helper::eael_onpage_edit_template_markup( get_the_ID(), $table_td[ $j ]['template'] );
--- a/essential-addons-for-elementor-lite/includes/Elements/Feature_List.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Feature_List.php
@@ -1065,6 +1065,7 @@


             if ( $item['eael_feature_list_icon_type'] == 'image' ) {
+            $item['eael_feature_list_img'] = Helper::eael_wpml_translate_media( $item['eael_feature_list_img'] ); // WPML Media Translation compatibility
             $this->add_render_attribute( 'feature_list_image' . $index, [
                 'src'   => esc_url( $item['eael_feature_list_img']['url'] ),
                 'class' => 'eael-feature-list-img',
--- a/essential-addons-for-elementor-lite/includes/Elements/Filterable_Gallery.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Filterable_Gallery.php
@@ -3769,6 +3769,7 @@
         $video_gallery_yt_privacy = ! empty( $settings['video_gallery_yt_privacy'] ) && 'yes' === $settings['video_gallery_yt_privacy'] ? 1 : 0;

         foreach ($gallery_items as $gallery) {
+            $gallery['eael_fg_gallery_img'] = Helper::eael_wpml_translate_media( $gallery['eael_fg_gallery_img'] ); // WPML Media Translation compatibility
             $gallery_store[$counter]['title']        = Helper::eael_wp_kses($gallery['eael_fg_gallery_item_name']);
             $gallery_store[$counter]['content']      = $this->parse_text_editor( wp_kses( $gallery['eael_fg_gallery_item_content'], Helper::eael_allowed_tags() ) );
             $gallery_store[$counter]['id']           = $gallery['_id'];
--- a/essential-addons-for-elementor-lite/includes/Elements/Flip_Box.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Flip_Box.php
@@ -2730,7 +2730,7 @@
 	                    if ( ! empty( $settings['eael_flipbox_front_templates'] ) && Helper::is_elementor_publish_template( $settings['eael_flipbox_front_templates'] ) ) {
 		                    // WPML Compatibility
 		                    if ( ! is_array( $settings['eael_flipbox_front_templates'] ) ) {
-			                    $settings['eael_flipbox_front_templates'] = apply_filters( 'wpml_object_id', $settings['eael_flipbox_front_templates'], 'wp_template', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
+			                    $settings['eael_flipbox_front_templates'] = apply_filters( 'wpml_object_id', $settings['eael_flipbox_front_templates'], 'elementor_library', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
 		                    }
                             // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
 		                    echo Plugin::$instance->frontend->get_builder_content( $settings['eael_flipbox_front_templates'], true );
@@ -2777,7 +2777,7 @@
 	                    if ( ! empty( $settings['eael_flipbox_back_templates'] ) && Helper::is_elementor_publish_template( $settings['eael_flipbox_back_templates'] ) ) {
 		                    // WPML Compatibility
 		                    if ( ! is_array( $settings['eael_flipbox_back_templates'] ) ) {
-			                    $settings['eael_flipbox_back_templates'] = apply_filters( 'wpml_object_id', $settings['eael_flipbox_back_templates'], 'wp_template', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
+			                    $settings['eael_flipbox_back_templates'] = apply_filters( 'wpml_object_id', $settings['eael_flipbox_back_templates'], 'elementor_library', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
 		                    }
                             // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
 		                    echo Plugin::$instance->frontend->get_builder_content( $settings['eael_flipbox_back_templates'], true );
--- a/essential-addons-for-elementor-lite/includes/Elements/Image_Accordion.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Image_Accordion.php
@@ -1059,6 +1059,7 @@
             <?php
 	        $active    = $img_accordion['eael_accordion_is_active'];
 	        $activeCSS = ( $active === 'yes' ? ' flex: 3 1 0%;' : '' );
+	        $img_accordion['eael_accordion_bg'] = Helper::eael_wpml_translate_media( $img_accordion['eael_accordion_bg'] ); // WPML Media Translation compatibility
 	        $this->add_render_attribute(
 		        'eael-image-accordion-item-wrapper-' . $key,
 		        [
--- a/essential-addons-for-elementor-lite/includes/Elements/Info_Box.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Info_Box.php
@@ -2502,6 +2502,7 @@
         }

         $infobox_image = $this->get_settings('eael_infobox_image');
+        $infobox_image = Helper::eael_wpml_translate_media( $infobox_image ); // WPML Media Translation compatibility
         $infobox_image_url = Group_Control_Image_Size::get_attachment_image_src($infobox_image['id'], 'thumbnail', $settings);
         if (empty($infobox_image_url)){
 	        $infobox_image_url = $infobox_image['url'];
@@ -2616,7 +2617,7 @@

                         // WPML Compatibility
                         if ( ! is_array( $settings['eael_primary_templates'] ) ) {
-                            $settings['eael_primary_templates'] = apply_filters( 'wpml_object_id', $settings['eael_primary_templates'], 'wp_template', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
+                            $settings['eael_primary_templates'] = apply_filters( 'wpml_object_id', $settings['eael_primary_templates'], 'elementor_library', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
                         }

 	                    Helper::eael_onpage_edit_template_markup( get_the_ID(), $settings['eael_primary_templates'] );
--- a/essential-addons-for-elementor-lite/includes/Elements/Login_Register.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Login_Register.php
@@ -6713,6 +6713,13 @@
 		$this->page_id_for_popup = get_queried_object_id();

 		//handle form illustration
+		// WPML Media Translation compatibility
+		if ( ! empty( $this->ds['lr_form_image'] ) ) {
+			$this->ds['lr_form_image'] = HelperCLass::eael_wpml_translate_media( $this->ds['lr_form_image'] );
+		}
+		if ( ! empty( $this->ds['lr_form_logo'] ) ) {
+			$this->ds['lr_form_logo'] = HelperCLass::eael_wpml_translate_media( $this->ds['lr_form_logo'] );
+		}
 		$form_image_id               = ! empty( $this->ds['lr_form_image']['id'] ) ? $this->ds['lr_form_image']['id'] : '';
 		$this->form_illustration_pos = ! empty( $this->ds['lr_form_image_position'] ) ? $this->ds['lr_form_image_position'] : 'left';
 		$this->form_illustration_url = Group_Control_Image_Size::get_attachment_image_src( $form_image_id, 'lr_form_image', $this->ds );
--- a/essential-addons-for-elementor-lite/includes/Elements/Post_Grid.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Post_Grid.php
@@ -1827,8 +1827,9 @@
         $offset = $settings['offset'] ? absint( $settings['offset'] ) : 0;
         $posts_per_page = isset($args['posts_per_page']) && $args['posts_per_page'] > 0 ? $args['posts_per_page'] : -1 ;

-        set_transient( 'eael_post_grid_read_more_button_text_'. $this->get_id(), $this->get_settings_for_display('read_more_button_text'), DAY_IN_SECONDS );
-        set_transient( 'eael_post_grid_excerpt_expanison_indicator_'. $this->get_id(), $this->get_settings_for_display('excerpt_expanison_indicator'), DAY_IN_SECONDS );
+        $eael_lang_suffix = HelperClass::eael_lang_suffix();
+        set_transient( 'eael_post_grid_read_more_button_text_'. $this->get_id() . $eael_lang_suffix, $this->get_settings_for_display('read_more_button_text'), DAY_IN_SECONDS );
+        set_transient( 'eael_post_grid_excerpt_expanison_indicator_'. $this->get_id() . $eael_lang_suffix, $this->get_settings_for_display('excerpt_expanison_indicator'), DAY_IN_SECONDS );
         $settings['read_more_button_text'] = $this->get_settings_for_display('read_more_button_text');
         $settings['excerpt_expanison_indicator'] = $this->get_settings_for_display('excerpt_expanison_indicator');

--- a/essential-addons-for-elementor-lite/includes/Elements/Pricing_Table.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Pricing_Table.php
@@ -2573,7 +2573,8 @@
         <?php if ('style-1' === $settings['eael_pricing_table_style']) : ?>
             <div class="eael-pricing-item <?php echo esc_attr($featured_class); ?>">
                 <div class="header">
-                    <<?php echo esc_html($settings['eael_pricing_table_title_tag']); ?> class="title"><?php echo wp_kses( $settings['eael_pricing_table_title'], HelperClass::eael_allowed_tags() ); ?></<?php echo esc_html($settings['eael_pricing_table_title_tag']); ?>>
+                    <?php $eael_pricing_table_title_tag = HelperClass::eael_validate_html_tag( $settings['eael_pricing_table_title_tag'] ); ?>
+                    <<?php echo esc_html( $eael_pricing_table_title_tag ); ?> class="title"><?php echo wp_kses( $settings['eael_pricing_table_title'], HelperClass::eael_allowed_tags() ); ?></<?php echo esc_html( $eael_pricing_table_title_tag ); ?>>
                 </div>
                 <div class="eael-pricing-tag">
                     <?php
--- a/essential-addons-for-elementor-lite/includes/Elements/Sticky_Video.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Sticky_Video.php
@@ -749,6 +749,9 @@
     protected function render()
     {
         $settings = $this->get_settings_for_display();
+        // WPML Media Translation compatibility
+        $settings['eaelsv_overlay_image'] = Helper::eael_wpml_translate_media( $settings['eaelsv_overlay_image'] );
+        $settings['eaelsv_hosted_url']    = Helper::eael_wpml_translate_media( $settings['eaelsv_hosted_url'] );
         $iconNew = $settings['eaelsv_icon_new'];
         $sticky = isset( $settings['eaelsv_is_sticky'] ) ? $settings['eaelsv_is_sticky'] : 'yes';
         $autoplay = ($settings['eaelsv_autopaly'] == 'yes') ? $settings['eaelsv_autopaly'] : 'no';
--- a/essential-addons-for-elementor-lite/includes/Elements/Team_Member.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Team_Member.php
@@ -1031,6 +1031,7 @@

         $settings = $this->get_settings_for_display();
 		$team_member_image = $settings['eael_team_member_image'] ?? '';
+		$team_member_image = HelperClass::eael_wpml_translate_media( $team_member_image ); // WPML Media Translation compatibility
 		$image_url = $team_member_image['url'] ?? '';
 		$alt_text = $settings['eael_team_member_name'] ?? '';

--- a/essential-addons-for-elementor-lite/includes/Elements/Testimonial.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Testimonial.php
@@ -901,6 +901,7 @@

 	protected function render_testimonial_image() {
 		$settings = $this->get_settings();
+		$settings['image'] = HelperClass::eael_wpml_translate_media( $settings['image'] ); // WPML Media Translation compatibility
 		$image = Group_Control_Image_Size::get_attachment_image_html( $settings );
 		if( ! empty($image) && ! empty($settings['eael_testimonial_enable_avatar']) ) {
 			ob_start();
--- a/essential-addons-for-elementor-lite/includes/Elements/Woo_Product_Gallery.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Woo_Product_Gallery.php
@@ -3284,6 +3284,7 @@
 				$all_taxonomy = 'product_tag';
 			}

+			$settings['eael_all_tab_thumb'] = HelperClass::eael_wpml_translate_media( $settings['eael_all_tab_thumb'] ); // WPML Media Translation compatibility
 			if ( $show_cat_thumb && !empty($settings['eael_all_tab_thumb']['url'])) {
 				$show_all_cat_thumb = '<img src="' . esc_url( $settings['eael_all_tab_thumb']['url'] ) . '" />';
 			} else {
--- a/essential-addons-for-elementor-lite/includes/Traits/Ajax_Handler.php
+++ b/essential-addons-for-elementor-lite/includes/Traits/Ajax_Handler.php
@@ -172,8 +172,9 @@
 		}

 		if ( $class == 'Essential_Addons_ElementorElementsPost_Grid' ) {
-			$settings['read_more_button_text']       = get_transient( 'eael_post_grid_read_more_button_text_' . $widget_id );
-			$settings['excerpt_expanison_indicator'] = get_transient( 'eael_post_grid_excerpt_expanison_indicator_' . $widget_id );
+			$eael_lang_suffix = HelperClass::eael_lang_suffix( $page_id );
+			$settings['read_more_button_text']       = get_transient( 'eael_post_grid_read_more_button_text_' . $widget_id . $eael_lang_suffix );
+			$settings['excerpt_expanison_indicator'] = get_transient( 'eael_post_grid_excerpt_expanison_indicator_' . $widget_id . $eael_lang_suffix );

 			if ( $settings['orderby'] === 'rand' && ! empty( $_REQUEST['post__not_in'] ) ) {
 				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
--- a/essential-addons-for-elementor-lite/includes/Traits/Helper.php
+++ b/essential-addons-for-elementor-lite/includes/Traits/Helper.php
@@ -488,19 +488,62 @@

 	/**
 	 * eael_wpml_template_translation
+	 *
+	 * Resolve an Elementor template/library id to its translation in the current
+	 * language. Works for both WPML and Polylang:
+	 *  - WPML auto-registers elementor_library and answers wpml_object_id.
+	 *  - Polylang does NOT register elementor_library as translatable by default, so
+	 *    its wpml_object_id compat filter would return the id unchanged. We therefore
+	 *    resolve via pll_get_post(), which honours the translation group directly.
+	 *
 	 * @param $id
 	 * @return mixed|void
 	 */
     public function eael_wpml_template_translation($id){
 	    $postType = get_post_type( $id );
-	    if ( 'elementor_library' === $postType ) {
-			// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
-		    return apply_filters( 'wpml_object_id', $id, $postType, true );
+	    if ( 'elementor_library' !== $postType ) {
+		    return $id;
 	    }
-	    return $id;
+
+	    // Polylang path (independent of the translatable-post-type setting).
+	    if ( function_exists( 'pll_get_post' ) && function_exists( 'pll_current_language' ) ) {
+		    $lang = pll_current_language();
+		    if ( $lang ) {
+			    $translated = pll_get_post( $id, $lang );
+			    // pll_get_post returns false when no translation exists for $lang;
+			    // keep the original id in that case.
+			    if ( $translated ) {
+				    return $translated;
+			    }
+		    }
+		    return $id;
+	    }
+
+	    // WPML path.
+		// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
+	    return apply_filters( 'wpml_object_id', $id, $postType, true );
     }

 	/**
+	 * Register Elementor's template library as translatable in Polylang.
+	 *
+	 * Polylang ships no Elementor integration, so elementor_library is not
+	 * translatable out of the box — which means saved templates embedded in EA
+	 * widgets cannot be mapped to the current language. Opt the post type in so the
+	 * translation group (and Polylang's own UI) works for these templates.
+	 *
+	 * Hooked to: pll_get_post_types
+	 *
+	 * @param array $post_types
+	 * @param bool  $is_settings
+	 * @return array
+	 */
+	public function eael_pll_translate_elementor_library( $post_types, $is_settings = false ) {
+		$post_types['elementor_library'] = 'elementor_library';
+		return $post_types;
+	}
+
+	/**
 	 * eael_sanitize_template_param
      * Removes special characters that are illegal in filenames
      *
--- a/essential-addons-for-elementor-lite/includes/Traits/Woo_Product_Comparable.php
+++ b/essential-addons-for-elementor-lite/includes/Traits/Woo_Product_Comparable.php
@@ -1969,6 +1969,19 @@
 					continue;
 				}

+				// SECURITY FIX: do not expose non-published / inaccessible products to unauthenticated callers.
+				// Mirrors the quickview handler guards (CVE-2026-1004).
+				$compare_post = get_post( $product_id );
+				if ( ! $product->is_visible() ) {
+					continue;
+				}
+				if ( ! current_user_can( 'edit_post', $product_id ) && ( ! $compare_post || 'publish' !== $compare_post->post_status ) ) {
+					continue;
+				}
+				if ( ! current_user_can( 'edit_post', $product_id ) && post_password_required( $compare_post ) ) {
+					continue;
+				}
+
 				$product->fields = [];

 				// custom attributes
@@ -2215,6 +2228,19 @@
 					continue;
 				}

+				// SECURITY FIX: do not expose non-published / inaccessible products to unauthenticated callers.
+				// Mirrors the quickview handler guards (CVE-2026-1004).
+				$compare_post = get_post( $product_id );
+				if ( ! $product->is_visible() ) {
+					continue;
+				}
+				if ( ! current_user_can( 'edit_post', $product_id ) && ( ! $compare_post || 'publish' !== $compare_post->post_status ) ) {
+					continue;
+				}
+				if ( ! current_user_can( 'edit_post', $product_id ) && post_password_required( $compare_post ) ) {
+					continue;
+				}
+
 				$product->fields = [];

 				// custom attributes

Frequently Asked Questions

Atomic Edge WAF security layer inspecting website traffic.

How Atomic Edge Works

Simple Setup. Powerful Security.

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

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Black & McDonald logo representing Enterprise tier security and support for Atomic Edge WAF.Covenant House Toronto logo featuring a dove and text for Atomic Edge Enterprise planAlzheimer Society Canada logo representing trusted organizations and security partners.University of Toronto logo representing trusted organizations using Atomic Edge WAFSpecsavvers logo, trusted developers and organizations using Atomic Edge securityHarvard Medical School logo representing trusted organizations using Atomic Edge WAF.