Plugin Directory

Changeset 3446520


Ignore:
Timestamp:
01/25/2026 12:27:38 PM (2 months ago)
Author:
sarangan112
Message:

Update trunk to v1.2.2: Added settings page and custom date range

Location:
winter-snow-effect/trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • winter-snow-effect/trunk/assets/js/snow.js

    r3431295 r3446520  
    44
    55(function () {
    6     // Create canvas
    7     const canvas = document.createElement('canvas');
    8     canvas.id = 'wse-snow-canvas';
    9     document.body.appendChild(canvas);
     6    const startSnow = () => {
     7        if (!document.body) {
     8            setTimeout(startSnow, 50);
     9            return;
     10        }
    1011
    11     const ctx = canvas.getContext('2d');
    12     let width = window.innerWidth;
    13     let height = window.innerHeight;
     12        // Get settings from WordPress localized script with deep fallbacks
     13        const s = typeof wse_settings !== 'undefined' ? wse_settings : {};
     14        const settings = {
     15            flakeCount: parseInt(s.flakeCount) || 35,
     16            minSpeed: parseFloat(s.minSpeed) || 0.5,
     17            maxSpeed: parseFloat(s.maxSpeed) || 1.5
     18        };
    1419
    15     canvas.width = width;
    16     canvas.height = height;
     20        // Create canvas
     21        const canvas = document.createElement('canvas');
     22        canvas.id = 'wse-snow-canvas';
     23        document.body.appendChild(canvas);
    1724
    18     // Snowflakes array
    19     const flakes = [];
    20     // Adjust flake count based on screen width
    21     // < 768px (mobile): 6 flakes (as requested)
    22     // >= 768px (desktop): 35 flakes
    23     const isMobile = window.innerWidth < 768;
    24     const maxFlakes = isMobile ? 6 : 35;
     25        const ctx = canvas.getContext('2d');
     26        let width = window.innerWidth;
     27        let height = window.innerHeight;
    2528
    26     // Resize handler
    27     window.addEventListener('resize', function () {
    28         width = window.innerWidth;
    29         height = window.innerHeight;
    3029        canvas.width = width;
    3130        canvas.height = height;
    32     });
    3331
    34     // Snowflake class
    35     class Snowflake {
    36         constructor() {
    37             this.x = Math.random() * width;
    38             this.y = Math.random() * height;
     32        const isMobile = window.innerWidth < 768;
    3933
    40             // Adjust size based on device
    41             // Mobile: 20px - 35px (Bigger flakes)
    42             // Desktop: 10px - 30px
    43             this.size = isMobile
    44                 ? Math.random() * 15 + 20
    45                 : Math.random() * 20 + 10;
     34        // If mobile, reduce flake count to 20% of setting (minimum 6)
     35        const density = isMobile ? 0.2 : 1.0;
     36        const maxFlakes = Math.max(isMobile ? 6 : 1, Math.floor(settings.flakeCount * density));
    4637
    47             this.speed = Math.random() * 1 + 0.5; // Moderate gentle speed
    48             this.sway = Math.random() - 0.5;
    49             this.swaySpeed = Math.random() * 0.01 + 0.005;
    50             this.angle = Math.random() * Math.PI * 2;
    51             this.opacity = Math.random() * 0.3 + 0.6; // Higher opacity (0.6 to 0.9) for visibility
    52         }
     38        // Snowflakes array
     39        const flakes = [];
    5340
    54         update() {
    55             this.y += this.speed;
    56             this.angle += this.swaySpeed;
    57             this.x += Math.sin(this.angle) * 1.5;
     41        // Resize handler
     42        window.addEventListener('resize', function () {
     43            width = window.innerWidth;
     44            height = window.innerHeight;
     45            canvas.width = width;
     46            canvas.height = height;
     47        });
    5848
    59             // Wrap around screen
    60             if (this.y > height) {
    61                 this.y = -10;
     49        // Snowflake class
     50        class Snowflake {
     51            constructor() {
     52                this.reset();
     53                this.y = Math.random() * height; // Initial random Y
     54            }
     55
     56            reset() {
    6257                this.x = Math.random() * width;
     58                this.y = -20;
     59
     60                // Size: Mobile (20-35px), Desktop (10-30px)
     61                this.size = isMobile
     62                    ? Math.random() * 15 + 20
     63                    : Math.random() * 20 + 10;
     64
     65                // Speed from settings
     66                const range = Math.max(0.1, settings.maxSpeed - settings.minSpeed);
     67                this.speed = Math.random() * range + settings.minSpeed;
     68
     69                this.swaySpeed = Math.random() * 0.01 + 0.005;
     70                this.angle = Math.random() * Math.PI * 2;
     71                this.opacity = Math.random() * 0.3 + 0.6;
    6372            }
    64             if (this.x > width) {
    65                 this.x = 0;
    66             } else if (this.x < 0) {
    67                 this.x = width;
     73
     74            update() {
     75                this.y += this.speed;
     76                this.angle += this.swaySpeed;
     77                this.x += Math.sin(this.angle) * 1.5;
     78
     79                // Reset if out of bounds
     80                if (this.y > height) {
     81                    this.reset();
     82                }
     83                if (this.x > width) {
     84                    this.x = 0;
     85                } else if (this.x < 0) {
     86                    this.x = width;
     87                }
     88            }
     89
     90            draw() {
     91                ctx.font = `${this.size}px sans-serif`;
     92                ctx.fillStyle = `rgba(255, 255, 255, ${this.opacity})`;
     93                ctx.shadowColor = 'rgba(0, 0, 0, 0.3)';
     94                ctx.shadowBlur = 4;
     95                ctx.fillText('*', this.x, this.y);
     96                ctx.shadowBlur = 0;
    6897            }
    6998        }
    7099
    71         draw() {
    72             ctx.font = `${this.size}px sans-serif`;
    73             ctx.fillStyle = `rgba(255, 255, 255, ${this.opacity})`;
     100        // Initialize flakes
     101        for (let i = 0; i < maxFlakes; i++) {
     102            flakes.push(new Snowflake());
     103        }
    74104
    75             // Shadow for visibility
    76             ctx.shadowColor = 'rgba(0, 0, 0, 0.3)';
    77             ctx.shadowBlur = 4;
     105        // Animation loop
     106        function animate() {
     107            ctx.clearRect(0, 0, width, height);
     108            flakes.forEach(flake => {
     109                flake.update();
     110                flake.draw();
     111            });
     112            requestAnimationFrame(animate);
     113        }
    78114
    79             ctx.fillText('*', this.x, this.y);
     115        animate();
     116    };
    80117
    81             // Reset shadow to avoid affecting other potential draws if shared context (good practice)
    82             ctx.shadowBlur = 0;
    83         }
     118    // Run when ready
     119    if (document.readyState === 'complete' || document.readyState === 'interactive') {
     120        startSnow();
     121    } else {
     122        document.addEventListener('DOMContentLoaded', startSnow);
    84123    }
    85 
    86     // Initialize flakes
    87     for (let i = 0; i < maxFlakes; i++) {
    88         flakes.push(new Snowflake());
    89     }
    90 
    91     // Animation loop
    92     function animate() {
    93         ctx.clearRect(0, 0, width, height);
    94         flakes.forEach(flake => {
    95             flake.update();
    96             flake.draw();
    97         });
    98         requestAnimationFrame(animate);
    99     }
    100 
    101     animate();
    102124})();
  • winter-snow-effect/trunk/readme.txt

    r3431295 r3446520  
    44Requires at least: 5.0
    55Tested up to: 6.9
    6 Stable tag: 1.1
     6Stable tag: 1.2.2
    77Requires PHP: 7.0
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    1010
    11 Automatically adds a falling snow effect to your website only during winter months (December, January, February).
     11Automatically adds a customizable falling snow effect to your website.
    1212
    1313== Description ==
    1414
    15 Bring the winter spirit to your WordPress site with the Winter Snow Effect plugin. This lightweight plugin automatically detects the current month and enables a beautiful, non-intrusive falling snow animation during the winter season (December, January, and February).
     15Bring the winter spirit to your WordPress site with the Winter Snow Effect plugin. This lightweight plugin allows you to enable a beautiful, non-intrusive falling snow animation during the winter season or any custom date range you choose.
    1616
    1717**Features:**
    18 *   **Automatic Detection:** Activates only during winter months.
     18*   **Customizable Timing:** Choose specific months or a custom date range for the snow effect.
     19*   **Performance Controls:** Adjust the number of snowflakes to balance visuals and site speed.
     20*   **Visual Customization:** Control the falling speed of the snow.
    1921*   **Lightweight:** Minimal CSS and JavaScript for optimal performance.
    20 *   **Responsive:** optimized for smartphones and tablets.
    21 *   **No Configuration Needed:** Simply install and activate.
     22*   **Responsive:** Automatically optimized for smartphones and tablets.
    2223
    2324== Installation ==
     
    25261.  Upload the plugin files to the `/wp-content/plugins/winter-snow-effect` directory, or install the plugin through the WordPress plugins screen directly.
    26272.  Activate the plugin through the 'Plugins' screen in WordPress.
    27 3.  Enjoy the snow during the winter months!
     283.  Navigate to **Settings > Winter Snow** to customize your effect.
    2829
    2930== Frequently Asked Questions ==
    3031
    3132= When does the snow appear? =
    32 The snow effect is active only during December, January, and February.
     33By default, the snow appears in December, January, and February. You can change this in the plugin settings to any combination of months or a specific date range.
    3334
    34 = Can I disable it? =
    35 Deactivate the plugin to stop the snow effect.
     35= Can I control how much snow is shown? =
     36Yes, the settings page allows you to adjust the flake count and speed.
    3637
    3738== Changelog ==
     39
     40= 1.2 =
     41*   New: Added Settings Page under Settings > Winter Snow.
     42*   New: Support for Custom Date Ranges (Start/End dates).
     43*   New: Customizable flake count and falling speed.
     44*   Refactor: Modernized PHP code structure using a class-based approach.
    3845
    3946= 1.1 =
  • winter-snow-effect/trunk/winter-snow-effect.php

    r3431295 r3446520  
    33Plugin Name: Winter Snow Effect
    44Description: Automatically adds a falling snow effect to your website only during winter months (December, January, February).
    5 Version: 1.1
     5Version: 1.2.2
    66Author: Sarangan Thillaiampalam
    77Author URI: https://sarangan.dk
     
    1313}
    1414
    15 /**
    16  * Check if the current month is a winter month (Dec, Jan, Feb).
    17  *
    18  * @return bool True if winter, false otherwise.
    19  */
    20 function wse_is_winter() {
    21     $current_month = (int) gmdate( 'n' );
    22     // 12 = December, 1 = January, 2 = February
    23     return in_array( $current_month, array( 12, 1, 2 ), true );
     15class WinterSnowEffect {
     16
     17    private $options;
     18
     19    public function __construct() {
     20        add_action( 'admin_menu', array( $this, 'add_plugin_page' ) );
     21        add_action( 'admin_init', array( $this, 'page_init' ) );
     22        add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
     23
     24        // Add settings link on the plugins page
     25        $plugin_basename = plugin_basename( __FILE__ );
     26        add_filter( "plugin_action_links_{$plugin_basename}", array( $this, 'add_settings_link' ) );
     27    }
     28
     29    /**
     30     * Add options page
     31     */
     32    public function add_plugin_page() {
     33        add_options_page(
     34            'Settings Admin',
     35            'Winter Snow',
     36            'manage_options',
     37            'wse-setting-admin',
     38            array( $this, 'create_admin_page' )
     39        );
     40    }
     41
     42    /**
     43     * Options page callback
     44     */
     45    public function create_admin_page() {
     46        $this->options = get_option( 'wse_settings' );
     47        ?>
     48        <div class="wrap">
     49            <h1>Winter Snow Effect Settings</h1>
     50            <form method="post" action="options.php">
     51            <?php
     52                settings_fields( 'wse_option_group' );
     53                do_settings_sections( 'wse-setting-admin' );
     54                submit_button();
     55            ?>
     56            </form>
     57        </div>
     58        <?php
     59    }
     60
     61    /**
     62     * Register and add settings
     63     */
     64    public function page_init() {
     65        register_setting(
     66            'wse_option_group',
     67            'wse_settings',
     68            array( $this, 'sanitize' )
     69        );
     70
     71        add_settings_section(
     72            'setting_section_id',
     73            'General Settings',
     74            array( $this, 'print_section_info' ),
     75            'wse-setting-admin'
     76        );
     77
     78        add_settings_field(
     79            'display_mode',
     80            'Display Mode',
     81            array( $this, 'display_mode_callback' ),
     82            'wse-setting-admin',
     83            'setting_section_id'
     84        );
     85
     86        add_settings_field(
     87            'months',
     88            'Active Months (Standard Mode)',
     89            array( $this, 'months_callback' ),
     90            'wse-setting-admin',
     91            'setting_section_id'
     92        );
     93
     94        add_settings_field(
     95            'custom_range',
     96            'Custom Date Range',
     97            array( $this, 'custom_range_callback' ),
     98            'wse-setting-admin',
     99            'setting_section_id'
     100        );
     101
     102        add_settings_field(
     103            'flake_count',
     104            'Flake Count',
     105            array( $this, 'flake_count_callback' ),
     106            'wse-setting-admin',
     107            'setting_section_id'
     108        );
     109
     110        add_settings_field(
     111            'flake_speed',
     112            'Min/Max Speed',
     113            array( $this, 'flake_speed_callback' ),
     114            'wse-setting-admin',
     115            'setting_section_id'
     116        );
     117    }
     118
     119    /**
     120     * Sanitize each setting field as needed
     121     */
     122    public function sanitize( $input ) {
     123        $new_input = array();
     124       
     125        $new_input['display_mode'] = isset( $input['display_mode'] ) ? sanitize_text_field( $input['display_mode'] ) : 'standard';
     126
     127        if ( isset( $input['months'] ) && is_array( $input['months'] ) ) {
     128            $new_input['months'] = array_map( 'intval', $input['months'] );
     129        } else {
     130            $new_input['months'] = array();
     131        }
     132
     133        $new_input['start_date'] = isset( $input['start_date'] ) ? sanitize_text_field( $input['start_date'] ) : '';
     134        $new_input['end_date']   = isset( $input['end_date'] ) ? sanitize_text_field( $input['end_date'] ) : '';
     135
     136        $new_input['flake_count'] = isset( $input['flake_count'] ) ? absint( $input['flake_count'] ) : 35;
     137       
     138        // Handle decimal commas (common in many locales) by converting to dots
     139        $min_raw = isset( $input['min_speed'] ) ? str_replace( ',', '.', $input['min_speed'] ) : '0.5';
     140        $max_raw = isset( $input['max_speed'] ) ? str_replace( ',', '.', $input['max_speed'] ) : '1.5';
     141       
     142        $new_input['min_speed'] = floatval( $min_raw );
     143        $new_input['max_speed'] = floatval( $max_raw );
     144
     145        // Ensure max is not less than min
     146        if ( $new_input['max_speed'] < $new_input['min_speed'] ) {
     147            $new_input['max_speed'] = $new_input['min_speed'] + 1.0;
     148        }
     149
     150        return $new_input;
     151    }
     152
     153    public function print_section_info() {
     154        print 'Configure when and how the snow effect appears on your site.';
     155    }
     156
     157    public function display_mode_callback() {
     158        $options = get_option( 'wse_settings' );
     159        $mode    = isset( $options['display_mode'] ) ? $options['display_mode'] : 'standard';
     160        ?>
     161        <select id="display_mode" name="wse_settings[display_mode]">
     162            <option value="standard" <?php selected( $mode, 'standard' ); ?>>Standard (Selected Months)</option>
     163            <option value="custom" <?php selected( $mode, 'custom' ); ?>>Custom Date Range</option>
     164        </select>
     165        <?php
     166    }
     167
     168    public function months_callback() {
     169        $options      = get_option( 'wse_settings' );
     170        $saved_months = isset( $options['months'] ) ? (array) $options['months'] : array( 12, 1, 2 );
     171        $months       = array(
     172            1 => 'January', 2 => 'February', 3 => 'March', 4 => 'April',
     173            5 => 'May', 6 => 'June', 7 => 'July', 8 => 'August',
     174            9 => 'September', 10 => 'October', 11 => 'November', 12 => 'December'
     175        );
     176
     177        foreach ( $months as $num => $name ) {
     178            printf(
     179                '<label style="margin-right: 15px;"><input type="checkbox" name="wse_settings[months][]" value="%s" %s /> %s</label>',
     180                $num,
     181                checked( in_array( $num, $saved_months ), true, false ),
     182                $name
     183            );
     184            if ( $num % 3 === 0 ) echo '<br/>';
     185        }
     186    }
     187
     188    public function custom_range_callback() {
     189        $options    = get_option( 'wse_settings' );
     190        $start_date = isset( $options['start_date'] ) ? $options['start_date'] : '';
     191        $end_date   = isset( $options['end_date'] ) ? $options['end_date'] : '';
     192        ?>
     193        <label>Start: <input type="date" name="wse_settings[start_date]" value="<?php echo esc_attr( $start_date ); ?>" /></label>
     194        <label style="margin-left: 20px;">End: <input type="date" name="wse_settings[end_date]" value="<?php echo esc_attr( $end_date ); ?>" /></label>
     195        <p class="description">Only used if Display Mode is set to "Custom Date Range".</p>
     196        <?php
     197    }
     198
     199    public function flake_count_callback() {
     200        $options = get_option( 'wse_settings' );
     201        $count   = isset( $options['flake_count'] ) ? $options['flake_count'] : 35;
     202        ?>
     203        <input type="number" name="wse_settings[flake_count]" value="<?php echo esc_attr( $count ); ?>" min="1" max="200" />
     204        <p class="description">Recommended: 20-50. High values may affect performance.</p>
     205        <?php
     206    }
     207
     208    public function flake_speed_callback() {
     209        $options   = get_option( 'wse_settings' );
     210        $min_speed = isset( $options['min_speed'] ) ? $options['min_speed'] : 0.5;
     211        $max_speed = isset( $options['max_speed'] ) ? $options['max_speed'] : 1.5;
     212        ?>
     213        Min: <input type="number" step="0.1" name="wse_settings[min_speed]" value="<?php echo esc_attr( $min_speed ); ?>" />
     214        Max: <input type="number" step="0.1" name="wse_settings[max_speed]" value="<?php echo esc_attr( $max_speed ); ?>" />
     215        <?php
     216    }
     217
     218    /**
     219     * Check if snow should be shown based on settings
     220     */
     221    public function should_show_snow() {
     222        $options = get_option( 'wse_settings' );
     223       
     224        // Ensure options is an array for safe index access
     225        if ( ! is_array( $options ) ) {
     226            $options = array();
     227        }
     228
     229        $mode = isset( $options['display_mode'] ) ? $options['display_mode'] : 'standard';
     230
     231        if ( $mode === 'custom' ) {
     232            $start = isset( $options['start_date'] ) ? $options['start_date'] : '';
     233            $end   = isset( $options['end_date'] ) ? $options['end_date'] : '';
     234
     235            if ( empty( $start ) || empty( $end ) ) {
     236                return false;
     237            }
     238
     239            // Use site local time for comparison if possible, otherwise gmdate
     240            $today = current_time( 'Y-m-d' );
     241            return ( $today >= $start && $today <= $end );
     242        } else {
     243            // Standard mode: check current month
     244            $current_month = (int) current_time( 'n' );
     245            $saved_months  = isset( $options['months'] ) ? (array) $options['months'] : array( 12, 1, 2 );
     246           
     247            // If saved_months is set but empty (user unchecked all), snow won't show.
     248            // However, if the key is missing (fresh install), it uses the fallback.
     249            return in_array( $current_month, $saved_months );
     250        }
     251    }
     252
     253    /**
     254     * Enqueue scripts and styles
     255     */
     256    public function enqueue_scripts() {
     257        if ( $this->should_show_snow() ) {
     258            $options = get_option( 'wse_settings' );
     259            if ( ! is_array( $options ) ) {
     260                $options = array();
     261            }
     262           
     263            wp_enqueue_style( 'wse-snow-style', plugin_dir_url( __FILE__ ) . 'assets/css/snow.css', array(), '1.2.1' );
     264            wp_enqueue_script( 'wse-snow-script', plugin_dir_url( __FILE__ ) . 'assets/js/snow.js', array(), '1.2.1', true );
     265
     266            // Pass settings to JS
     267            wp_localize_script( 'wse-snow-script', 'wse_settings', array(
     268                'flakeCount' => isset( $options['flake_count'] ) ? (int) $options['flake_count'] : 35,
     269                'minSpeed'   => isset( $options['min_speed'] ) ? (float) $options['min_speed'] : 0.5,
     270                'maxSpeed'   => isset( $options['max_speed'] ) ? (float) $options['max_speed'] : 1.5,
     271            ) );
     272        }
     273    }
     274    /**
     275     * Add settings link to the plugins page
     276     */
     277    public function add_settings_link( $links ) {
     278        $settings_link = '<a href="options-general.php?page=wse-setting-admin">' . __( 'Settings' ) . '</a>';
     279        array_unshift( $links, $settings_link );
     280        return $links;
     281    }
    24282}
    25283
    26 /**
    27  * Enqueue scripts and styles only if it is winter.
    28  */
    29 function wse_enqueue_scripts() {
    30     if ( wse_is_winter() ) {
    31         wp_enqueue_style( 'wse-snow-style', plugin_dir_url( __FILE__ ) . 'assets/css/snow.css', array(), '1.1' );
    32         wp_enqueue_script( 'wse-snow-script', plugin_dir_url( __FILE__ ) . 'assets/js/snow.js', array(), '1.1', true );
    33     }
    34 }
    35 add_action( 'wp_enqueue_scripts', 'wse_enqueue_scripts' );
     284new WinterSnowEffect();
Note: See TracChangeset for help on using the changeset viewer.