1

I'm building a custom plugin that's just a basic event countdown timer. You can input a date and time to countdown to, then paste the shortcode into a page in your website to display how many days, hours, minutes, and seconds until the event. I'm using PHP to generate the form and JavaScript to pull the data from the form to render it to the page. I set up a "preview" section in the settings to make sure the countdown is correct, data persists, etc. It works great (see screenshot #1)!

enter image description here

However, when I use my shortcode [mbc_countdown_clock] on an external page, it doesn't pull the event date data into the divs that the shortcode generates. I have made sure the shortcode is generating the HTML properly as well by adding text in the divs and it is visible. When I check the console on the page the shortcode is running on, I see this:

enter image description here

In the 2nd red box, the numbers on the left count up in one-second intervals, so something is working, but I can't figure out why it can't display the property(s) of 'value' on the non-settings page. I have my one PHP file for my plugin and two Js files: one for the countdown clock, the other for the date picker on my settings page (I'm not including that one in this post right now).

I've tried looking it up, but I can't find a good resource that has helped so far. Any thoughts?

PHP code:

register_activation_hook( __FILE__, 'mbc-countdown-clock' );
register_deactivation_hook( __FILE__, 'mbc-countdown-clock' );

wp_enqueue_script('moment_js', plugin_dir_url( __FILE__ ) .'/moment.js', array(), null, true);
wp_enqueue_script('cdc-picker', plugin_dir_url( __FILE__ ) .'/mbc_datepicker.js', array(), null, true);
wp_enqueue_script('cdc-settings', plugin_dir_url( __FILE__ ) .'/mbc_cdc_settings.js', array(), null, true);

wp_enqueue_style('cdc-css', plugin_dir_url( __FILE__ )  .'/mbc_datepicker.css', false, 1.1,  'all');


function addMenu(){
add_menu_page('Countdown Clock', 'Countdown Clock', 4, 'countdown-clock', 
'countdownMenu');
}
add_action('admin_menu', 'addMenu');


if (is_admin ()) {
add_action('adminMenu', 'add_myMenu');
add_action('admin_init', 'register_mySettings');
}

function register_mySettings(){
add_option('mbccdc_datepicker', 'Date Picker');
add_option('mbccdc_timepicker', 'Time  Picker');
register_setting('mbccdc', 'cdc_datepicker');
register_setting('mbccdc', 'cdc_timepicker');
}

function countdownMenu(){
?>
<div id="mbc-countdown-dash">
    <div class="mbc-cdc-header">
        <h1>Timer Settings</h1>
    </div>

    <div class="mbc-cdc-display">
        <form method="post" action="options.php">
        <?php settings_fields('mbccdc');
              do_settings_sections('mbccdc');?>

            <p>Countdown To Date:<input type="text" name="cdc_datepicker" 
class="datepicker" id="mbc-cdc-date" value="<?php echo esc_attr( get_option( 
'cdc_datepicker' ) ); ?>"></p>

            <p>Countdown To Time:<input type="time" step="1" 
name="cdc_timepicker" id="mbc-cdc-timepicker" value="<?php echo esc_attr( 
get_option( 'cdc_timepicker' ) ); ?>"></p>

           <input type="submit" value="Save Changes" id="mbccdc-submit" />

        </form>

        <div class="mbc-cdc-clock-preview">
            <div><span id="mbc-cdc-preview-days">  </span></div>
            <div><span id="mbc-cdc-preview-hours">  </span></div>
            <div><span id="mbc-cdc-preview-minutes">  </span></div>
            <div><span id="mbc-cdc-preview-seconds">  </span></div>
        </div>
    </div>

    </div>

<?php
}
function mbc_cdc_shortcode() {
    ?>
    <div class="mbc-cdc-clock-onpage">
        <div><span id="mbc-cdc-onpage-days">  H</span></div>
        <div><span id="mbc-cdc-onpage-hours">  E</span></div>
        <div><span id="mbc-cdc-onpage-minutes">  LL</span></div>
        <div><span id="mbc-cdc-onpage-seconds">  O</span></div>
    </div>
    </div>

    <?php
}

add_shortcode( 'mbc_countdown_clock', 'mbc_cdc_shortcode');

JS mbc_cdc_settings file:

console.log('mbc_cdc_settings.js is working!');


