skip to Main Content

I create function to get the date and turn it to countdown.
This my function code:

function countdown() {
    global $product;

    $start = get_post_meta( get_the_ID() , 'yung_product_date_start', true );
    $end = get_post_meta( get_the_ID() , 'yung_product_date_end', true );
    if ( $start && $end ) {
        $current = strtotime(date("Y/m/d"));
        $date = strtotime($start);
        $end_date = strtotime($end);
        if (( $date == $current || $current > $date ) && $current != $end_date && $end_date > $current) {
            wp_enqueue_script( "countdown", get_template_directory_uri() . '/assets/js/countdown.js', "1.0", true );
        
            wp_localize_script(
                "countdown",
                'countdown_js',
                array(
                    'to' => $end,
                    'from' => $start
                )
            );
            echo '<div id="product-countdown">
                <span id="countdown-counter"></span>
            </div>';
        } 
    }
}
add_action( 'woocommerce_before_add_to_cart_form', 'countdown' );

And this my javascript code which is in "countdown.js" file:

    jQuery(function($){
    "use strict";

    var from = countdown_js.from;
    var to = countdown_js.to;

    // Update the count down every 1 second
    var countDownDate = new Date(to).getTime();

    var x = setInterval(function() {

        // Get today's date and time
        var now = new Date().getTime();

        // Find the distance between now and the count down date
        var distance = countDownDate - now;

        // Time calculations for days, hours, minutes and seconds
        var days = Math.floor(distance / (1000 * 60 * 60 * 24));
        var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
        var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
        var seconds = Math.floor((distance % (1000 * 60)) / 1000);

        if ( days<10 ) {
            var days = '0' + days;
        }
        if ( hours<10 ) {
            var hours = '0' + hours;
        }
        if ( minutes<10 ) {
            var minutes = '0' + minutes;
        }
        if ( seconds<10 ) {
            var seconds = '0' + seconds;
        }

        if ( days == 0 ) {
            var days = '';
        } else {
            days += ' : '
        }

        $('#countdown-counter').each( function() {
            var html = days + hours + " : " + minutes + " : " + seconds;
            $(this).html(html);
        });

        if (distance < 0) {
            clearInterval(x);
            $('#product-countdown').css("display", "none");
        }
    }, 1000);
});

This code works on single product page, but when I try this in the product archive, it only works on the first product and does not work on the rest products. I want each product to have own countdown. What should I do please help me!

2

Answers


  1. Chosen as BEST ANSWER

    Thanks to pianka for helping me to figure out this problem. I finally edited these codes and it finally worked.

    function countdown() {
        global $product;
    
        $start = get_post_meta( get_the_ID() , 'yung_product_date_start', true );
        $end = get_post_meta( get_the_ID() , 'yung_product_date_end', true );
    
        if ( $start && $end ) {
            $current = strtotime(date("Y/m/d"));
            $date = strtotime($start);
            $end_date = strtotime($end);
            if (( $date == $current || $current > $date ) && $current != $end_date && $end_date > $current) {
                wp_enqueue_script( "countdown", get_template_directory_uri() . '/assets/js/countdown.js', "1.0", true );
                
                echo '<div class="product-countdown">
                    <span class="countdown-counter" countdown="'. $end .'"></span>
                </div>';
            } ?>
            <?php 
        }
    }
    add_action( 'woocommerce_before_add_to_cart_form', 'countdown' );
    

    and javascript code:

    jQuery(function($){
    "use strict";
    
        $('.countdown-counter').each( function() {
            var to = $(this).attr("countdown");
            var thisis = $(this);
            var parent = $(this).parent();
            var countDownDate = new Date(to).getTime();
    
            // Update the count down every 1 second
            var x = setInterval(function() {
                // Get today's date and time
                var now = new Date().getTime();
    
                // Find the distance between now and the count down date
                var distance = countDownDate - now;
    
                // Time calculations for days, hours, minutes and seconds
                var days = Math.floor(distance / (1000 * 60 * 60 * 24));
                var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
                var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
                var seconds = Math.floor((distance % (1000 * 60)) / 1000);
    
                if ( days<10 ) {
                    var days = '0' + days;
                }
                if ( hours<10 ) {
                    var hours = '0' + hours;
                }
                if ( minutes<10 ) {
                    var minutes = '0' + minutes;
                }
                if ( seconds<10 ) {
                    var seconds = '0' + seconds;
                }
    
                if ( days == 0 ) {
                    var days = '';
                } else {
                    days += ' : '
                }
    
                var html = days + hours + " : " + minutes + " : " + seconds;
                thisis.html(html);
    
                if (distance < 0) {
                    clearInterval(x);
                    parent.css("display", "none");
                }
            }, 1000);
            thisis.removeAttr("countdown");
        });
    });
    

  2. In HTML ids are supposed to be unique identifiers, therefore jQuery does not select all of them when you do $("#countdown-counter"). Technically, there are ways to select multiple elements with the same id in vanilla JS, but I don’t suggest it. What you want to do is use classes.

    So:

         echo '<div class="product-countdown">
               <span class="countdown-counter"></span>
            </div>';
    

    and

            $('.countdown-counter').each( function() {
                var html = days + hours + " : " + minutes + " : " + seconds;
                $(this).html(html);
            });
    

    EDIT:

    I’m now realizing how your source code is used and the fact that you are adding the countdown.js script multiple times on the same page* (not really, see note below), and you are passing the from and to variables via the countdown_js object. The second problem is the critical one: you are constantly overwriting countdown_js with the data from another product. This object is not "confined" in the product, but it’s at the page level.

    Let’s say you have product A and product B. You add a countdown to product A and this sets coundown_js.from = x, countdown_js.to = y. Then you add a countdown to product B and this sets coundown_js.from = z, countdown_js.to = w. This overrides x and y and when the page reaches the browser, both the countdown are initialized using the from and to attributes equal to z and w.

    This is why "it is the same value for all products!".

    The way I would fix this is to remove the countdown_js and use data attributes. The result would be:

            if (( $date == $current || $current > $date ) && $current != $end_date && $end_date > $current) {
                wp_enqueue_script( "countdown", get_template_directory_uri() . '/assets/js/countdown.js', "1.0$i", true );
    
                echo '<div class="product-countdown" data-to="'.$end.'" data-from="'.$start.'">
                    <span class="countdown-counter"></span>
                </div>';
            } 
    

    These attributes are now specific to the specific countdown "instance" and can be easily accessed with javascript:

    $('.product-countdown').dataset.from;
    $('.product-countdown').dataset.to;
    

    You definitely need to tweak your js code to make this work, also because the line $('#product-countdown').css("display", "none"); doesn’t work anymore with classes. The way I would approach this is to iterate over .product-countdown and access .countdown-counter from the parent.


    *The note below: with WordPress it’s not a problem if you enqueue a the same script multiple times, see https://wordpress.stackexchange.com/a/123549

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search