Plugin Directory

Changeset 3401134


Ignore:
Timestamp:
11/23/2025 04:57:21 AM (3 months ago)
Author:
madnesscode1
Message:

feat: SEO optimization, UX improvements, and analytics enhancements (v1.0.3)

Location:
madnesschat-button/tags/1.0.2
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • madnesschat-button/tags/1.0.2/admin/class-mcnb-admin.php

    r3398221 r3401134  
    1515        // Añadir branding profesional
    1616        add_action( 'admin_notices', array( $this, 'show_professional_branding' ) );
     17       
     18        // Mostrar notice de review después de guardar
     19        add_action( 'admin_notices', array( $this, 'show_review_notice' ) );
     20       
     21        // Manejar dismiss del notice de review
     22        add_action( 'wp_ajax_mcnb_dismiss_review_notice', array( $this, 'dismiss_review_notice' ) );
    1723    }
    1824
     
    7581        ?>
    7682        <div class="wrap mcnb-settings">
    77             <h1><?php esc_html_e( 'MadnessChat Button', 'madnesschat-button' ); ?></h1>
    7883            <h2 class="nav-tab-wrapper">
    7984                <a href="<?php echo esc_url( admin_url( 'admin.php?page=mcnb&tab=basic' ) ); ?>" class="nav-tab <?php echo ( 'basic' === $active_tab ) ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Básico', 'madnesschat-button' ); ?></a>
     
    237242                <?php endif; ?>
    238243            </div>
     244           
     245            <!-- Footer con call-to-action para reviews -->
     246            <div class="mcnb-review-footer" style="margin-top: 40px; padding: 20px; background: #f8f9fa; border-radius: 8px; border: 1px solid #e9ecef; text-align: center;">
     247                <p style="margin: 0 0 12px 0; font-size: 15px; color: #495057;">
     248                    <span style="font-size: 18px; margin-right: 6px;">⭐</span>
     249                    <strong><?php esc_html_e( '¿Te gusta MadnessChat Button?', 'madnesschat-button' ); ?></strong>
     250                </p>
     251                <p style="margin: 0 0 16px 0; font-size: 14px; color: #6c757d;">
     252                    <?php esc_html_e( 'Ayudanos con una reseña positiva, ¡toma menos de 10 segundos!', 'madnesschat-button' ); ?>
     253                </p>
     254                <p style="margin: 0;">
     255                    <a href="https://wordpress.org/support/plugin/madnesschat-button/reviews/#new-post" target="_blank" rel="noopener noreferrer" class="button button-primary" style="text-decoration: none;">
     256                        <span class="dashicons dashicons-star-filled" style="font-size: 16px; vertical-align: middle; margin-right: 4px;"></span>
     257                        <?php esc_html_e( 'Dejar una reseña', 'madnesschat-button' ); ?>
     258                        <span class="dashicons dashicons-external" style="font-size: 14px; vertical-align: middle; margin-left: 4px;"></span>
     259                    </a>
     260                </p>
     261            </div>
    239262        </div>
    240263        <?php
     
    521544        return $plugin_data['Version'] ?? '1.0.2';
    522545    }
     546   
     547    /**
     548     * Mostrar notice discreto para pedir reviews después de guardar
     549     */
     550    public function show_review_notice() {
     551        $screen = get_current_screen();
     552        if ( ! $screen || $screen->id !== 'toplevel_page_mcnb' ) {
     553            return;
     554        }
     555       
     556        // Verificar si el usuario ya descartó el notice
     557        $dismissed = get_user_meta( get_current_user_id(), 'mcnb_review_notice_dismissed', true );
     558        if ( $dismissed ) {
     559            return;
     560        }
     561       
     562        // Solo mostrar si se guardó recientemente (en los últimos 30 segundos)
     563        // o si es la primera vez que se guarda
     564        $last_save = get_user_meta( get_current_user_id(), 'mcnb_last_save', true );
     565        $settings_saved = isset( $_GET['settings-updated'] ) && $_GET['settings-updated'] === 'true';
     566       
     567        if ( ! $settings_saved && ( ! $last_save || ( time() - $last_save ) > 30 ) ) {
     568            return;
     569        }
     570       
     571        ?>
     572        <div class="notice notice-info is-dismissible mcnb-review-notice" style="border-left-color: #25D366; padding: 15px 20px;">
     573            <p style="margin: 0; font-size: 14px; line-height: 1.6;">
     574                <span style="font-size: 18px; margin-right: 8px; vertical-align: middle;">⭐</span>
     575                <strong><?php esc_html_e( '¿Te gusta MadnessChat Button?', 'madnesschat-button' ); ?></strong>
     576                <?php esc_html_e( 'Ayudanos con una reseña positiva, ¡toma menos de 10 segundos!', 'madnesschat-button' ); ?>
     577                <a href="https://wordpress.org/support/plugin/madnesschat-button/reviews/#new-post" target="_blank" rel="noopener noreferrer" class="button button-primary" style="margin-left: 12px; vertical-align: middle;">
     578                    <?php esc_html_e( 'Dejar reseña', 'madnesschat-button' ); ?>
     579                    <span class="dashicons dashicons-external" style="font-size: 14px; vertical-align: middle; margin-left: 4px;"></span>
     580                </a>
     581            </p>
     582        </div>
     583        <script>
     584        jQuery(document).ready(function($) {
     585            $(document).on('click', '.mcnb-review-notice .notice-dismiss', function() {
     586                $.ajax({
     587                    url: ajaxurl,
     588                    type: 'POST',
     589                    data: {
     590                        action: 'mcnb_dismiss_review_notice',
     591                        nonce: '<?php echo esc_js( wp_create_nonce( 'mcnb_dismiss_review_notice' ) ); ?>'
     592                    }
     593                });
     594            });
     595        });
     596        </script>
     597        <?php
     598    }
     599   
     600    /**
     601     * Manejar dismiss del notice de review
     602     */
     603    public function dismiss_review_notice() {
     604        if ( ! current_user_can( 'manage_options' ) ) {
     605            wp_die( -1, 403 );
     606        }
     607       
     608        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     609        $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
     610        if ( ! wp_verify_nonce( $nonce, 'mcnb_dismiss_review_notice' ) ) {
     611            wp_die( -1, 403 );
     612        }
     613       
     614        update_user_meta( get_current_user_id(), 'mcnb_review_notice_dismissed', true );
     615        wp_send_json_success();
     616    }
    523617}
    524618
  • madnesschat-button/tags/1.0.2/admin/class-mcnb-simple-dashboard.php

    r3398221 r3401134  
    108108                <div class="mcnb-dashboard-actions">
    109109                    <select id="mcnb-period-selector" class="mcnb-select">
    110                         <option value="24hours"><?php esc_html_e( 'Últimas 24 horas', 'madnesschat-button' ); ?></option>
    111                         <option value="7days" selected><?php esc_html_e( 'Últimos 7 días', 'madnesschat-button' ); ?></option>
    112                         <option value="30days"><?php esc_html_e( 'Últimos 30 días', 'madnesschat-button' ); ?></option>
    113                         <option value="90days"><?php esc_html_e( 'Últimos 90 días', 'madnesschat-button' ); ?></option>
     110                        <option value="24hours" <?php selected( $period, '24hours' ); ?>><?php esc_html_e( 'Últimas 24 horas', 'madnesschat-button' ); ?></option>
     111                        <option value="7days" <?php selected( $period, '7days' ); ?>><?php esc_html_e( 'Últimos 7 días', 'madnesschat-button' ); ?></option>
     112                        <option value="30days" <?php selected( $period, '30days' ); ?>><?php esc_html_e( 'Últimos 30 días', 'madnesschat-button' ); ?></option>
     113                        <option value="90days" <?php selected( $period, '90days' ); ?>><?php esc_html_e( 'Últimos 90 días', 'madnesschat-button' ); ?></option>
    114114                    </select>
    115115                    <button id="mcnb-export-data" class="button button-secondary" disabled title="<?php echo esc_attr__( 'Esta función está disponible en la versión Pro', 'madnesschat-button' ); ?>">
     
    517517        $additional_script = "
    518518        jQuery(document).ready(function($) {
     519            // Selector de período - siempre funciona
     520            $('#mcnb-period-selector').on('change', function() {
     521                var period = $(this).val();
     522                var currentUrl = new URL(window.location);
     523                currentUrl.searchParams.set('period', period);
     524                window.location.href = currentUrl.toString();
     525            });
     526
     527            // Sincronizar selector con URL
     528            var urlParams = new URLSearchParams(window.location.search);
     529            var selectedPeriod = urlParams.get('period') || '7days';
     530            $('#mcnb-period-selector').val(selectedPeriod);
     531
     532            // Botón de actualizar
     533            $('#mcnb-refresh-data').on('click', function() {
     534                window.location.reload();
     535            });
     536
     537            // Botón de exportar (solo si mcnbDashboard está definido)
    519538            if (typeof mcnbDashboard !== 'undefined') {
    520                 $('.mcnb-button-test > div > div').on('click', function() {
    521                     $(this).css('transform', 'scale(0.95)');
    522                     setTimeout(function() {
    523                         $(this).css('transform', 'scale(1)');
    524                     }.bind(this), 150);
    525                 });
    526 
    527                 $('#mcnb-period-selector').on('change', function() {
    528                     var period = $(this).val();
    529                     var currentUrl = new URL(window.location);
    530                     currentUrl.searchParams.set('period', period);
    531                     window.location.href = currentUrl.toString();
    532                 });
    533 
    534                 var urlParams = new URLSearchParams(window.location.search);
    535                 var selectedPeriod = urlParams.get('period') || '7days';
    536                 $('#mcnb-period-selector').val(selectedPeriod);
    537 
    538                 $('#mcnb-refresh-data').on('click', function() {
    539                     window.location.reload();
    540                 });
    541 
    542                 // Función de exportar solo disponible en versión Pro
    543539                $('#mcnb-export-data').on('click', function(e) {
    544540                    // Verificar si el botón está deshabilitado (versión gratuita)
     
    564560                    \$form.remove();
    565561                });
     562
     563                $('.mcnb-button-test > div > div').on('click', function() {
     564                    $(this).css('transform', 'scale(0.95)');
     565                    setTimeout(function() {
     566                        $(this).css('transform', 'scale(1)');
     567                    }.bind(this), 150);
     568                });
    566569            }
    567570        });
  • madnesschat-button/tags/1.0.2/assets/js/mcnb-dashboard.js

    r3398221 r3401134  
    4747
    4848        loadDashboardData(silent = false) {
     49            // Solo ejecutar si estamos en el dashboard completo (tiene elementos específicos)
     50            // No ejecutar en el dashboard simple
     51            if (!$('#total-clicks').length && !$('#clicks-chart').length) {
     52                return; // Dashboard simple - no hacer nada
     53            }
     54
    4955            if (!silent) {
    5056                this.showLoading();
     
    7884        showLoading() {
    7985            $('.mcnb-chart-loading').addClass('active');
    80             $('.mcnb-kpi-value').text('-');
     86            // Solo cambiar valores si existen los elementos específicos del dashboard completo
     87            // No afectar el dashboard simple que usa .mcnb-kpi-value directamente
     88            $('#total-clicks').text('-');
     89            $('#conversion-rate').text('-');
     90            $('#mobile-percentage').text('-');
     91            $('#peak-hour').text('-');
    8192        }
    8293
     
    100111
    101112        updateKPIs(data) {
    102             // Total Clicks
    103             $('#total-clicks').text(this.formatNumber(data.total_clicks));
    104             $('#clicks-change').text(this.formatChange(data.growth_rate.growth_rate))
    105                 .removeClass('positive negative neutral')
    106                 .addClass(this.getChangeClass(data.growth_rate.growth_rate));
     113            // Solo actualizar si los elementos existen (dashboard completo)
     114            // No afectar el dashboard simple
     115            if ($('#total-clicks').length) {
     116                // Total Clicks
     117                $('#total-clicks').text(this.formatNumber(data.total_clicks));
     118            }
     119            if ($('#clicks-change').length) {
     120                $('#clicks-change').text(this.formatChange(data.growth_rate.growth_rate))
     121                    .removeClass('positive negative neutral')
     122                    .addClass(this.getChangeClass(data.growth_rate.growth_rate));
     123            }
    107124
    108125            // Conversion Rate
    109             $('#conversion-rate').text(data.conversion_rate.rate + '%');
     126            if ($('#conversion-rate').length) {
     127                $('#conversion-rate').text(data.conversion_rate.rate + '%');
     128            }
    110129           
    111130            // Mobile Percentage
    112             const mobileData = data.device_breakdown.find(d => d.device === 'Mobile');
    113             const mobilePercentage = mobileData ?
    114                 Math.round((mobileData.clicks / data.total_clicks) * 100) : 0;
    115             $('#mobile-percentage').text(mobilePercentage + '%');
     131            if ($('#mobile-percentage').length) {
     132                const mobileData = data.device_breakdown.find(d => d.device === 'Mobile');
     133                const mobilePercentage = mobileData ?
     134                    Math.round((mobileData.clicks / data.total_clicks) * 100) : 0;
     135                $('#mobile-percentage').text(mobilePercentage + '%');
     136            }
    116137
    117138            // Peak Hour
    118             const peakHour = data.hourly_distribution.reduce((max, hour) =>
    119                 hour.clicks > max.clicks ? hour : max, data.hourly_distribution[0]);
    120             $('#peak-hour').text(this.formatHour(peakHour.hour));
    121             $('#peak-clicks').text(peakHour.clicks + ' clicks');
     139            if ($('#peak-hour').length) {
     140                const peakHour = data.hourly_distribution.reduce((max, hour) =>
     141                    hour.clicks > max.clicks ? hour : max, data.hourly_distribution[0]);
     142                $('#peak-hour').text(this.formatHour(peakHour.hour));
     143                $('#peak-clicks').text(peakHour.clicks + ' clicks');
     144            }
    122145        }
    123146
     
    603626
    604627    // Initialize dashboard when DOM is ready
     628    // Solo inicializar si estamos en el dashboard completo (tiene elementos específicos)
    605629    $(document).ready(() => {
    606         new MCNBDashboard();
     630        // Verificar si estamos en el dashboard completo o simple
     631        if ($('#total-clicks').length || $('#clicks-chart').length) {
     632            // Dashboard completo - inicializar
     633            new MCNBDashboard();
     634        }
     635        // Dashboard simple - no inicializar, los valores se muestran directamente desde PHP
    607636    });
    608637
  • madnesschat-button/tags/1.0.2/includes/class-mcnb-analytics.php

    r3398221 r3401134  
    6565        }
    6666
    67         global $wpdb;
    68         $table_name = $wpdb->prefix . 'mcnb_analytics';
    69        
    70         // Recopilar datos del click
     67        // Verificar si es versión Pro
     68        $is_pro = apply_filters( 'mcnb/is_pro', false );
     69
     70        global $wpdb;
     71        $table_name = $wpdb->prefix . 'mcnb_analytics';
     72       
     73        // Datos básicos (siempre se recopilan)
    7174        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    7275        $page_url = isset( $_POST['page_url'] ) ? esc_url_raw( wp_unslash( $_POST['page_url'] ) ) : '';
    73         // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    74         $page_title = isset( $_POST['page_title'] ) ? sanitize_text_field( wp_unslash( $_POST['page_title'] ) ) : '';
    75         // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    76         $user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
    77         // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    78         $referrer = isset( $_SERVER['HTTP_REFERER'] ) ? esc_url_raw( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : '';
    79         // Sanitizar y validar button_config (JSON)
    80         $button_config = '{}';
    81         if ( isset( $_POST['button_config'] ) ) {
    82             // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    83             $config_raw = wp_unslash( $_POST['button_config'] );
    84             // Si es un string JSON, decodificar, sanitizar y volver a codificar
    85             if ( is_string( $config_raw ) ) {
    86                 $config_decoded = json_decode( $config_raw, true );
    87                 if ( json_last_error() === JSON_ERROR_NONE && is_array( $config_decoded ) ) {
    88                     // Sanitizar cada campo del array
    89                     $config_sanitized = array();
    90                     foreach ( $config_decoded as $key => $value ) {
    91                         $sanitized_key = sanitize_key( $key );
    92                         if ( is_string( $value ) ) {
    93                             $config_sanitized[ $sanitized_key ] = sanitize_text_field( $value );
    94                         } elseif ( is_array( $value ) ) {
    95                             $config_sanitized[ $sanitized_key ] = map_deep( $value, 'sanitize_text_field' );
    96                         } else {
    97                             $config_sanitized[ $sanitized_key ] = $value;
    98                         }
    99                     }
    100                     $button_config = wp_json_encode( $config_sanitized );
    101                 }
    102             } elseif ( is_array( $config_raw ) ) {
    103                 // Si ya es un array, sanitizar directamente
    104                 $config_sanitized = map_deep( $config_raw, 'sanitize_text_field' );
    105                 $button_config = wp_json_encode( $config_sanitized );
    106             }
    107         }
    10876       
    10977        $data = array(
    11078            'click_date' => current_time( 'mysql' ),
    11179            'page_url' => $page_url,
    112             'page_title' => $page_title,
    113             'user_agent' => $user_agent,
    114             'ip_address' => MCNB_Security::get_client_ip(),
    115             'referrer' => $referrer,
    116             'device_type' => self::detect_device_type(),
    117             'browser' => self::detect_browser(),
    118             'button_config' => $button_config
    11980        );
    12081
    121         // Detectar país por IP (opcional)
    122         $data['country'] = self::detect_country( $data['ip_address'] );
     82        // Solo recopilar datos avanzados si es versión Pro
     83        if ( $is_pro ) {
     84            // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     85            $page_title = isset( $_POST['page_title'] ) ? sanitize_text_field( wp_unslash( $_POST['page_title'] ) ) : '';
     86            // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     87            $user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
     88            // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     89            $referrer = isset( $_SERVER['HTTP_REFERER'] ) ? esc_url_raw( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : '';
     90           
     91            // Sanitizar y validar button_config (JSON)
     92            $button_config = '{}';
     93            if ( isset( $_POST['button_config'] ) ) {
     94                // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     95                $config_raw = wp_unslash( $_POST['button_config'] );
     96                // Si es un string JSON, decodificar, sanitizar y volver a codificar
     97                if ( is_string( $config_raw ) ) {
     98                    $config_decoded = json_decode( $config_raw, true );
     99                    if ( json_last_error() === JSON_ERROR_NONE && is_array( $config_decoded ) ) {
     100                        // Sanitizar cada campo del array
     101                        $config_sanitized = array();
     102                        foreach ( $config_decoded as $key => $value ) {
     103                            $sanitized_key = sanitize_key( $key );
     104                            if ( is_string( $value ) ) {
     105                                $config_sanitized[ $sanitized_key ] = sanitize_text_field( $value );
     106                            } elseif ( is_array( $value ) ) {
     107                                $config_sanitized[ $sanitized_key ] = map_deep( $value, 'sanitize_text_field' );
     108                            } else {
     109                                $config_sanitized[ $sanitized_key ] = $value;
     110                            }
     111                        }
     112                        $button_config = wp_json_encode( $config_sanitized );
     113                    }
     114                } elseif ( is_array( $config_raw ) ) {
     115                    // Si ya es un array, sanitizar directamente
     116                    $config_sanitized = map_deep( $config_raw, 'sanitize_text_field' );
     117                    $button_config = wp_json_encode( $config_sanitized );
     118                }
     119            }
     120           
     121            // Datos avanzados solo para Pro
     122            $data['page_title'] = $page_title;
     123            $data['user_agent'] = $user_agent;
     124            $data['ip_address'] = MCNB_Security::get_client_ip();
     125            $data['referrer'] = $referrer;
     126            $data['device_type'] = self::detect_device_type();
     127            $data['browser'] = self::detect_browser();
     128            $data['button_config'] = $button_config;
     129           
     130            // Detectar país por IP (solo Pro)
     131            $data['country'] = self::detect_country( $data['ip_address'] );
     132        } else {
     133            // Versión gratuita: solo datos mínimos
     134            $data['page_title'] = '';
     135            $data['user_agent'] = '';
     136            $data['ip_address'] = '';
     137            $data['referrer'] = '';
     138            $data['device_type'] = '';
     139            $data['browser'] = '';
     140            $data['button_config'] = '{}';
     141            $data['country'] = '';
     142        }
    123143
    124144        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
  • madnesschat-button/tags/1.0.2/includes/class-mcnb-settings.php

    r3398221 r3401134  
    274274        add_settings_section(
    275275            'mcnb_section_basic',
    276             __( 'Basic Settings', 'madnesschat-button' ),
    277             function() { echo '<p>' . esc_html__( 'Configure your WhatsApp button.', 'madnesschat-button' ) . '</p>'; },
     276            __( 'Configuración básica', 'madnesschat-button' ),
     277            function() { echo '<p>' . esc_html__( 'Configurá tu botón de WhatsApp.', 'madnesschat-button' ) . '</p>'; },
    278278            'mcnb_basic'
    279279        );
    280280
    281         self::add_field( 'main_config', __( 'Configuración Principal', 'madnesschat-button' ), function() {
     281        self::add_field( 'main_config', __( 'Configuración básica', 'madnesschat-button' ), function() {
    282282            $options = self::get_options();
    283283            echo '<div class="mcnb-field-group">';
     
    288288            echo '<label class="mcnb-field-label">' . esc_html__( 'Número de WhatsApp', 'madnesschat-button' ) . '</label>';
    289289            echo '<input type="text" name="mcnb_basic_options[phone_number]" value="' . esc_attr( $options['phone_number'] ) . '" class="mcnb-input mcnb-phone-input" placeholder="5491122334455" />';
    290             printf( '<p class="description">%s</p>', esc_html__( 'Ingresa el número con código de país, sin + ni espacios. Ejemplo: 5491122334455', 'madnesschat-button' ) );
     290            printf( '<p class="description">%s</p>', esc_html__( 'Ingresá el número con código de país, sin + ni espacios. Ejemplo: 5491122334455', 'madnesschat-button' ) );
    291291            echo '</div>';
    292292            echo '</div>';
     
    304304            echo '<div class="mcnb-field-row">';
    305305            echo '<div class="mcnb-field-col">';
    306             echo '<label class="mcnb-field-label">' . esc_html__( 'Posición en pantalla', 'madnesschat-button' ) . '</label>';
     306            echo '<label class="mcnb-field-label">' . esc_html__( 'Ajustá la posición', 'madnesschat-button' ) . '</label>';
    307307            echo '<select name="mcnb_basic_options[position]" class="mcnb-select">';
    308308            foreach ( array( 'bottom-right' => __( 'Abajo derecha', 'madnesschat-button' ), 'bottom-left' => __( 'Abajo izquierda', 'madnesschat-button' ) ) as $value => $label ) {
     
    320320            echo '</div>';
    321321            echo '</div>';
    322             printf( '<p class="description">%s</p>', esc_html__( 'Configura el número, mensaje y posición del botón en tu sitio web.', 'madnesschat-button' ) );
     322            printf( '<p class="description">%s</p>', esc_html__( 'Configurá el número, mensaje y posición del botón en tu sitio web.', 'madnesschat-button' ) );
    323323            echo '</div>';
    324324        }, 'mcnb_section_basic', 'mcnb_basic' );
     
    337337            echo '<span class="mcnb-toggle-slider"></span>';
    338338            echo '</div>';
    339             echo esc_html__( 'Configuración responsive por dispositivo', 'madnesschat-button' );
     339            echo esc_html__( 'Configurá tamaños diferentes por dispositivo', 'madnesschat-button' );
    340340            echo '</label>';
    341341            echo '<p class="mcnb-field-hint">' . esc_html__( 'Permite configurar diferentes tamaños y posiciones para móvil, tablet, laptop y desktop.', 'madnesschat-button' ) . '</p>';
     
    346346            echo '<div id="mcnb_basic_size" class="mcnb-field-row">';
    347347            echo '<div class="mcnb-field-col">';
    348             echo '<label class="mcnb-field-label">' . esc_html__( 'Tamaño del botón', 'madnesschat-button' ) . '</label>';
     348            echo '<label class="mcnb-field-label">' . esc_html__( 'Elegí el tamaño', 'madnesschat-button' ) . '</label>';
    349349            echo '<div class="mcnb-size-options">';
    350350            $values = array( '48' => '48px', '56' => '56px', '64' => '64px', '72' => '72px', '80' => '80px' );
     
    377377            echo '<div class="mcnb-field-row">';
    378378            echo '<div class="mcnb-field-col">';
    379             echo '<label class="mcnb-field-label">' . esc_html__( 'Color de fondo', 'madnesschat-button' ) . '</label>';
     379            echo '<label class="mcnb-field-label">' . esc_html__( 'Elegí el color de fondo', 'madnesschat-button' ) . '</label>';
    380380            echo '<input type="text" name="mcnb_basic_options[brand_color]" value="' . esc_attr( $options['brand_color'] ) . '" class="mcnb-color" />';
    381381            echo '<p class="mcnb-field-hint">' . esc_html__( 'Color principal del botón', 'madnesschat-button' ) . '</p>';
    382382            echo '</div>';
    383383            echo '<div class="mcnb-field-col">';
    384             echo '<label class="mcnb-field-label">' . esc_html__( 'Color del ícono/texto', 'madnesschat-button' ) . '</label>';
     384            echo '<label class="mcnb-field-label">' . esc_html__( 'Elegí el color del ícono', 'madnesschat-button' ) . '</label>';
    385385            echo '<input type="text" name="mcnb_basic_options[text_color]" value="' . esc_attr( $options['text_color'] ) . '" class="mcnb-color" />';
    386386            echo '<p class="mcnb-field-hint">' . esc_html__( 'Color del ícono y texto', 'madnesschat-button' ) . '</p>';
     
    412412                ),
    413413                'custom' => array(
    414                     'label' => __( 'Personalizado', 'madnesschat-button' ),
     414                    'label' => __( 'Personalizá tu ícono', 'madnesschat-button' ),
    415415                    'icon' => '<span style="font-size:20px;">🔧</span>'
    416416                )
     
    437437            echo '<label class="mcnb-field-label">' . esc_html__( 'URL del ícono personalizado', 'madnesschat-button' ) . '</label>';
    438438            echo '<input type="url" name="mcnb_basic_options[custom_icon]" value="' . esc_attr( $options['custom_icon'] ) . '" class="mcnb-input" placeholder="https://ejemplo.com/mi-icono.svg" />';
    439             echo '<p class="description">' . esc_html__( 'Ingresa la URL de una imagen (SVG, PNG, JPG) o código HTML personalizado.', 'madnesschat-button' ) . '</p>';
     439            echo '<p class="description">' . esc_html__( 'Ingresá la URL de una imagen (SVG, PNG, JPG) o código HTML personalizado.', 'madnesschat-button' ) . '</p>';
    440440            echo '</div>';
    441441            echo '</div>';
     
    444444            echo '<div id="mcnb_responsive_config" class="mcnb-field-row" style="display:none;">';
    445445            echo '<div class="mcnb-field-col-full">';
    446             echo '<h4 style="margin: 0 0 16px 0; color: #333;">' . esc_html__( 'Configuración por Dispositivo', 'madnesschat-button' ) . '</h4>';
     446            echo '<h4 style="margin: 0 0 16px 0; color: #333;">' . esc_html__( 'Configurá por dispositivo', 'madnesschat-button' ) . '</h4>';
    447447           
    448448            $devices = array(
     
    507507                echo '<span class="mcnb-toggle-slider"></span>';
    508508                echo '</div>';
    509                 echo esc_html__( 'Mostrar etiqueta', 'madnesschat-button' );
     509                echo esc_html__( 'Mostrá la etiqueta', 'madnesschat-button' );
    510510                echo '</label>';
    511511                echo '</div>';
     
    519519            echo '</div>';
    520520           
    521             printf( '<p class="description">%s</p>', esc_html__( 'Configura el tamaño, estilo, colores e ícono del botón para que se adapte a tu marca.', 'madnesschat-button' ) );
     521            printf( '<p class="description">%s</p>', esc_html__( 'Configurá el tamaño, estilo, colores e ícono del botón para que se adapte a tu marca.', 'madnesschat-button' ) );
    522522            echo '</div>';
    523523        }, 'mcnb_section_basic', 'mcnb_basic' );
     
    533533            echo '<span class="mcnb-toggle-slider"></span>';
    534534            echo '</div>';
    535             echo esc_html__( 'Mostrar etiqueta de texto', 'madnesschat-button' );
     535            echo esc_html__( 'Mostrá la etiqueta de texto', 'madnesschat-button' );
    536536            echo '</label>';
    537537            echo '</div>';
     
    543543            echo '</div>';
    544544            echo '<div class="mcnb-field-col">';
    545             echo '<label class="mcnb-field-label">' . esc_html__( 'Posición de la etiqueta', 'madnesschat-button' ) . '</label>';
     545            echo '<label class="mcnb-field-label">' . esc_html__( 'Ajustá la posición de la etiqueta', 'madnesschat-button' ) . '</label>';
    546546            $positions = array(
    547547                'left' => __( 'Izquierda', 'madnesschat-button' ),
     
    573573            echo '<span class="mcnb-toggle-slider"></span>';
    574574            echo '</div>';
    575             echo esc_html__( 'Activar sombra', 'madnesschat-button' );
     575            echo esc_html__( 'Activá la sombra', 'madnesschat-button' );
    576576            echo '</label>';
    577577            echo '<p class="mcnb-field-hint">' . esc_html__( 'Añade profundidad visual al botón', 'madnesschat-button' ) . '</p>';
     
    583583            echo '<span class="mcnb-toggle-slider"></span>';
    584584            echo '</div>';
    585             echo esc_html__( 'Activar borde', 'madnesschat-button' );
     585            echo esc_html__( 'Activá el borde', 'madnesschat-button' );
    586586            echo '</label>';
    587587            echo '<p class="mcnb-field-hint">' . esc_html__( 'Contorno decorativo alrededor del botón', 'madnesschat-button' ) . '</p>';
     
    592592            echo '<div class="mcnb-field-row mcnb-border-options" style="display:none;">';
    593593            echo '<div class="mcnb-field-col">';
    594             echo '<label class="mcnb-field-label">' . esc_html__( 'Grosor del borde (px)', 'madnesschat-button' ) . '</label>';
     594            echo '<label class="mcnb-field-label">' . esc_html__( 'Ajustá el grosor del borde', 'madnesschat-button' ) . '</label>';
    595595            echo '<input type="number" name="mcnb_basic_options[border_width]" value="' . esc_attr( $options['border_width'] ) . '" min="1" max="10" class="small-text" />';
    596596            echo '</div>';
    597597            echo '<div class="mcnb-field-col">';
    598             echo '<label class="mcnb-field-label">' . esc_html__( 'Color del borde', 'madnesschat-button' ) . '</label>';
     598            echo '<label class="mcnb-field-label">' . esc_html__( 'Elegí el color del borde', 'madnesschat-button' ) . '</label>';
    599599            echo '<input type="text" name="mcnb_basic_options[border_color]" value="' . esc_attr( $options['border_color'] ) . '" class="mcnb-color" />';
    600600            echo '</div>';
     
    629629            // Efectos hover
    630630            echo '<div class="mcnb-field-row">';
    631             echo '<div class="mcnb-field-col">';
     631            echo '<div class="mcnb-field-col-full">';
    632632            echo '<label class="mcnb-field-label">' . esc_html__( 'Efecto al pasar el mouse', 'madnesschat-button' ) . '</label>';
    633633            $hovers = array(
     
    645645            echo '<p class="mcnb-field-hint">' . esc_html__( 'Interacción visual cuando el usuario pasa el mouse', 'madnesschat-button' ) . '</p>';
    646646            echo '</div>';
    647             echo '<div class="mcnb-field-col">';
    648             echo '<div class="mcnb-effects-preview" style="padding:20px;background:#f8f9fa;border-radius:8px;text-align:center;">';
    649             echo '<div class="mcnb-effect-demo" style="width:50px;height:50px;background:#25D366;border-radius:50%;margin:0 auto;display:flex;align-items:center;justify-content:center;color:white;cursor:pointer;transition:all 0.2s ease;">';
    650             echo '<span style="font-size:20px;">💬</span>';
    651             echo '</div>';
    652             echo '<p style="margin:8px 0 0;font-size:12px;color:#6c757d;">' . esc_html__( 'Preview del efecto', 'madnesschat-button' ) . '</p>';
    653             echo '</div>';
    654             echo '</div>';
    655             echo '</div>';
    656            
    657             printf( '<p class="description">%s</p>', esc_html__( 'Configura sombras, bordes, animaciones y efectos hover para hacer el botón más atractivo.', 'madnesschat-button' ) );
     647            echo '</div>';
     648           
     649            printf( '<p class="description">%s</p>', esc_html__( 'Configurá sombras, bordes, animaciones y efectos hover para hacer el botón más atractivo.', 'madnesschat-button' ) );
    658650            echo '</div>';
    659651        }, 'mcnb_section_basic', 'mcnb_basic' );
     
    661653        add_settings_section(
    662654            'mcnb_section_visibility',
    663             __( 'Visibility and Targeting', 'madnesschat-button' ),
    664             function() { echo '<p>' . esc_html__( 'Control where and when the button is displayed.', 'madnesschat-button' ) . '</p>'; },
     655            __( 'Visibilidad y targeting', 'madnesschat-button' ),
     656            function() { echo '<p>' . esc_html__( 'Controlá dónde y cuándo se muestra el botón.', 'madnesschat-button' ) . '</p>'; },
    665657            'mcnb_visibility'
    666658        );
     
    744736        self::add_field( 'schedule', __( 'Horario de atención', 'madnesschat-button' ), function() {
    745737            $options = self::get_options();
    746             echo '<label><input type="checkbox" name="mcnb_basic_options[schedule_enabled]" value="1" ' . checked( $options['schedule_enabled'], true, false ) . ' /> ' . esc_html__( 'Activar horario', 'madnesschat-button' ) . '</label><br />';
     738            echo '<label><input type="checkbox" name="mcnb_basic_options[schedule_enabled]" value="1" ' . checked( $options['schedule_enabled'], true, false ) . ' /> ' . esc_html__( 'Activá el horario', 'madnesschat-button' ) . '</label><br />';
    747739            echo '<input type="time" name="mcnb_basic_options[schedule_start]" value="' . esc_attr( $options['schedule_start'] ) . '" /> - ';
    748740            echo '<input type="time" name="mcnb_basic_options[schedule_end]" value="' . esc_attr( $options['schedule_end'] ) . '" />';
     
    751743        add_settings_section(
    752744            'mcnb_section_privacy',
    753             __( 'Privacy and Analytics', 'madnesschat-button' ),
    754             function() { echo '<p>' . esc_html__( 'Consent and measurement.', 'madnesschat-button' ) . '</p>'; },
     745            __( 'Privacidad y analíticas', 'madnesschat-button' ),
     746            function() { echo '<p>' . esc_html__( 'Consentimiento y medición.', 'madnesschat-button' ) . '</p>'; },
    755747            'mcnb_privacy'
    756748        );
    757749
     750        self::add_field( 'analytics', __( 'Analytics Básico', 'madnesschat-button' ), function() {
     751            $options = self::get_options();
     752            $is_pro = apply_filters( 'mcnb/is_pro', false );
     753            echo '<div class="mcnb-field-group">';
     754            echo '<div class="mcnb-field-row">';
     755            echo '<div class="mcnb-field-col-full">';
     756            echo '<label class="mcnb-toggle-label">';
     757            echo '<div class="mcnb-toggle">';
     758            echo '<input type="checkbox" name="mcnb_basic_options[analytics_enabled]" value="1" ' . checked( $options['analytics_enabled'], true, false ) . ' />';
     759            echo '<span class="mcnb-toggle-slider"></span>';
     760            echo '</div>';
     761            echo esc_html__( 'Activá el tracking de clicks', 'madnesschat-button' );
     762            echo '</label>';
     763            echo '<p class="mcnb-field-hint">' . esc_html__( 'Versión gratuita: Solo registra fecha/hora y URL básica para contar clicks. Versión Pro: Recopila datos detallados (dispositivo, navegador, país, referrer, etc.) para análisis avanzados.', 'madnesschat-button' ) . '</p>';
     764            if ( ! $is_pro ) {
     765                echo '<div style="margin-top: 12px; padding: 12px; background: #f8f9fa; border-left: 3px solid #667eea; border-radius: 4px;">';
     766                echo '<p style="margin: 0; font-size: 13px; color: #495057;">';
     767                echo '<strong>' . esc_html__( '💡 Versión Pro:', 'madnesschat-button' ) . '</strong> ';
     768                echo esc_html__( 'Desbloqueá analytics avanzados con reportes detallados, exportación de datos, análisis por dispositivo/navegador/ubicación e insights automáticos.', 'madnesschat-button' );
     769                echo ' <a href="mailto:[email protected]?subject=Solicito%20Versión%20Pro" style="color: #667eea; text-decoration: none;">' . esc_html__( 'Conocer más →', 'madnesschat-button' ) . '</a>';
     770                echo '</p>';
     771                echo '</div>';
     772            }
     773            echo '</div>';
     774            echo '</div>';
     775            echo '</div>';
     776        }, 'mcnb_section_privacy', 'mcnb_privacy' );
     777
    758778        self::add_field( 'gdpr', __( 'GDPR', 'madnesschat-button' ), function() {
    759779            $options = self::get_options();
    760             echo '<label><input type="checkbox" name="mcnb_basic_options[gdpr_enabled]" value="1" ' . checked( $options['gdpr_enabled'], true, false ) . ' /> ' . esc_html__( 'Solicitar consentimiento antes de abrir WhatsApp', 'madnesschat-button' ) . '</label><br /><br />';
    761            
    762             echo '<div style="margin-top: 15px;">';
    763             echo '<label style="display: block; margin-bottom: 5px; font-weight: 600;">' . esc_html__( 'Mensaje de consentimiento:', 'madnesschat-button' ) . '</label>';
     780            echo '<div class="mcnb-field-group">';
     781            echo '<div class="mcnb-field-row">';
     782            echo '<div class="mcnb-field-col-full">';
     783            echo '<label class="mcnb-toggle-label">';
     784            echo '<div class="mcnb-toggle">';
     785            echo '<input type="checkbox" name="mcnb_basic_options[gdpr_enabled]" value="1" ' . checked( $options['gdpr_enabled'], true, false ) . ' />';
     786            echo '<span class="mcnb-toggle-slider"></span>';
     787            echo '</div>';
     788            echo esc_html__( 'Solicitá consentimiento antes de abrir WhatsApp', 'madnesschat-button' );
     789            echo '</label>';
     790            echo '</div>';
     791            echo '</div>';
     792           
     793            echo '<div class="mcnb-field-row">';
     794            echo '<div class="mcnb-field-col-full">';
     795            echo '<label class="mcnb-field-label">' . esc_html__( 'Mensaje de consentimiento', 'madnesschat-button' ) . '</label>';
    764796            echo '<input type="text" name="mcnb_basic_options[gdpr_message]" value="' . esc_attr( $options['gdpr_message'] ) . '" class="large-text" placeholder="' . esc_attr__( 'Usamos WhatsApp para atenderte. ¿Aceptas continuar?', 'madnesschat-button' ) . '" />';
    765797            echo '</div>';
    766            
    767             echo '<div style="margin-top: 15px;">';
    768             echo '<label style="display: block; margin-bottom: 5px; font-weight: 600;">' . esc_html__( 'Texto del botón de aceptar:', 'madnesschat-button' ) . '</label>';
     798            echo '</div>';
     799           
     800            echo '<div class="mcnb-field-row">';
     801            echo '<div class="mcnb-field-col-full">';
     802            echo '<label class="mcnb-field-label">' . esc_html__( 'Texto del botón de aceptar', 'madnesschat-button' ) . '</label>';
    769803            echo '<input type="text" name="mcnb_basic_options[gdpr_button_label]" value="' . esc_attr( $options['gdpr_button_label'] ) . '" class="regular-text" placeholder="' . esc_attr__( 'Aceptar y continuar', 'madnesschat-button' ) . '" />';
    770804            echo '</div>';
     805            echo '</div>';
     806            echo '</div>';
    771807    }, 'mcnb_section_privacy', 'mcnb_privacy' );
    772808
    773809    self::add_field( 'utm', __( 'UTM', 'madnesschat-button' ), function() {
    774810            $options = self::get_options();
    775             echo '<label><input type="checkbox" name="mcnb_basic_options[utm_enabled]" value="1" ' . checked( $options['utm_enabled'], true, false ) . ' /> ' . esc_html__( 'Añadir parámetros UTM al enlace', 'madnesschat-button' ) . '</label><br />';
     811            echo '<label><input type="checkbox" name="mcnb_basic_options[utm_enabled]" value="1" ' . checked( $options['utm_enabled'], true, false ) . ' /> ' . esc_html__( 'Añadí parámetros UTM al enlace', 'madnesschat-button' ) . '</label><br />';
    776812            echo '<input type="text" name="mcnb_basic_options[utm_source]" value="' . esc_attr( $options['utm_source'] ) . '" class="small-text" /> ';
    777813            echo '<input type="text" name="mcnb_basic_options[utm_medium]" value="' . esc_attr( $options['utm_medium'] ) . '" class="small-text" /> ';
     
    782818        add_settings_section(
    783819            'mcnb_section_advanced',
    784             __( 'Advanced Features', 'madnesschat-button' ),
    785             function() { echo '<p>' . esc_html__( 'Premium features to maximize conversions.', 'madnesschat-button' ) . '</p>'; },
     820            __( 'Funciones avanzadas', 'madnesschat-button' ),
     821            function() { echo '<p>' . esc_html__( 'Funciones premium para maximizar conversiones.', 'madnesschat-button' ) . '</p>'; },
    786822            'mcnb_advanced'
    787823        );
     
    794830            echo '<div class="mcnb-pro-feature-content">';
    795831            echo '<h3>' . esc_html__( 'Múltiples Agentes', 'madnesschat-button' ) . '</h3>';
    796             echo '<p>' . esc_html__( 'Configura varios números de WhatsApp con rotación automática según horarios de disponibilidad.', 'madnesschat-button' ) . '</p>';
     832            echo '<p>' . esc_html__( 'Configurá varios números de WhatsApp con rotación automática según horarios de disponibilidad.', 'madnesschat-button' ) . '</p>';
    797833            echo '<ul class="mcnb-feature-benefits">';
    798834            echo '<li><span class="dashicons dashicons-yes"></span> ' . esc_html__( 'Múltiples números de WhatsApp', 'madnesschat-button' ) . '</li>';
  • madnesschat-button/tags/1.0.2/madnesschat-button.php

    r3398410 r3401134  
    33 * Plugin Name: MadnessChat Button
    44 * Description: Easy-to-configure floating WhatsApp button with GDPR compliance, basic analytics, and smart triggers.
    5  * Version: 1.0.2
     5 * Version: 1.0.3
    66 * Author: madnesscode1
    77 * Requires at least: 5.6
     
    3939}
    4040
    41 define( 'MCNB_VERSION', '1.0.2' );
     41define( 'MCNB_VERSION', '1.0.3' );
    4242define( 'MCNB_SLUG', 'madnesschat-button' );
    4343define( 'MCNB_FILE', __FILE__ );
  • madnesschat-button/tags/1.0.2/readme.txt

    r3399016 r3401134  
    55Tested up to: 6.8
    66Requires PHP: 7.3
    7 Stable tag: 1.0.2
     7Stable tag: 1.0.3
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    1010
    11 Easy-to-configure floating WhatsApp button for WordPress. Perfect for contacting your visitors.
     11Add a customizable WhatsApp chat button to your WordPress site — 4 styles, 6 animations, responsive sizes by device, GDPR-ready.
    1212
    1313== Description ==
     14
     15This plugin helps you add a WhatsApp floating button, WhatsApp contact widget, or WhatsApp chat icon without coding. Ideal for small businesses looking to increase conversions and customer support.
    1416
    1517**MadnessChat Button** is a simple and free solution to integrate a WhatsApp chat button into your WordPress website. Perfect for blogs, small businesses, and personal projects.
     
    127129== Changelog ==
    128130
     131= 1.0.3 =
     132* SEO optimization: Updated short description with keywords (WhatsApp button, WhatsApp chat, WhatsApp widget)
     133* Added SEO paragraph in description section for better WordPress.org search visibility
     134* Added review call-to-action: Footer message and admin notice after saving settings
     135* UI improvements: Removed duplicate title, unified style to friendly Spanish (informal tone)
     136* Removed duplicate preview in Visual Effects section (already shown in sidebar)
     137* Fixed dashboard statistics: Prevented values from disappearing due to JavaScript conflicts
     138* Added Analytics field in Privacy tab with clear Basic vs Pro separation
     139* Optimized data collection: Free version only collects essential data (date, URL), Pro version collects detailed analytics (device, browser, country, IP, etc.)
     140* Improved dashboard period selector synchronization
     141* Enhanced user experience with consistent informal Spanish language throughout admin panel
     142
    129143= 1.0.2 =
    130144* Changed all prefixes from "mcnb" to "mcnb" to comply with WordPress naming conventions (minimum 4 characters)
     
    143157== Upgrade Notice ==
    144158
     159= 1.0.3 =
     160SEO and UX improvements update. Better search visibility, review prompts, improved dashboard stability, and optimized data collection. Free version now collects minimal data for privacy. Recommended update for all users.
     161
    145162= 1.0.2 =
    146163Important WordPress.org compliance update. Prefixes updated to meet naming standards. Enhanced security and code quality. No breaking changes - all functionality remains the same.
Note: See TracChangeset for help on using the changeset viewer.