Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- 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_