Plugin Directory

Changeset 3380762


Ignore:
Timestamp:
10/19/2025 10:40:44 AM (4 months ago)
Author:
veelo
Message:

Update to version 1.5.8 from GitHub

Location:
popup-for-elementor
Files:
8 edited
1 copied

Legend:

Unmodified
Added
Removed
  • popup-for-elementor/tags/1.5.8/assets/popup-widget.js

    r3300275 r3380762  
    55        const cookieExpiry = parseInt(config.cookieExpiry, 10) || 7;
    66        const delayInMilliseconds = parseInt(config.delay, 10) || 0;
     7        const isSelectorMode = (config.triggerBySelector === 'yes' && config.triggerSelector && config.triggerSelector.trim() !== '');
     8
    79        let isClosing = false;
    8 
     10        let popupOpenedAt = 0;   // marca de última apertura (ms)
     11        let lastExitTs = 0;      // anti-rebote de exit-intent (ms)
     12        const EXIT_COOLDOWN_MS = 1200;
     13       
    914        const $popupOverlay = $('.popup-overlay');
    1015        const $popupContent = $popupOverlay.find('.popup-content');
     
    4449
    4550            console.log("Showing popup.");
     51            popupOpenedAt = Date.now();
    4652            $popupOverlay.css({
    4753                display: 'flex',
     
    5965        function closePopup() {
    6066            console.log("Attempting to close popup...");
     67       
     68            if (popupOpenedAt && (Date.now() - popupOpenedAt) < 250) {
     69                console.log("Close ignored due to debounce after open.");
     70                return;
     71            }
     72       
    6173            if (isClosing) {
    6274                console.log("Popup is already closing. Aborting.");
    6375                return;
    6476            }
    65 
     77       
    6678            isClosing = true;
    6779            console.log("Closing popup...");
    68 
     80       
     81            let handled = false;
    6982            $popupContent
    70                 .removeClass('animate__fadeIn')
    71                 .addClass('animate__fadeOut')
    72                 .one('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function () {
     83                .removeClass('animate__fadeIn')
     84                .addClass('animate__fadeOut')
     85                .one('animationend', function (e) {
     86                    if (handled) return;
     87                    if (e.target !== this) return;
     88                    handled = true;
     89       
    7390                    console.log("Fade-out animation ended. Hiding popup.");
    7491                    $popupOverlay.css({
     
    7794                        opacity: 0,
    7895                    });
    79                     $popupContent.removeClass('animate__fadeOut'); 
    80                     isClosing = false; 
     96                    $popupContent.removeClass('animate__fadeOut');
     97                    isClosing = false;
    8198                    console.log("Popup closed successfully.");
    8299                });
    83 
     100       
    84101            setTimeout(() => {
    85                 if (isClosing) {
     102                if (!handled) {
    86103                    console.warn("Fallback triggered: Forcing popup closure.");
     104                    handled = true;
    87105                    $popupOverlay.css({
    88106                        display: 'none',
     
    91109                    });
    92110                    $popupContent.removeClass('animate__fadeOut');
    93                     isClosing = false;
    94                 }
    95             }, 500);
    96         }
     111                    isClosing = false;
     112                }
     113            }, 700);
     114        }
     115       
    97116
    98117        function handlePopupDisplay() {
     
    122141        if (config.exitIntent === 'yes') {
    123142            console.log("IntentExit habilitado.");
     143       
    124144            $(document).on('mouseleave', function (e) {
    125                 console.log(`Intento de salida detectado: clientY = ${e.clientY}`);
    126                 if (e.clientY < 0) {
     145                const now = Date.now();
     146                const nearTop = (e.clientY <= 0 || e.clientY <= 20);
     147                const leavingWindow = (e.relatedTarget === null);
     148       
     149                console.log(`Intento de salida: clientY=${e.clientY}, nearTop=${nearTop}, leaving=${leavingWindow}`);
     150       
     151                if (config.exitIntentDisplayMode === 'once' && getCookie(cookieName)) {
     152                    console.log('ExitIntent en modo "once" y cookie presente. No se muestra.');
     153                    return;
     154                }
     155       
     156                if (isClosing || (popupOpenedAt && (now - popupOpenedAt) < 250)) {
     157                    console.log('Ignorado: está cerrando o se acaba de abrir.');
     158                    return;
     159                }
     160       
     161                if (now - lastExitTs < EXIT_COOLDOWN_MS) {
     162                    console.log('Cooldown activo. Ignorando ExitIntent repetido.');
     163                    return;
     164                }
     165       
     166                if (nearTop || leavingWindow) {
     167                    lastExitTs = now;
    127168                    console.log("Mostrando popup por IntentExit.");
    128169                    showPopup();
     170       
     171                    if (config.exitIntentDisplayMode === 'once') {
     172                        setCookie(cookieName, 'true', cookieExpiry);
     173                        console.log(`Cookie "${cookieName}" marcada por ExitIntent durante ${cookieExpiry} días.`);
     174                    }
    129175                }
    130176            });
     
    132178            console.log("IntentExit no habilitado.");
    133179        }
    134         if (config.showOnScroll === 'yes') {
    135             console.log(`On Scroll habilitado. Porcentaje configurado: ${config.scrollPercentage}%`);
    136 
    137             let scrollTriggered = false;
    138 
    139             $(window).on('scroll', function () {
    140                 if (scrollTriggered) return;
    141 
    142                 const scrollTop = $(window).scrollTop();
    143                 const windowHeight = $(window).height();
    144                 const documentHeight = $(document).height();
    145                 const scrolledPercentage = (scrollTop / (documentHeight - windowHeight)) * 100;
    146 
    147                 if (scrolledPercentage >= config.scrollPercentage) {
    148                     console.log(`Porcentaje de scroll alcanzado: ${scrolledPercentage.toFixed(2)}%`);
    149                     showPopup();
    150                     scrollTriggered = true;
    151                     $(window).off('scroll');
    152                 }
    153             });
    154         } else {
    155             console.log("On Scroll no habilitado.");
    156         }
     180
    157181
    158182        $popupOverlay.on('click', function (e) {
     
    170194        });
    171195
    172         handlePopupDisplay();
    173     });
    174 })(jQuery);
     196        if (isSelectorMode) {
     197            const raw = config.triggerSelector.trim();
     198            const selector = /^[.#]/.test(raw) ? raw : ('.' + raw);
     199            $(document).off('click.popupfeSelector');
     200            console.log('[PopupFE] Trigger por selector activo →', selector, '| matches:', document.querySelectorAll(selector).length);
     201            $(document).on('click.popupfeSelector', selector, function(e){
     202              if ($popupOverlay.is(':visible') || isClosing) return;
     203              showPopup();
     204            });
     205          }
     206
     207   
     208            handlePopupDisplay();
     209        });
     210    })(jQuery);
     211   
  • popup-for-elementor/tags/1.5.8/includes/editor-options.php

    r3300275 r3380762  
    11<?php
    2 // Adds options to Elementor editor for configuring the popup
    3 if ( ! defined( 'ABSPATH' ) ) {
    4     exit; // Exit if accessed directly
     2// File: popup-handler.php
     3// Dynamically passes configuration from Elementor controls to the JavaScript.
     4
     5if (!defined('ABSPATH')) {
     6    exit;
    57}
    6 class Popupfe_Popup_Widget extends \Elementor\Widget_Base
     8function popup_for_elementor_register_assets()
    79{
    8     public function get_name()
    9     {
    10         return "popup_widget";
    11     }
    12     public function get_title()
    13     {
    14         return esc_html__("Popup Widget", "popup-for-elementor");
    15     }
     10    if (!is_admin()) {
     11        wp_register_script(
     12            'popup-widget-js',
     13            plugin_dir_url(__FILE__) . '../assets/popup-widget.js',
     14            array('jquery'),
     15            '1.0.0',
     16            true
     17        );
     18        $post_id = get_the_ID();
    1619
    17     public function get_categories()
    18     {
    19         return ["basic"];
    20     }
    21     public function get_icon() {
    22         return 'eicon-table-of-contents';
    23           }
    24 
    25     protected function _register_controls()
    26     {
    27         // Content controls
    28         $this->start_controls_section("content_section", [
    29             "label" => esc_html__("Content", "popup-for-elementor"),
    30             "tab" => \Elementor\Controls_Manager::TAB_CONTENT,
    31         ]);
    32 
    33         $templates = [];
    34         if (class_exists("\Elementor\Plugin")) {
    35             $template_manager = \Elementor\Plugin::instance()->templates_manager->get_source(
    36                 "local"
     20        if ($post_id) {
     21            $dynamic_config = array(
     22                'showOnLoad'           => get_post_meta($post_id, '_elementor_popup_show_on_load', true) ?: 'no',
     23                'delay'                => (int) get_post_meta($post_id, '_elementor_popup_delay', true) ?: 0,
     24                'showOnScroll'         => get_post_meta($post_id, '_elementor_popup_show_on_scroll', true) === 'yes',
     25                'scrollPercentage'     => (int) (get_post_meta($post_id, '_elementor_popup_scroll_percentage', true) ?: 50),
     26                'exitIntent'           => get_post_meta($post_id, '_elementor_popup_exit_intent', true) === 'yes',
     27                'exitIntentDisplayMode'=> get_post_meta($post_id, '_elementor_exit_intent_display_mode', true) ?: 'always',
     28                'cookieName'           => 'popup_seen',
     29                'cookieExpiry'         => 7,
     30                'triggerBySelector' => get_post_meta($post_id, '_elementor_trigger_selector_enabled', true) === 'yes',
     31                'triggerSelector'   => get_post_meta($post_id, '_elementor_trigger_selector', true) ?: '',
     32               
    3733            );
    38             $templates_raw = $template_manager
    39                 ? $template_manager->get_items()
    40                 : [];
    41             foreach ($templates_raw as $template) {
    42                 $templates[$template["template_id"]] = $template["title"];
    43             }
     34           
     35            wp_localize_script(
     36                'popup-widget-js',
     37                'PopupForElementorConfig',
     38                $dynamic_config
     39            );
    4440        }
    45 
    46         $this->add_control("template_id", [
    47             "label" => esc_html__("Select Template", "popup-for-elementor"),
    48             "type" => \Elementor\Controls_Manager::SELECT2, // Cambiado a SELECT2
    49             "options" => $templates, // Asegúrate de que $templates tiene las opciones disponibles
    50             "default" => "",
    51             "description" => esc_html__(
    52                 "Choose a template from your Elementor library.",
    53                 "popup-for-elementor"
    54             ),
    55         ]);
    56 
    57         $this->add_control("template_create_link", [
    58             "type" => \Elementor\Controls_Manager::RAW_HTML,
    59             "raw" => sprintf(
    60                 '<a href="%s" target="_blank" class="elementor-button elementor-button-success" style="margin-top: 10px;">%s</a>',
    61                 admin_url("edit.php?post_type=elementor_library"),
    62                 esc_html__("Create New Template", "popup-for-elementor")
    63             ),
    64             "content_classes" => "elementor-control-field",
    65         ]);
    66 
    67         $this->add_control("upgrade_to_pro_notice1", [
    68             "type" => \Elementor\Controls_Manager::RAW_HTML,
    69             "raw" => sprintf(
    70                 '<div style="margin-top: 20px; padding: 24px; background: linear-gradient(135deg, #1e1e1e, #2b2b2b); border: 1px solid #3c3c3c; border-radius: 8px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.2);">
    71                     <strong style="display: block; color: #ffffff; font-size: 14px; font-weight: 300; margin-bottom: 12px;">%s</strong>
    72                     <a href="%s" target="_blank" style="display: inline-block; padding: 10px 20px; background-color: #d33a92; color: #fff; border-radius: 4px; text-decoration: none; font-weight: 600; transition: background-color 0.3s;">
    73                         %s
    74                     </a>
    75                 </div>',
    76                 esc_html__("Need more triggers like Scroll, OnClick, or AdBlock detection?", "popup-for-elementor"),
    77                 "https://popupforelementor.com/en/home/#buy",
    78                 esc_html__("Get Popup for Elementor Pro", "popup-for-elementor")
    79             ),
    80             "content_classes" => "elementor-control-field",
    81         ]);
    82 
    83         $this->end_controls_section();
    84 
    85         // Style controls
    86         $this->start_controls_section("style_section", [
    87             "label" => esc_html__("Popup window", "popup-for-elementor"),
    88             "tab" => \Elementor\Controls_Manager::TAB_STYLE,
    89         ]);
    90         $this->add_responsive_control(
    91             'popup_background',
    92             [
    93                 'label' => esc_html__('Background Color', 'popup-for-elementor'),
    94                 'type' => \Elementor\Controls_Manager::COLOR,
    95                 'selectors' => [
    96                     '{{WRAPPER}} .popup-content' => 'background-color: {{VALUE}};',
    97                 ],
    98             ]
    99         );
    100 
    101         $this->add_control("overlay_color", [
    102             "label" => esc_html__("Overlay Color", "popup-for-elementor"),
    103             "type" => \Elementor\Controls_Manager::COLOR,
    104             "default" => "rgba(0, 0, 0, 0.5)",
    105             "selectors" => [
    106                 "{{WRAPPER}} .popup-overlay" => "background-color: {{VALUE}};",
    107             ],
    108         ]);
    109 
    110         $this->add_control("border_radius", [
    111             "label" => esc_html__("Border Radius", "popup-for-elementor"),
    112             "type" => \Elementor\Controls_Manager::SLIDER,
    113             "default" => [
    114                 "size" => 10,
    115             ],
    116             "selectors" => [
    117                 "{{WRAPPER}} .popup-content" =>
    118                     "border-radius: {{SIZE}}{{UNIT}};",
    119             ],
    120         ]);
    121 
    122         $this->add_group_control(
    123             \Elementor\Group_Control_Box_Shadow::get_type(),
    124             [
    125                 "name" => "popup_box_shadow",
    126                 "label" => esc_html__("Box Shadow", "popup-for-elementor"),
    127                 "selector" => "{{WRAPPER}} .popup-content",
    128                 "description" => esc_html__(
    129                     "Configure the shadow settings directly.",
    130                     "popup-for-elementor"
    131                 ),
    132             ]
    133         );
    134 
    135         $this->add_responsive_control("popup_width", [
    136             "label" => esc_html__("Popup Width", "popup-for-elementor"),
    137             "type" => \Elementor\Controls_Manager::SELECT,
    138             "default" => "400px",
    139             "options" => [
    140                 "auto" => esc_html__("Auto (Fit Content)", "popup-for-elementor"),
    141                 "custom" => esc_html__("Custom", "popup-for-elementor"),
    142             ],
    143             "selectors" => [
    144                 "{{WRAPPER}} .popup-content" => "width: {{VALUE}};",
    145             ],
    146         ]);
    147        
    148         $this->add_responsive_control("custom_popup_width", [
    149             "label" => esc_html__("Custom Width", "popup-for-elementor"),
    150             "type" => \Elementor\Controls_Manager::SLIDER,
    151             "default" => [
    152                 "size" => 400,
    153                 "unit" => "px",
    154             ],
    155             "size_units" => ["px", "%", "vw"],
    156             "range" => [
    157                 "px" => [
    158                     "min" => 100,
    159                     "max" => 2000,
    160                     "step" => 10,
    161                 ],
    162                 "%" => [
    163                     "min" => 1,
    164                     "max" => 100,
    165                 ],
    166                 "vw" => [
    167                     "min" => 1,
    168                     "max" => 100,
    169                 ],
    170             ],
    171             "condition" => [
    172                 "popup_width" => "custom",
    173             ],
    174             "selectors" => [
    175                 "{{WRAPPER}} .popup-content" => "width: {{SIZE}}{{UNIT}};",
    176             ],
    177         ]);
    178        
    179 
    180         $this->add_responsive_control("popup_height", [
    181             "label" => esc_html__("Popup Height", "popup-for-elementor"),
    182             "type" => \Elementor\Controls_Manager::SELECT,
    183             "default" => "auto",
    184             "options" => [
    185                 "auto" => esc_html__("Auto (Fit Content)", "popup-for-elementor"),
    186                 "custom" => esc_html__("Custom", "popup-for-elementor"),
    187             ],
    188             "selectors" => [
    189                 "{{WRAPPER}} .popup-content" => "height: {{VALUE}};",
    190             ],
    191         ]);
    192        
    193         $this->add_responsive_control("custom_popup_height", [
    194             "label" => esc_html__("Custom Height", "popup-for-elementor"),
    195             "type" => \Elementor\Controls_Manager::SLIDER,
    196             "default" => [
    197                 "size" => 400,
    198                 "unit" => "px",
    199             ],
    200             "size_units" => ["px", "%", "vh"],
    201             "range" => [
    202                 "px" => [
    203                     "min" => 100,
    204                     "max" => 2000,
    205                     "step" => 10,
    206                 ],
    207                 "%" => [
    208                     "min" => 1,
    209                     "max" => 100,
    210                 ],
    211                 "vh" => [
    212                     "min" => 1,
    213                     "max" => 100,
    214                 ],
    215             ],
    216             "condition" => [
    217                 "popup_height" => "custom",
    218             ],
    219             "selectors" => [
    220                 "{{WRAPPER}} .popup-content" => "height: {{SIZE}}{{UNIT}};",
    221             ],
    222         ]);
    223        
    224 
    225 
    226         $this->add_responsive_control("horizontal_position", [
    227             "label" => esc_html__("Horizontal Position", "popup-for-elementor"),
    228             "type" => \Elementor\Controls_Manager::CHOOSE,
    229             "options" => [
    230                 "flex-start" => [
    231                     "title" => esc_html__("Left", "popup-for-elementor"),
    232                     "icon" => "eicon-h-align-left",
    233                 ],
    234                 "center" => [
    235                     "title" => esc_html__("Center", "popup-for-elementor"),
    236                     "icon" => "eicon-h-align-center",
    237                 ],
    238                 "flex-end" => [
    239                     "title" => esc_html__("Right", "popup-for-elementor"),
    240                     "icon" => "eicon-h-align-right",
    241                 ],
    242             ],
    243             "default" => "center",
    244             "selectors" => [
    245                 "{{WRAPPER}} .popup-overlay" => "justify-content: {{VALUE}};",
    246             ],
    247         ]);
    248 
    249         $this->add_responsive_control("vertical_position", [
    250             "label" => esc_html__("Vertical Position", "popup-for-elementor"),
    251             "type" => \Elementor\Controls_Manager::CHOOSE,
    252             "options" => [
    253                 "flex-start" => [
    254                     "title" => esc_html__("Top", "popup-for-elementor"),
    255                     "icon" => "eicon-v-align-top",
    256                 ],
    257                 "center" => [
    258                     "title" => esc_html__("Center", "popup-for-elementor"),
    259                     "icon" => "eicon-v-align-middle",
    260                 ],
    261                 "flex-end" => [
    262                     "title" => esc_html__("Bottom", "popup-for-elementor"),
    263                     "icon" => "eicon-v-align-bottom",
    264                 ],
    265             ],
    266             "default" => "center",
    267             "selectors" => [
    268                 "{{WRAPPER}} .popup-overlay" => "align-items: {{VALUE}};",
    269             ],
    270         ]);
    271 
    272         // Control para el margen (Responsive)
    273         $this->add_responsive_control(
    274             'popup_margin',
    275             [
    276                 'label' => esc_html__('Margin', 'popup-for-elementor'),
    277                 'type' => \Elementor\Controls_Manager::DIMENSIONS,
    278                 'size_units' => ['px', '%', 'em'],
    279                 'selectors' => [
    280                     '{{WRAPPER}} .popup-content' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
    281                 ],
    282             ]
    283         );
    284 
    285         // Control para el padding (Responsive)
    286         $this->add_responsive_control(
    287             'popup_padding',
    288             [
    289                 'label' => esc_html__('Padding', 'popup-for-elementor'),
    290                 'type' => \Elementor\Controls_Manager::DIMENSIONS,
    291                 'size_units' => ['px', '%', 'em'],
    292                 'selectors' => [
    293                     '{{WRAPPER}} .popup-content' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
    294                 ],
    295             ]
    296         );
    297 
    298 
    299         $this->end_controls_section();
    300 
    301         // Animation
    302 
    303         $this->start_controls_section("animation_section_custom", [
    304             "label" => esc_html__("Animation", "popup-for-elementor"),
    305             "tab" => \Elementor\Controls_Manager::TAB_STYLE, // Colocamos esta sección en la pestaña de estilo
    306         ]);
    307 
    308         $this->add_control("popup_animation_in", [
    309             "label" => esc_html__("Entrance Animation", "popup-for-elementor"),
    310             "type" => \Elementor\Controls_Manager::SELECT,
    311             "options" => [
    312                 "none" => esc_html__("None", "popup-for-elementor"),
    313                 "animate__fadeIn" => esc_html__("Fade In", "popup-for-elementor"),
    314                 "animate__fadeInUp" => esc_html__("Fade In Up", "popup-for-elementor"),
    315                 "anixmate__fadeInDown" => esc_html__("Fade In Down", "popup-for-elementor"),
    316                 "animate__fadeInLeft" => esc_html__("Fade In Left", "popup-for-elementor"),
    317                 "animate__fadeInRight" => esc_html__("Fade In Right", "popup-for-elementor"),
    318                 "animate__zoomIn" => esc_html__("Zoom In", "popup-for-elementor"),
    319                 "animate__slideInUp" => esc_html__("Slide In Up", "popup-for-elementor"),
    320                 "animate__slideInDown" => esc_html__("Slide In Down", "popup-for-elementor"),
    321                 "animate__slideInLeft" => esc_html__("Slide In Left", "popup-for-elementor"),
    322                 "animate__slideInRight" => esc_html__("Slide In Right", "popup-for-elementor"),
    323             ],
    324             "default" => "animate__fadeIn",
    325             "description" => esc_html__(
    326                 "Choose an animation for the popup to appear.",
    327                 "popup-for-elementor"
    328             ),
    329         ]);
    330 
    331         $this->add_control("popup_animation_out", [
    332             "label" => esc_html__("Exit Animation", "popup-for-elementor"),
    333             "type" => \Elementor\Controls_Manager::SELECT,
    334             "options" => [
    335                 "none" => esc_html__("None", "popup-for-elementor"),
    336                 "animate__fadeOut" => esc_html__("Fade Out", "popup-for-elementor"),
    337                 "animate__fadeOutUp" => esc_html__("Fade Out Up", "popup-for-elementor"),
    338                 "animate__fadeOutDown" => esc_html__("Fade Out Down", "popup-for-elementor"),
    339                 "animate__fadeOutLeft" => esc_html__("Fade Out Left", "popup-for-elementor"),
    340                 "animate__fadeOutRight" => esc_html__("Fade Out Right", "popup-for-elementor"),
    341                 "animate__zoomOut" => esc_html__("Zoom Out", "popup-for-elementor"),
    342                 "animate__slideOutUp" => esc_html__("Slide Out Up", "popup-for-elementor"),
    343                 "animate__slideOutDown" => esc_html__("Slide Out Down", "popup-for-elementor"),
    344                 "animate__slideOutLeft" => esc_html__("Slide Out Left", "popup-for-elementor"),
    345                 "animate__slideOutRight" => esc_html__(
    346                     "Slide Out Right",
    347                     "popup-for-elementor"
    348                 ),
    349             ],
    350             "default" => "animate__fadeOut",
    351             "description" => esc_html__(
    352                 "Choose an animation for the popup to disappear.",
    353                 "popup-for-elementor"
    354             ),
    355         ]);
    356 
    357         $this->add_control("animation_duration_custom", [
    358             "label" => esc_html__("Animation Duration (ms)", "popup-for-elementor"),
    359             "type" => \Elementor\Controls_Manager::SLIDER,
    360             "size_units" => ["ms"],
    361             "range" => [
    362                 "ms" => [
    363                     "min" => 100,
    364                     "max" => 3000,
    365                     "step" => 100,
    366                 ],
    367             ],
    368             "default" => [
    369                 "size" => 500,
    370                 "unit" => "ms",
    371             ],
    372             "selectors" => [
    373                 "{{WRAPPER}} .popup-content" =>
    374                     "animation-duration: {{SIZE}}{{UNIT}};",
    375             ],
    376         ]);
    377 
    378         $this->end_controls_section();
    379         //Close Button
    380 
    381         $this->start_controls_section("close_button_section", [
    382             "label" => esc_html__("Close Button", "popup-for-elementor"),
    383             "tab" => \Elementor\Controls_Manager::TAB_STYLE,
    384         ]);
    385         $this->add_control("hide_close_button", [
    386             "label" => esc_html__("Hide Close Button", "popup-for-elementor"),
    387             "type" => \Elementor\Controls_Manager::SWITCHER,
    388             "label_on" => esc_html__("Yes", "popup-for-elementor"),
    389             "label_off" => esc_html__("No", "popup-for-elementor"),
    390             "return_value" => "yes",
    391             "default" => "no",
    392             "selectors" => [
    393                 "{{WRAPPER}} .popup-close" => "display: none;",
    394             ],
    395         ]);
    396        
    397         $this->add_control("close_button_background_color", [
    398             "label" => esc_html__("Close Button Background", "popup-for-elementor"),
    399             "type" => \Elementor\Controls_Manager::COLOR,
    400             "selectors" => [
    401                 "{{WRAPPER}} .popup-close" => "background-color: {{VALUE}};",
    402             ],
    403         ]);
    404 
    405         $this->add_control("close_button_hover_background_color", [
    406             "label" => esc_html__("Close Button Hover Background", "popup-for-elementor"),
    407             "type" => \Elementor\Controls_Manager::COLOR,
    408             "selectors" => [
    409                 "{{WRAPPER}} .popup-close:hover" =>
    410                     "background-color: {{VALUE}};",
    411             ],
    412         ]);
    413 
    414         $this->add_control("close_button_color", [
    415             "label" => esc_html__("Close Button Color", "popup-for-elementor"),
    416             "type" => \Elementor\Controls_Manager::COLOR,
    417             "selectors" => [
    418                 "{{WRAPPER}} .popup-close" => "color: {{VALUE}};",
    419             ],
    420         ]);
    421 
    422         $this->add_control("close_button_hover_color", [
    423             "label" => esc_html__("Close Button Hover Color", "popup-for-elementor"),
    424             "type" => \Elementor\Controls_Manager::COLOR,
    425             "selectors" => [
    426                 "{{WRAPPER}} .popup-close:hover" => "color: {{VALUE}};",
    427             ],
    428         ]);
    429 
    430         $this->add_control("close_button_size", [
    431             "label" => esc_html__("Close Button Size", "popup-for-elementor"),
    432             "type" => \Elementor\Controls_Manager::SLIDER,
    433             "size_units" => ["px"], // Solo permite px
    434             "range" => [
    435                 "px" => [
    436                     "min" => 10,
    437                     "max" => 100,
    438                 ],
    439             ],
    440             "default" => [
    441                 "unit" => "px",
    442                 "size" => 40, // Tamaño por defecto del botón de cerrar
    443             ],
    444             "selectors" => [
    445                 "{{WRAPPER}} .popup-close" =>
    446                     "width: {{SIZE}}{{UNIT}}; height: {{SIZE}}{{UNIT}}; font-size: calc({{SIZE}}{{UNIT}} / 2);",
    447             ],
    448             "description" => esc_html__(
    449                 "Adjust the size of the close button.",
    450                 "popup-for-elementor"
    451             ),
    452         ]);
    453         $this->add_control("close_button_alignment", [
    454             "label" => esc_html__("Close Button Alignment", "popup-for-elementor"),
    455             "type" => \Elementor\Controls_Manager::CHOOSE,
    456             "options" => [
    457                 "left" => [
    458                     "title" => esc_html__("Left", "popup-for-elementor"),
    459                     "icon" => "eicon-h-align-left",
    460                 ],
    461                 "right" => [
    462                     "title" => esc_html__("Right", "popup-for-elementor"),
    463                     "icon" => "eicon-h-align-right",
    464                 ],
    465             ],
    466             "default" => "right",
    467             "selectors" => [
    468                 "{{WRAPPER}} .popup-close" => "{{VALUE}}: 10px;",
    469             ],
    470             "description" => esc_html__(
    471                 "Align the close button to the left or right.",
    472                 "popup-for-elementor"
    473             ),
    474         ]);
    475 
    476         $this->add_control("close_button_border_radius", [
    477             "label" => esc_html__("Close Button Border Radius", "popup-for-elementor"),
    478             "type" => \Elementor\Controls_Manager::SLIDER,
    479             "size_units" => ["px"], // Solo permite px
    480             "range" => [
    481                 "px" => [
    482                     "min" => 0,
    483                     "max" => 50,
    484                 ],
    485             ],
    486             "selectors" => [
    487                 "{{WRAPPER}} .popup-close" =>
    488                     "border-radius: {{SIZE}}{{UNIT}};",
    489             ],
    490             "description" => esc_html__(
    491                 "Controls the border radius of the close button.",
    492                 "popup-for-elementor"
    493             ),
    494         ]);
    495 
    496         $this->end_controls_section();
    497 
    498         // Visibility controls
    499 $this->start_controls_section("visibility_section", [
    500     "label" => esc_html__("Visibility", "popup-for-elementor"),
    501     "tab" => \Elementor\Controls_Manager::TAB_CONTENT,
    502 ]);
    503 
    504 $this->add_control("show_on_load", [
    505     "label" => esc_html__("Show on Page Load", "popup-for-elementor"),
    506     "type" => \Elementor\Controls_Manager::SWITCHER,
    507     "default" => "",
    508     "description" => esc_html__("Activate to show popup when the page loads. Will disable other visibility options.", "popup-for-elementor"),
    509     "condition" => [
    510         "show_after_delay_enabled!" => "yes",
    511         "show_on_exit_intent!" => "yes",
    512         "show_once!" => "yes",
    513     ],
    514 ]);
    515 
    516 $this->add_control("show_after_delay_enabled", [
    517     "label" => esc_html__("Enable Show After Delay", "popup-for-elementor"),
    518     "type" => \Elementor\Controls_Manager::SWITCHER,
    519     "default" => "",
    520     "description" => esc_html__("Activate to show popup after a delay. Will disable other visibility options.", "popup-for-elementor"),
    521     "condition" => [
    522         "show_on_load!" => "yes",
    523         "show_on_exit_intent!" => "yes",
    524         "show_once!" => "yes",
    525     ],
    526 ]);
    527 
    528 $this->add_control("show_after_delay", [
    529     "label" => esc_html__("Delay (seconds)", "popup-for-elementor"),
    530     "type" => \Elementor\Controls_Manager::NUMBER,
    531     "default" => 3,
    532     "condition" => [
    533         "show_after_delay_enabled" => "yes",
    534     ],
    535 ]);
    536 
    537 $this->add_control("show_on_exit_intent", [
    538     "label" => esc_html__("Show on Exit Intent", "popup-for-elementor"),
    539     "type" => \Elementor\Controls_Manager::SWITCHER,
    540     "default" => "",
    541     "description" => esc_html__("Activate to show popup when the user intends to exit. Will disable other visibility options.", "popup-for-elementor"),
    542     "condition" => [
    543         "show_on_load!" => "yes",
    544         "show_after_delay_enabled!" => "yes",
    545         "show_once!" => "yes",
    546     ],
    547 ]);
    548 $this->add_control("show_once", [
    549     "label" => esc_html__("Show Only Once", "popup-for-elementor"),
    550     "type" => \Elementor\Controls_Manager::SWITCHER,
    551     "default" => "",
    552     "description" => esc_html__("Show the popup only once per session.", "popup-for-elementor"),
    553     "condition" => [
    554         "show_on_load!" => "yes",
    555         "show_after_delay_enabled!" => "yes",
    556         "show_on_exit_intent!" => "yes",
    557     ],
    558 ]);
    559 
    560 $this->add_control("upgrade_to_pro_notice2", [
    561     "type" => \Elementor\Controls_Manager::RAW_HTML,
    562     "raw" => sprintf(
    563         '<div style="margin-top: 20px; padding: 24px; background: linear-gradient(135deg, #1e1e1e, #2b2b2b); border: 1px solid #3c3c3c; border-radius: 8px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.2);">
    564             <strong style="display: block; color: #ffffff; font-size: 14px; font-weight: 300; margin-bottom: 12px;">%s</strong>
    565             <a href="%s" target="_blank" style="display: inline-block; padding: 10px 20px; background-color: #d33a92; color: #fff; border-radius: 4px; text-decoration: none; font-weight: 600; transition: background-color 0.3s;">
    566                 %s
    567             </a>
    568         </div>',
    569         esc_html__("Need more triggers like Scroll, OnClick, or AdBlock detection?", "popup-for-elementor"),
    570         "https://popupforelementor.com/en/home/#buy",
    571         esc_html__("Get Popup for Elementor Pro", "popup-for-elementor")
    572     ),
    573     "content_classes" => "elementor-control-field",
    574 ]);
    575 $this->end_controls_section();
    576     $this->start_controls_section("refresh_section", [
    577             "label" => esc_html__("Refresh", "popup-for-elementor"),
    578             "tab" => \Elementor\Controls_Manager::TAB_CONTENT,
    579         ]);
    580 
    581         $this->add_control(
    582             'refresh_popup',
    583             [
    584                 'label' => esc_html__('Refresh Popup', 'popup-for-elementor'),
    585                 'type' => \Elementor\Controls_Manager::BUTTON,
    586                 'button_type' => 'success',
    587                 'text' => esc_html__('Refresh', 'popup-for-elementor'),
    588                 'description' => esc_html__('Click to refresh the popup content.', 'popup-for-elementor'),
    589                 'frontend_available' => true,
    590             ]
    591         );
    592         $this->add_control("upgrade_to_pro_notice3", [
    593             "type" => \Elementor\Controls_Manager::RAW_HTML,
    594             "raw" => sprintf(
    595                 '<div style="margin-top: 20px; padding: 24px; background: linear-gradient(135deg, #1e1e1e, #2b2b2b); border: 1px solid #3c3c3c; border-radius: 8px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.2);">
    596                     <strong style="display: block; color: #ffffff; font-size: 14px; font-weight: 300; margin-bottom: 12px;">%s</strong>
    597                     <a href="%s" target="_blank" style="display: inline-block; padding: 10px 20px; background-color: #d33a92; color: #fff; border-radius: 4px; text-decoration: none; font-weight: 600; transition: background-color 0.3s;">
    598                         %s
    599                     </a>
    600                 </div>',
    601                 esc_html__("Need more triggers like Scroll, OnClick, or AdBlock detection?", "popup-for-elementor"),
    602                 "https://popupforelementor.com/en/home/#buy",
    603                 esc_html__("Get Popup for Elementor Pro", "popup-for-elementor")
    604             ),
    605             "content_classes" => "elementor-control-field",
    606         ]);
    607         $this->end_controls_section();
    608         $this->start_controls_section("upgrade_section", [
    609             "label" => esc_html__("Popup for Elementor (PRO)", "popup-for-elementor"),
    610             "tab"   => null,
    611         ]);
    612        
    613         $this->add_control("pro_upgrade_box", [
    614             "type" => \Elementor\Controls_Manager::RAW_HTML,
    615             "raw" => sprintf(
    616                 '<div style="padding: 24px; background: linear-gradient(135deg, #1e1e1e, #2b2b2b); border: 1px solid #3c3c3c; border-radius: 8px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.2);">
    617                     <h3 style="color: #ffffff; font-size: 16px; margin-bottom: 12px; font-weight: 600;">%s</h3>
    618                     <p style="color: #bbbbbb; font-size: 13px; margin-bottom: 20px;">%s</p>
    619                     <a href="%s" target="_blank" style="display: inline-block; padding: 10px 20px; background-color: #d33a92; color: #fff; border-radius: 4px; text-decoration: none; font-weight: 600; transition: background-color 0.3s;">
    620                         %s
    621                     </a>
    622                 </div>',
    623                 esc_html__("Unlock More Power", "popup-for-elementor"),
    624                 esc_html__("Upgrade to Pro and access all premium triggers and features.", "popup-for-elementor"),
    625                 "https://popupforelementor.com/en/home/#buy",
    626                 esc_html__("Upgrade to Pro", "popup-for-elementor")
    627             ),
    628         ]);
    629        
    630         $this->end_controls_section();
    631        
    632        
    633 
    634     }
    635 
    636     protected function render()
    637     {
    638         $settings = $this->get_settings_for_display();
    639 
    640         // Configuraciones dinámicas para pasar al script
    641         $config = [
    642             'showOnLoad' => isset($settings['show_on_load']) && $settings['show_on_load'] === 'yes' ? 'yes' : 'no',
    643             'delay' => isset($settings['show_after_delay']) ? (int) $settings['show_after_delay'] * 1000 : 0,
    644             'exitIntent' => isset($settings['show_on_exit_intent']) && $settings['show_on_exit_intent'] === 'yes' ? 'yes' : 'no',
    645             'showOnce' => isset($settings['show_once']) && $settings['show_once'] === 'yes' ? 'yes' : 'no',
    646             'cookieName' => 'popup_seen',
    647             'cookieExpiry' => 7,
    648         ];
    649 
    650         // Pasar configuraciones dinámicas al script
    651         wp_localize_script(
    652             'popup-widget-js',
    653             'PopupForElementorConfig',
    654             $config
    655         );
    656 
    657 
    658         // Obtener animaciones seleccionadas y duración
    659         $animation_in = $settings['popup_animation_in'] ?? 'animate__fadeIn';
    660         $animation_out = $settings['popup_animation_out'] ?? 'animate__fadeOut';
    661         $animation_duration = isset($settings['animation_duration_custom']['size'])
    662             ? (int) $settings['animation_duration_custom']['size']
    663             : 500;
    664 
    665         // Renderizar plantilla de Elementor si está configurada
    666        if (!empty($settings['template_id']) && class_exists('\Elementor\Plugin')) {
    667     $popup_content = \Elementor\Plugin::instance()->frontend->get_builder_content_for_display($settings['template_id']);
    668 
    669     if (\Elementor\Plugin::$instance->editor->is_edit_mode()) {
    670         // Recuperar la URL del editor de Elementor
    671         $edit_url = admin_url('post.php?post=' . absint($settings['template_id']) . '&action=elementor');
    672 
    673         // Solo eliminar etiquetas que no afecten la funcionalidad
    674         $filtered_content = preg_replace('/<meta\b[^>]*>(.*?)<\/meta>/is', '', $popup_content);
    675         $filtered_content = preg_replace('/<link\b[^>]*>(.*?)<\/link>/is', '', $filtered_content);
    676 
    677         // Crear contenido para el modal
    678         $popup_content = '
    679             <div class="elementor-template-button-wrapper" style="text-align: center; margin-top: 15px;">
    680                 <a href="javascript:void(0);"
    681                    class="popup-edit-button elementor-button elementor-button-success elementor-size-sm button-edit-custom"
    682 data-popup-id="' . esc_attr( 'popup_' . get_the_ID() . '_' . $settings['template_id'] ) . '"
    683                    data-edit-url="' . esc_url($edit_url) . '"
    684                    id="open-modal">
    685                    <i class="eicon-edit" style="margin-right: 8px;"></i>' . esc_html__('Edit Template', 'popup-for-elementor') . '
    686                 </a>
    687             </div>
    688             <div class="popup-editor-content">
    689                 ' . $filtered_content . '
    690             </div>';
     41        wp_enqueue_script('popup-widget-js');
    69142    }
    69243}
     44add_action('wp_enqueue_scripts', 'popup_for_elementor_register_assets');
    69345
     46add_action('admin_enqueue_scripts', function () {
     47    wp_dequeue_script('popup-widget-js');
     48    wp_deregister_script('popup-widget-js');
     49}, PHP_INT_MAX);
    69450
    695         // Generar un identificador único para el popup
    696         $current_page_id = get_the_ID();
    697         $popup_id = get_post_meta($settings['template_id'], '_popup_id_' . $current_page_id, true);
    698 
    699         if (empty($popup_id)) {
    700             $popup_id = 'popup_' . $current_page_id . '_' . uniqid();
    701             update_post_meta($settings['template_id'], '_popup_id_' . $current_page_id, $popup_id);
    702         }
    703 
    704         // Renderizar el HTML del popup con ID único
    705         $styles = '';
    706         if (!defined('ELEMENTOR_VERSION') || !\Elementor\Plugin::$instance->editor->is_edit_mode()) {
    707             // Aplicar estilos para ocultar el popup fuera del editor
    708             $styles = 'display: none; visibility: hidden; opacity: 1;';
    709         }
    710 
    711         function filter_popup_content($content)
    712         {
    713             // Lista de etiquetas peligrosas a eliminar (pero manteniendo SVGs y estilos de Elementor)
    714             $dangerous_tags = ['iframe', 'embed', 'object', 'applet', 'meta', 'link'];
    715 
    716             foreach ($dangerous_tags as $tag) {
    717                 $content = preg_replace('/<' . $tag . '.*?>.*?<\/' . $tag . '>/is', '', $content);
    718                 $content = preg_replace('/<' . $tag . '.*?>/is', '', $content);
    719             }
    720 
    721             return $content;
    722         }
    723 
    724         /* Escaping is not applied here because the content has already been filtered
    725         by `filter_popup_content()`, which removes dangerous tags.
    726         Using `esc_html()` would break Elementor's functionality.
    727         This code has been reviewed and is safe. */
    728 
    729         $popup_content_filtered = filter_popup_content($popup_content);
    730 
    731         echo '<div id="' . esc_attr($popup_id) . '" class="popup-overlay popup-widget" style="' . esc_attr($styles) . '">
    732     <div class="popup-content animate__animated ' . esc_attr($animation_in) . '"
    733          style="position: relative; animation-duration: ' . esc_attr($animation_duration) . 'ms;">
    734          <button class="popup-close">&times;</button>';
    735          
    736 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    737 echo $popup_content_filtered;
    738 
    739 echo '</div></div>';
    740 
    741 // This script controls the popup behavior (open/close, animations, hover effects).
    742 // It must be injected directly here because Elementor dynamically refreshes widget content.
    743 // Using wp_enqueue_script or wp_add_inline_script would not persist across reloads.
    744 
    745         echo '<script>
    746     (function($) {
    747         $(document).ready(function() {
    748             const popup = $("#' .
    749             esc_attr($popup_id) .
    750             '");
    751             const popupContent = popup.find(".popup-content");
    752 
    753             if (popup.length) {
    754                 // Abrir popup con animación de entrada
    755                 popup.closest(".elementor-widget-popup_widget").off("click").on("click", function(e) {
    756                     e.preventDefault();
    757                     popup.css({
    758                         display: "flex",
    759                         visibility: "visible"
    760                     });
    761                     popupContent.removeClass("' .
    762             esc_attr($animation_out) .
    763             '").addClass("' .
    764             esc_attr($animation_in) .
    765             '");
    766                 });
    767 
    768                 // Cerrar popup con animación de salida
    769                 popup.find(".popup-close").off("click").on("click", function(e) {
    770                     e.stopPropagation();
    771                     popupContent
    772                         .removeClass("' .
    773             esc_attr($animation_in) .
    774             '")
    775                         .addClass("' .
    776             esc_attr($animation_out) .
    777             '");
    778 
    779                     // Esperar la duración de la animación antes de ocultar el popup
    780                     const duration = ' .
    781             esc_attr($animation_duration) .
    782             ';
    783                     setTimeout(function() {
    784                         popup.css({
    785                             display: "none",
    786                             visibility: "hidden"
    787                         });
    788                         popupContent.removeClass("' .
    789             esc_attr($animation_out) .
    790             '");
    791                     }, duration);
    792                 });
    793 
    794                 // Hover en el botón para cambiar el fondo del popup
    795                 popup.find(".popup-edit-button").on("mouseenter", function() {
    796                     popupContent.css("background-color", "#ffebf2");
    797                 }).on("mouseleave", function() {
    798                     popupContent.css("background-color", "");
    799                 });
    800             } else {
    801                 console.error("Popup element not found in the DOM.");
    802             }
    803         });
    804         elementor.hooks.addAction("panel/open_editor/widget", function (panel, model) {
    805     panel.$el.on("click", ".elementor-control-refresh_popup .elementor-button", function () {
    806         console.log("¡Botón clicado! Refrescando el widget...");
    807 
    808         // Simular un cambio en el modelo
    809         model.set("refresh_trigger", Date.now()); // Valor ficticio para forzar el cambio
    810         model.trigger("change"); // Notificar el cambio a Elementor
    811 
    812         // Verificar si Elementor actualiza la vista
    813         setTimeout(function () {
    814             console.log("Intentando recargar la vista previa...");
    815             elementor.reloadPreview(); // Forzar la recarga si no responde
    816             elementor.once("preview:loaded", function () {
    817                 console.log("Vista previa recargada correctamente.");
    818 
    819                 // Reabrir el popup después de recargar la vista previa
    820                 const $popupOverlay = jQuery(".popup-overlay");
    821                 if ($popupOverlay.length) {
    822                     console.log("Reabriendo el popup...");
    823                     $popupOverlay.css({
    824                         display: "",
    825                         visibility: "",
    826                         opacity: 1,
    827                     });
    828                     console.log("Popup reabierto correctamente.");
    829                 } else {
    830                     console.error("No se encontró el popup en el DOM.");
    831                 }
    832             });
    833         }, 500); // Fallback por si el trigger no es suficiente
    834     });
    835 });
    836     })(jQuery);
    837 </script>';
    838 
    839 // This script controls the custom modal editor outside the iframe (open, close, panel resize).
    840 // Since the modal is rendered outside the iframe (via editor/after_footer),
    841 // this script needs to access it using parent.jQuery.
    842 // It must be echoed directly to stay bound to the button rendered in the iframe.
    843 
    844         echo '<div id="custom-modal">
    845         <div class="modal-container">
    846             <div class="modal-header">
    847                 <div class="modal-title" style="display: flex; align-items: center;">
    848                     <div style="width: 40px; height: 40px; background-color: white; border-radius: 50%; display: flex; justify-content: center; align-items: center; margin-right: 10px;">
    849                         <span class="eicon-table-of-contents" style="font-size: 20px; color: #333;"></span> <!-- Icono de Elementor -->
    850                     </div>
    851                     ' . esc_html__("Popup for Elementor", "popup-for-elementor") . '
    852                 </div>
    853                 <button id="close-modal">&times;</button>
    854             </div>
    855             <iframe id="modal-iframe" src=""></iframe>
    856         </div>
    857       </div>';
    858 
    859       echo '<script>
    860       (function($) {
    861           $(document).ready(function() {
    862               const $modal = $("#custom-modal");
    863               const $iframe = $("#modal-iframe");
    864               const $closeButton = $("#close-modal");
    865      
    866               let originalPanelStyles = {}; // Guardamos los estilos originales
    867      
    868               function refreshWidget() {
    869                   console.log("Ejecutando refresh del widget...");
    870                   if (typeof parent.elementor !== "undefined" && parent.elementor.reloadPreview) {
    871                       parent.elementor.reloadPreview();
    872                       parent.elementor.once("preview:loaded", function() {
    873                           console.log("Vista previa recargada correctamente.");
    874                       });
    875                   }
    876               }
    877      
    878               function toggleElementorPanel(reduce) {
    879                   if (typeof parent.jQuery !== "undefined") {
    880                       const $panel = parent.jQuery("#elementor-panel");
    881                       const $preview = parent.jQuery("#elementor-preview");
    882      
    883                       if (reduce) {
    884                           console.log("Guardando estado del panel y reduciéndolo...");
    885                           originalPanelStyles = {
    886                               width: $panel.css("width"),
    887                               minWidth: $panel.css("min-width"),
    888                               maxWidth: $panel.css("max-width"),
    889                               overflow: $panel.css("overflow"),
    890                               visibility: $panel.css("visibility"),
    891                               opacity: $panel.css("opacity"),
    892                           };
    893      
    894                           $panel.css({
    895                               "width": "60px",
    896                               "min-width": "60px",
    897                               "max-width": "60px",
    898                               "overflow": "hidden",
    899                               "visibility": "hidden",
    900                               "opacity": "0",
    901                               "transition": "width 0.3s ease-in-out"
    902                           });
    903      
    904                           $preview.css({
    905                               "width": "calc(100% - 60px)",
    906                               "transition": "width 0.3s ease-in-out"
    907                           });
    908                       } else {
    909                           console.log("Restaurando el panel de Elementor...");
    910                           $panel.css(originalPanelStyles);
    911      
    912                           $preview.css({
    913                               "width": "calc(100% - " + originalPanelStyles.width + ")"
    914                           });
    915                       }
    916                   }
    917               }
    918      
    919               $("#open-modal").on("click", function() {
    920                   console.log("Modal abierto, reduciendo panel en la ventana principal...");
    921                   const editUrl = $(this).data("edit-url");
    922                   $iframe.attr("src", editUrl);
    923                   $modal.removeClass("hide").addClass("show");
    924      
    925                   toggleElementorPanel(true);
    926               });
    927      
    928               $closeButton.on("click", function() {
    929                   console.log("Cerrando modal, restaurando panel en la ventana principal...");
    930                   $modal.removeClass("show").addClass("hide");
    931      
    932                   setTimeout(() => {
    933                       $iframe.attr("src", ""); // Limpiar el iframe
    934                       toggleElementorPanel(false);
    935                       refreshWidget();
    936                   }, 300);
    937               });
    938      
    939               console.log("Script de reducción de panel cargado.");
    940           });
    941       })(jQuery);
    942       </script>';
    943     }
    944 }
  • popup-for-elementor/tags/1.5.8/popup-for-elementor.php

    r3331799 r3380762  
    22/**
    33 * Plugin Name: Popup for Elementor
    4  * Plugin URI: https://popupforelementor.com
    5  * Description: Enhance your Elementor website with fully customizable popups. Includes triggers, animations, and advanced settings to improve user interaction and engagement.
    6  * Version: 1.5.7
     4 * Plugin URI: https://www.popupforelementor.com
     5 * Description: Create powerful, fully customizable popups directly in Elementor Free — includes click, delay, load, and exit-intent triggers, animations, and smart visibility controls to boost user engagement.
     6 * Version: 1.5.8
    77 * Author: Veelo
    88 * Author URI: https://www.veelo.es
     
    1111 * License: GPLv2 or later
    1212 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
    13  * Requires at least: 5.6
     13 * Requires at least: 5.8
    1414 * Requires PHP: 7.4
    1515 * Requires Plugins: elementor
    16  * Tested up to: 6.9
     16 * Tested up to: 6.8.3
    1717 */
     18
    1819
    1920
  • popup-for-elementor/tags/1.5.8/readme.txt

    r3331799 r3380762  
    11=== Popup for Elementor === 
    22Contributors: veelo 
    3 Tags: popup, elementor, modal, wordpress popup, elementor free 
    4 Requires at least: 5.6 
    5 Tested up to: 6.9 
     3Tags: popup, elementor, modal, wordpress popup, elementor free, popup maker, popup builder, modal window 
     4Requires at least: 5.8 
     5Tested up to: 6.8.3 
    66Requires PHP: 7.4 
    7 Stable tag: 1.5.7 
     7Stable tag: 1.5.8 
    88License: GPLv2 or later 
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html 
    1010
    11 Create customizable popups using Elementor Free. Lightweight and easy to use — no coding or Elementor Pro required.
     11Create powerful, customizable popups with **Elementor Free** — no coding or Elementor Pro required.
    1212
    1313== Description ==
    1414
    15 **Popup for Elementor** brings a native popup widget to **Elementor Free**. Design beautiful, responsive popups directly inside the Elementor editor with full control over appearance, triggers, and behavior.
     15**Popup for Elementor** is the easiest and most lightweight popup builder for **Elementor Free**. 
     16Design responsive, conversion-focused popups directly inside Elementor with full visual control — 100% no-code and performance-optimized.
    1617
    17 No need for Elementor Pro or third-party modal plugins. Everything you need is built-in.
     18Unlike other popup plugins, this one works **without Elementor Pro** and **without third-party modal builders**. Everything is native, simple, and fast.
    1819
    19 ### Features Included in the Free Version
     20### 🔹 Key Features
    2021
    21 – **Design Freedom** 
    22   Create pixel-perfect popups with Elementor. Customize layout, colors, borders, padding, animations, close button, overlay, and more.
     22– **Design Freedom with Elementor** 
     23  Build beautiful popups visually. Control layout, colors, padding, overlay, borders, animations, and close buttons. 
    2324
    24 – **Trigger Options (Free)** 
     25– **Free Trigger Options (No Pro Needed)** 
    2526  – Show on page load 
    2627  – Show after a delay (in seconds) 
    27   – Show on exit intent 
    28   – Option to show only once (cookie-based)
     28  – Show on exit intent *(improved)* 
     29  – Show on click *(new in 1.5.8)* 
     30  – Option to show only once (cookie-based, now works with all triggers)
    2931
    30 – **Popup Behavior Controls** 
     32– **Smart Popup Behavior** 
    3133  – Close popup on ESC key 
    3234  – Close when clicking outside (overlay) 
    33   – Option to disable right-click inside the popup
     35  – Option to disable right-click inside popup content
    3436
    3537– **Elementor Template Integration** 
    36   – Load any Elementor template inside the popup for maximum flexibility
     38  – Load any Elementor section or saved template directly inside the popup for ultimate flexibility
    3739
    38 – **Performance Focused** 
    39   – Clean and lightweight code 
    40   – Optimized loading 
    41   – Fully responsive
    42   – Compatible with any WordPress theme
     40– **Performance-First** 
     41  – Lightweight JavaScript and CSS 
     42  – Clean code, no dependencies 
     43  – Fully responsive and SEO-friendly
     44  – Works with any WordPress theme
    4345
    4446– **No Elementor Pro Required** 
    45   All features are 100% compatible with **Elementor Free**
     47  Every feature works natively with **Elementor Free**.
    4648
    47 **Pro version available** (optional): 
    48 The Pro version includes additional features and triggers, such as: 
    49 – Show on scroll 
    50 – Show on click 
    51 – Show on user inactivity 
    52 – Show based on referral URL 
    53 – Show on specific URLs or schedules 
    54 – Show based on login status 
     49**Optional Pro Version:** 
     50Adds advanced targeting and automation features: 
     51– Scroll-based and inactivity triggers 
     52– Referral URL and login-based display 
     53– Time-scheduled popups 
    5554– AdBlock detection 
    56 – Dynamic content loading with enhanced performance 
    57 
    58 The free version works independently and does not require the Pro version.
     55– Dynamic content loading for speed and personalization 
    5956
    6057**Official Website:** https://www.popupforelementor.com 
     
    6259**Support:** [email protected] 
    6360We respond to support requests within 48 hours. 
    64 Live chat is also available on the official website with typical response times between 2 and 3 hours.
     61Live chat available on our website with typical response times between 2 and 3 hours.
    6562
    6663== Installation ==
    6764
    68651. Download the plugin ZIP file. 
    69 2. In your WordPress admin, go to **Plugins > Add New**. 
     662. In your WordPress admin, go to **Plugins Add New**. 
    70673. Click **Upload Plugin** and select the downloaded file. 
    71684. Click **Install Now**, then **Activate**. 
    72 5. Go to **Elementor > Widgets** and search for **Popup for Elementor**.
     695. In Elementor, search for **Popup for Elementor** in the widget panel.
    7370
    7471== Frequently Asked Questions ==
    7572
    7673= Do I need Elementor Pro? = 
    77 No. This plugin works perfectly with **Elementor Free**.
     74No. Popup for Elementor works perfectly with **Elementor Free**.
     75
     76= How do I make a popup appear when users click a button or link? = 
     77Use the new **Click Trigger** (added in version 1.5.8). 
     78You can set a CSS selector or Elementor element to open the popup.
    7879
    7980= Can I control when the popup appears? = 
    80 Yes. You can configure triggers: on load, after delay, or when the user is about to exit the page.
     81Yes — you can trigger it **on load**, **after a delay**, **on click**, or **on exit intent**.
    8182
    82 = Can I prevent the popup from showing multiple times? = 
    83 Yes. You can activate the "show only once" option, which uses cookies to prevent repeated popups.
     83= Can I show the popup only once? = 
     84Yes. Enable the **Show only once** option to use a cookie that prevents the popup from appearing again.
    8485
    8586= Can I use Elementor templates inside the popup? = 
    86 Absolutely. You can insert any Elementor section or template inside the popup container.
     87Absolutely. Load any Elementor template or section inside the popup container.
    8788
    8889== Screenshots ==
    8990
    90 1. Popup settings inside the Elementor editor 
    91 2. Triggers and visibility controls 
     911. Popup widget settings inside the Elementor editor 
     922. Trigger and visibility controls 
    92933. Popup design customization 
    93944. Example popup rendered on the page 
    94 5. Elementor template loaded in a popup
     955. Elementor template loaded inside a popup
    9596
    9697== Changelog ==
     98
     99= 1.5.8 = 
     100* **New:** Added **Click Trigger** to the free version (previously Pro only). 
     101* **Improved:** Exit Intent detection logic rewritten for smoother, more accurate behavior. 
     102* **Improved:** “Show only once” option now works across all triggers. 
     103* **Fix:** Minor issues when combining multiple triggers. 
     104* **Update:** Tested up to WordPress 6.8.3 and Elementor 3.22+. 
     105* **UI:** Minor visual and label adjustments in the widget controls. 
    97106
    98107= 1.5.7 = 
     
    115124* Integrated cookie-based visibility control. 
    116125* Full Elementor Free compatibility. 
    117 * Pro version (optional) adds extended triggers: On Scroll, On Click, Referral-based, Inactivity, Schedule-based, Login detection, and AdBlock detection.
     126* Pro version adds advanced targeting: scroll, referral, inactivity, schedule, login, and AdBlock detection.
    118127
    119128== Upgrade Notice ==
    120129
    121 = 1.5.7 = 
    122 Recommended update: improves stability, fixes close button behavior, and ensures compatibility with WordPress 6.9.
     130= 1.5.8 = 
     131🚀 Major update! Adds **Click Trigger** to the free version, improves Exit Intent detection, and enhances “Show only once” cookie logic. 
     132Recommended update for all users.
  • popup-for-elementor/trunk/assets/popup-widget.js

    r3300275 r3380762  
    55        const cookieExpiry = parseInt(config.cookieExpiry, 10) || 7;
    66        const delayInMilliseconds = parseInt(config.delay, 10) || 0;
     7        const isSelectorMode = (config.triggerBySelector === 'yes' && config.triggerSelector && config.triggerSelector.trim() !== '');
     8
    79        let isClosing = false;
    8 
     10        let popupOpenedAt = 0;   // marca de última apertura (ms)
     11        let lastExitTs = 0;      // anti-rebote de exit-intent (ms)
     12        const EXIT_COOLDOWN_MS = 1200;
     13       
    914        const $popupOverlay = $('.popup-overlay');
    1015        const $popupContent = $popupOverlay.find('.popup-content');
     
    4449
    4550            console.log("Showing popup.");
     51            popupOpenedAt = Date.now();
    4652            $popupOverlay.css({
    4753                display: 'flex',
     
    5965        function closePopup() {
    6066            console.log("Attempting to close popup...");
     67       
     68            if (popupOpenedAt && (Date.now() - popupOpenedAt) < 250) {
     69                console.log("Close ignored due to debounce after open.");
     70                return;
     71            }
     72       
    6173            if (isClosing) {
    6274                console.log("Popup is already closing. Aborting.");
    6375                return;
    6476            }
    65 
     77       
    6678            isClosing = true;
    6779            console.log("Closing popup...");
    68 
     80       
     81            let handled = false;
    6982            $popupContent
    70                 .removeClass('animate__fadeIn')
    71                 .addClass('animate__fadeOut')
    72                 .one('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function () {
     83                .removeClass('animate__fadeIn')
     84                .addClass('animate__fadeOut')
     85                .one('animationend', function (e) {
     86                    if (handled) return;
     87                    if (e.target !== this) return;
     88                    handled = true;
     89       
    7390                    console.log("Fade-out animation ended. Hiding popup.");
    7491                    $popupOverlay.css({
     
    7794                        opacity: 0,
    7895                    });
    79                     $popupContent.removeClass('animate__fadeOut'); 
    80                     isClosing = false; 
     96                    $popupContent.removeClass('animate__fadeOut');
     97                    isClosing = false;
    8198                    console.log("Popup closed successfully.");
    8299                });
    83 
     100       
    84101            setTimeout(() => {
    85                 if (isClosing) {
     102                if (!handled) {
    86103                    console.warn("Fallback triggered: Forcing popup closure.");
     104                    handled = true;
    87105                    $popupOverlay.css({
    88106                        display: 'none',
     
    91109                    });
    92110                    $popupContent.removeClass('animate__fadeOut');
    93                     isClosing = false;
    94                 }
    95             }, 500);
    96         }
     111                    isClosing = false;
     112                }
     113            }, 700);
     114        }
     115       
    97116
    98117        function handlePopupDisplay() {
     
    122141        if (config.exitIntent === 'yes') {
    123142            console.log("IntentExit habilitado.");
     143       
    124144            $(document).on('mouseleave', function (e) {
    125                 console.log(`Intento de salida detectado: clientY = ${e.clientY}`);
    126                 if (e.clientY < 0) {
     145                const now = Date.now();
     146                const nearTop = (e.clientY <= 0 || e.clientY <= 20);
     147                const leavingWindow = (e.relatedTarget === null);
     148       
     149                console.log(`Intento de salida: clientY=${e.clientY}, nearTop=${nearTop}, leaving=${leavingWindow}`);
     150       
     151                if (config.exitIntentDisplayMode === 'once' && getCookie(cookieName)) {
     152                    console.log('ExitIntent en modo "once" y cookie presente. No se muestra.');
     153                    return;
     154                }
     155       
     156                if (isClosing || (popupOpenedAt && (now - popupOpenedAt) < 250)) {
     157                    console.log('Ignorado: está cerrando o se acaba de abrir.');
     158                    return;
     159                }
     160       
     161                if (now - lastExitTs < EXIT_COOLDOWN_MS) {
     162                    console.log('Cooldown activo. Ignorando ExitIntent repetido.');
     163                    return;
     164                }
     165       
     166                if (nearTop || leavingWindow) {
     167                    lastExitTs = now;
    127168                    console.log("Mostrando popup por IntentExit.");
    128169                    showPopup();
     170       
     171                    if (config.exitIntentDisplayMode === 'once') {
     172                        setCookie(cookieName, 'true', cookieExpiry);
     173                        console.log(`Cookie "${cookieName}" marcada por ExitIntent durante ${cookieExpiry} días.`);
     174                    }
    129175                }
    130176            });
     
    132178            console.log("IntentExit no habilitado.");
    133179        }
    134         if (config.showOnScroll === 'yes') {
    135             console.log(`On Scroll habilitado. Porcentaje configurado: ${config.scrollPercentage}%`);
    136 
    137             let scrollTriggered = false;
    138 
    139             $(window).on('scroll', function () {
    140                 if (scrollTriggered) return;
    141 
    142                 const scrollTop = $(window).scrollTop();
    143                 const windowHeight = $(window).height();
    144                 const documentHeight = $(document).height();
    145                 const scrolledPercentage = (scrollTop / (documentHeight - windowHeight)) * 100;
    146 
    147                 if (scrolledPercentage >= config.scrollPercentage) {
    148                     console.log(`Porcentaje de scroll alcanzado: ${scrolledPercentage.toFixed(2)}%`);
    149                     showPopup();
    150                     scrollTriggered = true;
    151                     $(window).off('scroll');
    152                 }
    153             });
    154         } else {
    155             console.log("On Scroll no habilitado.");
    156         }
     180
    157181
    158182        $popupOverlay.on('click', function (e) {
     
    170194        });
    171195
    172         handlePopupDisplay();
    173     });
    174 })(jQuery);
     196        if (isSelectorMode) {
     197            const raw = config.triggerSelector.trim();
     198            const selector = /^[.#]/.test(raw) ? raw : ('.' + raw);
     199            $(document).off('click.popupfeSelector');
     200            console.log('[PopupFE] Trigger por selector activo →', selector, '| matches:', document.querySelectorAll(selector).length);
     201            $(document).on('click.popupfeSelector', selector, function(e){
     202              if ($popupOverlay.is(':visible') || isClosing) return;
     203              showPopup();
     204            });
     205          }
     206
     207   
     208            handlePopupDisplay();
     209        });
     210    })(jQuery);
     211   
  • popup-for-elementor/trunk/includes/editor-options.php

    r3300275 r3380762  
    11<?php
    2 // Adds options to Elementor editor for configuring the popup
    3 if ( ! defined( 'ABSPATH' ) ) {
    4     exit; // Exit if accessed directly
     2// File: popup-handler.php
     3// Dynamically passes configuration from Elementor controls to the JavaScript.
     4
     5if (!defined('ABSPATH')) {
     6    exit;
    57}
    6 class Popupfe_Popup_Widget extends \Elementor\Widget_Base
     8function popup_for_elementor_register_assets()
    79{
    8     public function get_name()
    9     {
    10         return "popup_widget";
    11     }
    12     public function get_title()
    13     {
    14         return esc_html__("Popup Widget", "popup-for-elementor");
    15     }
     10    if (!is_admin()) {
     11        wp_register_script(
     12            'popup-widget-js',
     13            plugin_dir_url(__FILE__) . '../assets/popup-widget.js',
     14            array('jquery'),
     15            '1.0.0',
     16            true
     17        );
     18        $post_id = get_the_ID();
    1619
    17     public function get_categories()
    18     {
    19         return ["basic"];
    20     }
    21     public function get_icon() {
    22         return 'eicon-table-of-contents';
    23           }
    24 
    25     protected function _register_controls()
    26     {
    27         // Content controls
    28         $this->start_controls_section("content_section", [
    29             "label" => esc_html__("Content", "popup-for-elementor"),
    30             "tab" => \Elementor\Controls_Manager::TAB_CONTENT,
    31         ]);
    32 
    33         $templates = [];
    34         if (class_exists("\Elementor\Plugin")) {
    35             $template_manager = \Elementor\Plugin::instance()->templates_manager->get_source(
    36                 "local"
     20        if ($post_id) {
     21            $dynamic_config = array(
     22                'showOnLoad'           => get_post_meta($post_id, '_elementor_popup_show_on_load', true) ?: 'no',
     23                'delay'                => (int) get_post_meta($post_id, '_elementor_popup_delay', true) ?: 0,
     24                'showOnScroll'         => get_post_meta($post_id, '_elementor_popup_show_on_scroll', true) === 'yes',
     25                'scrollPercentage'     => (int) (get_post_meta($post_id, '_elementor_popup_scroll_percentage', true) ?: 50),
     26                'exitIntent'           => get_post_meta($post_id, '_elementor_popup_exit_intent', true) === 'yes',
     27                'exitIntentDisplayMode'=> get_post_meta($post_id, '_elementor_exit_intent_display_mode', true) ?: 'always',
     28                'cookieName'           => 'popup_seen',
     29                'cookieExpiry'         => 7,
     30                'triggerBySelector' => get_post_meta($post_id, '_elementor_trigger_selector_enabled', true) === 'yes',
     31                'triggerSelector'   => get_post_meta($post_id, '_elementor_trigger_selector', true) ?: '',
     32               
    3733            );
    38             $templates_raw = $template_manager
    39                 ? $template_manager->get_items()
    40                 : [];
    41             foreach ($templates_raw as $template) {
    42                 $templates[$template["template_id"]] = $template["title"];
    43             }
     34           
     35            wp_localize_script(
     36                'popup-widget-js',
     37                'PopupForElementorConfig',
     38                $dynamic_config
     39            );
    4440        }
    45 
    46         $this->add_control("template_id", [
    47             "label" => esc_html__("Select Template", "popup-for-elementor"),
    48             "type" => \Elementor\Controls_Manager::SELECT2, // Cambiado a SELECT2
    49             "options" => $templates, // Asegúrate de que $templates tiene las opciones disponibles
    50             "default" => "",
    51             "description" => esc_html__(
    52                 "Choose a template from your Elementor library.",
    53                 "popup-for-elementor"
    54             ),
    55         ]);
    56 
    57         $this->add_control("template_create_link", [
    58             "type" => \Elementor\Controls_Manager::RAW_HTML,
    59             "raw" => sprintf(
    60                 '<a href="%s" target="_blank" class="elementor-button elementor-button-success" style="margin-top: 10px;">%s</a>',
    61                 admin_url("edit.php?post_type=elementor_library"),
    62                 esc_html__("Create New Template", "popup-for-elementor")
    63             ),
    64             "content_classes" => "elementor-control-field",
    65         ]);
    66 
    67         $this->add_control("upgrade_to_pro_notice1", [
    68             "type" => \Elementor\Controls_Manager::RAW_HTML,
    69             "raw" => sprintf(
    70                 '<div style="margin-top: 20px; padding: 24px; background: linear-gradient(135deg, #1e1e1e, #2b2b2b); border: 1px solid #3c3c3c; border-radius: 8px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.2);">
    71                     <strong style="display: block; color: #ffffff; font-size: 14px; font-weight: 300; margin-bottom: 12px;">%s</strong>
    72                     <a href="%s" target="_blank" style="display: inline-block; padding: 10px 20px; background-color: #d33a92; color: #fff; border-radius: 4px; text-decoration: none; font-weight: 600; transition: background-color 0.3s;">
    73                         %s
    74                     </a>
    75                 </div>',
    76                 esc_html__("Need more triggers like Scroll, OnClick, or AdBlock detection?", "popup-for-elementor"),
    77                 "https://popupforelementor.com/en/home/#buy",
    78                 esc_html__("Get Popup for Elementor Pro", "popup-for-elementor")
    79             ),
    80             "content_classes" => "elementor-control-field",
    81         ]);
    82 
    83         $this->end_controls_section();
    84 
    85         // Style controls
    86         $this->start_controls_section("style_section", [
    87             "label" => esc_html__("Popup window", "popup-for-elementor"),
    88             "tab" => \Elementor\Controls_Manager::TAB_STYLE,
    89         ]);
    90         $this->add_responsive_control(
    91             'popup_background',
    92             [
    93                 'label' => esc_html__('Background Color', 'popup-for-elementor'),
    94                 'type' => \Elementor\Controls_Manager::COLOR,
    95                 'selectors' => [
    96                     '{{WRAPPER}} .popup-content' => 'background-color: {{VALUE}};',
    97                 ],
    98             ]
    99         );
    100 
    101         $this->add_control("overlay_color", [
    102             "label" => esc_html__("Overlay Color", "popup-for-elementor"),
    103             "type" => \Elementor\Controls_Manager::COLOR,
    104             "default" => "rgba(0, 0, 0, 0.5)",
    105             "selectors" => [
    106                 "{{WRAPPER}} .popup-overlay" => "background-color: {{VALUE}};",
    107             ],
    108         ]);
    109 
    110         $this->add_control("border_radius", [
    111             "label" => esc_html__("Border Radius", "popup-for-elementor"),
    112             "type" => \Elementor\Controls_Manager::SLIDER,
    113             "default" => [
    114                 "size" => 10,
    115             ],
    116             "selectors" => [
    117                 "{{WRAPPER}} .popup-content" =>
    118                     "border-radius: {{SIZE}}{{UNIT}};",
    119             ],
    120         ]);
    121 
    122         $this->add_group_control(
    123             \Elementor\Group_Control_Box_Shadow::get_type(),
    124             [
    125                 "name" => "popup_box_shadow",
    126                 "label" => esc_html__("Box Shadow", "popup-for-elementor"),
    127                 "selector" => "{{WRAPPER}} .popup-content",
    128                 "description" => esc_html__(
    129                     "Configure the shadow settings directly.",
    130                     "popup-for-elementor"
    131                 ),
    132             ]
    133         );
    134 
    135         $this->add_responsive_control("popup_width", [
    136             "label" => esc_html__("Popup Width", "popup-for-elementor"),
    137             "type" => \Elementor\Controls_Manager::SELECT,
    138             "default" => "400px",
    139             "options" => [
    140                 "auto" => esc_html__("Auto (Fit Content)", "popup-for-elementor"),
    141                 "custom" => esc_html__("Custom", "popup-for-elementor"),
    142             ],
    143             "selectors" => [
    144                 "{{WRAPPER}} .popup-content" => "width: {{VALUE}};",
    145             ],
    146         ]);
    147        
    148         $this->add_responsive_control("custom_popup_width", [
    149             "label" => esc_html__("Custom Width", "popup-for-elementor"),
    150             "type" => \Elementor\Controls_Manager::SLIDER,
    151             "default" => [
    152                 "size" => 400,
    153                 "unit" => "px",
    154             ],
    155             "size_units" => ["px", "%", "vw"],
    156             "range" => [
    157                 "px" => [
    158                     "min" => 100,
    159                     "max" => 2000,
    160                     "step" => 10,
    161                 ],
    162                 "%" => [
    163                     "min" => 1,
    164                     "max" => 100,
    165                 ],
    166                 "vw" => [
    167                     "min" => 1,
    168                     "max" => 100,
    169                 ],
    170             ],
    171             "condition" => [
    172                 "popup_width" => "custom",
    173             ],
    174             "selectors" => [
    175                 "{{WRAPPER}} .popup-content" => "width: {{SIZE}}{{UNIT}};",
    176             ],
    177         ]);
    178        
    179 
    180         $this->add_responsive_control("popup_height", [
    181             "label" => esc_html__("Popup Height", "popup-for-elementor"),
    182             "type" => \Elementor\Controls_Manager::SELECT,
    183             "default" => "auto",
    184             "options" => [
    185                 "auto" => esc_html__("Auto (Fit Content)", "popup-for-elementor"),
    186                 "custom" => esc_html__("Custom", "popup-for-elementor"),
    187             ],
    188             "selectors" => [
    189                 "{{WRAPPER}} .popup-content" => "height: {{VALUE}};",
    190             ],
    191         ]);
    192        
    193         $this->add_responsive_control("custom_popup_height", [
    194             "label" => esc_html__("Custom Height", "popup-for-elementor"),
    195             "type" => \Elementor\Controls_Manager::SLIDER,
    196             "default" => [
    197                 "size" => 400,
    198                 "unit" => "px",
    199             ],
    200             "size_units" => ["px", "%", "vh"],
    201             "range" => [
    202                 "px" => [
    203                     "min" => 100,
    204                     "max" => 2000,
    205                     "step" => 10,
    206                 ],
    207                 "%" => [
    208                     "min" => 1,
    209                     "max" => 100,
    210                 ],
    211                 "vh" => [
    212                     "min" => 1,
    213                     "max" => 100,
    214                 ],
    215             ],
    216             "condition" => [
    217                 "popup_height" => "custom",
    218             ],
    219             "selectors" => [
    220                 "{{WRAPPER}} .popup-content" => "height: {{SIZE}}{{UNIT}};",
    221             ],
    222         ]);
    223        
    224 
    225 
    226         $this->add_responsive_control("horizontal_position", [
    227             "label" => esc_html__("Horizontal Position", "popup-for-elementor"),
    228             "type" => \Elementor\Controls_Manager::CHOOSE,
    229             "options" => [
    230                 "flex-start" => [
    231                     "title" => esc_html__("Left", "popup-for-elementor"),
    232                     "icon" => "eicon-h-align-left",
    233                 ],
    234                 "center" => [
    235                     "title" => esc_html__("Center", "popup-for-elementor"),
    236                     "icon" => "eicon-h-align-center",
    237                 ],
    238                 "flex-end" => [
    239                     "title" => esc_html__("Right", "popup-for-elementor"),
    240                     "icon" => "eicon-h-align-right",
    241                 ],
    242             ],
    243             "default" => "center",
    244             "selectors" => [
    245                 "{{WRAPPER}} .popup-overlay" => "justify-content: {{VALUE}};",
    246             ],
    247         ]);
    248 
    249         $this->add_responsive_control("vertical_position", [
    250             "label" => esc_html__("Vertical Position", "popup-for-elementor"),
    251             "type" => \Elementor\Controls_Manager::CHOOSE,
    252             "options" => [
    253                 "flex-start" => [
    254                     "title" => esc_html__("Top", "popup-for-elementor"),
    255                     "icon" => "eicon-v-align-top",
    256                 ],
    257                 "center" => [
    258                     "title" => esc_html__("Center", "popup-for-elementor"),
    259                     "icon" => "eicon-v-align-middle",
    260                 ],
    261                 "flex-end" => [
    262                     "title" => esc_html__("Bottom", "popup-for-elementor"),
    263                     "icon" => "eicon-v-align-bottom",
    264                 ],
    265             ],
    266             "default" => "center",
    267             "selectors" => [
    268                 "{{WRAPPER}} .popup-overlay" => "align-items: {{VALUE}};",
    269             ],
    270         ]);
    271 
    272         // Control para el margen (Responsive)
    273         $this->add_responsive_control(
    274             'popup_margin',
    275             [
    276                 'label' => esc_html__('Margin', 'popup-for-elementor'),
    277                 'type' => \Elementor\Controls_Manager::DIMENSIONS,
    278                 'size_units' => ['px', '%', 'em'],
    279                 'selectors' => [
    280                     '{{WRAPPER}} .popup-content' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
    281                 ],
    282             ]
    283         );
    284 
    285         // Control para el padding (Responsive)
    286         $this->add_responsive_control(
    287             'popup_padding',
    288             [
    289                 'label' => esc_html__('Padding', 'popup-for-elementor'),
    290                 'type' => \Elementor\Controls_Manager::DIMENSIONS,
    291                 'size_units' => ['px', '%', 'em'],
    292                 'selectors' => [
    293                     '{{WRAPPER}} .popup-content' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
    294                 ],
    295             ]
    296         );
    297 
    298 
    299         $this->end_controls_section();
    300 
    301         // Animation
    302 
    303         $this->start_controls_section("animation_section_custom", [
    304             "label" => esc_html__("Animation", "popup-for-elementor"),
    305             "tab" => \Elementor\Controls_Manager::TAB_STYLE, // Colocamos esta sección en la pestaña de estilo
    306         ]);
    307 
    308         $this->add_control("popup_animation_in", [
    309             "label" => esc_html__("Entrance Animation", "popup-for-elementor"),
    310             "type" => \Elementor\Controls_Manager::SELECT,
    311             "options" => [
    312                 "none" => esc_html__("None", "popup-for-elementor"),
    313                 "animate__fadeIn" => esc_html__("Fade In", "popup-for-elementor"),
    314                 "animate__fadeInUp" => esc_html__("Fade In Up", "popup-for-elementor"),
    315                 "anixmate__fadeInDown" => esc_html__("Fade In Down", "popup-for-elementor"),
    316                 "animate__fadeInLeft" => esc_html__("Fade In Left", "popup-for-elementor"),
    317                 "animate__fadeInRight" => esc_html__("Fade In Right", "popup-for-elementor"),
    318                 "animate__zoomIn" => esc_html__("Zoom In", "popup-for-elementor"),
    319                 "animate__slideInUp" => esc_html__("Slide In Up", "popup-for-elementor"),
    320                 "animate__slideInDown" => esc_html__("Slide In Down", "popup-for-elementor"),
    321                 "animate__slideInLeft" => esc_html__("Slide In Left", "popup-for-elementor"),
    322                 "animate__slideInRight" => esc_html__("Slide In Right", "popup-for-elementor"),
    323             ],
    324             "default" => "animate__fadeIn",
    325             "description" => esc_html__(
    326                 "Choose an animation for the popup to appear.",
    327                 "popup-for-elementor"
    328             ),
    329         ]);
    330 
    331         $this->add_control("popup_animation_out", [
    332             "label" => esc_html__("Exit Animation", "popup-for-elementor"),
    333             "type" => \Elementor\Controls_Manager::SELECT,
    334             "options" => [
    335                 "none" => esc_html__("None", "popup-for-elementor"),
    336                 "animate__fadeOut" => esc_html__("Fade Out", "popup-for-elementor"),
    337                 "animate__fadeOutUp" => esc_html__("Fade Out Up", "popup-for-elementor"),
    338                 "animate__fadeOutDown" => esc_html__("Fade Out Down", "popup-for-elementor"),
    339                 "animate__fadeOutLeft" => esc_html__("Fade Out Left", "popup-for-elementor"),
    340                 "animate__fadeOutRight" => esc_html__("Fade Out Right", "popup-for-elementor"),
    341                 "animate__zoomOut" => esc_html__("Zoom Out", "popup-for-elementor"),
    342                 "animate__slideOutUp" => esc_html__("Slide Out Up", "popup-for-elementor"),
    343                 "animate__slideOutDown" => esc_html__("Slide Out Down", "popup-for-elementor"),
    344                 "animate__slideOutLeft" => esc_html__("Slide Out Left", "popup-for-elementor"),
    345                 "animate__slideOutRight" => esc_html__(
    346                     "Slide Out Right",
    347                     "popup-for-elementor"
    348                 ),
    349             ],
    350             "default" => "animate__fadeOut",
    351             "description" => esc_html__(
    352                 "Choose an animation for the popup to disappear.",
    353                 "popup-for-elementor"
    354             ),
    355         ]);
    356 
    357         $this->add_control("animation_duration_custom", [
    358             "label" => esc_html__("Animation Duration (ms)", "popup-for-elementor"),
    359             "type" => \Elementor\Controls_Manager::SLIDER,
    360             "size_units" => ["ms"],
    361             "range" => [
    362                 "ms" => [
    363                     "min" => 100,
    364                     "max" => 3000,
    365                     "step" => 100,
    366                 ],
    367             ],
    368             "default" => [
    369                 "size" => 500,
    370                 "unit" => "ms",
    371             ],
    372             "selectors" => [
    373                 "{{WRAPPER}} .popup-content" =>
    374                     "animation-duration: {{SIZE}}{{UNIT}};",
    375             ],
    376         ]);
    377 
    378         $this->end_controls_section();
    379         //Close Button
    380 
    381         $this->start_controls_section("close_button_section", [
    382             "label" => esc_html__("Close Button", "popup-for-elementor"),
    383             "tab" => \Elementor\Controls_Manager::TAB_STYLE,
    384         ]);
    385         $this->add_control("hide_close_button", [
    386             "label" => esc_html__("Hide Close Button", "popup-for-elementor"),
    387             "type" => \Elementor\Controls_Manager::SWITCHER,
    388             "label_on" => esc_html__("Yes", "popup-for-elementor"),
    389             "label_off" => esc_html__("No", "popup-for-elementor"),
    390             "return_value" => "yes",
    391             "default" => "no",
    392             "selectors" => [
    393                 "{{WRAPPER}} .popup-close" => "display: none;",
    394             ],
    395         ]);
    396        
    397         $this->add_control("close_button_background_color", [
    398             "label" => esc_html__("Close Button Background", "popup-for-elementor"),
    399             "type" => \Elementor\Controls_Manager::COLOR,
    400             "selectors" => [
    401                 "{{WRAPPER}} .popup-close" => "background-color: {{VALUE}};",
    402             ],
    403         ]);
    404 
    405         $this->add_control("close_button_hover_background_color", [
    406             "label" => esc_html__("Close Button Hover Background", "popup-for-elementor"),
    407             "type" => \Elementor\Controls_Manager::COLOR,
    408             "selectors" => [
    409                 "{{WRAPPER}} .popup-close:hover" =>
    410                     "background-color: {{VALUE}};",
    411             ],
    412         ]);
    413 
    414         $this->add_control("close_button_color", [
    415             "label" => esc_html__("Close Button Color", "popup-for-elementor"),
    416             "type" => \Elementor\Controls_Manager::COLOR,
    417             "selectors" => [
    418                 "{{WRAPPER}} .popup-close" => "color: {{VALUE}};",
    419             ],
    420         ]);
    421 
    422         $this->add_control("close_button_hover_color", [
    423             "label" => esc_html__("Close Button Hover Color", "popup-for-elementor"),
    424             "type" => \Elementor\Controls_Manager::COLOR,
    425             "selectors" => [
    426                 "{{WRAPPER}} .popup-close:hover" => "color: {{VALUE}};",
    427             ],
    428         ]);
    429 
    430         $this->add_control("close_button_size", [
    431             "label" => esc_html__("Close Button Size", "popup-for-elementor"),
    432             "type" => \Elementor\Controls_Manager::SLIDER,
    433             "size_units" => ["px"], // Solo permite px
    434             "range" => [
    435                 "px" => [
    436                     "min" => 10,
    437                     "max" => 100,
    438                 ],
    439             ],
    440             "default" => [
    441                 "unit" => "px",
    442                 "size" => 40, // Tamaño por defecto del botón de cerrar
    443             ],
    444             "selectors" => [
    445                 "{{WRAPPER}} .popup-close" =>
    446                     "width: {{SIZE}}{{UNIT}}; height: {{SIZE}}{{UNIT}}; font-size: calc({{SIZE}}{{UNIT}} / 2);",
    447             ],
    448             "description" => esc_html__(
    449                 "Adjust the size of the close button.",
    450                 "popup-for-elementor"
    451             ),
    452         ]);
    453         $this->add_control("close_button_alignment", [
    454             "label" => esc_html__("Close Button Alignment", "popup-for-elementor"),
    455             "type" => \Elementor\Controls_Manager::CHOOSE,
    456             "options" => [
    457                 "left" => [
    458                     "title" => esc_html__("Left", "popup-for-elementor"),
    459                     "icon" => "eicon-h-align-left",
    460                 ],
    461                 "right" => [
    462                     "title" => esc_html__("Right", "popup-for-elementor"),
    463                     "icon" => "eicon-h-align-right",
    464                 ],
    465             ],
    466             "default" => "right",
    467             "selectors" => [
    468                 "{{WRAPPER}} .popup-close" => "{{VALUE}}: 10px;",
    469             ],
    470             "description" => esc_html__(
    471                 "Align the close button to the left or right.",
    472                 "popup-for-elementor"
    473             ),
    474         ]);
    475 
    476         $this->add_control("close_button_border_radius", [
    477             "label" => esc_html__("Close Button Border Radius", "popup-for-elementor"),
    478             "type" => \Elementor\Controls_Manager::SLIDER,
    479             "size_units" => ["px"], // Solo permite px
    480             "range" => [
    481                 "px" => [
    482                     "min" => 0,
    483                     "max" => 50,
    484                 ],
    485             ],
    486             "selectors" => [
    487                 "{{WRAPPER}} .popup-close" =>
    488                     "border-radius: {{SIZE}}{{UNIT}};",
    489             ],
    490             "description" => esc_html__(
    491                 "Controls the border radius of the close button.",
    492                 "popup-for-elementor"
    493             ),
    494         ]);
    495 
    496         $this->end_controls_section();
    497 
    498         // Visibility controls
    499 $this->start_controls_section("visibility_section", [
    500     "label" => esc_html__("Visibility", "popup-for-elementor"),
    501     "tab" => \Elementor\Controls_Manager::TAB_CONTENT,
    502 ]);
    503 
    504 $this->add_control("show_on_load", [
    505     "label" => esc_html__("Show on Page Load", "popup-for-elementor"),
    506     "type" => \Elementor\Controls_Manager::SWITCHER,
    507     "default" => "",
    508     "description" => esc_html__("Activate to show popup when the page loads. Will disable other visibility options.", "popup-for-elementor"),
    509     "condition" => [
    510         "show_after_delay_enabled!" => "yes",
    511         "show_on_exit_intent!" => "yes",
    512         "show_once!" => "yes",
    513     ],
    514 ]);
    515 
    516 $this->add_control("show_after_delay_enabled", [
    517     "label" => esc_html__("Enable Show After Delay", "popup-for-elementor"),
    518     "type" => \Elementor\Controls_Manager::SWITCHER,
    519     "default" => "",
    520     "description" => esc_html__("Activate to show popup after a delay. Will disable other visibility options.", "popup-for-elementor"),
    521     "condition" => [
    522         "show_on_load!" => "yes",
    523         "show_on_exit_intent!" => "yes",
    524         "show_once!" => "yes",
    525     ],
    526 ]);
    527 
    528 $this->add_control("show_after_delay", [
    529     "label" => esc_html__("Delay (seconds)", "popup-for-elementor"),
    530     "type" => \Elementor\Controls_Manager::NUMBER,
    531     "default" => 3,
    532     "condition" => [
    533         "show_after_delay_enabled" => "yes",
    534     ],
    535 ]);
    536 
    537 $this->add_control("show_on_exit_intent", [
    538     "label" => esc_html__("Show on Exit Intent", "popup-for-elementor"),
    539     "type" => \Elementor\Controls_Manager::SWITCHER,
    540     "default" => "",
    541     "description" => esc_html__("Activate to show popup when the user intends to exit. Will disable other visibility options.", "popup-for-elementor"),
    542     "condition" => [
    543         "show_on_load!" => "yes",
    544         "show_after_delay_enabled!" => "yes",
    545         "show_once!" => "yes",
    546     ],
    547 ]);
    548 $this->add_control("show_once", [
    549     "label" => esc_html__("Show Only Once", "popup-for-elementor"),
    550     "type" => \Elementor\Controls_Manager::SWITCHER,
    551     "default" => "",
    552     "description" => esc_html__("Show the popup only once per session.", "popup-for-elementor"),
    553     "condition" => [
    554         "show_on_load!" => "yes",
    555         "show_after_delay_enabled!" => "yes",
    556         "show_on_exit_intent!" => "yes",
    557     ],
    558 ]);
    559 
    560 $this->add_control("upgrade_to_pro_notice2", [
    561     "type" => \Elementor\Controls_Manager::RAW_HTML,
    562     "raw" => sprintf(
    563         '<div style="margin-top: 20px; padding: 24px; background: linear-gradient(135deg, #1e1e1e, #2b2b2b); border: 1px solid #3c3c3c; border-radius: 8px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.2);">
    564             <strong style="display: block; color: #ffffff; font-size: 14px; font-weight: 300; margin-bottom: 12px;">%s</strong>
    565             <a href="%s" target="_blank" style="display: inline-block; padding: 10px 20px; background-color: #d33a92; color: #fff; border-radius: 4px; text-decoration: none; font-weight: 600; transition: background-color 0.3s;">
    566                 %s
    567             </a>
    568         </div>',
    569         esc_html__("Need more triggers like Scroll, OnClick, or AdBlock detection?", "popup-for-elementor"),
    570         "https://popupforelementor.com/en/home/#buy",
    571         esc_html__("Get Popup for Elementor Pro", "popup-for-elementor")
    572     ),
    573     "content_classes" => "elementor-control-field",
    574 ]);
    575 $this->end_controls_section();
    576     $this->start_controls_section("refresh_section", [
    577             "label" => esc_html__("Refresh", "popup-for-elementor"),
    578             "tab" => \Elementor\Controls_Manager::TAB_CONTENT,
    579         ]);
    580 
    581         $this->add_control(
    582             'refresh_popup',
    583             [
    584                 'label' => esc_html__('Refresh Popup', 'popup-for-elementor'),
    585                 'type' => \Elementor\Controls_Manager::BUTTON,
    586                 'button_type' => 'success',
    587                 'text' => esc_html__('Refresh', 'popup-for-elementor'),
    588                 'description' => esc_html__('Click to refresh the popup content.', 'popup-for-elementor'),
    589                 'frontend_available' => true,
    590             ]
    591         );
    592         $this->add_control("upgrade_to_pro_notice3", [
    593             "type" => \Elementor\Controls_Manager::RAW_HTML,
    594             "raw" => sprintf(
    595                 '<div style="margin-top: 20px; padding: 24px; background: linear-gradient(135deg, #1e1e1e, #2b2b2b); border: 1px solid #3c3c3c; border-radius: 8px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.2);">
    596                     <strong style="display: block; color: #ffffff; font-size: 14px; font-weight: 300; margin-bottom: 12px;">%s</strong>
    597                     <a href="%s" target="_blank" style="display: inline-block; padding: 10px 20px; background-color: #d33a92; color: #fff; border-radius: 4px; text-decoration: none; font-weight: 600; transition: background-color 0.3s;">
    598                         %s
    599                     </a>
    600                 </div>',
    601                 esc_html__("Need more triggers like Scroll, OnClick, or AdBlock detection?", "popup-for-elementor"),
    602                 "https://popupforelementor.com/en/home/#buy",
    603                 esc_html__("Get Popup for Elementor Pro", "popup-for-elementor")
    604             ),
    605             "content_classes" => "elementor-control-field",
    606         ]);
    607         $this->end_controls_section();
    608         $this->start_controls_section("upgrade_section", [
    609             "label" => esc_html__("Popup for Elementor (PRO)", "popup-for-elementor"),
    610             "tab"   => null,
    611         ]);
    612        
    613         $this->add_control("pro_upgrade_box", [
    614             "type" => \Elementor\Controls_Manager::RAW_HTML,
    615             "raw" => sprintf(
    616                 '<div style="padding: 24px; background: linear-gradient(135deg, #1e1e1e, #2b2b2b); border: 1px solid #3c3c3c; border-radius: 8px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.2);">
    617                     <h3 style="color: #ffffff; font-size: 16px; margin-bottom: 12px; font-weight: 600;">%s</h3>
    618                     <p style="color: #bbbbbb; font-size: 13px; margin-bottom: 20px;">%s</p>
    619                     <a href="%s" target="_blank" style="display: inline-block; padding: 10px 20px; background-color: #d33a92; color: #fff; border-radius: 4px; text-decoration: none; font-weight: 600; transition: background-color 0.3s;">
    620                         %s
    621                     </a>
    622                 </div>',
    623                 esc_html__("Unlock More Power", "popup-for-elementor"),
    624                 esc_html__("Upgrade to Pro and access all premium triggers and features.", "popup-for-elementor"),
    625                 "https://popupforelementor.com/en/home/#buy",
    626                 esc_html__("Upgrade to Pro", "popup-for-elementor")
    627             ),
    628         ]);
    629        
    630         $this->end_controls_section();
    631        
    632        
    633 
    634     }
    635 
    636     protected function render()
    637     {
    638         $settings = $this->get_settings_for_display();
    639 
    640         // Configuraciones dinámicas para pasar al script
    641         $config = [
    642             'showOnLoad' => isset($settings['show_on_load']) && $settings['show_on_load'] === 'yes' ? 'yes' : 'no',
    643             'delay' => isset($settings['show_after_delay']) ? (int) $settings['show_after_delay'] * 1000 : 0,
    644             'exitIntent' => isset($settings['show_on_exit_intent']) && $settings['show_on_exit_intent'] === 'yes' ? 'yes' : 'no',
    645             'showOnce' => isset($settings['show_once']) && $settings['show_once'] === 'yes' ? 'yes' : 'no',
    646             'cookieName' => 'popup_seen',
    647             'cookieExpiry' => 7,
    648         ];
    649 
    650         // Pasar configuraciones dinámicas al script
    651         wp_localize_script(
    652             'popup-widget-js',
    653             'PopupForElementorConfig',
    654             $config
    655         );
    656 
    657 
    658         // Obtener animaciones seleccionadas y duración
    659         $animation_in = $settings['popup_animation_in'] ?? 'animate__fadeIn';
    660         $animation_out = $settings['popup_animation_out'] ?? 'animate__fadeOut';
    661         $animation_duration = isset($settings['animation_duration_custom']['size'])
    662             ? (int) $settings['animation_duration_custom']['size']
    663             : 500;
    664 
    665         // Renderizar plantilla de Elementor si está configurada
    666        if (!empty($settings['template_id']) && class_exists('\Elementor\Plugin')) {
    667     $popup_content = \Elementor\Plugin::instance()->frontend->get_builder_content_for_display($settings['template_id']);
    668 
    669     if (\Elementor\Plugin::$instance->editor->is_edit_mode()) {
    670         // Recuperar la URL del editor de Elementor
    671         $edit_url = admin_url('post.php?post=' . absint($settings['template_id']) . '&action=elementor');
    672 
    673         // Solo eliminar etiquetas que no afecten la funcionalidad
    674         $filtered_content = preg_replace('/<meta\b[^>]*>(.*?)<\/meta>/is', '', $popup_content);
    675         $filtered_content = preg_replace('/<link\b[^>]*>(.*?)<\/link>/is', '', $filtered_content);
    676 
    677         // Crear contenido para el modal
    678         $popup_content = '
    679             <div class="elementor-template-button-wrapper" style="text-align: center; margin-top: 15px;">
    680                 <a href="javascript:void(0);"
    681                    class="popup-edit-button elementor-button elementor-button-success elementor-size-sm button-edit-custom"
    682 data-popup-id="' . esc_attr( 'popup_' . get_the_ID() . '_' . $settings['template_id'] ) . '"
    683                    data-edit-url="' . esc_url($edit_url) . '"
    684                    id="open-modal">
    685                    <i class="eicon-edit" style="margin-right: 8px;"></i>' . esc_html__('Edit Template', 'popup-for-elementor') . '
    686                 </a>
    687             </div>
    688             <div class="popup-editor-content">
    689                 ' . $filtered_content . '
    690             </div>';
     41        wp_enqueue_script('popup-widget-js');
    69142    }
    69243}
     44add_action('wp_enqueue_scripts', 'popup_for_elementor_register_assets');
    69345
     46add_action('admin_enqueue_scripts', function () {
     47    wp_dequeue_script('popup-widget-js');
     48    wp_deregister_script('popup-widget-js');
     49}, PHP_INT_MAX);
    69450
    695         // Generar un identificador único para el popup
    696         $current_page_id = get_the_ID();
    697         $popup_id = get_post_meta($settings['template_id'], '_popup_id_' . $current_page_id, true);
    698 
    699         if (empty($popup_id)) {
    700             $popup_id = 'popup_' . $current_page_id . '_' . uniqid();
    701             update_post_meta($settings['template_id'], '_popup_id_' . $current_page_id, $popup_id);
    702         }
    703 
    704         // Renderizar el HTML del popup con ID único
    705         $styles = '';
    706         if (!defined('ELEMENTOR_VERSION') || !\Elementor\Plugin::$instance->editor->is_edit_mode()) {
    707             // Aplicar estilos para ocultar el popup fuera del editor
    708             $styles = 'display: none; visibility: hidden; opacity: 1;';
    709         }
    710 
    711         function filter_popup_content($content)
    712         {
    713             // Lista de etiquetas peligrosas a eliminar (pero manteniendo SVGs y estilos de Elementor)
    714             $dangerous_tags = ['iframe', 'embed', 'object', 'applet', 'meta', 'link'];
    715 
    716             foreach ($dangerous_tags as $tag) {
    717                 $content = preg_replace('/<' . $tag . '.*?>.*?<\/' . $tag . '>/is', '', $content);
    718                 $content = preg_replace('/<' . $tag . '.*?>/is', '', $content);
    719             }
    720 
    721             return $content;
    722         }
    723 
    724         /* Escaping is not applied here because the content has already been filtered
    725         by `filter_popup_content()`, which removes dangerous tags.
    726         Using `esc_html()` would break Elementor's functionality.
    727         This code has been reviewed and is safe. */
    728 
    729         $popup_content_filtered = filter_popup_content($popup_content);
    730 
    731         echo '<div id="' . esc_attr($popup_id) . '" class="popup-overlay popup-widget" style="' . esc_attr($styles) . '">
    732     <div class="popup-content animate__animated ' . esc_attr($animation_in) . '"
    733          style="position: relative; animation-duration: ' . esc_attr($animation_duration) . 'ms;">
    734          <button class="popup-close">&times;</button>';
    735          
    736 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    737 echo $popup_content_filtered;
    738 
    739 echo '</div></div>';
    740 
    741 // This script controls the popup behavior (open/close, animations, hover effects).
    742 // It must be injected directly here because Elementor dynamically refreshes widget content.
    743 // Using wp_enqueue_script or wp_add_inline_script would not persist across reloads.
    744 
    745         echo '<script>
    746     (function($) {
    747         $(document).ready(function() {
    748             const popup = $("#' .
    749             esc_attr($popup_id) .
    750             '");
    751             const popupContent = popup.find(".popup-content");
    752 
    753             if (popup.length) {
    754                 // Abrir popup con animación de entrada
    755                 popup.closest(".elementor-widget-popup_widget").off("click").on("click", function(e) {
    756                     e.preventDefault();
    757                     popup.css({
    758                         display: "flex",
    759                         visibility: "visible"
    760                     });
    761                     popupContent.removeClass("' .
    762             esc_attr($animation_out) .
    763             '").addClass("' .
    764             esc_attr($animation_in) .
    765             '");
    766                 });
    767 
    768                 // Cerrar popup con animación de salida
    769                 popup.find(".popup-close").off("click").on("click", function(e) {
    770                     e.stopPropagation();
    771                     popupContent
    772                         .removeClass("' .
    773             esc_attr($animation_in) .
    774             '")
    775                         .addClass("' .
    776             esc_attr($animation_out) .
    777             '");
    778 
    779                     // Esperar la duración de la animación antes de ocultar el popup
    780                     const duration = ' .
    781             esc_attr($animation_duration) .
    782             ';
    783                     setTimeout(function() {
    784                         popup.css({
    785                             display: "none",
    786                             visibility: "hidden"
    787                         });
    788                         popupContent.removeClass("' .
    789             esc_attr($animation_out) .
    790             '");
    791                     }, duration);
    792                 });
    793 
    794                 // Hover en el botón para cambiar el fondo del popup
    795                 popup.find(".popup-edit-button").on("mouseenter", function() {
    796                     popupContent.css("background-color", "#ffebf2");
    797                 }).on("mouseleave", function() {
    798                     popupContent.css("background-color", "");
    799                 });
    800             } else {
    801                 console.error("Popup element not found in the DOM.");
    802             }
    803         });
    804         elementor.hooks.addAction("panel/open_editor/widget", function (panel, model) {
    805     panel.$el.on("click", ".elementor-control-refresh_popup .elementor-button", function () {
    806         console.log("¡Botón clicado! Refrescando el widget...");
    807 
    808         // Simular un cambio en el modelo
    809         model.set("refresh_trigger", Date.now()); // Valor ficticio para forzar el cambio
    810         model.trigger("change"); // Notificar el cambio a Elementor
    811 
    812         // Verificar si Elementor actualiza la vista
    813         setTimeout(function () {
    814             console.log("Intentando recargar la vista previa...");
    815             elementor.reloadPreview(); // Forzar la recarga si no responde
    816             elementor.once("preview:loaded", function () {
    817                 console.log("Vista previa recargada correctamente.");
    818 
    819                 // Reabrir el popup después de recargar la vista previa
    820                 const $popupOverlay = jQuery(".popup-overlay");
    821                 if ($popupOverlay.length) {
    822                     console.log("Reabriendo el popup...");
    823                     $popupOverlay.css({
    824                         display: "",
    825                         visibility: "",
    826                         opacity: 1,
    827                     });
    828                     console.log("Popup reabierto correctamente.");
    829                 } else {
    830                     console.error("No se encontró el popup en el DOM.");
    831                 }
    832             });
    833         }, 500); // Fallback por si el trigger no es suficiente
    834     });
    835 });
    836     })(jQuery);
    837 </script>';
    838 
    839 // This script controls the custom modal editor outside the iframe (open, close, panel resize).
    840 // Since the modal is rendered outside the iframe (via editor/after_footer),
    841 // this script needs to access it using parent.jQuery.
    842 // It must be echoed directly to stay bound to the button rendered in the iframe.
    843 
    844         echo '<div id="custom-modal">
    845         <div class="modal-container">
    846             <div class="modal-header">
    847                 <div class="modal-title" style="display: flex; align-items: center;">
    848                     <div style="width: 40px; height: 40px; background-color: white; border-radius: 50%; display: flex; justify-content: center; align-items: center; margin-right: 10px;">
    849                         <span class="eicon-table-of-contents" style="font-size: 20px; color: #333;"></span> <!-- Icono de Elementor -->
    850                     </div>
    851                     ' . esc_html__("Popup for Elementor", "popup-for-elementor") . '
    852                 </div>
    853                 <button id="close-modal">&times;</button>
    854             </div>
    855             <iframe id="modal-iframe" src=""></iframe>
    856         </div>
    857       </div>';
    858 
    859       echo '<script>
    860       (function($) {
    861           $(document).ready(function() {
    862               const $modal = $("#custom-modal");
    863               const $iframe = $("#modal-iframe");
    864               const $closeButton = $("#close-modal");
    865      
    866               let originalPanelStyles = {}; // Guardamos los estilos originales
    867      
    868               function refreshWidget() {
    869                   console.log("Ejecutando refresh del widget...");
    870                   if (typeof parent.elementor !== "undefined" && parent.elementor.reloadPreview) {
    871                       parent.elementor.reloadPreview();
    872                       parent.elementor.once("preview:loaded", function() {
    873                           console.log("Vista previa recargada correctamente.");
    874                       });
    875                   }
    876               }
    877      
    878               function toggleElementorPanel(reduce) {
    879                   if (typeof parent.jQuery !== "undefined") {
    880                       const $panel = parent.jQuery("#elementor-panel");
    881                       const $preview = parent.jQuery("#elementor-preview");
    882      
    883                       if (reduce) {
    884                           console.log("Guardando estado del panel y reduciéndolo...");
    885                           originalPanelStyles = {
    886                               width: $panel.css("width"),
    887                               minWidth: $panel.css("min-width"),
    888                               maxWidth: $panel.css("max-width"),
    889                               overflow: $panel.css("overflow"),
    890                               visibility: $panel.css("visibility"),
    891                               opacity: $panel.css("opacity"),
    892                           };
    893      
    894                           $panel.css({
    895                               "width": "60px",
    896                               "min-width": "60px",
    897                               "max-width": "60px",
    898                               "overflow": "hidden",
    899                               "visibility": "hidden",
    900                               "opacity": "0",
    901                               "transition": "width 0.3s ease-in-out"
    902                           });
    903      
    904                           $preview.css({
    905                               "width": "calc(100% - 60px)",
    906                               "transition": "width 0.3s ease-in-out"
    907                           });
    908                       } else {
    909                           console.log("Restaurando el panel de Elementor...");
    910                           $panel.css(originalPanelStyles);
    911      
    912                           $preview.css({
    913                               "width": "calc(100% - " + originalPanelStyles.width + ")"
    914                           });
    915                       }
    916                   }
    917               }
    918      
    919               $("#open-modal").on("click", function() {
    920                   console.log("Modal abierto, reduciendo panel en la ventana principal...");
    921                   const editUrl = $(this).data("edit-url");
    922                   $iframe.attr("src", editUrl);
    923                   $modal.removeClass("hide").addClass("show");
    924      
    925                   toggleElementorPanel(true);
    926               });
    927      
    928               $closeButton.on("click", function() {
    929                   console.log("Cerrando modal, restaurando panel en la ventana principal...");
    930                   $modal.removeClass("show").addClass("hide");
    931      
    932                   setTimeout(() => {
    933                       $iframe.attr("src", ""); // Limpiar el iframe
    934                       toggleElementorPanel(false);
    935                       refreshWidget();
    936                   }, 300);
    937               });
    938      
    939               console.log("Script de reducción de panel cargado.");
    940           });
    941       })(jQuery);
    942       </script>';
    943     }
    944 }
  • popup-for-elementor/trunk/popup-for-elementor.php

    r3331799 r3380762  
    22/**
    33 * Plugin Name: Popup for Elementor
    4  * Plugin URI: https://popupforelementor.com
    5  * Description: Enhance your Elementor website with fully customizable popups. Includes triggers, animations, and advanced settings to improve user interaction and engagement.
    6  * Version: 1.5.7
     4 * Plugin URI: https://www.popupforelementor.com
     5 * Description: Create powerful, fully customizable popups directly in Elementor Free — includes click, delay, load, and exit-intent triggers, animations, and smart visibility controls to boost user engagement.
     6 * Version: 1.5.8
    77 * Author: Veelo
    88 * Author URI: https://www.veelo.es
     
    1111 * License: GPLv2 or later
    1212 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
    13  * Requires at least: 5.6
     13 * Requires at least: 5.8
    1414 * Requires PHP: 7.4
    1515 * Requires Plugins: elementor
    16  * Tested up to: 6.9
     16 * Tested up to: 6.8.3
    1717 */
     18
    1819
    1920
  • popup-for-elementor/trunk/readme.txt

    r3331799 r3380762  
    11=== Popup for Elementor === 
    22Contributors: veelo 
    3 Tags: popup, elementor, modal, wordpress popup, elementor free 
    4 Requires at least: 5.6 
    5 Tested up to: 6.9 
     3Tags: popup, elementor, modal, wordpress popup, elementor free, popup maker, popup builder, modal window 
     4Requires at least: 5.8 
     5Tested up to: 6.8.3 
    66Requires PHP: 7.4 
    7 Stable tag: 1.5.7 
     7Stable tag: 1.5.8 
    88License: GPLv2 or later 
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html 
    1010
    11 Create customizable popups using Elementor Free. Lightweight and easy to use — no coding or Elementor Pro required.
     11Create powerful, customizable popups with **Elementor Free** — no coding or Elementor Pro required.
    1212
    1313== Description ==
    1414
    15 **Popup for Elementor** brings a native popup widget to **Elementor Free**. Design beautiful, responsive popups directly inside the Elementor editor with full control over appearance, triggers, and behavior.
     15**Popup for Elementor** is the easiest and most lightweight popup builder for **Elementor Free**. 
     16Design responsive, conversion-focused popups directly inside Elementor with full visual control — 100% no-code and performance-optimized.
    1617
    17 No need for Elementor Pro or third-party modal plugins. Everything you need is built-in.
     18Unlike other popup plugins, this one works **without Elementor Pro** and **without third-party modal builders**. Everything is native, simple, and fast.
    1819
    19 ### Features Included in the Free Version
     20### 🔹 Key Features
    2021
    21 – **Design Freedom** 
    22   Create pixel-perfect popups with Elementor. Customize layout, colors, borders, padding, animations, close button, overlay, and more.
     22– **Design Freedom with Elementor** 
     23  Build beautiful popups visually. Control layout, colors, padding, overlay, borders, animations, and close buttons. 
    2324
    24 – **Trigger Options (Free)** 
     25– **Free Trigger Options (No Pro Needed)** 
    2526  – Show on page load 
    2627  – Show after a delay (in seconds) 
    27   – Show on exit intent 
    28   – Option to show only once (cookie-based)
     28  – Show on exit intent *(improved)* 
     29  – Show on click *(new in 1.5.8)* 
     30  – Option to show only once (cookie-based, now works with all triggers)
    2931
    30 – **Popup Behavior Controls** 
     32– **Smart Popup Behavior** 
    3133  – Close popup on ESC key 
    3234  – Close when clicking outside (overlay) 
    33   – Option to disable right-click inside the popup
     35  – Option to disable right-click inside popup content
    3436
    3537– **Elementor Template Integration** 
    36   – Load any Elementor template inside the popup for maximum flexibility
     38  – Load any Elementor section or saved template directly inside the popup for ultimate flexibility
    3739
    38 – **Performance Focused** 
    39   – Clean and lightweight code 
    40   – Optimized loading 
    41   – Fully responsive
    42   – Compatible with any WordPress theme
     40– **Performance-First** 
     41  – Lightweight JavaScript and CSS 
     42  – Clean code, no dependencies 
     43  – Fully responsive and SEO-friendly
     44  – Works with any WordPress theme
    4345
    4446– **No Elementor Pro Required** 
    45   All features are 100% compatible with **Elementor Free**
     47  Every feature works natively with **Elementor Free**.
    4648
    47 **Pro version available** (optional): 
    48 The Pro version includes additional features and triggers, such as: 
    49 – Show on scroll 
    50 – Show on click 
    51 – Show on user inactivity 
    52 – Show based on referral URL 
    53 – Show on specific URLs or schedules 
    54 – Show based on login status 
     49**Optional Pro Version:** 
     50Adds advanced targeting and automation features: 
     51– Scroll-based and inactivity triggers 
     52– Referral URL and login-based display 
     53– Time-scheduled popups 
    5554– AdBlock detection 
    56 – Dynamic content loading with enhanced performance 
    57 
    58 The free version works independently and does not require the Pro version.
     55– Dynamic content loading for speed and personalization 
    5956
    6057**Official Website:** https://www.popupforelementor.com 
     
    6259**Support:** [email protected] 
    6360We respond to support requests within 48 hours. 
    64 Live chat is also available on the official website with typical response times between 2 and 3 hours.
     61Live chat available on our website with typical response times between 2 and 3 hours.
    6562
    6663== Installation ==
    6764
    68651. Download the plugin ZIP file. 
    69 2. In your WordPress admin, go to **Plugins > Add New**. 
     662. In your WordPress admin, go to **Plugins Add New**. 
    70673. Click **Upload Plugin** and select the downloaded file. 
    71684. Click **Install Now**, then **Activate**. 
    72 5. Go to **Elementor > Widgets** and search for **Popup for Elementor**.
     695. In Elementor, search for **Popup for Elementor** in the widget panel.
    7370
    7471== Frequently Asked Questions ==
    7572
    7673= Do I need Elementor Pro? = 
    77 No. This plugin works perfectly with **Elementor Free**.
     74No. Popup for Elementor works perfectly with **Elementor Free**.
     75
     76= How do I make a popup appear when users click a button or link? = 
     77Use the new **Click Trigger** (added in version 1.5.8). 
     78You can set a CSS selector or Elementor element to open the popup.
    7879
    7980= Can I control when the popup appears? = 
    80 Yes. You can configure triggers: on load, after delay, or when the user is about to exit the page.
     81Yes — you can trigger it **on load**, **after a delay**, **on click**, or **on exit intent**.
    8182
    82 = Can I prevent the popup from showing multiple times? = 
    83 Yes. You can activate the "show only once" option, which uses cookies to prevent repeated popups.
     83= Can I show the popup only once? = 
     84Yes. Enable the **Show only once** option to use a cookie that prevents the popup from appearing again.
    8485
    8586= Can I use Elementor templates inside the popup? = 
    86 Absolutely. You can insert any Elementor section or template inside the popup container.
     87Absolutely. Load any Elementor template or section inside the popup container.
    8788
    8889== Screenshots ==
    8990
    90 1. Popup settings inside the Elementor editor 
    91 2. Triggers and visibility controls 
     911. Popup widget settings inside the Elementor editor 
     922. Trigger and visibility controls 
    92933. Popup design customization 
    93944. Example popup rendered on the page 
    94 5. Elementor template loaded in a popup
     955. Elementor template loaded inside a popup
    9596
    9697== Changelog ==
     98
     99= 1.5.8 = 
     100* **New:** Added **Click Trigger** to the free version (previously Pro only). 
     101* **Improved:** Exit Intent detection logic rewritten for smoother, more accurate behavior. 
     102* **Improved:** “Show only once” option now works across all triggers. 
     103* **Fix:** Minor issues when combining multiple triggers. 
     104* **Update:** Tested up to WordPress 6.8.3 and Elementor 3.22+. 
     105* **UI:** Minor visual and label adjustments in the widget controls. 
    97106
    98107= 1.5.7 = 
     
    115124* Integrated cookie-based visibility control. 
    116125* Full Elementor Free compatibility. 
    117 * Pro version (optional) adds extended triggers: On Scroll, On Click, Referral-based, Inactivity, Schedule-based, Login detection, and AdBlock detection.
     126* Pro version adds advanced targeting: scroll, referral, inactivity, schedule, login, and AdBlock detection.
    118127
    119128== Upgrade Notice ==
    120129
    121 = 1.5.7 = 
    122 Recommended update: improves stability, fixes close button behavior, and ensures compatibility with WordPress 6.9.
     130= 1.5.8 = 
     131🚀 Major update! Adds **Click Trigger** to the free version, improves Exit Intent detection, and enhances “Show only once” cookie logic. 
     132Recommended update for all users.
Note: See TracChangeset for help on using the changeset viewer.