function mbcTimer(){


    //EVENT DATE AND TIME
    const eventDate = document.getElementById('mbc-cdc-date').value;
    const eventTime = document.getElementById('mbc-cdc-timepicker').value;
    const concatEvent = new Date (eventDate + ' ' + eventTime).getTime();
    const today = new Date().getTime();

    const distance = concatEvent - today;

    const days = Math.floor (distance / (1000 * 60 * 60 * 24));
    const hours = Math.floor ((distance % (1000 * 60 * 60 *24)) / (1000 * 60 * 60));
    const minutes = Math.floor ((distance % (1000 * 60 * 60)) / (1000 * 60));
    const seconds = Math.floor ((distance % (1000 * 60)) / 1000);

//PREVIEW
    document.getElementById('mbc-cdc-preview-days').innerHTML = "<h3> Days: </h3>" + "<p>" + days + "</p>";
    document.getElementById('mbc-cdc-preview-hours').innerHTML = "<h3> Hours: </h3>" + "<p>" + hours + "</p>";
    document.getElementById('mbc-cdc-preview-minutes').innerHTML = "<h3> Minutes: </h3>" + "<p>" + minutes + "</p>";
    document.getElementById('mbc-cdc-preview-seconds').innerHTML = "<h3> Seconds: </h3>" + "<p>" + seconds + "</p>";

//PAGE RENDER
    document.getElementById('mbc-cdc-onpage-days').innerHTML = "<h3> Days: </h3>" + "<p>" + days + "</p>";
    document.getElementById('mbc-cdc-onpage-hours').innerHTML = "<h3> Hours: </h3>" + "<p>" + hours + "</p>";
    document.getElementById('mbc-cdc-onpage-minutes').innerHTML = "<h3> Minutes: </h3>" + "<p>" + minutes + "</p>";
    document.getElementById('mbc-cdc-onpage-seconds').innerHTML = "<h3> Seconds: </h3>" + "<p>" + seconds + "</p>";

    if (distance < 0){
    clearInterval(x);
    document.getElementById('mbc-cdc-preview-days').innerHTML = '0';
    document.getElementById('mbc-cdc-preview-hours').innerHTML = '0';
    document.getElementById('mbc-cdc-preview-minutes').innerHTML = '0';
    document.getElementById('mbc-cdc-preview-seconds').innerHTML = '0';
    document.getElementById('mbc-cdc-onpage-days').innerHTML = '0';
    document.getElementById('mbc-cdc-onpage-hours').innerHTML = '0';
    document.getElementById('mbc-cdc-onpage-minutes').innerHTML = '0';
    document.getElementById('mbc-cdc-onpage-seconds').innerHTML = '0';
}


}

timer = setInterval(mbcTimer, 1000);

Thanks in advance!

1

The error you're seeing in JS is due to those elements not existing, thus the cannot read property value of null

You're JS is using the HTML element output only in the countdownMenu function that is only called when on that specific menu page.

You need to output the value, even if in a hidden div, for your JS to work correctly:

function mbc_cdc_shortcode() {

    ?>
    <div class="mbc-cdc-clock-onpage">
        <input type="hidden" id="mbc-cdc-date" value="<?php echo esc_attr( get_option( 'cdc_datepicker' ) ); ?>">
        <input type="hidden" id="mbc-cdc-timepicker" value="<?php echo esc_attr( get_option( 'cdc_timepicker' ) ); ?>">
        <div><span id="mbc-cdc-onpage-days">  H</span></div>
        <div><span id="mbc-cdc-onpage-hours">  E</span></div>
        <div><span id="mbc-cdc-onpage-minutes">  LL</span></div>
        <div><span id="mbc-cdc-onpage-seconds">  O</span></div>
    </div>  </div>

    <?php
}

You should also put your JS code inside something that will only execute it once the DOM is loaded and ready (think that may be reason for null errors):

document.addEventListener("DOMContentLoaded", function(event) {
    // DOM is ready and loaded
});

Or if using jQuery there's a few way to do this:

jQuery(document).ready(function() {
    // DOM ready
});

Which is the same as

jQuery(function(){
    // DOM ready
});

If you want $ to be available since jQuery in WordPress noConflict (meaning $ is not set to jQuery object), you can use self invoking func passing jQuery object:

(function($){

    $(function(){
        //dom ready
    });

})(jQuery);
  • Thanks, sMyles! I did just that and it resolved my previous issue, however now my console is throwing an "Uncaught TypeError: Cannot read property 'value' of null" error that's pointing to this line and I'm not sure why: const eventDate = document.getElementById('mbc-cdc-date').value; – photogcoder Mar 8 '18 at 21:19
  • probably due to dom not ready yet, updated my response – sMyles Mar 8 '18 at 21:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.