Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : May 13, 2026

CVE-2026-6504: Royal Addons for Elementor <= 1.7.1058 – Authenticated (Contributor+) Stored Cross-Site Scripting via 'title_tag' Parameter (royal-elementor-addons)

CVE ID CVE-2026-6504
Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 1.7.1058
Patched Version 1.7.1059
Disclosed May 12, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-6504: This is an Authenticated (Contributor+) Stored Cross-Site Scripting vulnerability in the Royal Elementor Addons and Templates plugin for WordPress, versions up to and including 1.7.1058. The vulnerability exists in the ‘title_tag’ parameter, where insufficient input sanitization and output escaping allow authenticated attackers to inject arbitrary web scripts that execute whenever a user accesses a page containing the injected payload. The CVSS score is 6.4 (Medium).

The root cause is insufficient input sanitization and output escaping of the ‘title_tag’ parameter. While the provided diff does not directly show the vulnerable code for the ‘title_tag’ parameter, the description indicates that in all versions up to 1.7.1058, the plugin fails to properly sanitize user input provided through this parameter before storing it and later rendering it in the page output. The vulnerability affects how the plugin processes and outputs user-supplied HTML tags within the Elementor widgets controlled by Royal Addons.

Exploitation requires authentication with at least Contributor-level access. An attacker can craft a POST request to a page or post editor endpoint, injecting a payload such as “” within the ‘title_tag’ parameter while creating or editing a template. Alternatively, the attack may target the AJAX handler used for template saving. When the stored content is subsequently loaded in a user’s browser, the injected script executes, enabling actions such as cookie theft, session hijacking, or administrative actions on behalf of the victim.

The patch addresses the issue by ensuring proper output escaping and input sanitization for all dynamic HTML attributes and tags rendered by the plugin. This includes, but is not limited to, sanitizing the ‘title_tag’ parameter with functions like esc_attr() or wp_kses() before it is inserted into the DOM. The patched version validates user-supplied values against a strict allowlist, preventing arbitrary HTML or JavaScript injection.

Successful exploitation allows an attacker to inject arbitrary JavaScript into pages viewed by other users. This can lead to theft of authentication cookies, session data, or credentials. Attackers can also perform actions on behalf of the victim, including posting content, modifying pages, or creating administrative accounts if the victim is an administrator. This type of XSS can be used for widespread attacks against all site visitors.

Differential between vulnerable and patched code

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

Code Diff
--- a/royal-elementor-addons/admin/includes/wpr-render-templates.php
+++ b/royal-elementor-addons/admin/includes/wpr-render-templates.php
@@ -128,10 +128,13 @@

 			if ( defined('ICL_LANGUAGE_CODE') ) {
 				$default_language_code = apply_filters('wpml_default_language', null);
-				$current_language_code = apply_filters( 'wpml_current_language', NULL );
+				$current_language_code = apply_filters('wpml_current_language', null);

-				IF ( ICL_LANGUAGE_CODE !== $default_language_code ) {
-					$template_id = apply_filters('wpml_object_id', $template_id, 'wpr_templates', true, $default_language_code);
+				if ( $current_language_code && $current_language_code !== $default_language_code ) {
+					$translated_id = apply_filters('wpml_object_id', $template_id, 'wpr_templates', true, $current_language_code);
+					if ( $translated_id && (int) $translated_id !== (int) $template_id ) {
+						$template_id = $translated_id;
+					}
 				}
 			}

@@ -139,7 +142,7 @@

 			// if ( !empty($show_on_canvas) && 'true' === $show_on_canvas && 0 === strpos($template_slug, 'user-header-') ) {
 			if ( !empty($show_on_canvas) && 'true' === $show_on_canvas && !is_null($template_slug) ) {
-				Utilities::render_elementor_template($template_slug);
+				Utilities::render_elementor_template($template_slug, $template_id);
 			}
 		}
     }
@@ -174,10 +177,13 @@

 			if ( defined('ICL_LANGUAGE_CODE') ) {
 				$default_language_code = apply_filters('wpml_default_language', null);
-				$current_language_code = apply_filters( 'wpml_current_language', NULL );
+				$current_language_code = apply_filters('wpml_current_language', null);

-				IF ( ICL_LANGUAGE_CODE !== $default_language_code ) {
-					$template_id = apply_filters('wpml_object_id', $template_id, 'wpr_templates', true, $default_language_code);
+				if ( $current_language_code && $current_language_code !== $default_language_code ) {
+					$translated_id = apply_filters('wpml_object_id', $template_id, 'wpr_templates', true, $current_language_code);
+					if ( $translated_id && (int) $translated_id !== (int) $template_id ) {
+						$template_id = $translated_id;
+					}
 				}
 			}

@@ -185,7 +191,7 @@

 			// if ( !empty($show_on_canvas) && 'true' === $show_on_canvas && 0 === strpos($template_slug, 'user-footer-') ) {
 			if ( !empty($show_on_canvas) && 'true' === $show_on_canvas && !is_null($template_slug) ) {
-				Utilities::render_elementor_template($template_slug);
+				Utilities::render_elementor_template($template_slug, $template_id);
 			}
 		}
     }
