Plugin Directory

Changeset 3325285


Ignore:
Timestamp:
07/09/2025 11:19:30 PM (9 months ago)
Author:
desk9
Message:

fixed error, countdown working now

Location:
smart-download-redirector
Files:
2 deleted
13 edited

Legend:

Unmodified
Added
Removed
  • smart-download-redirector/tags/1.0.0/admin/settings-page.php

    r3325102 r3325285  
    12881288    }
    12891289
    1290     // Check if settings were updated (WordPress core parameter, safe to check)
    1291     // Additional security: Only process if user has proper capabilities
    1292     if (current_user_can('manage_options') &&
    1293         isset($_GET['settings-updated']) &&
    1294         $_GET['settings-updated'] === 'true' &&
    1295         !get_settings_errors('smartdr_messages') // Prevent duplicate messages
    1296     ) {
     1290    // Check if settings were updated
     1291    // Use WordPress core function to check if options were updated - this is security-safe
     1292    $settings_updated = false;
     1293    if (current_user_can('manage_options')) {
     1294        // Check if any of our options were recently updated
     1295        $check_options = [
     1296            'smartdr_target_domains',
     1297            'smartdr_countdown_time',
     1298            'smartdr_redirect_delay',
     1299            'smartdr_styles',
     1300            'smartdr_layout_style'
     1301        ];
     1302       
     1303        foreach ($check_options as $option) {
     1304            if (get_transient('smartdr_option_updated_' . $option)) {
     1305                $settings_updated = true;
     1306                delete_transient('smartdr_option_updated_' . $option);
     1307                break;
     1308            }
     1309        }
     1310       
     1311        // Fallback: Check WordPress core parameter (already validated by WordPress)
     1312        if (!$settings_updated &&
     1313            filter_input(INPUT_GET, 'settings-updated', FILTER_SANITIZE_STRING) === 'true' &&
     1314            !get_settings_errors('smartdr_messages')
     1315        ) {
     1316            $settings_updated = true;
     1317        }
     1318    }
     1319   
     1320    if ($settings_updated) {
    12971321        add_settings_error(
    12981322            'smartdr_messages',
     
    13561380}
    13571381
    1358 /**
    1359  * Get WPML translated string
    1360  */
    1361 function smartdr_get_wpml_string($name, $original_value) {
    1362     if (function_exists('wpml_translate_single_string')) {
    1363         return wpml_translate_single_string('smart-download-redirector', $name, $original_value);
    1364     }
    1365     return $original_value;
    1366 }
     1382
     1383
     1384/**
     1385 * Set transient when options are updated for secure update detection
     1386 */
     1387function smartdr_option_updated($option_name) {
     1388    if (strpos($option_name, 'smartdr_') === 0) {
     1389        set_transient('smartdr_option_updated_' . $option_name, true, 60); // 1 minute
     1390    }
     1391}
     1392
     1393// Hook to track option updates
     1394add_action('updated_option', 'smartdr_option_updated');
    13671395
    13681396// Hook to register WPML strings when options are updated
  • smart-download-redirector/tags/1.0.0/assets/countdown.js

    r3325102 r3325285  
    11/**
    2  * Enhanced countdown timer with progress ring and step indicators
     2 * Simple and reliable countdown timer
    33 */
    4 jQuery(function($) {
     4(function($) {
    55    'use strict';
    66   
    7     // Debug helper
    8     var debug = function(msg, data) {
    9         if (window.console && console.log) {
    10             console.log('[SDR Debug]:', msg, data || '');
    11         }
    12     };
    13 
    14     debug('Script starting');
    15 
    16     // Validate data
    17     if (typeof smartdrData === 'undefined') {
    18         debug('ERROR: smartdrData missing');
    19         return;
     7    // Function to run when DOM is ready
     8    function initCountdown() {
     9        console.log('[SmartDR] Countdown script starting...');
     10       
     11        // Check if jQuery is available
     12        if (typeof $ === 'undefined') {
     13            console.error('[SmartDR] jQuery not available');
     14            return;
     15        }
     16       
     17        // Check if smartdrData is available
     18        if (typeof smartdrData === 'undefined') {
     19            console.error('[SmartDR] smartdrData not available');
     20            return;
     21        }
     22       
     23        console.log('[SmartDR] smartdrData:', smartdrData);
     24       
     25        // Check if we have a valid URL to countdown for
     26        if (!smartdrData.hasValidUrl) {
     27            console.log('[SmartDR] No valid URL - countdown not started');
     28            return;
     29        }
     30       
     31        // Get countdown time
     32        var countdownTime = parseInt(smartdrData.countdownTime) || 10;
     33        var redirectUrl = smartdrData.redirectUrl || '#';
     34        var redirectDelay = parseInt(smartdrData.redirectDelay) || 3000;
     35       
     36        console.log('[SmartDR] Configuration:', {
     37            countdownTime: countdownTime,
     38            redirectUrl: redirectUrl,
     39            redirectDelay: redirectDelay
     40        });
     41       
     42        // Find countdown elements
     43        var $counterNumber = $('#smartdr-countdown-number');
     44        var $counterText = $('#smartdr-countdown-text');
     45        var $progressBar = $('#smartdr-progress-bar');
     46        var $manualRedirect = $('.smartdr-manual-redirect');
     47        var $progressRing = $('.smartdr-progress-ring-circle');
     48       
     49        console.log('[SmartDR] Elements found:', {
     50            counterNumber: $counterNumber.length,
     51            counterText: $counterText.length,
     52            progressBar: $progressBar.length,
     53            manualRedirect: $manualRedirect.length,
     54            progressRing: $progressRing.length
     55        });
     56       
     57        // Determine which element to use
     58        var $activeElement = null;
     59        var layoutType = 'unknown';
     60       
     61        if ($counterNumber.length > 0) {
     62            $activeElement = $counterNumber;
     63            layoutType = 'circular';
     64            console.log('[SmartDR] Using circular layout');
     65        } else if ($counterText.length > 0) {
     66            $activeElement = $counterText;
     67            layoutType = 'progressbar';
     68            console.log('[SmartDR] Using progressbar layout');
     69        } else {
     70            console.error('[SmartDR] No countdown element found!');
     71            return;
     72        }
     73       
     74        // Initialize progress ring if available
     75        var circumference = 0;
     76        if ($progressRing.length > 0 && layoutType === 'circular') {
     77            try {
     78                var radius = $progressRing[0].r.baseVal.value;
     79                circumference = radius * 2 * Math.PI;
     80                $progressRing[0].style.strokeDasharray = circumference;
     81                $progressRing[0].style.strokeDashoffset = circumference;
     82                console.log('[SmartDR] Progress ring initialized, circumference:', circumference);
     83            } catch (e) {
     84                console.warn('[SmartDR] Progress ring initialization failed:', e);
     85            }
     86        }
     87       
     88        // Start countdown
     89        var timeLeft = countdownTime;
     90        var initialTime = countdownTime;
     91        var isComplete = false;
     92       
     93        console.log('[SmartDR] Starting countdown from', timeLeft);
     94       
     95        function updateCountdown() {
     96            if (isComplete) return;
     97           
     98            console.log('[SmartDR] Countdown tick:', timeLeft);
     99           
     100            // Update display based on layout type
     101            if (layoutType === 'circular') {
     102                $activeElement.text(timeLeft);
     103               
     104                // Update progress ring
     105                if ($progressRing.length > 0 && circumference > 0) {
     106                    var progress = (initialTime - timeLeft) / initialTime;
     107                    var offset = circumference - (progress * circumference);
     108                    $progressRing[0].style.strokeDashoffset = offset;
     109                }
     110            } else if (layoutType === 'progressbar') {
     111                var secondsText = smartdrData.secondsText || 'seconds remaining';
     112                $activeElement.text(timeLeft + ' ' + secondsText);
     113               
     114                // Update progress bar
     115                if ($progressBar.length > 0) {
     116                    var progress = (initialTime - timeLeft) / initialTime * 100;
     117                    $progressBar.css('width', progress + '%');
     118                }
     119            }
     120           
     121            // Check if countdown is complete
     122            if (timeLeft <= 0) {
     123                completeCountdown();
     124            } else {
     125                timeLeft--;
     126            }
     127        }
     128       
     129        function completeCountdown() {
     130            if (isComplete) return;
     131            isComplete = true;
     132           
     133            console.log('[SmartDR] Countdown complete!');
     134           
     135            // Clear interval
     136            clearInterval(countdownInterval);
     137           
     138            // Update display for completion
     139            if (layoutType === 'circular') {
     140                $activeElement.text('→');
     141               
     142                // Complete progress ring
     143                if ($progressRing.length > 0) {
     144                    $progressRing[0].style.strokeDashoffset = 0;
     145                }
     146            } else if (layoutType === 'progressbar') {
     147                var downloadReadyText = smartdrData.downloadReadyText || 'Download ready!';
     148                $activeElement.text(downloadReadyText);
     149               
     150                // Complete progress bar
     151                if ($progressBar.length > 0) {
     152                    $progressBar.css('width', '100%');
     153                }
     154            }
     155           
     156            // Show manual redirect link
     157            if ($manualRedirect.length > 0) {
     158                $manualRedirect.show();
     159            }
     160           
     161            // Start redirect timer
     162            console.log('[SmartDR] Starting redirect timer, delay:', redirectDelay + 'ms');
     163            setTimeout(function() {
     164                if (redirectUrl && redirectUrl !== '#') {
     165                    console.log('[SmartDR] Redirecting to:', redirectUrl);
     166                    window.location.href = redirectUrl;
     167                } else {
     168                    console.log('[SmartDR] No redirect URL, staying on page');
     169                }
     170            }, redirectDelay);
     171        }
     172       
     173        // Start the countdown
     174        updateCountdown(); // Initial update
     175        var countdownInterval = setInterval(updateCountdown, 1000);
     176       
     177        // Manual redirect handler
     178        $manualRedirect.find('a').on('click', function(e) {
     179            if (redirectUrl && redirectUrl !== '#') {
     180                console.log('[SmartDR] Manual redirect clicked');
     181                clearInterval(countdownInterval);
     182                // Let the link work normally
     183            } else {
     184                e.preventDefault();
     185                console.log('[SmartDR] Manual redirect clicked but no valid URL');
     186            }
     187        });
     188       
     189        console.log('[SmartDR] Countdown initialized successfully');
    20190    }
    21 
    22     // Get debug info safely
    23     var debugInfo = {
    24         countdownTime: smartdrData.countdownTime || 5,
    25         redirectDelay: smartdrData.redirectDelay || 3000,
    26         rawDelay: (smartdrData.debug && smartdrData.debug.rawDelay) || 3,
    27         msDelay: (smartdrData.debug && smartdrData.debug.msDelay) || 3000,
    28         defaultDelay: (smartdrData.debug && smartdrData.debug.defaultDelay) || 3000
    29     };
    30 
    31     // Log all debug info
    32     debug('Configuration:', debugInfo);
    33 
    34     // Get and validate countdown time
    35     var timeLeft = parseInt(smartdrData.countdownTime);
    36     if (isNaN(timeLeft) || timeLeft <= 0) {
    37         debug('ERROR: Invalid countdown time:', timeLeft);
    38         return;
     191   
     192    // Initialize when DOM is ready
     193    $(document).ready(function() {
     194        initCountdown();
     195    });
     196   
     197    // Fallback for cases where jQuery might not be loaded immediately
     198    if (document.readyState === 'loading') {
     199        document.addEventListener('DOMContentLoaded', function() {
     200            setTimeout(initCountdown, 100);
     201        });
     202    } else {
     203        setTimeout(initCountdown, 100);
    39204    }
    40 
    41     // Get and validate redirect delay
    42     var redirectDelay = parseInt(smartdrData.redirectDelay);
    43     debug('Parsed redirect delay:', redirectDelay);
    44    
    45     if (isNaN(redirectDelay) || redirectDelay < 1000) {
    46         debug('WARNING: Invalid redirect delay, using default');
    47         redirectDelay = debugInfo.defaultDelay;
    48     }
    49    
    50     debug('Final redirect delay:', redirectDelay + 'ms');
    51 
    52     // Get elements
    53     var $counter = $('#smartdr-countdown-number');
    54     var $ring = $('.smartdr-progress-ring-circle');
    55     var $steps = $('.smartdr-step');
    56     var $targetUrl = $('.smartdr-target-url');
    57     var $manualRedirect = $('.smartdr-manual-redirect');
    58 
    59     if (!$counter.length) {
    60         debug('ERROR: Counter element missing');
    61         return;
    62     }
    63 
    64     // Initialize progress ring
    65     var circumference = 0;
    66     if ($ring.length) {
    67         var radius = $ring[0].r.baseVal.value;
    68         circumference = radius * 2 * Math.PI;
    69         $ring[0].style.strokeDasharray = circumference;
    70         $ring[0].style.strokeDashoffset = circumference;
    71     }
    72 
    73     // Store initial time for progress calculations
    74     var initialTime = timeLeft;
    75     var countdownInterval;
    76     var currentStep = 1;
    77 
    78     // Update display function
    79     function updateDisplay() {
    80         // Update counter text
    81         $counter.text(timeLeft);
    82 
    83         // Update progress ring
    84         if ($ring.length) {
    85             var progress = (initialTime - timeLeft) / initialTime;
    86             var offset = circumference - (progress * circumference);
    87             $ring[0].style.strokeDashoffset = offset;
    88         }
    89 
    90         // Calculate current step
    91         var newStep;
    92         if (timeLeft > (initialTime * 2/3)) {
    93             newStep = 1;
    94         } else if (timeLeft > (initialTime * 1/3)) {
    95             newStep = 2;
    96         } else {
    97             newStep = 3;
    98         }
    99 
    100         // Only update if step changed
    101         if (newStep !== currentStep) {
    102             currentStep = newStep;
    103             // Update step indicators
    104             $steps.removeClass('active');
    105             $steps.slice(0, currentStep).addClass('active');
    106 
    107             // Show URL at appropriate step if enabled
    108             if (typeof smartdrData.showDestination !== 'undefined' && smartdrData.showDestination) {
    109                 $targetUrl.toggle(currentStep >= smartdrData.destinationStep);
    110             }
    111 
    112             // Show manual link at appropriate step if enabled
    113             if (typeof smartdrData.showManualLink !== 'undefined' && smartdrData.showManualLink) {
    114                 $manualRedirect.toggle(currentStep >= smartdrData.manualLinkStep);
    115             }
    116         }
    117     }
    118 
    119     // Handle countdown completion
    120     function complete() {
    121         debug('Countdown complete');
    122        
    123         // Clear interval
    124         clearInterval(countdownInterval);
    125        
    126         // Update display
    127         if ($ring.length) {
    128             $ring[0].style.strokeDashoffset = 0;
    129         }
    130         $steps.removeClass('active').eq(2).addClass('active');
    131        
    132         // Show both URL and manual link at completion if enabled
    133         if (typeof smartdrData.showDestination !== 'undefined' && smartdrData.showDestination) {
    134             $targetUrl.fadeIn(400);
    135         }
    136         if (typeof smartdrData.showManualLink !== 'undefined' && smartdrData.showManualLink) {
    137             $manualRedirect.fadeIn(400);
    138         }
    139 
    140         // Fade in the arrow with animation
    141         $counter.fadeOut(200, function() {
    142             $(this).text('→').fadeIn(200);
    143         });
    144 
    145         debug('Starting redirect timer:', {
    146             delay: redirectDelay,
    147             inSeconds: redirectDelay/1000,
    148             url: smartdrData.redirectUrl
    149         });
    150        
    151         // Start redirect timer
    152         setTimeout(function() {
    153             debug('Redirect timer complete, redirecting now');
    154             window.location.href = smartdrData.redirectUrl;
    155         }, redirectDelay);
    156     }
    157 
    158     // Start countdown
    159     debug('Starting countdown');
    160     updateDisplay(); // Initial display update
    161 
    162     countdownInterval = setInterval(function() {
    163         timeLeft--;
    164         debug('Tick:', timeLeft);
    165        
    166         if (timeLeft <= 0) {
    167             complete();
    168         } else {
    169             updateDisplay();
    170         }
    171     }, 1000);
    172 });
     205   
     206})(jQuery);
  • smart-download-redirector/tags/1.0.0/assets/styles.css

    r3325102 r3325285  
    4545}
    4646
     47.smartdr-info {
     48    padding: 1em;
     49    margin: 1em 0;
     50    background-color: #d1ecf1;
     51    border: 1px solid #b8daff;
     52    border-radius: 4px;
     53    color: #0c5460;
     54    text-align: center;
     55}
     56
     57/* Base countdown styles - applies to all layouts with circular progress */
    4758.smartdr-countdown {
    48     text-align: center;
    49     margin: 2em 0;
    50 }
    51 
    52 .smartdr-countdown-number {
     59    position: relative;
     60    width: 120px;
     61    height: 120px;
     62    margin: 0 auto 2em;
     63    display: flex;
     64    align-items: center;
     65    justify-content: center;
     66    text-align: center;
     67}
     68
     69.smartdr-countdown-number,
     70#smartdr-countdown-number {
     71    position: relative;
     72    z-index: 2;
     73    line-height: 1;
     74    display: flex;
     75    align-items: center;
     76    justify-content: center;
     77    width: 100%;
     78    height: 100%;
     79    color: var(--smartdr-counter-color, #2271b1);
    5380    font-size: var(--smartdr-counter-size, 4em);
    54     color: var(--smartdr-counter-color, #2271b1);
    55     font-weight: bold;
    56     line-height: 1;
    57     margin: 0.5em 0;
     81    font-weight: var(--smartdr-counter-font-weight, 600);
     82    margin: 0;
     83    padding: 0;
    5884}
    5985
    6086.smartdr-progress-ring {
     87    position: absolute;
     88    top: 0;
     89    left: 0;
     90    width: 120px;
     91    height: 120px;
    6192    transform: rotate(-90deg);
    62     transform-origin: 50% 50%;
     93    transform-origin: center;
    6394}
    6495
     
    85116    transition: opacity 0.3s ease;
    86117}
    87 
    88 
    89118
    90119.smartdr-step.active {
     
    113142    font-size: var(--smartdr-manual-link-size, 1em);
    114143    transition: color 0.2s ease;
     144    display: inline-block;
    115145}
    116146
     
    132162    margin-bottom: 1.5em;
    133163    text-align: center;
    134 }
    135 
    136 /* Standard and Compact Layout countdown styles */
    137 .smartdr-countdown {
    138     position: relative;
    139     width: 120px;
    140     height: 120px;
    141     margin: 0 auto 2em !important;
    142     display: flex !important;
    143     align-items: center !important;
    144     justify-content: center !important;
    145     text-align: center !important;
    146 }
    147 
    148 .smartdr-progress-ring {
    149     position: absolute;
    150     top: 0;
    151     left: 0;
    152     width: 120px;
    153     height: 120px;
    154     transform: rotate(-90deg);
    155     transform-origin: center;
    156 }
    157 
    158 .smartdr-progress-ring-circle {
    159     stroke: var(--smartdr-counter-color) !important;
    160     stroke-width: 4 !important;
    161     fill: transparent !important;
    162 }
    163 
    164 #smartdr-countdown-number {
    165     position: relative;
    166     z-index: 2;
    167     line-height: 1;
    168     display: flex;
    169     align-items: center;
    170     justify-content: center;
    171     width: 100%;
    172     height: 100%;
    173     color: var(--smartdr-counter-color);
    174     font-size: var(--smartdr-counter-size);
    175     font-weight: var(--smartdr-counter-font-weight);
    176 }
    177 
    178 .smartdr-manual-redirect {
    179     margin-top: 1.5em;
    180     text-align: center;
    181 }
    182 
    183 .smartdr-manual-link {
    184     color: var(--smartdr-manual-link-color);
    185     font-size: var(--smartdr-manual-link-size);
    186     text-decoration: none;
    187     transition: color 0.2s ease;
    188     display: inline-block;
    189 }
    190 
    191 .smartdr-manual-link:hover {
    192     color: var(--smartdr-manual-link-hover-color);
    193     text-decoration: underline;
     164    color: var(--smartdr-heading-color, #333333);
     165    font-size: var(--smartdr-heading-size, 32px);
     166    font-weight: 600;
     167    line-height: 1.4;
     168}
     169
     170/* Standard Layout - ensure proper centering */
     171.smartdr-layout-standard .smartdr-countdown {
     172    margin: 0 auto 2em;
    194173}
    195174
     
    216195    margin-bottom: 1em;
    217196    text-align: left;
    218     font-size: var(--smartdr-heading-size);
    219     color: var(--smartdr-heading-color);
     197    font-size: var(--smartdr-heading-size, 32px);
     198    color: var(--smartdr-heading-color, #333333);
    220199}
    221200
     
    230209    height: 120px;
    231210    margin: 0;
    232     display: flex !important;
    233     align-items: center !important;
    234     justify-content: center !important;
     211    display: flex;
     212    align-items: center;
     213    justify-content: center;
    235214}
    236215
     
    242221}
    243222
    244 .smartdr-layout-progressbar .smartdr-progress-text {
     223.smartdr-layout-progressbar .smartdr-progress-text,
     224.smartdr-layout-progressbar #smartdr-countdown-text {
    245225    margin-bottom: 1em;
    246     font-size: var(--smartdr-counter-size);
    247     color: var(--smartdr-counter-color);
    248     font-weight: var(--smartdr-counter-font-weight);
     226    font-size: var(--smartdr-counter-size, 36px);
     227    color: var(--smartdr-counter-color, #2271b1);
     228    font-weight: var(--smartdr-counter-font-weight, 600);
     229    display: block;
    249230}
    250231
     
    255236    overflow: hidden;
    256237    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
    257 }
    258 
    259 .smartdr-layout-progressbar .smartdr-progress-bar {
     238    margin-bottom: 1em;
     239}
     240
     241.smartdr-layout-progressbar .smartdr-progress-bar,
     242.smartdr-layout-progressbar #smartdr-progress-bar {
    260243    height: 100%;
    261     background: var(--smartdr-counter-color);
     244    background: var(--smartdr-counter-color, #2271b1);
    262245    border-radius: 10px;
    263246    width: 0%;
     
    283266    }
    284267
    285     .smartdr-countdown-number {
    286         font-size: calc(var(--smartdr-counter-size, 4em) * 0.8);
     268    .smartdr-countdown-number,
     269    #smartdr-countdown-number {
     270        font-size: calc(var(--smartdr-counter-size, 36px) * 0.8);
    287271    }
    288272
     
    292276    .smartdr-container h4,
    293277    .smartdr-container h5,
    294     .smartdr-container h6 {
    295         font-size: calc(var(--smartdr-heading-size, 1.8em) * 0.9);
     278    .smartdr-container h6,
     279    .smartdr-heading {
     280        font-size: calc(var(--smartdr-heading-size, 32px) * 0.9);
    296281    }
    297282
     
    314299        text-align: center;
    315300    }
     301
     302    /* Progressbar layout responsive */
     303    .smartdr-layout-progressbar .smartdr-progress-text,
     304    .smartdr-layout-progressbar #smartdr-countdown-text {
     305        font-size: calc(var(--smartdr-counter-size, 36px) * 0.8);
     306    }
    316307}
  • smart-download-redirector/tags/1.0.0/includes/redirect-functions.php

    r3325102 r3325285  
    1111}
    1212
    13 /**
    14  * Add custom query vars.
    15  *
    16  * @param array $vars The array of available query variables.
    17  * @return array Modified array of query variables.
    18  */
    19 function smartdr_query_vars($vars)
    20 {
    21     $vars[] = 'smartdr_download';
    22     return $vars;
    23 }
    24 
    25 /**
    26  * Handle template redirect for download URLs.
    27  */
    28 function smartdr_template_redirect()
    29 {
    30     $download_id = get_query_var('smartdr_download');
    31 
    32     if (! empty($download_id)) {
    33         $decoded_url = base64_decode($download_id);
    34        
    35         if (false === $decoded_url) {
    36             wp_die(esc_html__('Invalid download URL.', 'smart-download-redirector'));
    37         }
    38 
    39         if (! smartdr_validate_redirect_url($decoded_url)) {
    40             wp_die(esc_html__('Invalid download URL.', 'smart-download-redirector'));
    41         }
    42 
    43         // Check rate limit
    44         if (! smartdr_check_rate_limit()) {
    45             wp_die(esc_html__('Download rate limit exceeded. Please try again later.', 'smart-download-redirector'));
    46         }
    47 
    48         // Set up variables for the template
    49         $url = $decoded_url;
    50         $countdown_time = absint(get_option('smartdr_countdown_time', 10));
    51         $show_destination = get_option('smartdr_show_destination', true);
    52         $destination_display_step = absint(get_option('smartdr_destination_display_step', 1));
    53         $show_manual_link = get_option('smartdr_show_manual_link', true);
    54         $manual_link_display_step = absint(get_option('smartdr_manual_link_display_step', 2));
    55        
    56         // Get and validate redirect delay (1-10 seconds)
    57         $redirect_delay = get_option('smartdr_redirect_delay');
    58        
    59         // Ensure we have a valid numeric value
    60         if ($redirect_delay === false || !is_numeric($redirect_delay)) {
    61             $redirect_delay = 3; // Default to 3 seconds
    62         }
    63        
    64         // Convert to integer and constrain to valid range
    65         $redirect_delay = absint($redirect_delay);
    66         $redirect_delay = min(max($redirect_delay, 1), 10);
    67        
    68         // Convert to milliseconds for JavaScript
    69         $redirect_delay_ms = $redirect_delay * 1000;
    70        
    71         // Enqueue and localize the script with debug info
    72         wp_enqueue_script('smartdr-countdown');
    73         wp_localize_script(
    74             'smartdr-countdown',
    75             'smartdrData',
    76             [
    77                 'redirectUrl'   => $url,
    78                 'countdownTime' => $countdown_time,
    79                 'nonce'        => wp_create_nonce('smartdr-countdown'),
    80                 'showDestination' => $show_destination,
    81                 'destinationStep' => $destination_display_step,
    82                 'showManualLink' => $show_manual_link,
    83                 'manualLinkStep' => $manual_link_display_step,
    84                 'redirectDelay' => $redirect_delay_ms
    85             ]
    86         );
    87 
    88         // Load the countdown template
    89         include SMARTDR_PLUGIN_DIR . 'templates/download-page.php';
    90         exit;
    91     }
    92 }
    93 
    94 /**
    95  * Handle redirect validation on the download page
    96  */
    97 function smartdr_handle_download_redirect()
    98 {
    99     // Performance optimization: Only run this check when we have relevant parameters
    100     // This prevents the function from running on every page load
    101     if (empty($_GET['url']) && empty($_GET['smartdr_nonce'])) {
    102         return;
    103     }
    104 
    105     // Check if we're on the download page or if the URL contains 'download'
    106     $request_uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '';
    107     if (!is_page('download') && strpos($request_uri, '/download') === false) {
    108         return;
    109     }
    110 
    111     // Remove error_log for production
    112     // error_log('SMARTDR: Starting download redirect handler');
    113 
    114     // Verify nonce FIRST before processing any input
    115     $nonce = isset($_GET['smartdr_nonce']) ? sanitize_key(wp_unslash($_GET['smartdr_nonce'])) : '';
    116     if (empty($nonce) || !wp_verify_nonce($nonce, 'smartdr_download')) {
    117         // Remove error_log for production
    118         // error_log('SMARTDR: Invalid nonce');
    119         wp_die(esc_html__('Invalid or expired download link.', 'smart-download-redirector'));
    120         return;
    121     }
    122 
    123     // Now safely get and sanitize the URL parameter after nonce verification
    124     $url_param = isset($_GET['url']) ? sanitize_text_field(wp_unslash($_GET['url'])) : '';
    125    
    126     // Remove error_log for production
    127     // error_log('SMARTDR: Processing URL parameter: ' . $url_param);
    128    
    129     // If no URL parameter, show the default page content
    130     if (empty($url_param)) {
    131         // Remove error_log for production
    132         // error_log('SMARTDR: No URL parameter, showing default page');
    133         return;
    134     }
    135 
    136     // Decode URL if it's encoded
    137     $url = urldecode($url_param);
    138     // Remove error_log for production
    139     // error_log('SMARTDR: Decoded URL: ' . $url);
    140 
    141     // Normalize URL format
    142     $url = smartdr_normalize_url($url);
    143 
    144     // Validate URL
    145     if (!smartdr_validate_redirect_url($url)) {
    146         // Remove error_log for production
    147         // error_log('SMARTDR: URL validation failed for: ' . $url);
    148         wp_die(esc_html__('Invalid download URL.', 'smart-download-redirector'));
    149         return;
    150     }
    151 
    152     // Remove error_log for production
    153     // error_log('SMARTDR: URL validation successful for: ' . $url);
    154 
    155     // Create or get the download page
    156     $download_page = get_page_by_path('download');
    157     if (!$download_page) {
    158         // Create the download page if it doesn't exist
    159         $download_page_id = wp_insert_post([
    160             'post_title' => esc_html__('Download', 'smart-download-redirector'),
    161             'post_name' => 'download',
    162             'post_content' => '[smartdr_download_countdown]',
    163             'post_status' => 'publish',
    164             'post_type' => 'page',
    165             'comment_status' => 'closed',
    166             'ping_status' => 'closed'
    167         ]);
    168         $download_page = get_post($download_page_id);
    169     }
    170 
    171     // Ensure the page exists
    172     if (!$download_page) {
    173         // Remove error_log for production
    174         // error_log('SMARTDR: Failed to create or get download page');
    175         return;
    176     }
    177 
    178     // Set up the global post object
    179     global $wp_query, $post;
    180     $wp_query->is_page = true;
    181     $wp_query->is_singular = true;
    182     $wp_query->is_home = false;
    183     $wp_query->is_archive = false;
    184     $wp_query->is_category = false;
    185     $wp_query->query_vars['url'] = $url_param;
    186     $wp_query->query_vars['smartdr_nonce'] = $nonce;
    187    
    188     // Set up the post
    189     $post = $download_page;
    190     setup_postdata($post);
    191    
    192     // Force the content to contain our shortcode
    193     add_filter('the_content', function($content) {
    194         return '[smartdr_download_countdown]';
    195     }, 999999);
    196 }
    197 add_action('template_redirect', 'smartdr_handle_download_redirect', 1);
     13
     14
     15
    19816
    19917/**
     
    28199            // Check if domain matches
    282100            if ($domain === $target_domain) {
    283                 // Create redirect URL using query parameters
     101                // Create redirect URL using query parameters to the shortcode page
    284102                $redirect_url = add_query_arg([
    285                     'smartdr_url' => base64_encode($url),
     103                    'url' => urlencode($url),
    286104                    'smartdr_nonce' => wp_create_nonce('smartdr_download')
    287105                ], get_permalink($shortcode_page));
     
    377195{
    378196    if (! smartdr_validate_redirect_url($url)) {
    379         // Remove error_log for production
    380         // error_log('SMARTDR: URL validation failed in generate_download_url for: ' . $url);
    381197        return $url;
    382198    }
    383199
    384     // Remove error_log for production
    385     // error_log('SMARTDR: Generating download URL for: ' . $url);
    386     $redirect_url = home_url('/download/');
    387     $redirect_url = add_query_arg('url', urlencode($url), $redirect_url);
    388     $redirect_url = wp_nonce_url($redirect_url, 'smartdr_download', 'smartdr_nonce');
    389    
    390     // Remove error_log for production
    391     // error_log('SMARTDR: Generated redirect URL: ' . $redirect_url);
     200    // Get the shortcode page
     201    $shortcode_page = get_option('smartdr_shortcode_page');
     202   
     203    // If no shortcode page found, try to find it
     204    if (!$shortcode_page) {
     205        $pages = get_posts([
     206            'post_type' => 'page',
     207            'posts_per_page' => -1,
     208            'post_status' => 'publish'
     209        ]);
     210       
     211        foreach ($pages as $page) {
     212            if (has_shortcode($page->post_content, 'smartdr_download_countdown')) {
     213                $shortcode_page = $page->ID;
     214                update_option('smartdr_shortcode_page', $shortcode_page);
     215                break;
     216            }
     217        }
     218    }
     219   
     220    // If still no shortcode page found, return original URL
     221    if (!$shortcode_page) {
     222        return $url;
     223    }
     224
     225    // Create redirect URL using query parameters to the shortcode page
     226    $redirect_url = add_query_arg([
     227        'url' => urlencode($url),
     228        'smartdr_nonce' => wp_create_nonce('smartdr_download')
     229    ], get_permalink($shortcode_page));
     230   
    392231    return $redirect_url;
    393232}
     
    404243    }
    405244
    406     // Performance optimization: Only process if we have relevant parameters
    407     if (empty($_GET['smartdr_url']) && empty($_GET['smartdr_nonce'])) {
    408         return '';
    409     }
    410 
    411     // Verify nonce FIRST before processing any input
     245    // Check for URL parameters
     246    $url_param = isset($_GET['url']) ? sanitize_text_field(wp_unslash($_GET['url'])) : '';
    412247    $nonce = isset($_GET['smartdr_nonce']) ? sanitize_key(wp_unslash($_GET['smartdr_nonce'])) : '';
    413     if (empty($nonce) || !wp_verify_nonce($nonce, 'smartdr_download')) {
    414         return '<div class="smartdr-error">' . esc_html__('Invalid or expired download link.', 'smart-download-redirector') . '</div>';
    415     }
    416 
    417     // Now safely get and sanitize the URL parameter after nonce verification
    418     $url_param = isset($_GET['smartdr_url']) ? sanitize_text_field(wp_unslash($_GET['smartdr_url'])) : '';
    419 
    420     // If no URL parameter, return empty
    421     if (empty($url_param)) {
    422         return '';
    423     }
    424 
    425     // Decode base64 URL
    426     $url = base64_decode($url_param);
    427     if ($url === false) {
    428         return '<div class="smartdr-error">' . esc_html__('Invalid URL format.', 'smart-download-redirector') . '</div>';
    429     }
    430    
    431     // Normalize URL format
    432     $url = smartdr_normalize_url($url);
    433    
    434     if (!smartdr_validate_redirect_url($url)) {
    435         return '<div class="smartdr-error">' . esc_html__('Invalid download URL. Please check your target domains settings.', 'smart-download-redirector') . '</div>';
    436     }
    437    
    438     // Get countdown time from settings
     248    $url = null;
     249   
     250    if (!empty($url_param) && !empty($nonce)) {
     251        // Verify nonce
     252        if (wp_verify_nonce($nonce, 'smartdr_download')) {
     253            $decoded_url = urldecode($url_param);
     254            $decoded_url = smartdr_normalize_url($decoded_url);
     255           
     256            if (smartdr_validate_redirect_url($decoded_url)) {
     257                $url = $decoded_url;
     258            }
     259        }
     260    }
     261   
     262    // Get countdown configuration for template
    439263    $countdown_time = absint(get_option('smartdr_countdown_time', 10));
    440    
    441     // Get and validate redirect delay (1-10 seconds)
    442     $redirect_delay = get_option('smartdr_redirect_delay', 3);
    443     $redirect_delay = absint($redirect_delay);
     264    $redirect_delay = absint(get_option('smartdr_redirect_delay', 3));
    444265    $redirect_delay = min(max($redirect_delay, 1), 10);
    445     $redirect_delay_ms = $redirect_delay * 1000;
    446    
    447     // Enqueue required scripts and styles
    448     wp_enqueue_script('smartdr-countdown');
    449     wp_enqueue_style('smartdr-styles');
    450    
    451     // Localize script data
    452     wp_localize_script(
    453         'smartdr-countdown',
    454         'smartdrData',
    455         [
    456             'redirectUrl' => $url,
    457             'countdownTime' => $countdown_time,
    458             'nonce' => wp_create_nonce('smartdr-countdown'),
    459             'showDestination' => get_option('smartdr_show_destination', true),
    460             'destinationStep' => absint(get_option('smartdr_destination_display_step', 1)),
    461             'showManualLink' => get_option('smartdr_show_manual_link', true),
    462             'manualLinkStep' => absint(get_option('smartdr_manual_link_display_step', 2)),
    463             'redirectDelay' => $redirect_delay_ms,
    464             'ajaxurl' => admin_url('admin-ajax.php')
    465         ]
    466     );
     266   
     267    // If still no URL, show placeholder
     268    if (!$url) {
     269        return '<div class="smartdr-info">' . esc_html__('Download countdown will appear here when accessing a download link.', 'smart-download-redirector') . '</div>';
     270    }
     271
     272    // We have a valid URL, proceed with countdown
    467273   
    468274    // Start output buffering to capture template content
     
    486292        'custom_heading' => get_option('smartdr_custom_heading', esc_html__('Preparing Your Download', 'smart-download-redirector')),
    487293        'show_title' => get_option('smartdr_show_title', true),
    488         'manual_link_display_timing' => 'at_end', // Always show at end
     294        'manual_link_display_timing' => 'at_end',
    489295        'styles' => get_option('smartdr_styles', [])
    490296    ];
     
    498304    // Get buffered content
    499305    $content = ob_get_clean();
    500    
    501     // Always use custom style mode
    502     $style_mode = 'custom';
    503306   
    504307    // Get custom styles for CSS variables
     
    519322    // Wrap content in theme-independent container
    520323    return sprintf(
    521         '<div class="smartdr-container" data-smartdr-version="%s" data-style-mode="%s"%s>%s</div>',
     324        '<div class="smartdr-container" data-smartdr-version="%s" data-style-mode="custom"%s>%s</div>',
    522325        esc_attr(SMARTDR_VERSION),
    523         esc_attr($style_mode),
    524326        $style_attrs,
    525327        $content
     
    527329}
    528330add_shortcode('smartdr_download_countdown', 'smartdr_countdown_shortcode');
     331
     332/**
     333 * Get WPML translated string or fallback to original
     334 *
     335 * @param string $name The string name
     336 * @param string $original The original string
     337 * @return string The translated string or original
     338 */
     339function smartdr_get_wpml_string($name, $original) {
     340    // Try newer WPML API first (WPML 4.0+)
     341    if (function_exists('wpml_translate_single_string')) {
     342        return wpml_translate_single_string('smart-download-redirector', $name, $original);
     343    }
     344   
     345    // Fallback to older WPML API (WPML 3.x)
     346    if (function_exists('icl_t')) {
     347        return icl_t('smart-download-redirector', $name, $original);
     348    }
     349   
     350    // Fallback to original string if WPML is not available
     351    return $original;
     352}
    529353
    530354/**
  • smart-download-redirector/tags/1.0.0/smart-download-redirector.php

    r3325102 r3325285  
    4949        }
    5050    }
    51 
    52     // Flush rewrite rules.
    53     flush_rewrite_rules();
    5451}
    5552register_activation_hook(__FILE__, 'smartdr_activate');
     
    6057function smartdr_deactivate()
    6158{
    62     // Flush rewrite rules.
    63     flush_rewrite_rules();
     59    // Clean up on deactivation
    6460}
    6561register_deactivation_hook(__FILE__, 'smartdr_deactivate');
    66 
    67 /**
    68  * Initialize plugin.
    69  */
    70 function smartdr_init()
    71 {
    72     // Add rewrite rules.
    73     add_rewrite_rule(
    74         '^download/([^/]+)/?$',
    75         'index.php?smartdr_download=$matches[1]',
    76         'top'
    77     );
    78 
    79     // Add query vars.
    80     add_filter('query_vars', 'smartdr_query_vars');
    81 
    82     // Add template redirect.
    83     add_action('template_redirect', 'smartdr_template_redirect');
    84 }
    85 add_action('init', 'smartdr_init');
    8662
    8763/**
     
    9369function smartdr_register_assets()
    9470{
     71    // Register countdown script
    9572    wp_register_script(
    9673        'smartdr-countdown',
     
    9875        ['jquery'],
    9976        filemtime(SMARTDR_PLUGIN_DIR . 'assets/countdown.js'),
    100         false // Load in header.
     77        true // Load in footer for better performance
    10178    );
    10279
     
    11087}
    11188add_action('wp_enqueue_scripts', 'smartdr_register_assets');
     89
     90/**
     91 * Check if we need to enqueue countdown assets based on content
     92 */
     93function smartdr_maybe_enqueue_assets()
     94{
     95    // Check if we're on a page with the shortcode
     96    global $post;
     97    $should_enqueue = false;
     98   
     99    if (is_object($post) && has_shortcode($post->post_content, 'smartdr_download_countdown')) {
     100        $should_enqueue = true;
     101    }
     102   
     103    // Check if we're on a download URL (with URL parameters)
     104    if (isset($_GET['url']) && isset($_GET['smartdr_nonce'])) {
     105        $should_enqueue = true;
     106    }
     107   
     108    if ($should_enqueue) {
     109        wp_enqueue_script('smartdr-countdown');
     110        wp_enqueue_style('smartdr-styles');
     111       
     112        // Prepare localization data
     113        $url_param = isset($_GET['url']) ? sanitize_text_field(wp_unslash($_GET['url'])) : '';
     114        $nonce = isset($_GET['smartdr_nonce']) ? sanitize_key(wp_unslash($_GET['smartdr_nonce'])) : '';
     115        $url = null;
     116       
     117        if (!empty($url_param) && !empty($nonce)) {
     118            // Verify nonce
     119            if (wp_verify_nonce($nonce, 'smartdr_download')) {
     120                $decoded_url = urldecode($url_param);
     121                $decoded_url = smartdr_normalize_url($decoded_url);
     122               
     123                if (smartdr_validate_redirect_url($decoded_url)) {
     124                    $url = $decoded_url;
     125                }
     126            }
     127        }
     128       
     129        // Always prepare countdown configuration
     130        $countdown_time = absint(get_option('smartdr_countdown_time', 10));
     131        $redirect_delay = absint(get_option('smartdr_redirect_delay', 3));
     132        $redirect_delay = min(max($redirect_delay, 1), 10);
     133        $redirect_delay_ms = $redirect_delay * 1000;
     134       
     135        // Localize script with data
     136        wp_localize_script(
     137            'smartdr-countdown',
     138            'smartdrData',
     139            [
     140                'redirectUrl' => $url ? $url : '',
     141                'countdownTime' => $countdown_time,
     142                'nonce' => wp_create_nonce('smartdr-countdown'),
     143                'showDestination' => get_option('smartdr_show_destination', true),
     144                'destinationStep' => absint(get_option('smartdr_destination_display_step', 1)),
     145                'showManualLink' => get_option('smartdr_show_manual_link', true),
     146                'manualLinkStep' => absint(get_option('smartdr_manual_link_display_step', 2)),
     147                'redirectDelay' => $redirect_delay_ms,
     148                'secondsText' => __('seconds remaining', 'smart-download-redirector'),
     149                'downloadReadyText' => __('Download ready!', 'smart-download-redirector'),
     150                'hasValidUrl' => !empty($url)
     151            ]
     152        );
     153       
     154        // Add CSS variables for styling
     155        $styles = get_option('smartdr_styles', array());
     156        $default_styles = array(
     157            'heading_color' => '#212121',
     158            'heading_size' => '32px',
     159            'counter_color' => '#00897B',
     160            'counter_size' => '36px',
     161            'counter_font_weight' => 'bold',
     162            'background_color' => '#ffffff',
     163            'border_radius' => '8px',
     164            'border_size' => '1px',
     165            'border_color' => '#dddddd',
     166            'manual_link_size' => '14px',
     167            'manual_link_color' => '#00897B',
     168            'manual_link_hover_color' => '#00695C'
     169        );
     170        $styles = array_merge($default_styles, $styles);
     171       
     172        // Add inline CSS with custom properties
     173        $inline_css = "
     174/* CSS Custom Properties for dynamic styling */
     175:root {
     176    --smartdr-counter-color: " . esc_attr($styles['counter_color']) . ";
     177    --smartdr-counter-size: " . esc_attr($styles['counter_size']) . ";
     178    --smartdr-counter-font-weight: " . (($styles['counter_font_weight'] === 'bold') ? '600' : 'normal') . ";
     179    --smartdr-heading-color: " . esc_attr($styles['heading_color']) . ";
     180    --smartdr-heading-size: " . esc_attr($styles['heading_size']) . ";
     181    --smartdr-manual-link-size: " . esc_attr($styles['manual_link_size']) . ";
     182    --smartdr-manual-link-color: " . esc_attr($styles['manual_link_color']) . ";
     183    --smartdr-manual-link-hover-color: " . esc_attr($styles['manual_link_hover_color']) . ";
     184    --smartdr-bg-color: " . esc_attr($styles['background_color']) . ";
     185    --smartdr-border-radius: " . esc_attr($styles['border_radius']) . ";
     186    --smartdr-border-size: " . esc_attr($styles['border_size']) . ";
     187    --smartdr-border-color: " . esc_attr($styles['border_color']) . ";
     188}";
     189        wp_add_inline_style('smartdr-styles', $inline_css);
     190    }
     191}
     192add_action('wp_enqueue_scripts', 'smartdr_maybe_enqueue_assets', 20);
  • smart-download-redirector/tags/1.0.0/templates/download-page.php

    r3325102 r3325285  
    1717$countdown_time = absint(get_option('smartdr_countdown_time', 10));
    1818$show_manual_link = get_option('smartdr_show_manual_link', true);
    19 // Manual link always shows at the end of countdown (last 10%)
    2019$show_title = get_option('smartdr_show_title', true);
    2120$redirect_delay = absint(get_option('smartdr_redirect_delay', 3));
     
    2726$manual_link_text = smartdr_get_wpml_string('Manual Link Text', $manual_link_text_original);
    2827
    29 // Always use custom style mode
    30 $style_mode = 'custom';
    31 $styles = get_option('smartdr_styles', array());
    32 
    3328// Get layout style setting
    3429$layout_style = get_option('smartdr_layout_style', 'standard');
    35 
    36 // For theme mode, try to detect actual theme colors
    37 $theme_primary_color = '#0073aa'; // WordPress default fallback
    38 if ($style_mode === 'theme') {
    39     // Try to get theme colors from various sources
    40     $theme_colors = wp_get_global_styles(array('color'));
    41    
    42     // Check for block theme colors
    43     if (isset($theme_colors['palette']['theme'])) {
    44         foreach ($theme_colors['palette']['theme'] as $color) {
    45             if (isset($color['slug']) && in_array($color['slug'], ['primary', 'accent', 'secondary'])) {
    46                 $theme_primary_color = $color['color'];
    47                 break;
    48             }
    49         }
    50     }
    51    
    52     // Fallback: check theme supports and customizer colors
    53     if ($theme_primary_color === '#0073aa') {
    54         // Check for customizer primary color
    55         $customizer_primary = get_theme_mod('primary_color');
    56         if ($customizer_primary) {
    57             $theme_primary_color = $customizer_primary;
    58         } else {
    59             // Check for accent color
    60             $accent_color = get_theme_mod('accent_color');
    61             if ($accent_color) {
    62                 $theme_primary_color = $accent_color;
    63             }
    64         }
    65     }
    66 }
    67 
    68 // Default fallbacks for custom mode
    69 $default_styles = array(
    70     'heading_color' => '#212121',
    71     'heading_size' => '32px',
    72     'counter_color' => '#00897B',
    73     'counter_size' => '36px',
    74     'counter_font_weight' => 'bold',
    75     'background_color' => '#ffffff',
    76     'border_radius' => '8px',
    77     'border_size' => '1px',
    78     'border_color' => '#dddddd',
    79     'manual_link_size' => '14px',
    80     'manual_link_color' => '#00897B',
    81     'manual_link_hover_color' => '#00695C'
    82 );
    83 
    84 $styles = array_merge($default_styles, $styles);
    85 
    86 // Get destination box styles
    87 $destination_styles = get_option('smartdr_destination_styles', array());
    88 $default_destination_styles = array(
    89     'background_color' => '#f8f9fa',
    90     'border_size' => '1px',
    91     'border_color' => '#dee2e6',
    92     'border_radius' => '4px',
    93     'text_size' => '14px'
    94 );
    95 $destination_styles = array_merge($default_destination_styles, $destination_styles);
    96 
    97 // Generate inline styles
    98 $heading_style = sprintf(
    99     'color: %s; font-size: %s;',
    100     esc_attr($styles['heading_color']),
    101     esc_attr($styles['heading_size'])
    102 );
    103 
    104 // Generate destination box style
    105 $destination_box_style = sprintf(
    106     'background-color: %s; border: %s solid %s; border-radius: %s; font-size: %s;',
    107     esc_attr($destination_styles['background_color']),
    108     esc_attr($destination_styles['border_size']),
    109     esc_attr($destination_styles['border_color']),
    110     esc_attr($destination_styles['border_radius']),
    111     esc_attr($destination_styles['text_size'])
    112 );
    11330?>
    11431
     
    18097
    18198<?php
    182 // Add inline styles using WordPress proper method
    183 $inline_css = "
    184 /* CSS Custom Properties for dynamic styling */
    185 :root {
    186     --smartdr-counter-color: " . esc_attr($styles['counter_color']) . ";
    187     --smartdr-counter-size: " . esc_attr($styles['counter_size']) . ";
    188     --smartdr-counter-font-weight: " . (($styles['counter_font_weight'] === 'bold') ? '600' : 'normal') . ";
    189     --smartdr-heading-color: " . esc_attr($styles['heading_color']) . ";
    190     --smartdr-heading-size: " . esc_attr($styles['heading_size']) . ";
    191     --smartdr-manual-link-size: " . esc_attr($styles['manual_link_size']) . ";
    192     --smartdr-manual-link-color: " . esc_attr($styles['manual_link_color']) . ";
    193     --smartdr-manual-link-hover-color: " . esc_attr($styles['manual_link_hover_color']) . ";
    194 }
    195 
    196 /* All layout and static styles are now in assets/styles.css */
    197 /* Only CSS Custom Properties remain here for dynamic theming */
    198 ";
    199 wp_add_inline_style('smartdr-styles', $inline_css);
     99// CSS Custom Properties are now handled in the main plugin file
     100// to ensure proper timing and availability
    200101?>
    201102
    202 <?php
    203 // Add inline script using WordPress proper method
    204 $inline_js = "
    205 jQuery(document).ready(function($) {
    206     var countdownTime = " . esc_js($countdown_time) . ";
    207     var showManualLink = " . ($show_manual_link ? 'true' : 'false') . ";
    208     var manualLinkTiming = 'at_end'; // Always show at end
    209     var layoutStyle = '" . esc_js($layout_style) . "';
    210     var redirectUrl = '" . esc_js($url) . "';
    211     var downloadReadyText = '" . esc_js(__('Download ready!', 'smart-download-redirector')) . "';
    212     var secondsRemainingText = '" . esc_js(__('seconds remaining', 'smart-download-redirector')) . "';
    213    
    214     // Get smartdrData from localized script
    215     if (typeof smartdrData !== 'undefined') {
    216         var redirectDelay = smartdrData.redirectDelay;
    217        
    218         // Debug values
    219         console.log('[SMARTDR Debug] Initial settings:', {
    220             countdownTime: countdownTime + ' seconds',
    221             redirectDelay: (redirectDelay / 1000) + ' seconds',
    222             showManualLink: showManualLink,
    223             manualLinkTiming: manualLinkTiming,
    224             layoutStyle: layoutStyle
    225         });
    226        
    227         var \$manualRedirect = \$('.smartdr-manual-redirect');
    228         var \$countdownNumber = \$('#smartdr-countdown-number');
    229         var \$countdownText = \$('#smartdr-countdown-text');
    230         var \$progressBar = \$('#smartdr-progress-bar');
    231         var circle = document.querySelector('.smartdr-progress-ring-circle');
    232         var isRedirecting = false;
    233 
    234         // Initialize circular progress (for standard and compact layouts)
    235         if (circle) {
    236             var radius = circle.r.baseVal.value;
    237             var circumference = radius * 2 * Math.PI;
    238             circle.style.strokeDasharray = circumference + ' ' + circumference;
    239             circle.style.strokeDashoffset = circumference;
    240         }
    241 
    242         // IMPORTANT: Manual link must NEVER be visible during countdown
    243         // Force hide and ensure it stays hidden until countdown is complete
    244         \$manualRedirect.hide().css('visibility', 'hidden');
    245        
    246         // Additional safeguard: prevent any accidental showing during countdown
    247         function ensureManualLinkHidden() {
    248             if (!countdownComplete && !manualLinkShown) {
    249                 \$manualRedirect.hide().css('visibility', 'hidden');
    250             }
    251         }
    252 
    253         function setProgress(percent) {
    254             // Update circular progress (standard and compact layouts)
    255             if (circle) {
    256                 var offset = circumference - (percent / 100 * circumference);
    257                 circle.style.strokeDashoffset = offset;
    258             }
    259            
    260             // Update horizontal progress bar (progressbar layout)
    261             if (\$progressBar.length > 0) {
    262                 \$progressBar.css('width', percent + '%');
    263             }
    264         }
    265 
    266         var manualLinkShown = false; // Track if manual link has been shown
    267         var countdownComplete = false; // Track if countdown has finished
    268        
    269         function complete() {
    270             console.log('[SMARTDR Debug] Countdown complete');
    271            
    272             // Mark countdown as complete - manual link can now be shown
    273             countdownComplete = true;
    274            
    275             // Update progress to 100%
    276             setProgress(100);
    277 
    278             // Update countdown displays based on layout
    279             if (layoutStyle === 'progressbar') {
    280                 // For progressbar layout, update text
    281                 \$countdownText.fadeOut(200, function() {
    282                     \$(this).text(downloadReadyText).fadeIn(200);
    283                    
    284                     // Show manual link after text update if enabled (only after countdown is complete)
    285                     if (showManualLink && !manualLinkShown && countdownComplete) {
    286                         \$manualRedirect.css('visibility', 'visible').fadeIn(400);
    287                         manualLinkShown = true;
    288                         console.log('[SMARTDR Debug] ✅ Manual link shown after countdown completion');
    289                     }
    290                 });
    291             } else {
    292                 // For standard and compact layouts, show arrow
    293                 \$countdownNumber.fadeOut(200, function() {
    294                     \$(this).text('→').fadeIn(200);
    295                    
    296                     // Show manual link after arrow appears if enabled (only after countdown is complete)
    297                     if (showManualLink && !manualLinkShown && countdownComplete) {
    298                         \$manualRedirect.css('visibility', 'visible').fadeIn(400);
    299                         manualLinkShown = true;
    300                         console.log('[SMARTDR Debug] ✅ Manual link shown after countdown completion');
    301                     }
    302                 });
    303             }
    304 
    305             // Redirect after configured delay
    306             console.log('[SMARTDR Debug] Will redirect in ' + (redirectDelay/1000) + ' seconds');
    307             setTimeout(function() {
    308                 console.log('[SMARTDR Debug] Redirecting now');
    309                 window.location.href = redirectUrl;
    310             }, redirectDelay);
    311         }
    312 
    313         function countdown() {
    314             var timeLeft = countdownTime;
    315            
    316             var timer = setInterval(function() {
    317                 if (isRedirecting) {
    318                     clearInterval(timer);
    319                     return;
    320                 }
    321 
    322                 timeLeft--;
    323                 var progress = ((countdownTime - timeLeft) / countdownTime) * 100;
    324                 setProgress(progress);
    325                
    326                 // Update display based on layout
    327                 if (layoutStyle === 'progressbar') {
    328                     // Update progressbar text with remaining seconds
    329                     \$countdownText.text(timeLeft + ' ' + secondsRemainingText);
    330                 } else {
    331                     // Update countdown number for circular layouts
    332                     \$countdownNumber.text(timeLeft);
    333                 }
    334 
    335                 // Safeguard: Ensure manual link stays hidden during countdown
    336                 ensureManualLinkHidden();
    337 
    338                 // Complete countdown when time reaches zero
    339                 if (timeLeft <= 0) {
    340                     clearInterval(timer);
    341                     complete();
    342                 }
    343             }, 1000);
    344         }
    345 
    346         countdown();
    347     } else {
    348         console.error('[SMARTDR] smartdrData not found - countdown will not work');
    349     }
    350 });
    351 ";
    352 wp_add_inline_script('smartdr-countdown', $inline_js);
    353 ?>
     103 
  • smart-download-redirector/trunk/admin/settings-page.php

    r3325102 r3325285  
    12881288    }
    12891289
    1290     // Check if settings were updated (WordPress core parameter, safe to check)
    1291     // Additional security: Only process if user has proper capabilities
    1292     if (current_user_can('manage_options') &&
    1293         isset($_GET['settings-updated']) &&
    1294         $_GET['settings-updated'] === 'true' &&
    1295         !get_settings_errors('smartdr_messages') // Prevent duplicate messages
    1296     ) {
     1290    // Check if settings were updated
     1291    // Use WordPress core function to check if options were updated - this is security-safe
     1292    $settings_updated = false;
     1293    if (current_user_can('manage_options')) {
     1294        // Check if any of our options were recently updated
     1295        $check_options = [
     1296            'smartdr_target_domains',
     1297            'smartdr_countdown_time',
     1298            'smartdr_redirect_delay',
     1299            'smartdr_styles',
     1300            'smartdr_layout_style'
     1301        ];
     1302       
     1303        foreach ($check_options as $option) {
     1304            if (get_transient('smartdr_option_updated_' . $option)) {
     1305                $settings_updated = true;
     1306                delete_transient('smartdr_option_updated_' . $option);
     1307                break;
     1308            }
     1309        }
     1310       
     1311        // Fallback: Check WordPress core parameter (already validated by WordPress)
     1312        if (!$settings_updated &&
     1313            filter_input(INPUT_GET, 'settings-updated', FILTER_SANITIZE_STRING) === 'true' &&
     1314            !get_settings_errors('smartdr_messages')
     1315        ) {
     1316            $settings_updated = true;
     1317        }
     1318    }
     1319   
     1320    if ($settings_updated) {
    12971321        add_settings_error(
    12981322            'smartdr_messages',
     
    13561380}
    13571381
    1358 /**
    1359  * Get WPML translated string
    1360  */
    1361 function smartdr_get_wpml_string($name, $original_value) {
    1362     if (function_exists('wpml_translate_single_string')) {
    1363         return wpml_translate_single_string('smart-download-redirector', $name, $original_value);
    1364     }
    1365     return $original_value;
    1366 }
     1382
     1383
     1384/**
     1385 * Set transient when options are updated for secure update detection
     1386 */
     1387function smartdr_option_updated($option_name) {
     1388    if (strpos($option_name, 'smartdr_') === 0) {
     1389        set_transient('smartdr_option_updated_' . $option_name, true, 60); // 1 minute
     1390    }
     1391}
     1392
     1393// Hook to track option updates
     1394add_action('updated_option', 'smartdr_option_updated');
    13671395
    13681396// Hook to register WPML strings when options are updated
  • smart-download-redirector/trunk/assets/countdown.js

    r3325102 r3325285  
    11/**
    2  * Enhanced countdown timer with progress ring and step indicators
     2 * Simple and reliable countdown timer
    33 */
    4 jQuery(function($) {
     4(function($) {
    55    'use strict';
    66   
    7     // Debug helper
    8     var debug = function(msg, data) {
    9         if (window.console && console.log) {
    10             console.log('[SDR Debug]:', msg, data || '');
    11         }
    12     };
    13 
    14     debug('Script starting');
    15 
    16     // Validate data
    17     if (typeof smartdrData === 'undefined') {
    18         debug('ERROR: smartdrData missing');
    19         return;
     7    // Function to run when DOM is ready
     8    function initCountdown() {
     9        console.log('[SmartDR] Countdown script starting...');
     10       
     11        // Check if jQuery is available
     12        if (typeof $ === 'undefined') {
     13            console.error('[SmartDR] jQuery not available');
     14            return;
     15        }
     16       
     17        // Check if smartdrData is available
     18        if (typeof smartdrData === 'undefined') {
     19            console.error('[SmartDR] smartdrData not available');
     20            return;
     21        }
     22       
     23        console.log('[SmartDR] smartdrData:', smartdrData);
     24       
     25        // Check if we have a valid URL to countdown for
     26        if (!smartdrData.hasValidUrl) {
     27            console.log('[SmartDR] No valid URL - countdown not started');
     28            return;
     29        }
     30       
     31        // Get countdown time
     32        var countdownTime = parseInt(smartdrData.countdownTime) || 10;
     33        var redirectUrl = smartdrData.redirectUrl || '#';
     34        var redirectDelay = parseInt(smartdrData.redirectDelay) || 3000;
     35       
     36        console.log('[SmartDR] Configuration:', {
     37            countdownTime: countdownTime,
     38            redirectUrl: redirectUrl,
     39            redirectDelay: redirectDelay
     40        });
     41       
     42        // Find countdown elements
     43        var $counterNumber = $('#smartdr-countdown-number');
     44        var $counterText = $('#smartdr-countdown-text');
     45        var $progressBar = $('#smartdr-progress-bar');
     46        var $manualRedirect = $('.smartdr-manual-redirect');
     47        var $progressRing = $('.smartdr-progress-ring-circle');
     48       
     49        console.log('[SmartDR] Elements found:', {
     50            counterNumber: $counterNumber.length,
     51            counterText: $counterText.length,
     52            progressBar: $progressBar.length,
     53            manualRedirect: $manualRedirect.length,
     54            progressRing: $progressRing.length
     55        });
     56       
     57        // Determine which element to use
     58        var $activeElement = null;
     59        var layoutType = 'unknown';
     60       
     61        if ($counterNumber.length > 0) {
     62            $activeElement = $counterNumber;
     63            layoutType = 'circular';
     64            console.log('[SmartDR] Using circular layout');
     65        } else if ($counterText.length > 0) {
     66            $activeElement = $counterText;
     67            layoutType = 'progressbar';
     68            console.log('[SmartDR] Using progressbar layout');
     69        } else {
     70            console.error('[SmartDR] No countdown element found!');
     71            return;
     72        }
     73       
     74        // Initialize progress ring if available
     75        var circumference = 0;
     76        if ($progressRing.length > 0 && layoutType === 'circular') {
     77            try {
     78                var radius = $progressRing[0].r.baseVal.value;
     79                circumference = radius * 2 * Math.PI;
     80                $progressRing[0].style.strokeDasharray = circumference;
     81                $progressRing[0].style.strokeDashoffset = circumference;
     82                console.log('[SmartDR] Progress ring initialized, circumference:', circumference);
     83            } catch (e) {
     84                console.warn('[SmartDR] Progress ring initialization failed:', e);
     85            }
     86        }
     87       
     88        // Start countdown
     89        var timeLeft = countdownTime;
     90        var initialTime = countdownTime;
     91        var isComplete = false;
     92       
     93        console.log('[SmartDR] Starting countdown from', timeLeft);
     94       
     95        function updateCountdown() {
     96            if (isComplete) return;
     97           
     98            console.log('[SmartDR] Countdown tick:', timeLeft);
     99           
     100            // Update display based on layout type
     101            if (layoutType === 'circular') {
     102                $activeElement.text(timeLeft);
     103               
     104                // Update progress ring
     105                if ($progressRing.length > 0 && circumference > 0) {
     106                    var progress = (initialTime - timeLeft) / initialTime;
     107                    var offset = circumference - (progress * circumference);
     108                    $progressRing[0].style.strokeDashoffset = offset;
     109                }
     110            } else if (layoutType === 'progressbar') {
     111                var secondsText = smartdrData.secondsText || 'seconds remaining';
     112                $activeElement.text(timeLeft + ' ' + secondsText);
     113               
     114                // Update progress bar
     115                if ($progressBar.length > 0) {
     116                    var progress = (initialTime - timeLeft) / initialTime * 100;
     117                    $progressBar.css('width', progress + '%');
     118                }
     119            }
     120           
     121            // Check if countdown is complete
     122            if (timeLeft <= 0) {
     123                completeCountdown();
     124            } else {
     125                timeLeft--;
     126            }
     127        }
     128       
     129        function completeCountdown() {
     130            if (isComplete) return;
     131            isComplete = true;
     132           
     133            console.log('[SmartDR] Countdown complete!');
     134           
     135            // Clear interval
     136            clearInterval(countdownInterval);
     137           
     138            // Update display for completion
     139            if (layoutType === 'circular') {
     140                $activeElement.text('→');
     141               
     142                // Complete progress ring
     143                if ($progressRing.length > 0) {
     144                    $progressRing[0].style.strokeDashoffset = 0;
     145                }
     146            } else if (layoutType === 'progressbar') {
     147                var downloadReadyText = smartdrData.downloadReadyText || 'Download ready!';
     148                $activeElement.text(downloadReadyText);
     149               
     150                // Complete progress bar
     151                if ($progressBar.length > 0) {
     152                    $progressBar.css('width', '100%');
     153                }
     154            }
     155           
     156            // Show manual redirect link
     157            if ($manualRedirect.length > 0) {
     158                $manualRedirect.show();
     159            }
     160           
     161            // Start redirect timer
     162            console.log('[SmartDR] Starting redirect timer, delay:', redirectDelay + 'ms');
     163            setTimeout(function() {
     164                if (redirectUrl && redirectUrl !== '#') {
     165                    console.log('[SmartDR] Redirecting to:', redirectUrl);
     166                    window.location.href = redirectUrl;
     167                } else {
     168                    console.log('[SmartDR] No redirect URL, staying on page');
     169                }
     170            }, redirectDelay);
     171        }
     172       
     173        // Start the countdown
     174        updateCountdown(); // Initial update
     175        var countdownInterval = setInterval(updateCountdown, 1000);
     176       
     177        // Manual redirect handler
     178        $manualRedirect.find('a').on('click', function(e) {
     179            if (redirectUrl && redirectUrl !== '#') {
     180                console.log('[SmartDR] Manual redirect clicked');
     181                clearInterval(countdownInterval);
     182                // Let the link work normally
     183            } else {
     184                e.preventDefault();
     185                console.log('[SmartDR] Manual redirect clicked but no valid URL');
     186            }
     187        });
     188       
     189        console.log('[SmartDR] Countdown initialized successfully');
    20190    }
    21 
    22     // Get debug info safely
    23     var debugInfo = {
    24         countdownTime: smartdrData.countdownTime || 5,
    25         redirectDelay: smartdrData.redirectDelay || 3000,
    26         rawDelay: (smartdrData.debug && smartdrData.debug.rawDelay) || 3,
    27         msDelay: (smartdrData.debug && smartdrData.debug.msDelay) || 3000,
    28         defaultDelay: (smartdrData.debug && smartdrData.debug.defaultDelay) || 3000
    29     };
    30 
    31     // Log all debug info
    32     debug('Configuration:', debugInfo);
    33 
    34     // Get and validate countdown time
    35     var timeLeft = parseInt(smartdrData.countdownTime);
    36     if (isNaN(timeLeft) || timeLeft <= 0) {
    37         debug('ERROR: Invalid countdown time:', timeLeft);
    38         return;
     191   
     192    // Initialize when DOM is ready
     193    $(document).ready(function() {
     194        initCountdown();
     195    });
     196   
     197    // Fallback for cases where jQuery might not be loaded immediately
     198    if (document.readyState === 'loading') {
     199        document.addEventListener('DOMContentLoaded', function() {
     200            setTimeout(initCountdown, 100);
     201        });
     202    } else {
     203        setTimeout(initCountdown, 100);
    39204    }
    40 
    41     // Get and validate redirect delay
    42     var redirectDelay = parseInt(smartdrData.redirectDelay);
    43     debug('Parsed redirect delay:', redirectDelay);
    44    
    45     if (isNaN(redirectDelay) || redirectDelay < 1000) {
    46         debug('WARNING: Invalid redirect delay, using default');
    47         redirectDelay = debugInfo.defaultDelay;
    48     }
    49    
    50     debug('Final redirect delay:', redirectDelay + 'ms');
    51 
    52     // Get elements
    53     var $counter = $('#smartdr-countdown-number');
    54     var $ring = $('.smartdr-progress-ring-circle');
    55     var $steps = $('.smartdr-step');
    56     var $targetUrl = $('.smartdr-target-url');
    57     var $manualRedirect = $('.smartdr-manual-redirect');
    58 
    59     if (!$counter.length) {
    60         debug('ERROR: Counter element missing');
    61         return;
    62     }
    63 
    64     // Initialize progress ring
    65     var circumference = 0;
    66     if ($ring.length) {
    67         var radius = $ring[0].r.baseVal.value;
    68         circumference = radius * 2 * Math.PI;
    69         $ring[0].style.strokeDasharray = circumference;
    70         $ring[0].style.strokeDashoffset = circumference;
    71     }
    72 
    73     // Store initial time for progress calculations
    74     var initialTime = timeLeft;
    75     var countdownInterval;
    76     var currentStep = 1;
    77 
    78     // Update display function
    79     function updateDisplay() {
    80         // Update counter text
    81         $counter.text(timeLeft);
    82 
    83         // Update progress ring
    84         if ($ring.length) {
    85             var progress = (initialTime - timeLeft) / initialTime;
    86             var offset = circumference - (progress * circumference);
    87             $ring[0].style.strokeDashoffset = offset;
    88         }
    89 
    90         // Calculate current step
    91         var newStep;
    92         if (timeLeft > (initialTime * 2/3)) {
    93             newStep = 1;
    94         } else if (timeLeft > (initialTime * 1/3)) {
    95             newStep = 2;
    96         } else {
    97             newStep = 3;
    98         }
    99 
    100         // Only update if step changed
    101         if (newStep !== currentStep) {
    102             currentStep = newStep;
    103             // Update step indicators
    104             $steps.removeClass('active');
    105             $steps.slice(0, currentStep).addClass('active');
    106 
    107             // Show URL at appropriate step if enabled
    108             if (typeof smartdrData.showDestination !== 'undefined' && smartdrData.showDestination) {
    109                 $targetUrl.toggle(currentStep >= smartdrData.destinationStep);
    110             }
    111 
    112             // Show manual link at appropriate step if enabled
    113             if (typeof smartdrData.showManualLink !== 'undefined' && smartdrData.showManualLink) {
    114                 $manualRedirect.toggle(currentStep >= smartdrData.manualLinkStep);
    115             }
    116         }
    117     }
    118 
    119     // Handle countdown completion
    120     function complete() {
    121         debug('Countdown complete');
    122        
    123         // Clear interval
    124         clearInterval(countdownInterval);
    125        
    126         // Update display
    127         if ($ring.length) {
    128             $ring[0].style.strokeDashoffset = 0;
    129         }
    130         $steps.removeClass('active').eq(2).addClass('active');
    131        
    132         // Show both URL and manual link at completion if enabled
    133         if (typeof smartdrData.showDestination !== 'undefined' && smartdrData.showDestination) {
    134             $targetUrl.fadeIn(400);
    135         }
    136         if (typeof smartdrData.showManualLink !== 'undefined' && smartdrData.showManualLink) {
    137             $manualRedirect.fadeIn(400);
    138         }
    139 
    140         // Fade in the arrow with animation
    141         $counter.fadeOut(200, function() {
    142             $(this).text('→').fadeIn(200);
    143         });
    144 
    145         debug('Starting redirect timer:', {
    146             delay: redirectDelay,
    147             inSeconds: redirectDelay/1000,
    148             url: smartdrData.redirectUrl
    149         });
    150        
    151         // Start redirect timer
    152         setTimeout(function() {
    153             debug('Redirect timer complete, redirecting now');
    154             window.location.href = smartdrData.redirectUrl;
    155         }, redirectDelay);
    156     }
    157 
    158     // Start countdown
    159     debug('Starting countdown');
    160     updateDisplay(); // Initial display update
    161 
    162     countdownInterval = setInterval(function() {
    163         timeLeft--;
    164         debug('Tick:', timeLeft);
    165        
    166         if (timeLeft <= 0) {
    167             complete();
    168         } else {
    169             updateDisplay();
    170         }
    171     }, 1000);
    172 });
     205   
     206})(jQuery);
  • smart-download-redirector/trunk/assets/styles.css

    r3325102 r3325285  
    4545}
    4646
     47.smartdr-info {
     48    padding: 1em;
     49    margin: 1em 0;
     50    background-color: #d1ecf1;
     51    border: 1px solid #b8daff;
     52    border-radius: 4px;
     53    color: #0c5460;
     54    text-align: center;
     55}
     56
     57/* Base countdown styles - applies to all layouts with circular progress */
    4758.smartdr-countdown {
    48     text-align: center;
    49     margin: 2em 0;
    50 }
    51 
    52 .smartdr-countdown-number {
     59    position: relative;
     60    width: 120px;
     61    height: 120px;
     62    margin: 0 auto 2em;
     63    display: flex;
     64    align-items: center;
     65    justify-content: center;
     66    text-align: center;
     67}
     68
     69.smartdr-countdown-number,
     70#smartdr-countdown-number {
     71    position: relative;
     72    z-index: 2;
     73    line-height: 1;
     74    display: flex;
     75    align-items: center;
     76    justify-content: center;
     77    width: 100%;
     78    height: 100%;
     79    color: var(--smartdr-counter-color, #2271b1);
    5380    font-size: var(--smartdr-counter-size, 4em);
    54     color: var(--smartdr-counter-color, #2271b1);
    55     font-weight: bold;
    56     line-height: 1;
    57     margin: 0.5em 0;
     81    font-weight: var(--smartdr-counter-font-weight, 600);
     82    margin: 0;
     83    padding: 0;
    5884}
    5985
    6086.smartdr-progress-ring {
     87    position: absolute;
     88    top: 0;
     89    left: 0;
     90    width: 120px;
     91    height: 120px;
    6192    transform: rotate(-90deg);
    62     transform-origin: 50% 50%;
     93    transform-origin: center;
    6394}
    6495
     
    85116    transition: opacity 0.3s ease;
    86117}
    87 
    88 
    89118
    90119.smartdr-step.active {
     
    113142    font-size: var(--smartdr-manual-link-size, 1em);
    114143    transition: color 0.2s ease;
     144    display: inline-block;
    115145}
    116146
     
    132162    margin-bottom: 1.5em;
    133163    text-align: center;
    134 }
    135 
    136 /* Standard and Compact Layout countdown styles */
    137 .smartdr-countdown {
    138     position: relative;
    139     width: 120px;
    140     height: 120px;
    141     margin: 0 auto 2em !important;
    142     display: flex !important;
    143     align-items: center !important;
    144     justify-content: center !important;
    145     text-align: center !important;
    146 }
    147 
    148 .smartdr-progress-ring {
    149     position: absolute;
    150     top: 0;
    151     left: 0;
    152     width: 120px;
    153     height: 120px;
    154     transform: rotate(-90deg);
    155     transform-origin: center;
    156 }
    157 
    158 .smartdr-progress-ring-circle {
    159     stroke: var(--smartdr-counter-color) !important;
    160     stroke-width: 4 !important;
    161     fill: transparent !important;
    162 }
    163 
    164 #smartdr-countdown-number {
    165     position: relative;
    166     z-index: 2;
    167     line-height: 1;
    168     display: flex;
    169     align-items: center;
    170     justify-content: center;
    171     width: 100%;
    172     height: 100%;
    173     color: var(--smartdr-counter-color);
    174     font-size: var(--smartdr-counter-size);
    175     font-weight: var(--smartdr-counter-font-weight);
    176 }
    177 
    178 .smartdr-manual-redirect {
    179     margin-top: 1.5em;
    180     text-align: center;
    181 }
    182 
    183 .smartdr-manual-link {
    184     color: var(--smartdr-manual-link-color);
    185     font-size: var(--smartdr-manual-link-size);
    186     text-decoration: none;
    187     transition: color 0.2s ease;
    188     display: inline-block;
    189 }
    190 
    191 .smartdr-manual-link:hover {
    192     color: var(--smartdr-manual-link-hover-color);
    193     text-decoration: underline;
     164    color: var(--smartdr-heading-color, #333333);
     165    font-size: var(--smartdr-heading-size, 32px);
     166    font-weight: 600;
     167    line-height: 1.4;
     168}
     169
     170/* Standard Layout - ensure proper centering */
     171.smartdr-layout-standard .smartdr-countdown {
     172    margin: 0 auto 2em;
    194173}
    195174
     
    216195    margin-bottom: 1em;
    217196    text-align: left;
    218     font-size: var(--smartdr-heading-size);
    219     color: var(--smartdr-heading-color);
     197    font-size: var(--smartdr-heading-size, 32px);
     198    color: var(--smartdr-heading-color, #333333);
    220199}
    221200
     
    230209    height: 120px;
    231210    margin: 0;
    232     display: flex !important;
    233     align-items: center !important;
    234     justify-content: center !important;
     211    display: flex;
     212    align-items: center;
     213    justify-content: center;
    235214}
    236215
     
    242221}
    243222
    244 .smartdr-layout-progressbar .smartdr-progress-text {
     223.smartdr-layout-progressbar .smartdr-progress-text,
     224.smartdr-layout-progressbar #smartdr-countdown-text {
    245225    margin-bottom: 1em;
    246     font-size: var(--smartdr-counter-size);
    247     color: var(--smartdr-counter-color);
    248     font-weight: var(--smartdr-counter-font-weight);
     226    font-size: var(--smartdr-counter-size, 36px);
     227    color: var(--smartdr-counter-color, #2271b1);
     228    font-weight: var(--smartdr-counter-font-weight, 600);
     229    display: block;
    249230}
    250231
     
    255236    overflow: hidden;
    256237    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
    257 }
    258 
    259 .smartdr-layout-progressbar .smartdr-progress-bar {
     238    margin-bottom: 1em;
     239}
     240
     241.smartdr-layout-progressbar .smartdr-progress-bar,
     242.smartdr-layout-progressbar #smartdr-progress-bar {
    260243    height: 100%;
    261     background: var(--smartdr-counter-color);
     244    background: var(--smartdr-counter-color, #2271b1);
    262245    border-radius: 10px;
    263246    width: 0%;
     
    283266    }
    284267
    285     .smartdr-countdown-number {
    286         font-size: calc(var(--smartdr-counter-size, 4em) * 0.8);
     268    .smartdr-countdown-number,
     269    #smartdr-countdown-number {
     270        font-size: calc(var(--smartdr-counter-size, 36px) * 0.8);
    287271    }
    288272
     
    292276    .smartdr-container h4,
    293277    .smartdr-container h5,
    294     .smartdr-container h6 {
    295         font-size: calc(var(--smartdr-heading-size, 1.8em) * 0.9);
     278    .smartdr-container h6,
     279    .smartdr-heading {
     280        font-size: calc(var(--smartdr-heading-size, 32px) * 0.9);
    296281    }
    297282
     
    314299        text-align: center;
    315300    }
     301
     302    /* Progressbar layout responsive */
     303    .smartdr-layout-progressbar .smartdr-progress-text,
     304    .smartdr-layout-progressbar #smartdr-countdown-text {
     305        font-size: calc(var(--smartdr-counter-size, 36px) * 0.8);
     306    }
    316307}
  • smart-download-redirector/trunk/includes/redirect-functions.php

    r3325102 r3325285  
    1111}
    1212
    13 /**
    14  * Add custom query vars.
    15  *
    16  * @param array $vars The array of available query variables.
    17  * @return array Modified array of query variables.
    18  */
    19 function smartdr_query_vars($vars)
    20 {
    21     $vars[] = 'smartdr_download';
    22     return $vars;
    23 }
    24 
    25 /**
    26  * Handle template redirect for download URLs.
    27  */
    28 function smartdr_template_redirect()
    29 {
    30     $download_id = get_query_var('smartdr_download');
    31 
    32     if (! empty($download_id)) {
    33         $decoded_url = base64_decode($download_id);
    34        
    35         if (false === $decoded_url) {
    36             wp_die(esc_html__('Invalid download URL.', 'smart-download-redirector'));
    37         }
    38 
    39         if (! smartdr_validate_redirect_url($decoded_url)) {
    40             wp_die(esc_html__('Invalid download URL.', 'smart-download-redirector'));
    41         }
    42 
    43         // Check rate limit
    44         if (! smartdr_check_rate_limit()) {
    45             wp_die(esc_html__('Download rate limit exceeded. Please try again later.', 'smart-download-redirector'));
    46         }
    47 
    48         // Set up variables for the template
    49         $url = $decoded_url;
    50         $countdown_time = absint(get_option('smartdr_countdown_time', 10));
    51         $show_destination = get_option('smartdr_show_destination', true);
    52         $destination_display_step = absint(get_option('smartdr_destination_display_step', 1));
    53         $show_manual_link = get_option('smartdr_show_manual_link', true);
    54         $manual_link_display_step = absint(get_option('smartdr_manual_link_display_step', 2));
    55        
    56         // Get and validate redirect delay (1-10 seconds)
    57         $redirect_delay = get_option('smartdr_redirect_delay');
    58        
    59         // Ensure we have a valid numeric value
    60         if ($redirect_delay === false || !is_numeric($redirect_delay)) {
    61             $redirect_delay = 3; // Default to 3 seconds
    62         }
    63        
    64         // Convert to integer and constrain to valid range
    65         $redirect_delay = absint($redirect_delay);
    66         $redirect_delay = min(max($redirect_delay, 1), 10);
    67        
    68         // Convert to milliseconds for JavaScript
    69         $redirect_delay_ms = $redirect_delay * 1000;
    70        
    71         // Enqueue and localize the script with debug info
    72         wp_enqueue_script('smartdr-countdown');
    73         wp_localize_script(
    74             'smartdr-countdown',
    75             'smartdrData',
    76             [
    77                 'redirectUrl'   => $url,
    78                 'countdownTime' => $countdown_time,
    79                 'nonce'        => wp_create_nonce('smartdr-countdown'),
    80                 'showDestination' => $show_destination,
    81                 'destinationStep' => $destination_display_step,
    82                 'showManualLink' => $show_manual_link,
    83                 'manualLinkStep' => $manual_link_display_step,
    84                 'redirectDelay' => $redirect_delay_ms
    85             ]
    86         );
    87 
    88         // Load the countdown template
    89         include SMARTDR_PLUGIN_DIR . 'templates/download-page.php';
    90         exit;
    91     }
    92 }
    93 
    94 /**
    95  * Handle redirect validation on the download page
    96  */
    97 function smartdr_handle_download_redirect()
    98 {
    99     // Performance optimization: Only run this check when we have relevant parameters
    100     // This prevents the function from running on every page load
    101     if (empty($_GET['url']) && empty($_GET['smartdr_nonce'])) {
    102         return;
    103     }
    104 
    105     // Check if we're on the download page or if the URL contains 'download'
    106     $request_uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '';
    107     if (!is_page('download') && strpos($request_uri, '/download') === false) {
    108         return;
    109     }
    110 
    111     // Remove error_log for production
    112     // error_log('SMARTDR: Starting download redirect handler');
    113 
    114     // Verify nonce FIRST before processing any input
    115     $nonce = isset($_GET['smartdr_nonce']) ? sanitize_key(wp_unslash($_GET['smartdr_nonce'])) : '';
    116     if (empty($nonce) || !wp_verify_nonce($nonce, 'smartdr_download')) {
    117         // Remove error_log for production
    118         // error_log('SMARTDR: Invalid nonce');
    119         wp_die(esc_html__('Invalid or expired download link.', 'smart-download-redirector'));
    120         return;
    121     }
    122 
    123     // Now safely get and sanitize the URL parameter after nonce verification
    124     $url_param = isset($_GET['url']) ? sanitize_text_field(wp_unslash($_GET['url'])) : '';
    125    
    126     // Remove error_log for production
    127     // error_log('SMARTDR: Processing URL parameter: ' . $url_param);
    128    
    129     // If no URL parameter, show the default page content
    130     if (empty($url_param)) {
    131         // Remove error_log for production
    132         // error_log('SMARTDR: No URL parameter, showing default page');
    133         return;
    134     }
    135 
    136     // Decode URL if it's encoded
    137     $url = urldecode($url_param);
    138     // Remove error_log for production
    139     // error_log('SMARTDR: Decoded URL: ' . $url);
    140 
    141     // Normalize URL format
    142     $url = smartdr_normalize_url($url);
    143 
    144     // Validate URL
    145     if (!smartdr_validate_redirect_url($url)) {
    146         // Remove error_log for production
    147         // error_log('SMARTDR: URL validation failed for: ' . $url);
    148         wp_die(esc_html__('Invalid download URL.', 'smart-download-redirector'));
    149         return;
    150     }
    151 
    152     // Remove error_log for production
    153     // error_log('SMARTDR: URL validation successful for: ' . $url);
    154 
    155     // Create or get the download page
    156     $download_page = get_page_by_path('download');
    157     if (!$download_page) {
    158         // Create the download page if it doesn't exist
    159         $download_page_id = wp_insert_post([
    160             'post_title' => esc_html__('Download', 'smart-download-redirector'),
    161             'post_name' => 'download',
    162             'post_content' => '[smartdr_download_countdown]',
    163             'post_status' => 'publish',
    164             'post_type' => 'page',
    165             'comment_status' => 'closed',
    166             'ping_status' => 'closed'
    167         ]);
    168         $download_page = get_post($download_page_id);
    169     }
    170 
    171     // Ensure the page exists
    172     if (!$download_page) {
    173         // Remove error_log for production
    174         // error_log('SMARTDR: Failed to create or get download page');
    175         return;
    176     }
    177 
    178     // Set up the global post object
    179     global $wp_query, $post;
    180     $wp_query->is_page = true;
    181     $wp_query->is_singular = true;
    182     $wp_query->is_home = false;
    183     $wp_query->is_archive = false;
    184     $wp_query->is_category = false;
    185     $wp_query->query_vars['url'] = $url_param;
    186     $wp_query->query_vars['smartdr_nonce'] = $nonce;
    187    
    188     // Set up the post
    189     $post = $download_page;
    190     setup_postdata($post);
    191    
    192     // Force the content to contain our shortcode
    193     add_filter('the_content', function($content) {
    194         return '[smartdr_download_countdown]';
    195     }, 999999);
    196 }
    197 add_action('template_redirect', 'smartdr_handle_download_redirect', 1);
     13
     14
     15
    19816
    19917/**
     
    28199            // Check if domain matches
    282100            if ($domain === $target_domain) {
    283                 // Create redirect URL using query parameters
     101                // Create redirect URL using query parameters to the shortcode page
    284102                $redirect_url = add_query_arg([
    285                     'smartdr_url' => base64_encode($url),
     103                    'url' => urlencode($url),
    286104                    'smartdr_nonce' => wp_create_nonce('smartdr_download')
    287105                ], get_permalink($shortcode_page));
     
    377195{
    378196    if (! smartdr_validate_redirect_url($url)) {
    379         // Remove error_log for production
    380         // error_log('SMARTDR: URL validation failed in generate_download_url for: ' . $url);
    381197        return $url;
    382198    }
    383199
    384     // Remove error_log for production
    385     // error_log('SMARTDR: Generating download URL for: ' . $url);
    386     $redirect_url = home_url('/download/');
    387     $redirect_url = add_query_arg('url', urlencode($url), $redirect_url);
    388     $redirect_url = wp_nonce_url($redirect_url, 'smartdr_download', 'smartdr_nonce');
    389    
    390     // Remove error_log for production
    391     // error_log('SMARTDR: Generated redirect URL: ' . $redirect_url);
     200    // Get the shortcode page
     201    $shortcode_page = get_option('smartdr_shortcode_page');
     202   
     203    // If no shortcode page found, try to find it
     204    if (!$shortcode_page) {
     205        $pages = get_posts([
     206            'post_type' => 'page',
     207            'posts_per_page' => -1,
     208            'post_status' => 'publish'
     209        ]);
     210       
     211        foreach ($pages as $page) {
     212            if (has_shortcode($page->post_content, 'smartdr_download_countdown')) {
     213                $shortcode_page = $page->ID;
     214                update_option('smartdr_shortcode_page', $shortcode_page);
     215                break;
     216            }
     217        }
     218    }
     219   
     220    // If still no shortcode page found, return original URL
     221    if (!$shortcode_page) {
     222        return $url;
     223    }
     224
     225    // Create redirect URL using query parameters to the shortcode page
     226    $redirect_url = add_query_arg([
     227        'url' => urlencode($url),
     228        'smartdr_nonce' => wp_create_nonce('smartdr_download')
     229    ], get_permalink($shortcode_page));
     230   
    392231    return $redirect_url;
    393232}
     
    404243    }
    405244
    406     // Performance optimization: Only process if we have relevant parameters
    407     if (empty($_GET['smartdr_url']) && empty($_GET['smartdr_nonce'])) {
    408         return '';
    409     }
    410 
    411     // Verify nonce FIRST before processing any input
     245    // Check for URL parameters
     246    $url_param = isset($_GET['url']) ? sanitize_text_field(wp_unslash($_GET['url'])) : '';
    412247    $nonce = isset($_GET['smartdr_nonce']) ? sanitize_key(wp_unslash($_GET['smartdr_nonce'])) : '';
    413     if (empty($nonce) || !wp_verify_nonce($nonce, 'smartdr_download')) {
    414         return '<div class="smartdr-error">' . esc_html__('Invalid or expired download link.', 'smart-download-redirector') . '</div>';
    415     }
    416 
    417     // Now safely get and sanitize the URL parameter after nonce verification
    418     $url_param = isset($_GET['smartdr_url']) ? sanitize_text_field(wp_unslash($_GET['smartdr_url'])) : '';
    419 
    420     // If no URL parameter, return empty
    421     if (empty($url_param)) {
    422         return '';
    423     }
    424 
    425     // Decode base64 URL
    426     $url = base64_decode($url_param);
    427     if ($url === false) {
    428         return '<div class="smartdr-error">' . esc_html__('Invalid URL format.', 'smart-download-redirector') . '</div>';
    429     }
    430    
    431     // Normalize URL format
    432     $url = smartdr_normalize_url($url);
    433    
    434     if (!smartdr_validate_redirect_url($url)) {
    435         return '<div class="smartdr-error">' . esc_html__('Invalid download URL. Please check your target domains settings.', 'smart-download-redirector') . '</div>';
    436     }
    437    
    438     // Get countdown time from settings
     248    $url = null;
     249   
     250    if (!empty($url_param) && !empty($nonce)) {
     251        // Verify nonce
     252        if (wp_verify_nonce($nonce, 'smartdr_download')) {
     253            $decoded_url = urldecode($url_param);
     254            $decoded_url = smartdr_normalize_url($decoded_url);
     255           
     256            if (smartdr_validate_redirect_url($decoded_url)) {
     257                $url = $decoded_url;
     258            }
     259        }
     260    }
     261   
     262    // Get countdown configuration for template
    439263    $countdown_time = absint(get_option('smartdr_countdown_time', 10));
    440    
    441     // Get and validate redirect delay (1-10 seconds)
    442     $redirect_delay = get_option('smartdr_redirect_delay', 3);
    443     $redirect_delay = absint($redirect_delay);
     264    $redirect_delay = absint(get_option('smartdr_redirect_delay', 3));
    444265    $redirect_delay = min(max($redirect_delay, 1), 10);
    445     $redirect_delay_ms = $redirect_delay * 1000;
    446    
    447     // Enqueue required scripts and styles
    448     wp_enqueue_script('smartdr-countdown');
    449     wp_enqueue_style('smartdr-styles');
    450    
    451     // Localize script data
    452     wp_localize_script(
    453         'smartdr-countdown',
    454         'smartdrData',
    455         [
    456             'redirectUrl' => $url,
    457             'countdownTime' => $countdown_time,
    458             'nonce' => wp_create_nonce('smartdr-countdown'),
    459             'showDestination' => get_option('smartdr_show_destination', true),
    460             'destinationStep' => absint(get_option('smartdr_destination_display_step', 1)),
    461             'showManualLink' => get_option('smartdr_show_manual_link', true),
    462             'manualLinkStep' => absint(get_option('smartdr_manual_link_display_step', 2)),
    463             'redirectDelay' => $redirect_delay_ms,
    464             'ajaxurl' => admin_url('admin-ajax.php')
    465         ]
    466     );
     266   
     267    // If still no URL, show placeholder
     268    if (!$url) {
     269        return '<div class="smartdr-info">' . esc_html__('Download countdown will appear here when accessing a download link.', 'smart-download-redirector') . '</div>';
     270    }
     271
     272    // We have a valid URL, proceed with countdown
    467273   
    468274    // Start output buffering to capture template content
     
    486292        'custom_heading' => get_option('smartdr_custom_heading', esc_html__('Preparing Your Download', 'smart-download-redirector')),
    487293        'show_title' => get_option('smartdr_show_title', true),
    488         'manual_link_display_timing' => 'at_end', // Always show at end
     294        'manual_link_display_timing' => 'at_end',
    489295        'styles' => get_option('smartdr_styles', [])
    490296    ];
     
    498304    // Get buffered content
    499305    $content = ob_get_clean();
    500    
    501     // Always use custom style mode
    502     $style_mode = 'custom';
    503306   
    504307    // Get custom styles for CSS variables
     
    519322    // Wrap content in theme-independent container
    520323    return sprintf(
    521         '<div class="smartdr-container" data-smartdr-version="%s" data-style-mode="%s"%s>%s</div>',
     324        '<div class="smartdr-container" data-smartdr-version="%s" data-style-mode="custom"%s>%s</div>',
    522325        esc_attr(SMARTDR_VERSION),
    523         esc_attr($style_mode),
    524326        $style_attrs,
    525327        $content
     
    527329}
    528330add_shortcode('smartdr_download_countdown', 'smartdr_countdown_shortcode');
     331
     332/**
     333 * Get WPML translated string or fallback to original
     334 *
     335 * @param string $name The string name
     336 * @param string $original The original string
     337 * @return string The translated string or original
     338 */
     339function smartdr_get_wpml_string($name, $original) {
     340    // Try newer WPML API first (WPML 4.0+)
     341    if (function_exists('wpml_translate_single_string')) {
     342        return wpml_translate_single_string('smart-download-redirector', $name, $original);
     343    }
     344   
     345    // Fallback to older WPML API (WPML 3.x)
     346    if (function_exists('icl_t')) {
     347        return icl_t('smart-download-redirector', $name, $original);
     348    }
     349   
     350    // Fallback to original string if WPML is not available
     351    return $original;
     352}
    529353
    530354/**
  • smart-download-redirector/trunk/readme.txt

    r3325102 r3325285  
    31313. Use the Settings->Download Redirector screen to configure the plugin
    32324. Add domains to the target list to start redirecting downloads
     335. Create a page (e.g., "Download") and add the shortcode `[smartdr_download_countdown]` to display the countdown functionality
     346. The plugin will automatically redirect matching links to your download page
    3335
    3436== Frequently Asked Questions ==
  • smart-download-redirector/trunk/smart-download-redirector.php

    r3325102 r3325285  
    4949        }
    5050    }
    51 
    52     // Flush rewrite rules.
    53     flush_rewrite_rules();
    5451}
    5552register_activation_hook(__FILE__, 'smartdr_activate');
     
    6057function smartdr_deactivate()
    6158{
    62     // Flush rewrite rules.
    63     flush_rewrite_rules();
     59    // Clean up on deactivation
    6460}
    6561register_deactivation_hook(__FILE__, 'smartdr_deactivate');
    66 
    67 /**
    68  * Initialize plugin.
    69  */
    70 function smartdr_init()
    71 {
    72     // Add rewrite rules.
    73     add_rewrite_rule(
    74         '^download/([^/]+)/?$',
    75         'index.php?smartdr_download=$matches[1]',
    76         'top'
    77     );
    78 
    79     // Add query vars.
    80     add_filter('query_vars', 'smartdr_query_vars');
    81 
    82     // Add template redirect.
    83     add_action('template_redirect', 'smartdr_template_redirect');
    84 }
    85 add_action('init', 'smartdr_init');
    8662
    8763/**
     
    9369function smartdr_register_assets()
    9470{
     71    // Register countdown script
    9572    wp_register_script(
    9673        'smartdr-countdown',
     
    9875        ['jquery'],
    9976        filemtime(SMARTDR_PLUGIN_DIR . 'assets/countdown.js'),
    100         false // Load in header.
     77        true // Load in footer for better performance
    10178    );
    10279
     
    11087}
    11188add_action('wp_enqueue_scripts', 'smartdr_register_assets');
     89
     90/**
     91 * Check if we need to enqueue countdown assets based on content
     92 */
     93function smartdr_maybe_enqueue_assets()
     94{
     95    // Check if we're on a page with the shortcode
     96    global $post;
     97    $should_enqueue = false;
     98   
     99    if (is_object($post) && has_shortcode($post->post_content, 'smartdr_download_countdown')) {
     100        $should_enqueue = true;
     101    }
     102   
     103    // Check if we're on a download URL (with URL parameters)
     104    if (isset($_GET['url']) && isset($_GET['smartdr_nonce'])) {
     105        $should_enqueue = true;
     106    }
     107   
     108    if ($should_enqueue) {
     109        wp_enqueue_script('smartdr-countdown');
     110        wp_enqueue_style('smartdr-styles');
     111       
     112        // Prepare localization data
     113        $url_param = isset($_GET['url']) ? sanitize_text_field(wp_unslash($_GET['url'])) : '';
     114        $nonce = isset($_GET['smartdr_nonce']) ? sanitize_key(wp_unslash($_GET['smartdr_nonce'])) : '';
     115        $url = null;
     116       
     117        if (!empty($url_param) && !empty($nonce)) {
     118            // Verify nonce
     119            if (wp_verify_nonce($nonce, 'smartdr_download')) {
     120                $decoded_url = urldecode($url_param);
     121                $decoded_url = smartdr_normalize_url($decoded_url);
     122               
     123                if (smartdr_validate_redirect_url($decoded_url)) {
     124                    $url = $decoded_url;
     125                }
     126            }
     127        }
     128       
     129        // Always prepare countdown configuration
     130        $countdown_time = absint(get_option('smartdr_countdown_time', 10));
     131        $redirect_delay = absint(get_option('smartdr_redirect_delay', 3));
     132        $redirect_delay = min(max($redirect_delay, 1), 10);
     133        $redirect_delay_ms = $redirect_delay * 1000;
     134       
     135        // Localize script with data
     136        wp_localize_script(
     137            'smartdr-countdown',
     138            'smartdrData',
     139            [
     140                'redirectUrl' => $url ? $url : '',
     141                'countdownTime' => $countdown_time,
     142                'nonce' => wp_create_nonce('smartdr-countdown'),
     143                'showDestination' => get_option('smartdr_show_destination', true),
     144                'destinationStep' => absint(get_option('smartdr_destination_display_step', 1)),
     145                'showManualLink' => get_option('smartdr_show_manual_link', true),
     146                'manualLinkStep' => absint(get_option('smartdr_manual_link_display_step', 2)),
     147                'redirectDelay' => $redirect_delay_ms,
     148                'secondsText' => __('seconds remaining', 'smart-download-redirector'),
     149                'downloadReadyText' => __('Download ready!', 'smart-download-redirector'),
     150                'hasValidUrl' => !empty($url)
     151            ]
     152        );
     153       
     154        // Add CSS variables for styling
     155        $styles = get_option('smartdr_styles', array());
     156        $default_styles = array(
     157            'heading_color' => '#212121',
     158            'heading_size' => '32px',
     159            'counter_color' => '#00897B',
     160            'counter_size' => '36px',
     161            'counter_font_weight' => 'bold',
     162            'background_color' => '#ffffff',
     163            'border_radius' => '8px',
     164            'border_size' => '1px',
     165            'border_color' => '#dddddd',
     166            'manual_link_size' => '14px',
     167            'manual_link_color' => '#00897B',
     168            'manual_link_hover_color' => '#00695C'
     169        );
     170        $styles = array_merge($default_styles, $styles);
     171       
     172        // Add inline CSS with custom properties
     173        $inline_css = "
     174/* CSS Custom Properties for dynamic styling */
     175:root {
     176    --smartdr-counter-color: " . esc_attr($styles['counter_color']) . ";
     177    --smartdr-counter-size: " . esc_attr($styles['counter_size']) . ";
     178    --smartdr-counter-font-weight: " . (($styles['counter_font_weight'] === 'bold') ? '600' : 'normal') . ";
     179    --smartdr-heading-color: " . esc_attr($styles['heading_color']) . ";
     180    --smartdr-heading-size: " . esc_attr($styles['heading_size']) . ";
     181    --smartdr-manual-link-size: " . esc_attr($styles['manual_link_size']) . ";
     182    --smartdr-manual-link-color: " . esc_attr($styles['manual_link_color']) . ";
     183    --smartdr-manual-link-hover-color: " . esc_attr($styles['manual_link_hover_color']) . ";
     184    --smartdr-bg-color: " . esc_attr($styles['background_color']) . ";
     185    --smartdr-border-radius: " . esc_attr($styles['border_radius']) . ";
     186    --smartdr-border-size: " . esc_attr($styles['border_size']) . ";
     187    --smartdr-border-color: " . esc_attr($styles['border_color']) . ";
     188}";
     189        wp_add_inline_style('smartdr-styles', $inline_css);
     190    }
     191}
     192add_action('wp_enqueue_scripts', 'smartdr_maybe_enqueue_assets', 20);
  • smart-download-redirector/trunk/templates/download-page.php

    r3325102 r3325285  
    1717$countdown_time = absint(get_option('smartdr_countdown_time', 10));
    1818$show_manual_link = get_option('smartdr_show_manual_link', true);
    19 // Manual link always shows at the end of countdown (last 10%)
    2019$show_title = get_option('smartdr_show_title', true);
    2120$redirect_delay = absint(get_option('smartdr_redirect_delay', 3));
     
    2726$manual_link_text = smartdr_get_wpml_string('Manual Link Text', $manual_link_text_original);
    2827
    29 // Always use custom style mode
    30 $style_mode = 'custom';
    31 $styles = get_option('smartdr_styles', array());
    32 
    3328// Get layout style setting
    3429$layout_style = get_option('smartdr_layout_style', 'standard');
    35 
    36 // For theme mode, try to detect actual theme colors
    37 $theme_primary_color = '#0073aa'; // WordPress default fallback
    38 if ($style_mode === 'theme') {
    39     // Try to get theme colors from various sources
    40     $theme_colors = wp_get_global_styles(array('color'));
    41    
    42     // Check for block theme colors
    43     if (isset($theme_colors['palette']['theme'])) {
    44         foreach ($theme_colors['palette']['theme'] as $color) {
    45             if (isset($color['slug']) && in_array($color['slug'], ['primary', 'accent', 'secondary'])) {
    46                 $theme_primary_color = $color['color'];
    47                 break;
    48             }
    49         }
    50     }
    51    
    52     // Fallback: check theme supports and customizer colors
    53     if ($theme_primary_color === '#0073aa') {
    54         // Check for customizer primary color
    55         $customizer_primary = get_theme_mod('primary_color');
    56         if ($customizer_primary) {
    57             $theme_primary_color = $customizer_primary;
    58         } else {
    59             // Check for accent color
    60             $accent_color = get_theme_mod('accent_color');
    61             if ($accent_color) {
    62                 $theme_primary_color = $accent_color;
    63             }
    64         }
    65     }
    66 }
    67 
    68 // Default fallbacks for custom mode
    69 $default_styles = array(
    70     'heading_color' => '#212121',
    71     'heading_size' => '32px',
    72     'counter_color' => '#00897B',
    73     'counter_size' => '36px',
    74     'counter_font_weight' => 'bold',
    75     'background_color' => '#ffffff',
    76     'border_radius' => '8px',
    77     'border_size' => '1px',
    78     'border_color' => '#dddddd',
    79     'manual_link_size' => '14px',
    80     'manual_link_color' => '#00897B',
    81     'manual_link_hover_color' => '#00695C'
    82 );
    83 
    84 $styles = array_merge($default_styles, $styles);
    85 
    86 // Get destination box styles
    87 $destination_styles = get_option('smartdr_destination_styles', array());
    88 $default_destination_styles = array(
    89     'background_color' => '#f8f9fa',
    90     'border_size' => '1px',
    91     'border_color' => '#dee2e6',
    92     'border_radius' => '4px',
    93     'text_size' => '14px'
    94 );
    95 $destination_styles = array_merge($default_destination_styles, $destination_styles);
    96 
    97 // Generate inline styles
    98 $heading_style = sprintf(
    99     'color: %s; font-size: %s;',
    100     esc_attr($styles['heading_color']),
    101     esc_attr($styles['heading_size'])
    102 );
    103 
    104 // Generate destination box style
    105 $destination_box_style = sprintf(
    106     'background-color: %s; border: %s solid %s; border-radius: %s; font-size: %s;',
    107     esc_attr($destination_styles['background_color']),
    108     esc_attr($destination_styles['border_size']),
    109     esc_attr($destination_styles['border_color']),
    110     esc_attr($destination_styles['border_radius']),
    111     esc_attr($destination_styles['text_size'])
    112 );
    11330?>
    11431
     
    18097
    18198<?php
    182 // Add inline styles using WordPress proper method
    183 $inline_css = "
    184 /* CSS Custom Properties for dynamic styling */
    185 :root {
    186     --smartdr-counter-color: " . esc_attr($styles['counter_color']) . ";
    187     --smartdr-counter-size: " . esc_attr($styles['counter_size']) . ";
    188     --smartdr-counter-font-weight: " . (($styles['counter_font_weight'] === 'bold') ? '600' : 'normal') . ";
    189     --smartdr-heading-color: " . esc_attr($styles['heading_color']) . ";
    190     --smartdr-heading-size: " . esc_attr($styles['heading_size']) . ";
    191     --smartdr-manual-link-size: " . esc_attr($styles['manual_link_size']) . ";
    192     --smartdr-manual-link-color: " . esc_attr($styles['manual_link_color']) . ";
    193     --smartdr-manual-link-hover-color: " . esc_attr($styles['manual_link_hover_color']) . ";
    194 }
    195 
    196 /* All layout and static styles are now in assets/styles.css */
    197 /* Only CSS Custom Properties remain here for dynamic theming */
    198 ";
    199 wp_add_inline_style('smartdr-styles', $inline_css);
     99// CSS Custom Properties are now handled in the main plugin file
     100// to ensure proper timing and availability
    200101?>
    201102
    202 <?php
    203 // Add inline script using WordPress proper method
    204 $inline_js = "
    205 jQuery(document).ready(function($) {
    206     var countdownTime = " . esc_js($countdown_time) . ";
    207     var showManualLink = " . ($show_manual_link ? 'true' : 'false') . ";
    208     var manualLinkTiming = 'at_end'; // Always show at end
    209     var layoutStyle = '" . esc_js($layout_style) . "';
    210     var redirectUrl = '" . esc_js($url) . "';
    211     var downloadReadyText = '" . esc_js(__('Download ready!', 'smart-download-redirector')) . "';
    212     var secondsRemainingText = '" . esc_js(__('seconds remaining', 'smart-download-redirector')) . "';
    213    
    214     // Get smartdrData from localized script
    215     if (typeof smartdrData !== 'undefined') {
    216         var redirectDelay = smartdrData.redirectDelay;
    217        
    218         // Debug values
    219         console.log('[SMARTDR Debug] Initial settings:', {
    220             countdownTime: countdownTime + ' seconds',
    221             redirectDelay: (redirectDelay / 1000) + ' seconds',
    222             showManualLink: showManualLink,
    223             manualLinkTiming: manualLinkTiming,
    224             layoutStyle: layoutStyle
    225         });
    226        
    227         var \$manualRedirect = \$('.smartdr-manual-redirect');
    228         var \$countdownNumber = \$('#smartdr-countdown-number');
    229         var \$countdownText = \$('#smartdr-countdown-text');
    230         var \$progressBar = \$('#smartdr-progress-bar');
    231         var circle = document.querySelector('.smartdr-progress-ring-circle');
    232         var isRedirecting = false;
    233 
    234         // Initialize circular progress (for standard and compact layouts)
    235         if (circle) {
    236             var radius = circle.r.baseVal.value;
    237             var circumference = radius * 2 * Math.PI;
    238             circle.style.strokeDasharray = circumference + ' ' + circumference;
    239             circle.style.strokeDashoffset = circumference;
    240         }
    241 
    242         // IMPORTANT: Manual link must NEVER be visible during countdown
    243         // Force hide and ensure it stays hidden until countdown is complete
    244         \$manualRedirect.hide().css('visibility', 'hidden');
    245        
    246         // Additional safeguard: prevent any accidental showing during countdown
    247         function ensureManualLinkHidden() {
    248             if (!countdownComplete && !manualLinkShown) {
    249                 \$manualRedirect.hide().css('visibility', 'hidden');
    250             }
    251         }
    252 
    253         function setProgress(percent) {
    254             // Update circular progress (standard and compact layouts)
    255             if (circle) {
    256                 var offset = circumference - (percent / 100 * circumference);
    257                 circle.style.strokeDashoffset = offset;
    258             }
    259            
    260             // Update horizontal progress bar (progressbar layout)
    261             if (\$progressBar.length > 0) {
    262                 \$progressBar.css('width', percent + '%');
    263             }
    264         }
    265 
    266         var manualLinkShown = false; // Track if manual link has been shown
    267         var countdownComplete = false; // Track if countdown has finished
    268        
    269         function complete() {
    270             console.log('[SMARTDR Debug] Countdown complete');
    271            
    272             // Mark countdown as complete - manual link can now be shown
    273             countdownComplete = true;
    274            
    275             // Update progress to 100%
    276             setProgress(100);
    277 
    278             // Update countdown displays based on layout
    279             if (layoutStyle === 'progressbar') {
    280                 // For progressbar layout, update text
    281                 \$countdownText.fadeOut(200, function() {
    282                     \$(this).text(downloadReadyText).fadeIn(200);
    283                    
    284                     // Show manual link after text update if enabled (only after countdown is complete)
    285                     if (showManualLink && !manualLinkShown && countdownComplete) {
    286                         \$manualRedirect.css('visibility', 'visible').fadeIn(400);
    287                         manualLinkShown = true;
    288                         console.log('[SMARTDR Debug] ✅ Manual link shown after countdown completion');
    289                     }
    290                 });
    291             } else {
    292                 // For standard and compact layouts, show arrow
    293                 \$countdownNumber.fadeOut(200, function() {
    294                     \$(this).text('→').fadeIn(200);
    295                    
    296                     // Show manual link after arrow appears if enabled (only after countdown is complete)
    297                     if (showManualLink && !manualLinkShown && countdownComplete) {
    298                         \$manualRedirect.css('visibility', 'visible').fadeIn(400);
    299                         manualLinkShown = true;
    300                         console.log('[SMARTDR Debug] ✅ Manual link shown after countdown completion');
    301                     }
    302                 });
    303             }
    304 
    305             // Redirect after configured delay
    306             console.log('[SMARTDR Debug] Will redirect in ' + (redirectDelay/1000) + ' seconds');
    307             setTimeout(function() {
    308                 console.log('[SMARTDR Debug] Redirecting now');
    309                 window.location.href = redirectUrl;
    310             }, redirectDelay);
    311         }
    312 
    313         function countdown() {
    314             var timeLeft = countdownTime;
    315            
    316             var timer = setInterval(function() {
    317                 if (isRedirecting) {
    318                     clearInterval(timer);
    319                     return;
    320                 }
    321 
    322                 timeLeft--;
    323                 var progress = ((countdownTime - timeLeft) / countdownTime) * 100;
    324                 setProgress(progress);
    325                
    326                 // Update display based on layout
    327                 if (layoutStyle === 'progressbar') {
    328                     // Update progressbar text with remaining seconds
    329                     \$countdownText.text(timeLeft + ' ' + secondsRemainingText);
    330                 } else {
    331                     // Update countdown number for circular layouts
    332                     \$countdownNumber.text(timeLeft);
    333                 }
    334 
    335                 // Safeguard: Ensure manual link stays hidden during countdown
    336                 ensureManualLinkHidden();
    337 
    338                 // Complete countdown when time reaches zero
    339                 if (timeLeft <= 0) {
    340                     clearInterval(timer);
    341                     complete();
    342                 }
    343             }, 1000);
    344         }
    345 
    346         countdown();
    347     } else {
    348         console.error('[SMARTDR] smartdrData not found - countdown will not work');
    349     }
    350 });
    351 ";
    352 wp_add_inline_script('smartdr-countdown', $inline_js);
    353 ?>
     103 
Note: See TracChangeset for help on using the changeset viewer.