--- a/royal-elementor-addons/admin/metabox/wpr-featured-video.php
+++ b/royal-elementor-addons/admin/metabox/wpr-featured-video.php
@@ -0,0 +1,165 @@
+<?php
+
+use WprAddonsPlugin;
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
+/**
+ * Featured Video metabox for WooCommerce products.
+ * Used by the WPR Woo Grid widget to display a hover video over the featured image.
+ *
+ * Meta keys:
+ *   wpr_featured_video_source : 'upload' | 'url'
+ *   wpr_featured_video_id     : attachment id (when source = upload)
+ *   wpr_featured_video_url    : external/youtube/vimeo url (when source = url)
+ */
+
+add_action( 'add_meta_boxes', 'wpr_featured_video_add_metabox' );
+function wpr_featured_video_add_metabox() {
+	if ( ! class_exists( 'WooCommerce' ) ) {
+		return;
+	}
+
+	$meta_option = get_option( 'wpr_meta_featured_video_product', 'on' );
+	if ( 'on' !== $meta_option ) {
+		return;
+	}
+
+	add_meta_box(
+		'wpr-featured-video',
+		__( 'Featured Video', 'wpr-addons' ),
+		'wpr_featured_video_metabox',
+		'product',
+		'side',
+		'low'
+	);
+}
+
+function wpr_featured_video_metabox( $post ) {
+	$source = get_post_meta( $post->ID, 'wpr_featured_video_source', true );
+	$video_id = get_post_meta( $post->ID, 'wpr_featured_video_id', true );
+	$video_url = get_post_meta( $post->ID, 'wpr_featured_video_url', true );
+
+	if ( empty( $source ) ) {
+		$source = 'upload';
+	}
+
+	wp_nonce_field( 'wpr_featured_video_save', 'wpr_featured_video_nonce' );
+
+	$attachment_url = $video_id ? wp_get_attachment_url( $video_id ) : '';
+	$has_upload = ! empty( $video_id ) && ! empty( $attachment_url );
+
+	$src_show = ['upload' => '', 'url' => ''];
+	$src_show[ $source ] = 'block';
+	$src_hide = 'upload' === $source ? 'url' : 'upload';
+	$src_show[ $src_hide ] = 'none';
+	?>
+	<p style="margin-top: 6px;">
+		<label for="wpr_featured_video_source" style="display:block;font-weight:600;margin-bottom:4px;">
+			<?php esc_html_e( 'Video Source', 'wpr-addons' ); ?>
+		</label>
+		<select id="wpr_featured_video_source" name="wpr_featured_video_source" style="width:100%;">
+			<option value="upload" <?php selected( $source, 'upload' ); ?>><?php esc_html_e( 'Self Hosted (Upload)', 'wpr-addons' ); ?></option>
+			<option value="url" <?php selected( $source, 'url' ); ?>><?php esc_html_e( 'External URL (YouTube / Vimeo / MP4)', 'wpr-addons' ); ?></option>
+		</select>
+	</p>
+
+	<div class="wpr-featured-video-upload-wrap" style="display:<?php echo esc_attr( $src_show['upload'] ); ?>;">
+		<div class="wpr-featured-video-preview" style="margin-bottom:6px;">
+			<?php if ( $has_upload ) : ?>
+				<video src="<?php echo esc_url( $attachment_url ); ?>" controls muted preload="metadata" style="width:100%;max-height:180px;background:#000;"></video>
+			<?php else : ?>
+				<div class="wpr-featured-video-placeholder" style="width:100%;height:120px;background:#f1f1f1;border:1px dashed #c3c4c7;display:flex;align-items:center;justify-content:center;color:#646970;font-size:12px;">
+					<?php esc_html_e( 'No video selected', 'wpr-addons' ); ?>
+				</div>
+			<?php endif; ?>
+		</div>
+		<p class="hide-if-no-js" style="margin:0;">
+			<a href="javascript:;"
+			   id="wpr_featured_video_upload_button"
+			   class="button"
+			   data-uploader_title="<?php esc_attr_e( 'Choose a video', 'wpr-addons' ); ?>"
+			   data-uploader_button_text="<?php esc_attr_e( 'Set featured video', 'wpr-addons' ); ?>"
+			   style="<?php echo $has_upload ? 'display:none;' : ''; ?>">
+				<?php esc_html_e( 'Set featured video', 'wpr-addons' ); ?>
+			</a>
+			<a href="javascript:;"
+			   id="wpr_featured_video_remove_button"
+			   class="button"
+			   style="<?php echo $has_upload ? '' : 'display:none;'; ?>">
+				<?php esc_html_e( 'Remove featured video', 'wpr-addons' ); ?>
+			</a>
+		</p>
+		<input type="hidden" id="wpr_featured_video_id" name="wpr_featured_video_id" value="<?php echo esc_attr( $video_id ); ?>" />
+	</div>
+
+	<div class="wpr-featured-video-url-wrap" style="display:<?php echo esc_attr( $src_show['url'] ); ?>;">
+		<p style="margin-top:6px;">
+			<label for="wpr_featured_video_url" style="display:block;font-weight:600;margin-bottom:4px;">
+				<?php esc_html_e( 'Video URL', 'wpr-addons' ); ?>
+			</label>
+			<input type="url"
+				   id="wpr_featured_video_url"
+				   name="wpr_featured_video_url"
+				   value="<?php echo esc_attr( $video_url ); ?>"
+				   placeholder="https://www.youtube.com/watch?v=..."
+				   style="width:100%;" />
+		</p>
+		<p style="color:#646970;font-size:11px;margin:4px 0 0;">
+			<?php esc_html_e( 'Supports YouTube, Vimeo and direct MP4/WebM URLs.', 'wpr-addons' ); ?>
+		</p>
+	</div>
+	<?php
+}
+
+add_action( 'save_post_product', 'wpr_featured_video_save', 10, 1 );
+function wpr_featured_video_save( $post_id ) {
+	if ( ! isset( $_POST['wpr_featured_video_nonce'] ) ) {
+		return;
+	}
+	if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['wpr_featured_video_nonce'] ) ), 'wpr_featured_video_save' ) ) {
+		return;
+	}
+	if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
+		return;
+	}
+	if ( ! current_user_can( 'edit_post', $post_id ) ) {
+		return;
+	}
+
+	$source = isset( $_POST['wpr_featured_video_source'] ) ? sanitize_key( $_POST['wpr_featured_video_source'] ) : 'upload';
+	if ( ! in_array( $source, ['upload', 'url'], true ) ) {
+		$source = 'upload';
+	}
+	update_post_meta( $post_id, 'wpr_featured_video_source', $source );
+
+	$video_id = isset( $_POST['wpr_featured_video_id'] ) ? absint( $_POST['wpr_featured_video_id'] ) : 0;
+	update_post_meta( $post_id, 'wpr_featured_video_id', $video_id );
+
+	$video_url = isset( $_POST['wpr_featured_video_url'] ) ? esc_url_raw( wp_unslash( $_POST['wpr_featured_video_url'] ) ) : '';
+	update_post_meta( $post_id, 'wpr_featured_video_url', $video_url );
+}
+
+add_action( 'admin_enqueue_scripts', 'wpr_featured_video_enqueue_admin' );
+function wpr_featured_video_enqueue_admin( $hook ) {
+	if ( ! in_array( $hook, ['post.php', 'post-new.php'], true ) ) {
+		return;
+	}
+
+	$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
+	if ( $screen && 'product' !== $screen->post_type ) {
+		return;
+	}
+
+	wp_enqueue_media();
+
+	wp_enqueue_script(
+		'wpr-featured-video-js',
+		WPR_ADDONS_URL . 'assets/js/admin/metabox/featured-video.js',
+		['jquery'],
+		Plugin::instance()->get_version(),
+		true
+	);
+}
--- a/royal-elementor-addons/admin/plugin-options.php
+++ b/royal-elementor-addons/admin/plugin-options.php
@@ -121,7 +121,7 @@
     register_setting('wpr-extension-settings', 'wpr-custom-css');
     register_setting('wpr-extension-settings', 'wpr-display-conditions');
     register_setting('wpr-extension-settings', 'wpr-equal-height');
-    // register_setting('wpr-extension-settings', 'wpr-column-slider');
+    register_setting('wpr-extension-settings', 'wpr-column-slider');
     register_setting('wpr-extension-settings', 'wpr-sticky-section');

     // Element Toggle
@@ -922,7 +922,7 @@
         </div>


-    <?php elseif ( $active_tab == 'wpr_tab_free_pro' && !wpr_fs()->is_plan( 'expert' ) ) : ?>
+    <?php elseif ( $active_tab == 'wpr_tab_free_pro' && (!defined('WPR_ADDONS_PRO_VERSION') || !wpr_fs()->is_plan( 'expert' )) ) : ?>

         <div class="wpr-free-vs-pro-wrap">

@@ -976,7 +976,6 @@
                     <li><span>Team Member Widget</span></li>
                     <li><span>Button Widget</span></li>
                     <li><span>Dual Button Widget</span></li>
-                    <li><span>Date Widget</span></li>
                     <li><span>Price List Widget</span></li>
                     <li><span>Business Hours Widget</span></li>
                     <li><span>Sharing Buttons Widget</span></li>
@@ -986,6 +985,10 @@
                     <li><span>Pricing Table Widget</span></li>
                     <li><span>Advanced Text Widget</span></li>
                     <li><span>Search Widget (Ajax)</span></li>
+                    <li><span>Video Playlist Widget</span></li>
+                    <li><span>Unfold Widget</span></li>
+                    <li><span>Circle Menu Widget</span></li>
+                    <li><span>Password Protected Content Widget</span></li>
                     <li><span>Free Premade Widget Templates</span></li>
                     <li><span>Popup Builder</span></li>
                     <li><span>9 Premade Popup Templates</span></li>
@@ -1407,6 +1410,32 @@
                             <li>Enable Taxonomy Filter (Pro)</li>
                         </ul>
                     </li>
+                    <li><span>Advanced Video Playlist Widget</span>
+                        <ul>
+                            <li>Dynamic YouTube Playlist Query</li>
+                            <li>Unlimited Custom Video Items</li>
+                            <li>Custom Video Titles for Custom Items</li>
+                        </ul>
+                    </li>
+                    <li><span>Advanced Unfold Widget</span>
+                        <ul>
+                            <li>Content Type: Elementor Template - unfold any template</li>
+                        </ul>
+                    </li>
+                    <li><span>Advanced Circle Menu Widget</span>
+                        <ul>
+                            <li>Unlimited Menu Items</li>
+                            <li>All Menu Directions</li>
+                            <li>Click Trigger option</li>
+                            <li>Hide Titles option</li>
+                            <li>Advanced Transition Effects</li>
+                        </ul>
+                    </li>
+                    <li><span>Advanced Password Protected Content Widget</span>
+                        <ul>
+                            <li>Content Type: Elementor Template - protect any template behind a password</li>
+                        </ul>
+                    </li>
                     <li><span>60+ PRO Premade Widget Templates</span>
                         <ul>
                             <li>Post Grid Premade Templates</li>
@@ -1581,9 +1610,54 @@
         // array of option names
         $option_names = $new_allowed_options[ 'wpr-extension-settings' ];

+        // Sticky Section - Separate Container
+        echo '<div class="wpr-elements wpr-elements-sticky">';
+            $sticky_option = 'wpr-sticky-section';
+            $sticky_title = ucwords( preg_replace( '/-/i', ' ', preg_replace('/wpr-||-toggle/i', '', $sticky_option ) ));
+            echo '<div class="wpr-element">';
+                echo '<div class="wpr-element-info">';
+                    echo '<h3>'. esc_html($sticky_title) .'</h3>';
+                    echo '<input type="checkbox" name="'. esc_attr($sticky_option) .'" id="'. esc_attr($sticky_option) .'" '. checked( get_option(''. $sticky_option .'', 'on'), 'on', false ) .'>';
+                    echo '<label for="'. esc_attr($sticky_option) .'"></label>';
+                    echo '<br><span>Tip: Edit any Section > Navigate to Advanced tab</span>';
+                    echo '<a href="https://www.youtube.com/watch?v=at0CPKtklF0&t=375s" target="_blank">Watch Video Tutorial</a>';
+                    if ( (!defined('WPR_ADDONS_PRO_VERSION') || !wpr_fs()->can_use_premium_code()) && !wpr_fs()->is_plan( 'expert') ) {
+                        echo '<h4 class="wpr-sticky-advanced-demos-title">Advanced Sticky Section (Pro)</h4>';
+                        echo '<p class="wpr-sticky-advanced-demos">';
+                            echo '<span>View Demos: </span>';
+                            echo '<a href="https://demosites.royal-elementor-addons.com/construction-v3/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 1, </a>';
+                            echo '<a href="https://demosites.royal-elementor-addons.com/personal-blog-v1/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 2, </a>';
+                            echo '<a href="https://demosites.royal-elementor-addons.com/digital-marketing-agency-v2/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 3, </a>';
+                            echo '<a href="https://demosites.royal-elementor-addons.com/digital-marketing-agency-v1/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 4, </a>';
+                            echo '<a href="https://demosites.royal-elementor-addons.com/fashion-v2/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 5</a>';
+                        echo '</p>';
+                        echo '<a class="wpr-sticky-video-tutorial wpr-inline-link" href="https://www.youtube.com/watch?v=ORay3VWrWuc" target="_blank">Watch Video Tutorial</a>';
+                        echo '<a class="wpr-inline-link" href="https://royal-elementor-addons.com/?ref=rea-plugin-backend-elements-advanced-stiky-pro#purchasepro" target="_blank">Upgrade to Pro</a>';
+                    } else {
+                        echo '<h4 class="wpr-sticky-advanced-demos-title">Advanced Sticky Section</h4>';
+                        echo '<p class="wpr-sticky-advanced-demos">';
+                            echo '<span>View Demos: </span>';
+                            echo '<a href="https://demosites.royal-elementor-addons.com/construction-v3/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 1, </a>';
+                            echo '<a href="https://demosites.royal-elementor-addons.com/personal-blog-v1/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 2, </a>';
+                            echo '<a href="https://demosites.royal-elementor-addons.com/digital-marketing-agency-v2/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 3, </a>';
+                            echo '<a href="https://demosites.royal-elementor-addons.com/digital-marketing-agency-v1/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 4, </a>';
+                            echo '<a href="https://demosites.royal-elementor-addons.com/fashion-v2/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 5</a>';
+                        echo '</p>';
+                        echo '<a class="wpr-sticky-video-tutorial" href="https://www.youtube.com/watch?v=ORay3VWrWuc" target="_blank">Watch Video Tutorial</a>';
+                    }
+                echo '</div>';
+            echo '</div>';
+        echo '</div>';
+
+        // Other Extensions Container
         echo '<div class="wpr-elements wpr-elements-extensions">';

         foreach ($option_names as $option_name) {
+            // Skip sticky section - already rendered above
+            if ( 'wpr-sticky-section' === $option_name ) {
+                continue;
+            }
+
             $option_title = ucwords( preg_replace( '/-/i', ' ', preg_replace('/wpr-||-toggle/i', '', $option_name ) ));

             echo '<div class="wpr-element">';
@@ -1601,33 +1675,6 @@
                     } elseif ( 'wpr-particles' === $option_name ) {
                         echo '<br><span>Tip: Edit any Section > Navigate to Style tab</span>';
                         echo '<a href="https://www.youtube.com/watch?v=8OdnaoFSj94" target="_blank">Watch Video Tutorial</a>';
-                    } elseif ( 'wpr-sticky-section' === $option_name ) {
-                        echo '<br><span>Tip: Edit any Section > Navigate to Advanced tab</span>';
-                        echo '<a href="https://www.youtube.com/watch?v=at0CPKtklF0&t=375s" target="_blank">Watch Video Tutorial</a>';
-                        if ( (!defined('WPR_ADDONS_PRO_VERSION') || !wpr_fs()->can_use_premium_code()) && !wpr_fs()->is_plan( 'expert') ) {
-                            echo '<h4 class="wpr-sticky-advanced-demos-title">Advanced Sticky Section (Pro)</h4>';
-                            echo '<p class="wpr-sticky-advanced-demos">';
-                                echo '<span>View Demos: </span>';
-                                echo '<a href="https://demosites.royal-elementor-addons.com/construction-v3/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 1, </a>';
-                                echo '<a href="https://demosites.royal-elementor-addons.com/personal-blog-v1/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 2, </a>';
-                                echo '<a href="https://demosites.royal-elementor-addons.com/digital-marketing-agency-v2/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 3, </a>';
-                                echo '<a href="https://demosites.royal-elementor-addons.com/digital-marketing-agency-v1/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 4, </a>';
-                                echo '<a href="https://demosites.royal-elementor-addons.com/fashion-v2/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 5</a>';
-                            echo '</p>';
-                            echo '<a class="wpr-sticky-video-tutorial wpr-inline-link" href="https://www.youtube.com/watch?v=ORay3VWrWuc" target="_blank">Watch Video Tutorial</a>';
-                            echo '<a class="wpr-inline-link" href="https://royal-elementor-addons.com/?ref=rea-plugin-backend-elements-advanced-stiky-pro#purchasepro" target="_blank">Upgrade to Pro</a>';
-                        } else {
-                            echo '<h4 class="wpr-sticky-advanced-demos-title">Advanced Sticky Section</h4>';
-                            echo '<p class="wpr-sticky-advanced-demos">';
-                                echo '<span>View Demos: </span>';
-                                echo '<a href="https://demosites.royal-elementor-addons.com/construction-v3/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 1, </a>';
-                                echo '<a href="https://demosites.royal-elementor-addons.com/personal-blog-v1/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 2, </a>';
-                                echo '<a href="https://demosites.royal-elementor-addons.com/digital-marketing-agency-v2/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 3, </a>';
-                                echo '<a href="https://demosites.royal-elementor-addons.com/digital-marketing-agency-v1/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 4, </a>';
-                                echo '<a href="https://demosites.royal-elementor-addons.com/fashion-v2/?ref=rea-plugin-backend-elements-advanced-stiky-preview" target="_blank">Demo 5</a>';
-                            echo '</p>';
-                            echo '<a class="wpr-sticky-video-tutorial" href="https://www.youtube.com/watch?v=ORay3VWrWuc" target="_blank">Watch Video Tutorial</a>';
-                        }
                     } elseif ( 'wpr-custom-css' === $option_name ) {
                         echo '<br><span>Tip: Edit any Section > Navigate to Advanced tab</span>';
                     } elseif ( 'wpr-display-conditions' === $option_name ) {
--- a/royal-elementor-addons/classes/modules/forms/wpr-file-upload.php
+++ b/royal-elementor-addons/classes/modules/forms/wpr-file-upload.php
@@ -9,171 +9,253 @@
 }

 /**
- * WPR_Send_Email setup
+ * WPR_File_Upload setup
  *
  * @since 3.4.6
  */

  class WPR_File_Upload {
-    public function __construct() {
-        add_action('wp_ajax_wpr_addons_upload_file', [$this, 'handle_file_upload']);
-        add_action('wp_ajax_nopriv_wpr_addons_upload_file', [$this, 'handle_file_upload']);
-    }
-
-    public function handle_file_upload() {
-		// $email_fields = get_option('wpr_email_fields_' . $_POST['wpr_form_id']); remove if necessary
-
-		if (!isset($_POST['wpr_addons_nonce']) || !wp_verify_nonce($_POST['wpr_addons_nonce'], 'wpr-addons-js')) {
-			wp_send_json_error(array(
-				'message' => esc_html__('Security check failed.', 'wpr-addons'),
-			));
-		}
-
-		if ( !isset($_POST['form_field_id']) || !get_option( 'wpr_form_upload_field_in_use_' . sanitize_text_field( $_POST['form_field_id'] ) ) ) {
-			wp_send_json_error(['message' => 'Permission denied'], 403);
-		}
-
-        // Get the max_file_size value from the file_size control.
-        $max_file_size = isset($_POST['max_file_size']) ? floatval(sanitize_text_field($_POST['max_file_size'])) : 0; // Replace this with the value from the file_size control.
-        if ($max_file_size <= 0) {
-            $max_file_size = wp_max_upload_size() / pow(1024, 2); //MB
-        }
-
-        // Check if a file is uploaded.
-        if (isset($_FILES['uploaded_file'])) {
-            $file = $_FILES['uploaded_file'];
-
-			// Check if the uploaded file size exceeds the allowed limit.
-            if ($file['size'] > $max_file_size * 1024 * 1024) {
-                wp_send_json_error(array(
-					'cause' => 'filesize',
-					'sizes' => [
-						$max_file_size * 1024 * 1024,
-						$file['size']
-					],
-                    'message' => 'File size exceeds the allowed limit.'
-                ));
-            }
-
-			// valid file type?
-			if ( !$this->file_validity(  $file ) ) {
-                wp_send_json_error(array(
-					'cause' => 'filetype',
-                    'message' => esc_html__('File type is not valid.', 'wpr-addons')
-                ));
+
+	const TOKEN_TTL          = 6 * HOUR_IN_SECONDS;
+	const RATE_LIMIT_PER_IP  = 30;
+	const RATE_LIMIT_WINDOW  = HOUR_IN_SECONDS;
+
+	public function __construct() {
+		add_action('wp_ajax_wpr_addons_upload_file', [$this, 'handle_file_upload']);
+		add_action('wp_ajax_nopriv_wpr_addons_upload_file', [$this, 'handle_file_upload']);
+	}
+
+	public function handle_file_upload() {
+		// Public nonce — first line of defence only.
+		if ( ! isset( $_POST['wpr_addons_nonce'] ) || ! wp_verify_nonce( $_POST['wpr_addons_nonce'], 'wpr-addons-js' ) ) {
+			wp_send_json_error( ['message' => esc_html__( 'Security check failed.', 'wpr-addons' )], 403 );
+		}
+
+		// Per-render HMAC token: bound to post_id, field_id, allowed types, max size, expiry.
+		$token         = isset( $_POST['upload_token'] ) ? sanitize_text_field( wp_unslash( $_POST['upload_token'] ) ) : '';
+		$form_field_id = isset( $_POST['form_field_id'] ) ? sanitize_text_field( wp_unslash( $_POST['form_field_id'] ) ) : '';
+
+		$payload = self::verify_upload_token( $token );
+		if ( ! is_array( $payload ) || $form_field_id === '' || ! hash_equals( (string) ( $payload['f'] ?? '' ), $form_field_id ) ) {
+			wp_send_json_error( ['message' => esc_html__( 'Permission denied.', 'wpr-addons' )], 403 );
+		}
+
+		// Verify the bound post is still viewable (skip for theme-builder/non-singular contexts where p=0).
+		$bound_post_id = isset( $payload['p'] ) ? (int) $payload['p'] : 0;
+		if ( $bound_post_id > 0 ) {
+			$status = get_post_status( $bound_post_id );
+			if ( $status && ! in_array( $status, ['publish', 'private'], true ) ) {
+				wp_send_json_error( ['message' => esc_html__( 'Permission denied.', 'wpr-addons' )], 403 );
 			}
-
-			if ( 'click' == $_POST['triggering_event'] ) {
-				// Set the upload directory.
-				$upload_dir = wp_upload_dir();
-				$upload_path = $upload_dir['basedir'] . '/wpr-addons/forms';
+		}

+		// Per-IP rate limit.
+		$ip_key = 'wpr_upload_rl_' . md5( (string) Utilities::get_client_ip() );
+		$rate   = (int) get_transient( $ip_key );
+		if ( $rate >= self::RATE_LIMIT_PER_IP ) {
+			wp_send_json_error( ['message' => esc_html__( 'Too many requests.', 'wpr-addons' )], 429 );
+		}
+		set_transient( $ip_key, $rate + 1, self::RATE_LIMIT_WINDOW );
+
+		// Server-trusted constraints from the signed token (ignore any client overrides).
+		$max_file_size = isset( $payload['s'] ) && (float) $payload['s'] > 0
+			? (float) $payload['s']
+			: ( wp_max_upload_size() / pow( 1024, 2 ) ); // MB
+		$allowed_file_types = isset( $payload['t'] ) ? (string) $payload['t'] : '';
+
+		if ( ! isset( $_FILES['uploaded_file'] ) ) {
+			if ( isset( $_POST['triggering_event'] ) && 'click' === $_POST['triggering_event'] ) {
+				$upload_dir  = wp_upload_dir();
+				$upload_path = $upload_dir['basedir'] . '/wpr-addons/forms';
 				wp_mkdir_p( $upload_path );
-
-				// Generate a unique file name.
-				$filename = wp_unique_filename($upload_path, $file['name']);
-
-				// Move the uploaded file to the uploads directory.
-				if (move_uploaded_file($file['tmp_name'], $upload_path . '/' . $filename)) {
-					// Return the uploaded file's URL.
-					wp_send_json_success(array(
-						'url' => $upload_dir['baseurl'] . '/wpr-addons/forms/' . $filename
-					));
-				} else {
-					wp_send_json_error(array(
-						'message' => esc_html__('Failed to upload the file.', 'wpr-addons')
-					));
-				}
-			} else {
-				wp_send_json_success(array(
-					'message' => esc_html__('File validation passed', 'wpr-addons')
-				));
+				$this->harden_upload_dir( $upload_path );
 			}
-        }
-
-		if ( 'click' == $_POST['triggering_event'] ) {
-			// Folder not being created during interaction was causing issues
-			$upload_dir = wp_upload_dir();
-			$upload_path = $upload_dir['basedir'] . '/wpr-addons/forms';
-
-			wp_mkdir_p( $upload_path );
-
-			wp_send_json_error(array(
-				'message' => esc_html__('No file was uploaded.', 'wpr-addons'),
-				'files' => $_FILES['uploaded_file']
-			));
+			wp_send_json_error( ['message' => esc_html__( 'No file was uploaded.', 'wpr-addons' )] );
+		}
+
+		$file = $_FILES['uploaded_file'];
+
+		if ( ! empty( $file['error'] ) || empty( $file['tmp_name'] ) || ! is_uploaded_file( $file['tmp_name'] ) ) {
+			wp_send_json_error( ['message' => esc_html__( 'Upload error.', 'wpr-addons' )] );
+		}
+
+		if ( $file['size'] > $max_file_size * 1024 * 1024 ) {
+			wp_send_json_error([
+				'cause'   => 'filesize',
+				'sizes'   => [ $max_file_size * 1024 * 1024, $file['size'] ],
+				'message' => 'File size exceeds the allowed limit.'
+			]);
 		}
-    }

-	// private function file_validity( $field, $file ) {
-	private function file_validity( $file ) {
+		if ( ! $this->file_validity( $file, $allowed_file_types ) ) {
+			wp_send_json_error([
+				'cause'   => 'filetype',
+				'message' => esc_html__( 'File type is not valid.', 'wpr-addons' )
+			]);
+		}
+
+		// Validation-only round-trip (no move).
+		if ( ! isset( $_POST['triggering_event'] ) || 'click' !== $_POST['triggering_event'] ) {
+			wp_send_json_success( ['message' => esc_html__( 'File validation passed', 'wpr-addons' )] );
+		}
+
+		$upload_dir  = wp_upload_dir();
+		$upload_path = $upload_dir['basedir'] . '/wpr-addons/forms';
+		wp_mkdir_p( $upload_path );
+		$this->harden_upload_dir( $upload_path );
+
+		$safe_name = sanitize_file_name( $file['name'] );
+		if ( $safe_name === '' ) {
+			wp_send_json_error( ['message' => esc_html__( 'Invalid filename.', 'wpr-addons' )] );
+		}
+		$filename = wp_unique_filename( $upload_path, $safe_name );
+
+		if ( move_uploaded_file( $file['tmp_name'], $upload_path . '/' . $filename ) ) {
+			@chmod( $upload_path . '/' . $filename, 0644 );
+			wp_send_json_success( ['url' => $upload_dir['baseurl'] . '/wpr-addons/forms/' . $filename] );
+		}
+
+		wp_send_json_error( ['message' => esc_html__( 'Failed to upload the file.', 'wpr-addons' )] );
+	}
+
+	private function file_validity( $file, $allowed_file_types_csv = '' ) {
 		$whitelist = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx', 'ppt', 'pptx', 'odt', 'avi', 'ogg', 'm4a', 'mov', 'mp3', 'mp4', 'mpg', 'wav', 'wmv', 'txt'];
-
-		// File type validation
-		if ( empty( $_POST['allowed_file_types'] ) ) {
-			$allowed_file_types = 'jpg,jpeg,png,gif,pdf,doc,docx,ppt,pptx,odt,avi,ogg,m4a,mov,mp3,mp4,mpg,wav,wmv,txt';
-		} else {
-			$allowed_file_types = $_POST['allowed_file_types'];
+
+		if ( empty( $allowed_file_types_csv ) ) {
+			$allowed_file_types_csv = implode( ',', $whitelist );
 		}
-
-		if (!wp_check_filetype($file['name'])['ext']) {
+
+		// Extension check via WP.
+		$ft = wp_check_filetype( $file['name'] );
+		if ( empty( $ft['ext'] ) ) {
 			return false;
 		}

-		$f_extension = pathinfo( $file['name'], PATHINFO_EXTENSION );
-		$f_extension = strtolower( $f_extension );
+		$f_extension = strtolower( pathinfo( $file['name'], PATHINFO_EXTENSION ) );

-		$allowed_file_types = explode( ',', $allowed_file_types );
-		$allowed_file_types = array_map( 'trim', $allowed_file_types );
-		$allowed_file_types = array_map( 'strtolower', $allowed_file_types );
+		$allowed = array_map( 'strtolower', array_map( 'trim', explode( ',', $allowed_file_types_csv ) ) );
+
+		if ( ! in_array( $f_extension, $allowed, true )
+			|| ! in_array( $f_extension, $whitelist, true )
+			|| in_array( $f_extension, $this->get_exclusion_list(), true ) ) {
+			return false;
+		}

-		return ( in_array( $f_extension, $allowed_file_types ) && in_array( $f_extension, $whitelist ) && !in_array( $f_extension, $this->get_exclusion_list() ) );
+		// MIME check against actual file contents (defends against polyglots / spoofed extensions).
+		$check = wp_check_filetype_and_ext( $file['tmp_name'], $file['name'] );
+		if ( empty( $check['ext'] ) || empty( $check['type'] ) ) {
+			return false;
+		}
+
+		return true;
 	}

-    private function get_exclusion_list() {
+	private function get_exclusion_list() {
 		static $exclusionlist = false;
 		if ( ! $exclusionlist ) {
 			$exclusionlist = [
-				'php',
-				'php3',
-				'php4',
-				'php5',
-				'php6',
-				'phps',
-				'php7',
-				'phtml',
-				'shtml',
-				'pht',
-				'swf',
-				'html',
-				'asp',
-				'aspx',
-				'cmd',
-				'csh',
-				'bat',
-				'htm',
-				'hta',
-				'jar',
-				'exe',
-				'com',
-				'js',
-				'lnk',
-				'htaccess',
-				'htpasswd',
-				'phtml',
-				'ps1',
-				'ps2',
-				'py',
-				'rb',
-				'tmp',
-				'cgi',
-				'svg',
-        		'svgz'
+				'php', 'php3', 'php4', 'php5', 'php6', 'phps', 'php7', 'phtml', 'phar',
+				'shtml', 'pht', 'swf', 'html', 'htm', 'hta',
+				'asp', 'aspx', 'cmd', 'csh', 'bat', 'jar', 'exe', 'com',
+				'js', 'lnk', 'htaccess', 'htpasswd',
+				'ps1', 'ps2', 'py', 'rb', 'pl', 'tmp', 'cgi',
+				'svg', 'svgz'
 			];
 		}

 		return $exclusionlist;
 	}
+
+	/**
+	 * Drop deny-execute .htaccess and empty index.html into the uploads folder.
+	 */
+	private function harden_upload_dir( $path ) {
+		$htaccess = $path . '/.htaccess';
+		if ( ! file_exists( $htaccess ) ) {
+			$rules  = "# Royal Addons: deny script execution and listingn";
+			$rules .= "Options -Indexesn";
+			$rules .= "<IfModule mod_php.c>nphp_flag engine offn</IfModule>n";
+			$rules .= "<IfModule mod_php5.c>nphp_flag engine offn</IfModule>n";
+			$rules .= "<IfModule mod_php7.c>nphp_flag engine offn</IfModule>n";
+			$rules .= "<IfModule mod_php8.c>nphp_flag engine offn</IfModule>n";
+			$rules .= "<FilesMatch "\.(php|php3|php4|php5|php6|php7|phtml|phar|pl|py|jsp|asp|aspx|sh|cgi|svg|svgz|html?|hta|htaccess|htpasswd)$">n";
+			$rules .= "  Require all deniedn";
+			$rules .= "  <IfModule !mod_authz_core.c>n    Deny from alln  </IfModule>n";
+			$rules .= "</FilesMatch>n";
+			@file_put_contents( $htaccess, $rules );
+		}
+		$index = $path . '/index.html';
+		if ( ! file_exists( $index ) ) {
+			@file_put_contents( $index, '' );
+		}
+	}
+
+	/**
+	 * Mint a stateless, HMAC-signed upload token for a freshly rendered upload field.
+	 *
+	 * @param int    $post_id            Current post being viewed (0 if non-singular).
+	 * @param string $field_id           HTML id of the file input.
+	 * @param string $allowed_types_csv  Allowed file extensions (csv).
+	 * @param float  $max_size_mb        Per-file size cap (MB); 0 = server max.
+	 * @return string Token (payload.signature).
+	 */
+	public static function mint_upload_token( $post_id, $field_id, $allowed_types_csv = '', $max_size_mb = 0 ) {
+		$payload = [
+			'p' => (int) $post_id,
+			'f' => (string) $field_id,
+			't' => (string) $allowed_types_csv,
+			's' => (float) $max_size_mb,
+			'e' => time() + self::TOKEN_TTL,
+		];
+		$payload_b64 = self::b64url_encode( wp_json_encode( $payload ) );
+		$sig         = hash_hmac( 'sha256', $payload_b64, self::get_secret() );
+		return $payload_b64 . '.' . $sig;
+	}
+
+	public static function verify_upload_token( $token ) {
+		if ( ! is_string( $token ) || strpos( $token, '.' ) === false ) {
+			return false;
+		}
+		list( $payload_b64, $sig ) = explode( '.', $token, 2 );
+		if ( $payload_b64 === '' || $sig === '' ) {
+			return false;
+		}
+		$expected = hash_hmac( 'sha256', $payload_b64, self::get_secret() );
+		if ( ! hash_equals( $expected, $sig ) ) {
+			return false;
+		}
+		$json    = self::b64url_decode( $payload_b64 );
+		$payload = json_decode( $json, true );
+		if ( ! is_array( $payload ) || empty( $payload['e'] ) || time() > (int) $payload['e'] ) {
+			return false;
+		}
+		return $payload;
+	}
+
+	private static function get_secret() {
+		static $secret = null;
+		if ( null !== $secret ) {
+			return $secret;
+		}
+		$secret = get_option( 'wpr_upload_token_secret' );
+		if ( ! is_string( $secret ) || strlen( $secret ) < 32 ) {
+			$secret = wp_generate_password( 64, true, true );
+			update_option( 'wpr_upload_token_secret', $secret, false );
+		}
+		return $secret;
+	}
+
+	private static function b64url_encode( $data ) {
+		return rtrim( strtr( base64_encode( $data ), '+/', '-_' ), '=' );
+	}
+
+	private static function b64url_decode( $data ) {
+		$pad = strlen( $data ) % 4;
+		if ( $pad ) {
+			$data .= str_repeat( '=', 4 - $pad );
+		}
+		return base64_decode( strtr( $data, '-_', '+/' ) );
+	}
  }

- new WPR_File_Upload();
 No newline at end of file
+ new WPR_File_Upload();
--- a/royal-elementor-addons/classes/modules/wpr-woo-grid-helpers.php
+++ b/royal-elementor-addons/classes/modules/wpr-woo-grid-helpers.php
@@ -885,12 +885,206 @@
 			$src2 = '';
 		}

+		// Featured Video (plays by default over the product thumbnail)
+		$video_enabled = isset($settings['featured_video_enabled']) && 'yes' === $settings['featured_video_enabled'];
+		$video_data = $video_enabled ? self::get_featured_video_data( get_the_ID() ) : null;
+		$has_video = $video_enabled && $video_data;
+
 		if ( has_post_thumbnail() ) {
-			echo '<div class="wpr-grid-image-wrap" data-src="'. esc_url( $src ) .'"  data-img-on-hover="'. esc_attr( $settings['secondary_img_on_hover'] ) .'" data-src-secondary="'. esc_url( $src2 ) .'">';
+			echo '<div class="wpr-grid-image-wrap" data-src="'. esc_url( $src ) .'"  data-img-on-hover="'. esc_attr( $settings['secondary_img_on_hover'] ) .'" data-src-secondary="'. esc_url( $src2 ) .'" data-has-video="'. esc_attr( $has_video ? 'yes' : '' ) .'">';
 				echo '<img src="'. esc_url( $src ) .'" alt="'. esc_attr( $alt ) .'" class="wpr-anim-timing-'. esc_attr($settings[ 'image_effects_animation_timing']) .'">';
 				if ( 'yes' == $settings['secondary_img_on_hover'] ) {
 					echo '<img src="'. esc_url( $src2 ) . '" alt="'. esc_attr( $alt ) .'" class="wpr-hidden-img wpr-anim-timing-'. esc_attr($settings[ 'image_effects_animation_timing']) .'">';
 				}
+
+				if ( $has_video ) {
+					self::render_featured_video_markup( $video_data, $settings, $src );
+				}
+			echo '</div>';
+		}
+	}
+
+	/**
+	 * Build the featured video data for a given product id.
+	 * Returns null when no usable video is set.
+	 *
+	 * @param int $post_id
+	 * @return array|null { type: 'self'|'youtube'|'vimeo'|'external', url: string }
+	 */
+	public static function get_featured_video_data( $post_id ) {
+		$source = get_post_meta( $post_id, 'wpr_featured_video_source', true );
+		if ( empty( $source ) ) {
+			$source = 'upload';
+		}
+
+		$url = '';
+
+		if ( 'upload' === $source ) {
+			$video_id = absint( get_post_meta( $post_id, 'wpr_featured_video_id', true ) );
+			if ( $video_id ) {
+				$url = wp_get_attachment_url( $video_id );
+			}
+		} else {
+			$url = get_post_meta( $post_id, 'wpr_featured_video_url', true );
+		}
+
+		if ( empty( $url ) ) {
+			return null;
+		}
+
+		$type = self::detect_video_type( $url, $source );
+		if ( null === $type ) {
+			return null;
+		}
+
+		return [
+			'type' => $type,
+			'url'  => $url,
+		];
+	}
+
+	/**
+	 * Detect the video type from a URL.
+	 *
+	 * @param string $url
+	 * @param string $source 'upload' | 'url'
+	 * @return string|null 'self' | 'youtube' | 'vimeo' or null if unrecognized.
+	 */
+	public static function detect_video_type( $url, $source = 'url' ) {
+		if ( 'upload' === $source ) {
+			return 'self';
+		}
+
+		if ( preg_match( '#(youtube.com|youtu.be)#i', $url ) ) {
+			return 'youtube';
+		}
+
+		if ( preg_match( '#vimeo.com#i', $url ) ) {
+			return 'vimeo';
+		}
+
+		// Treat direct media files as self hosted.
+		if ( preg_match( '#.(mp4|webm|ogg|ogv|m4v|mov)(?.*)?$#i', $url ) ) {
+			return 'self';
+		}
+
+		return null;
+	}
+
+	/**
+	 * Extract the YouTube video id from a YouTube URL.
+	 */
+	public static function extract_youtube_id( $url ) {
+		$patterns = [
+			'#youtu.be/([A-Za-z0-9_-]{6,})#i',
+			'#youtube.com/(?:watch?.*?v=|embed/|shorts/|v/)([A-Za-z0-9_-]{6,})#i',
+		];
+		foreach ( $patterns as $pattern ) {
+			if ( preg_match( $pattern, $url, $matches ) ) {
+				return $matches[1];
+			}
+		}
+		return '';
+	}
+
+	/**
+	 * Extract the Vimeo video id from a Vimeo URL.
+	 */
+	public static function extract_vimeo_id( $url ) {
+		if ( preg_match( '#vimeo.com/(?:video/)?(d+)#i', $url, $matches ) ) {
+			return $matches[1];
+		}
+		return '';
+	}
+
+	/**
+	 * Render the featured video markup. The video is rendered on top of the
+	 * product thumbnail and plays by default (browser autoplay is only allowed
+	 * when the video is muted).
+	 *
+	 * @param array  $video    { type, url } from get_featured_video_data()
+	 * @param array  $settings Widget settings
+	 * @param string $poster   URL used as the poster frame for self-hosted videos
+	 */
+	public static function render_featured_video_markup( $video, $settings, $poster = '' ) {
+		// Videos are always muted: autoplay policies require it and a grid of
+		// products playing audio at the same time would be chaotic.
+		$loop = isset($settings['featured_video_loop']) ? 'yes' === $settings['featured_video_loop'] : true;
+
+		$wrap_attrs = [
+			'class'     => 'wpr-grid-featured-video',
+			'data-type' => $video['type'],
+			'data-url'  => $video['url'],
+			'data-loop' => $loop ? 'yes' : 'no',
+		];
+
+		$type = $video['type'];
+
+		if ( 'self' === $type || 'external' === $type ) {
+			$video_attrs = 'preload="auto" playsinline autoplay muted';
+			if ( $loop ) {
+				$video_attrs .= ' loop';
+			}
+			if ( ! empty( $poster ) ) {
+				$video_attrs .= ' poster="'. esc_url( $poster ) .'"';
+			}
+
+			echo '<div';
+			foreach ( $wrap_attrs as $key => $value ) {
+				echo ' '. esc_attr( $key ) .'="'. esc_attr( $value ) .'"';
+			}
+			echo '>';
+				echo '<video src="'. esc_url( $video['url'] ) .'" '. $video_attrs .'></video>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+			echo '</div>';
+		} elseif ( 'youtube' === $type ) {
+			$yt_id = self::extract_youtube_id( $video['url'] );
+			if ( empty( $yt_id ) ) {
+				return;
+			}
+			$wrap_attrs['data-video-id'] = $yt_id;
+
+			$yt_params = [
+				'autoplay'       => 1,
+				'mute'           => 1,
+				'controls'       => 0,
+				'modestbranding' => 1,
+				'rel'            => 0,
+				'playsinline'    => 1,
+				'loop'           => $loop ? 1 : 0,
+			];
+			if ( $loop ) {
+				$yt_params['playlist'] = $yt_id;
+			}
+			$yt_src = 'https://www.youtube.com/embed/'. rawurlencode( $yt_id ) .'?'. http_build_query( $yt_params );
+
+			echo '<div';
+			foreach ( $wrap_attrs as $key => $value ) {
+				echo ' '. esc_attr( $key ) .'="'. esc_attr( $value ) .'"';
+			}
+			echo '>';
+				echo '<iframe src="'. esc_url( $yt_src ) .'" loading="lazy" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>';
+			echo '</div>';
+		} elseif ( 'vimeo' === $type ) {
+			$vm_id = self::extract_vimeo_id( $video['url'] );
+			if ( empty( $vm_id ) ) {
+				return;
+			}
+			$wrap_attrs['data-video-id'] = $vm_id;
+
+			$vm_params = [
+				'autoplay'   => 1,
+				'muted'      => 1,
+				'background' => 1,
+				'loop'       => $loop ? 1 : 0,
+			];
+			$vm_src = 'https://player.vimeo.com/video/'. rawurlencode( $vm_id ) .'?'. http_build_query( $vm_params );
+
+			echo '<div';
+			foreach ( $wrap_attrs as $key => $value ) {
+				echo ' '. esc_attr( $key ) .'="'. esc_attr( $value ) .'"';
+			}
+			echo '>';
+				echo '<iframe src="'. esc_url( $vm_src ) .'" loading="lazy" frameborder="0" allow="autoplay" allowfullscreen></iframe>';
 			echo '</div>';
 		}
 	}
--- a/royal-elementor-addons/classes/utilities.php
+++ b/royal-elementor-addons/classes/utilities.php
@@ -516,8 +516,10 @@
 	/**
 	** Render Elementor Template
 	*/
-	public static function render_elementor_template( $slug ) {
-		$template_id = Utilities::get_template_id( $slug );
+	public static function render_elementor_template( $slug, $template_id = null ) {
+		if ( empty( $template_id ) ) {
+			$template_id = Utilities::get_template_id( $slug );
+		}
 		$type = get_post_meta(get_the_ID(), '_wpr_template_type', true) || get_post_meta($template_id, '_elementor_template_type', true);
 		$has_css = 'internal' === get_option( 'elementor_css_print_method' ) || '' !== $type;
 		$get_elementor_content = ElementorPlugin::instance()->frontend->get_builder_content_for_display( $template_id, $has_css);
@@ -543,6 +545,15 @@

 		$elementor = ElementorPlugin::instance();

+		// Ensure Elementor frontend style handle exists for nested/AJAX renders.
+		// if ( isset( $elementor->frontend ) && ! wp_style_is( 'elementor-frontend', 'registered' ) ) {
+		// 	$elementor->frontend->register_styles();
+		// }
+
+		// if ( wp_style_is( 'elementor-frontend', 'registered' ) && ! wp_style_is( 'elementor-frontend', 'enqueued' ) ) {
+		// 	wp_enqueue_style( 'elementor-frontend' );
+		// }
+
 		// Enable widget-level asset dependencies (icon fonts, widget CSS files)
 		// stored in the template's post meta by Elementor's asset system.
 		if ( class_exists( 'ElementorCoreBaseElements_Iteration_ActionsAssets' ) ) {
--- a/royal-elementor-addons/classes/woocommerce/wpr-compare-popup-action.php
+++ b/royal-elementor-addons/classes/woocommerce/wpr-compare-popup-action.php
@@ -46,6 +46,7 @@

         // Check if the page was created with Elementor
         if (ElementorPlugin::$instance->db->is_built_with_elementor($page_id)) {
+            Utilities::enqueue_inner_template_assets( $page_id );
             $content = ElementorPlugin::$instance->frontend->get_builder_content($page_id);
             wp_send_json_success(array('content' => $content, 'page_url' => get_page_link( $page_id )));
             // return new WP_REST_Response(array('content' => $content), 200);
--- a/royal-elementor-addons/extensions/wpr-column-slider.php
+++ b/royal-elementor-addons/extensions/wpr-column-slider.php
@@ -8,7 +8,7 @@
 	exit; // Exit if accessed directly.
 }

-class Wpr_Column_Slider {
+class Wpr_Column_Slider extends Wpr_Extensions_Base {
 	public function __construct() {
 		add_action( 'elementor/element/section/section_advanced/after_section_end', [ $this, 'register_controls' ], 10 );
 		add_action( 'elementor/section/print_template', array( $this, '_print_template' ), 10, 2 );
@@ -20,6 +20,135 @@
 		add_action( 'elementor/frontend/container/before_render', array( $this, '_before_render' ), 10, 1 );

 	}
+
+	private function get_slides_to_show_value( $value, $fallback = 1 ) {
+		$value = absint( $value );
+		$fallback = max( 1, absint( $fallback ) );
+
+		if ( $value < 1 ) {
+			$value = $fallback;
+		}
+
+		if ( ! $this->has_active_pro_license() ) {
+			$value = min( $value, 2 );
+		}
+
+		return $value;
+	}
+
+	private function get_slides_to_scroll_value( $value, $fallback = 1 ) {
+		$value = absint( $value );
+		$fallback = max( 1, absint( $fallback ) );
+
+		if ( $value < 1 ) {
+			$value = $fallback;
+		}
+
+		if ( ! $this->has_active_pro_license() ) {
+			$value = min( $value, 2 );
+		}
+
+		return $value;
+	}
+
+	private function add_control_slides_to_show( $element ) {
+		if ( ! $this->maybe_call_pro_method( 'WprAddonsProExtensionsWpr_Column_Slider_Pro', 'add_control_slides_to_show', [ $element ] ) ) {
+			$element->add_responsive_control(
+				'wpr_column_slider_slides_to_show',
+				[
+					'label' => esc_html__( 'Slides To Show', 'wpr-addons' ),
+					'description' => esc_html__( 'Number of slides visible at once. Free supports up to 2 slides per view.', 'wpr-addons' ),
+					'type' => Controls_Manager::NUMBER,
+					'default' => 1,
+					'min' => 1,
+					'max' => 2,
+					'condition' => [
+						'wpr_enable_column_slider' => 'yes',
+					],
+				]
+			);
+
+			$element->add_control(
+				'wpr_column_slider_slides_to_show_pro_notice',
+				[
+					'type' => Controls_Manager::RAW_HTML,
+					'raw' => 'More than 2 slides per view are available<br> in the <strong><a href="https://royal-elementor-addons.com/?ref=rea-plugin-panel-column-slider-upgrade-pro#purchasepro" target="_blank">Pro version</a></strong>',
+					'content_classes' => 'wpr-pro-notice',
+					'condition' => [
+						'wpr_enable_column_slider' => 'yes',
+					],
+				]
+			);
+		}
+	}
+
+	private function add_control_autoplay( $element ) {
+		if ( ! $this->maybe_call_pro_method( 'WprAddonsProExtensionsWpr_Column_Slider_Pro', 'add_control_autoplay', [ $element ] ) ) {
+			$element->add_control(
+				'wpr_enable_column_slider_autoplay',
+				[
+					'type' => Controls_Manager::SWITCHER,
+					'label' => sprintf( esc_html__( 'Autoplay %s', 'wpr-addons' ), '<i class="eicon-pro-icon"></i>' ),
+					'separator' => 'before',
+					'classes' => 'wpr-pro-control',
+					'condition' => [
+						'wpr_enable_column_slider' => 'yes',
+					],
+				]
+			);
+		}
+
+		$this->maybe_call_pro_method( 'WprAddonsProExtensionsWpr_Column_Slider_Pro', 'add_control_autoplay_delay', [ $element ] );
+	}
+
+	private function add_control_slides_to_scroll( $element ) {
+		if ( ! $this->maybe_call_pro_method( 'WprAddonsProExtensionsWpr_Column_Slider_Pro', 'add_control_slides_to_scroll', [ $element ] ) ) {
+			$element->add_control(
+				'wpr_column_slider_slides_to_scroll',
+				[
+					'label' => sprintf( esc_html__( 'Slides To Scroll %s', 'wpr-addons' ), '<i class="eicon-pro-icon"></i>' ),
+					'type' => Controls_Manager::NUMBER,
+					'default' => 1,
+					'min' => 1,
+					'max' => 2,
+					'classes' => 'wpr-pro-control',
+					'condition' => [
+						'wpr_enable_column_slider' => 'yes',
+					],
+				]
+			);
+		}
+	}
+
+	private function add_control_pagination_type( $element ) {
+		if ( ! $this->maybe_call_pro_method( 'WprAddonsProExtensionsWpr_Column_Slider_Pro', 'add_control_pagination_type', [ $element ] ) ) {
+			$element->add_control(
+				'wpr_cs_pag_type',
+				[
+					'label' => esc_html__( 'Pagination Type', 'wpr-addons' ),
+					'type' => Controls_Manager::SELECT,
+					'default' => 'fraction',
+					'options' => [
+						'fraction' => esc_html__( 'Fraction', 'wpr-addons' ),
+						'pro-bullets' => esc_html__( 'Bullets (Pro)', 'wpr-addons' ),
+						'pro-progressbar' => esc_html__( 'Progressbar (Pro)', 'wpr-addons' ),
+					],
+					'condition' => [
+						'wpr_enable_column_slider' => 'yes',
+						'wpr_enable_cs_pag' => 'yes',
+					],
+				]
+			);
+
+			Utilities::upgrade_pro_notice(
+				$element,
+				Controls_Manager::RAW_HTML,
+				'column-slider',
+				'wpr_cs_pag_type',
+				[ 'pro-bullets', 'pro-progressbar' ]
+			);
+		}
+	}

     public function register_controls( $element ) {

@@ -53,19 +182,7 @@
 			]
 		);

-		$element->add_responsive_control(
-			'wpr_column_slider_slides_to_show',
-			[
-				'label' => esc_html__( 'Slides To Show', 'wpr-addons' ),
-				'description' => esc_html__( 'Number of slides visible at once. Set different values per breakpoint for responsive behavior.', 'wpr-addons' ),
-				'type' => Controls_Manager::NUMBER,
-				'default' => 1,
-				'min' => 1,
-				'condition' => [
-					'wpr_enable_column_slider' => 'yes',
-				]
-			]
-		);
+		$this->add_control_slides_to_show( $element );

 		$element->add_responsive_control(
 			'wpr_column_slider_space_between',
@@ -79,6 +196,8 @@
 			]
 		);

+		$this->add_control_slides_to_scroll( $element );
+
 		$element->add_control(
 			'wpr_column_slider_speed',
 			[
@@ -445,23 +564,7 @@
 			]
 		);

-		$element->add_control(
-			'wpr_cs_pag_type',
-			[
-				'label' => esc_html__( 'Pagination Type', 'wpr-addons' ),
-				'type' => Controls_Manager::SELECT,
-				'default' => 'bullets',
-				'options' => [
-					'bullets' => esc_html__( 'Bullets', 'wpr-addons' ),
-					'fraction' => esc_html__( 'Fraction', 'wpr-addons' ),
-					'progressbar' => esc_html__( 'Progressbar', 'wpr-addons' ),
-				],
-				'condition' => [
-					'wpr_enable_column_slider' => 'yes',
-					'wpr_enable_cs_pag' => 'yes',
-				]
-			]
-		);
+		$this->add_control_pagination_type( $element );

 		$element->add_control(
 			'wpr_cs_pag_color',
@@ -619,31 +722,7 @@
 			]
 		);

-		$element->add_control (
-			'wpr_enable_column_slider_autoplay',
-			[
-				'type' => Controls_Manager::SWITCHER,
-				'label' => esc_html__( 'Autoplay', 'wpr-addons' ),
-				'render_type' => 'template',
-				'separator' => 'before',
-				'condition' => [
-					'wpr_enable_column_slider' => 'yes',
-				]
-			]
-		);
-
-		$element->add_control(
-			'wpr_column_slider_delay',
-			[
-				'label' => __( 'Delay', 'wpr-addons' ),
-				'type' => ElementorControls_Manager::NUMBER,
-				'default' => 1000,
-				'condition' => [
-					'wpr_enable_column_slider' => 'yes',
-					'wpr_enable_column_slider_autoplay' => 'yes'
-				]
-			]
-		);
+		$this->add_control_autoplay( $element );

 		$element->add_control (
 			'wpr_enable_column_slider_loop',
@@ -679,15 +758,16 @@
 			$navigation = $settings['wpr_enable_cs_nav'];
 			$pagination = $settings['wpr_enable_cs_pag'];
 			$pagination_type = isset($settings['wpr_cs_pag_type']) ? $settings['wpr_cs_pag_type'] : '';
-			$autoplay = $settings['wpr_enable_column_slider_autoplay'];
+			$autoplay = isset( $settings['wpr_enable_column_slider_autoplay'] ) ? $settings['wpr_enable_column_slider_autoplay'] : '';
 			$loop = $settings['wpr_enable_column_slider_loop'];
-			$slides_to_show = $settings['wpr_column_slider_slides_to_show'];
-			$slides_to_show_widescreen = isset($settings['wpr_column_slider_slides_to_show_widescreen']) ? $settings['wpr_column_slider_slides_to_show_widescreen'] : $slides_to_show;
-			$slides_to_show_laptop = isset($settings['wpr_column_slider_slides_to_show_laptop']) ? $settings['wpr_column_slider_slides_to_show_laptop'] : $settings['wpr_column_slider_slides_to_show'];
-			$slides_to_show_tablet_extra = isset($settings['wpr_column_slider_slides_to_show_tablet_extra']) ? $settings['wpr_column_slider_slides_to_show_tablet_extra'] : $slides_to_show_laptop;
-			$slides_to_show_tablet = isset($settings['wpr_column_slider_slides_to_show_tablet']) ? $settings['wpr_column_slider_slides_to_show_tablet'] : $slides_to_show_tablet_extra;
-			$slides_to_show_mobile_extra = isset($settings['wpr_column_slider_slides_to_show_mobile_extra']) ? $settings['wpr_column_slider_slides_to_show_mobile_extra'] : $slides_to_show_tablet;
-			$slides_to_show_mobile = isset($settings['wpr_column_slider_slides_to_show_mobile']) ? $settings['wpr_column_slider_slides_to_show_mobile'] : $slides_to_show_mobile_extra;
+			$slides_to_show = $this->get_slides_to_show_value( $settings['wpr_column_slider_slides_to_show'] );
+			$slides_to_show_widescreen = $this->get_slides_to_show_value( isset( $settings['wpr_column_slider_slides_to_show_widescreen'] ) ? $settings['wpr_column_slider_slides_to_show_widescreen'] : $slides_to_show, $slides_to_show );
+			$slides_to_show_laptop = $this->get_slides_to_show_value( isset( $settings['wpr_column_slider_slides_to_show_laptop'] ) ? $settings['wpr_column_slider_slides_to_show_laptop'] : $slides_to_show, $slides_to_show );
+			$slides_to_show_tablet_extra = $this->get_slides_to_show_value( isset( $settings['wpr_column_slider_slides_to_show_tablet_extra'] ) ? $settings['wpr_column_slider_slides_to_show_tablet_extra'] : $slides_to_show_laptop, $slides_to_show_laptop );
+			$slides_to_show_tablet = $this->get_slides_to_show_value( isset( $settings['wpr_column_slider_slides_to_show_tablet'] ) ? $settings['wpr_column_slider_slides_to_show_tablet'] : $slides_to_show_tablet_extra, $slides_to_show_tablet_extra );
+			$slides_to_show_mobile_extra = $this->get_slides_to_show_value( isset( $settings['wpr_column_slider_slides_to_show_mobile_extra'] ) ? $settings['wpr_column_slider_slides_to_show_mobile_extra'] : $slides_to_show_tablet, $slides_to_show_tablet );
+			$slides_to_show_mobile = $this->get_slides_to_show_value( isset( $settings['wpr_column_slider_slides_to_show_mobile'] ) ? $settings['wpr_column_slider_slides_to_show_mobile'] : $slides_to_show_mobile_extra, $slides_to_show_mobile_extra );
+			$slides_to_scroll = $this->get_slides_to_scroll_value( isset( $settings['wpr_column_slider_slides_to_scroll'] ) ? $settings['wpr_column_slider_slides_to_scroll'] : 1 );
 			$space_between = $settings['wpr_column_slider_space_between'];
 			$space_between_widescreen = isset($settings['wpr_column_slider_space_between_widescreen']) ? $settings['wpr_column_slider_space_between_widescreen'] : $space_between;
 			$space_between_laptop = isset($settings['wpr_column_slider_space_between_laptop']) ? $settings['wpr_column_slider_space_between_laptop'] : $space_between;
@@ -698,7 +778,16 @@
 			$delay = isset($settings['wpr_column_slider_delay']) ? $settings['wpr_column_slider_delay'] : '';
 			$speed = $settings['wpr_column_slider_speed'];

-			$column_slider_settings = array(
+			if ( ! $this->has_active_pro_license() ) {
+				$autoplay = '';
+				$delay = '';
+
+				if ( in_array( $pagination_type, [ 'bullets', 'progressbar', 'pro-bullets', 'pro-progressbar' ], true ) ) {
+					$pagination_type = 'fraction';
+				}
+			}
+
+			$column_slider_settings = [
 				'wpr_cs_navigation' => $navigation,
 				'wpr_cs_pagination' => $pagination,
 				'wpr_cs_pagination_type' => $pagination_type,
@@ -711,6 +800,7 @@
 				'wpr_cs_slides_to_show_tablet' => $slides_to_show_tablet,
 				'wpr_cs_slides_to_show_mobile_extra' => $slides_to_show_mobile_extra,
 				'wpr_cs_slides_to_show_mobile' => $slides_to_show_mobile,
+				'wpr_cs_slides_to_scroll' => $slides_to_scroll,
 				'wpr_cs_space_between' => $space_between,
 				'wpr_cs_space_between_widescreen' => $space_between_widescreen,
 				'wpr_cs_space_between_laptop' => $space_between_laptop,
@@ -721,7 +811,7 @@
 				'wpr_cs_delay' => $delay,
 				'wpr_cs_speed' => $speed,
 				// 'enable_on'   => $settings['wpr_enable_equal_height_on'],
-			);
+			];

 			if ( 'yes' === $settings['wpr_enable_cs_nav'] ) {
 				echo '<div class="wpr-column-slider-navigation">';
@@ -743,20 +833,40 @@

 		?>
 		<# if( 'yes' === settings.wpr_enable_column_slider ) {
+			var hasProColumnSlider = <?php echo $this->has_active_pro_license() ? 'true' : 'false'; ?>;
+			var getSlidesToShowValue = function( value, fallback ) {
+				var parsedValue = parseInt( value, 10 );
+				var parsedFallback = parseInt( fallback, 10 );
+
+				if ( isNaN( parsedFallback ) || parsedFallback < 1 ) {
+					parsedFallback = 1;
+				}
+
+				if ( isNaN( parsedValue ) || parsedValue < 1 ) {
+					parsedValue = parsedFallback;
+				}
+
+				if ( ! hasProColumnSlider ) {
+					parsedValue = Math.min( parsedValue, 2 );
+				}
+
+				return parsedValue;
+			};

 			<!-- view.addRenderAttribute( 'wpr_column_slider', 'id', 'wpr-column-slider-' + view.getID() ); -->
 			var navigation = settings.wpr_enable_cs_nav;
 			var pagination = settings.wpr_enable_cs_pag;
 			var pagination_type = settings.wpr_cs_pag_type ? settings.wpr_cs_pag_type : '';
-			var autoplay = settings.wpr_enable_column_slider_autoplay;
+			var autoplay = hasProColumnSlider ? settings.wpr_enable_column_slider_autoplay : '';
 			var loop = settings.wpr_enable_column_slider_loop;
-			var slides_to_show = settings.wpr_column_slider_slides_to_show;
-			var slides_to_show_widescreen = settings.wpr_column_slider_slides_to_show_widescreen ? settings.wpr_column_slider_slides_to_show_widescreen : slides_to_show;
-			var slides_to_show_laptop = settings.wpr_column_slider_slides_to_show_laptop ? settings.wpr_column_slider_slides_to_show_laptop : slides_to_show;
-			var slides_to_show_tablet_extra = settings.wpr_column_slider_slides_to_show_tablet_extra ? settings.wpr_column_slider_slides_to_show_tablet_extra : slides_to_show_laptop;
-			var slides_to_show_tablet = settings.wpr_column_slider_slides_to_show_tablet ? settings.wpr_column_slider_slides_to_show_tablet : slides_to_show_tablet_extra;
-			var slides_to_show_mobile_extra = settings.wpr_column_slider_slides_to_show_mobile_extra ? settings.wpr_column_slider_slides_to_show_mobile_extra : slides_to_show_tablet ;
-			var slides_to_show_mobile = settings.wpr_column_slider_slides_to_show_mobile ? settings.wpr_column_slider_slides_to_show_mobile : slides_to_show_mobile_extra;
+			var slides_to_show = getSlidesToShowValue( settings.wpr_column_slider_slides_to_show, 1 );
+			var slides_to_show_widescreen = getSlidesToShowValue( settings.wpr_column_slider_slides_to_show_widescreen, slides_to_show );
+			var slides_to_show_laptop = getSlidesToShowValue( settings.wpr_column_

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