EDIT 7/11/2021: If you happened to implement this recipe in the first couple days after I posted it, there was a bug that I somehow missed but has now been fixed. Please make sure to replace your Shortcode Markup with the updated version below.

Description

This shortcode displays a block of content according to a schedule or schedule category, and displays a countdown timer instead when no schedules are live.

Credits

When the live video stream embedded on our site wasn't live it just displayed a big blank box where the video would be. I wanted to show a countdown timer instead, so I searched for a recipe and found Countdown to Next Online Service by DJ Grick. We're not using ChOP, so I modified DJ's code to use a Rock schedule instead.

…and of course that's when I found Countdown to next Online Service by Randy Aufrecht, which did basically the same thing that I just did. So, I updated my code with some improvements from Randy's recipe, and turned it into a shortcode so it can be used with any arbitrary content and schedule(s) you want.

If my recipe helps you out, DJ and Randy deserve much of the credit.

Shortcode Details

Create a new Lava Shortcode with the following details:

  • Name: Content Countdown
  • Tag Name: contentcountdown
  • Tag Type: Block
  • Description: Displays a block of content according to a schedule or schedule category, and displays a countdown timer instead when no schedules are live.

Documentation:

<p><strong>Usage:</strong></p>
<pre>{[ contentcountdown scheduleid:'247' timerprompt:'Next Live Service Starts In:' startearly:'5' ]}<br>    [YOUR SCHEDULED CONTENT HERE]<br>{[ endcontentcountdown ]}
</pre>
<ul>
    <li><strong>scheduleid</strong> (integer, conditional) – The ID of the schedule to use for determining if the countdown timer or the content should be displayed. Required if <code>schedulecatid</code> is left blank.</li>
    <li><strong>schedulecategoryid</strong> (integer, conditional) – The ID of the schedule category to use for determining if the countdown timer or the content should be displayed. Required if <code>schedulecategoryid</code> is left blank.</li>
    <li><strong>startearly</strong> (integer, optional, default:<code>0</code>) – The number of minutes before the scheduled start time that the content should become available</li>
    <li><strong>timerprompt</strong> (integer, optional, default:<code>Starting in:</code>) – Text to be displayed when the schedule is not live. Set this value to an empty string to hide the prompt altogether.</li>
</ul>
<p>The <code>scheduleid</code> and <code>schedulecategoryid</code> settings are meant to be either or. If you provide a value for one you don't need to provide a value for the other.</p>
<p>Nothing is displayed in cases when a next occurrence can't be found.</p>

Shortcode Markup:

{%- assign scheduleid = scheduleid | Default:'0' | AsInteger -%}
{%- assign schedulecategoryid = schedulecategoryid | Default:'0' | AsInteger -%}
{%- capture occurrence -%}
    {%- if schedulecategoryid != 0 -%}
        {[- scheduledcontent schedulecategoryid:'{{ schedulecategoryid }}' showwhen:'both' lookaheaddays:'365' ]}
            {
                "IsLive": {{ IsLive }},
                "ScheduleID": {{ Schedule.Id }},
                "ScheduleName": "{{ Schedule.Name }}",
                "NextOccurrence": "{{ NextOccurrenceDateTime | Date: 'MM/dd/yyyy HH:mm:ss' }}",
                "OccurrenceEnd": "{{ OccurrenceEndDateTime | Date: 'MM/dd/yyyy HH:mm:ss' }}"
            }
        {[ endscheduledcontent -]}
    {%- elseif scheduleid != 0 -%}
        {[- scheduledcontent scheduleid:'{{ scheduleid }}' showwhen:'both' lookaheaddays:'365' ]}
            {
                "IsLive": {{ IsLive }},
                "ScheduleID": {{ Schedule.Id }},
                "ScheduleName": "{{ Schedule.Name }}",
                "NextOccurrence": "{{ NextOccurrenceDateTime | Date: 'MM/dd/yyyy HH:mm:ss' }}",
                "OccurrenceEnd": "{{ OccurrenceEndDateTime | Date: 'MM/dd/yyyy HH:mm:ss' }}"
            }
        {[ endscheduledcontent -]}
    {%- endif -%}
{%- endcapture -%}
{%- assign occurrence = occurrence | FromJSON -%}
{%- if occurrence != empty -%}
    {%- assign today = 'Now' | Date -%}
    {%- assign startTime = occurrence.NextOccurrence | AsDateTime -%}
    {%- assign startearly = startearly | Default:'0' | AsInteger | Times:-1 -%}
    {%- assign earlyStartTime = startTime | DateAdd:startEarly,'m' -%}
    {%- if occurrence.IsLive == true or today >= earlyStartTime %}{% assign isLive = true %}{% else %}{% assign isLive = false %}{% endif -%}
<div class="content" data-is-live="{{ occurrence.IsLive }}" data-schedule-id="{{ occurrence.ScheduleID }}" data-schedule="{{ occurrence.ScheduleName }}" data-next-start="{{ startTime | Date:'MMM dd, yyyy HH:mm:ss'}}" data-end="{{ occurrence.OccurrenceEnd }}">
    {%- if isLive == true -%}
        {{ blockContent }}
    {%- elseif isLive == false -%}
        {%- assign seconds = today | DateDiff:startTime,'s' -%}
        {%- assign days = seconds | DividedBy:86400 | Floor -%}
        {%- assign hours = seconds | Modulo:86400 | DividedBy:3600 | Floor -%}
        {%- assign minutes = seconds | Modulo:3600 | DividedBy:60 | Floor -%}
        {%- assign seconds = seconds | Modulo:60 | Floor -%}
<div class="countdown" data-start="{{ startTime | Date:'MMM dd, yyyy HH:mm:ss'}}">
    <div class="countdown-wrap">
        {%- if timerprompt != '' -%}
        <div class="prompt">
            <h2>{{ timerprompt | Default:'Starting in:' }}</h2>
        </div>
        {%- endif -%}
        <div class="timer">
            <time class="row">
                <div class="col-xs-3">
                    <span class="value days">{{ days }}</span>
                    <span class="label">days</span>
                </div>
                <div class="col-xs-3">
                    <span class="value hours">{{ hours }}</span>
                    <span class="label">hours</span>
                </div>
                <div class="col-xs-3">
                    <span class="value minutes">{{ minutes }}</span>
                    <span class="label">min</span>
                </div>
                <div class="col-xs-3">
                    <span class="value seconds">{{ seconds }}</span>
                    <span class="label">sec</span>
                </div>
            </time>
        </div>
    </div>
</div>
        {%- stylesheet id:'countdown-timer-css' -%}
            .countdown
            {
                width: 100%;
                text-align: center;
            }
            .countdown-wrap>div 
            { 
                display: inline-block;
                margin: 20px 0;
                vertical-align: middle;
            }
            .countdown h2
            {
                margin: 0 1em 0 0;
                font-size: 36px;
                line-height: 1.4;
            }
            .countdown time { display: block; }
            .countdown time .value
            {
                display: block;
                min-width: 2em;
                font-size: 38px;
                font-weight: bold;
                line-height: 1;
                letter-spacing: 2px;
            }
            .countdown time .label
            {
                padding: 0;
                font-size: 16px;
                color: inherit;
            }
        {%- endstylesheet -%}
        {%- javascript id:'countdown-timer-js' disableanonymousfunction:'true' -%}
            $(document).ready(function()
            {
                $('.countdown').each(function()
                {
                    // get the timer and each time unit element
                    var $timer = $(this);
                    var $time = $timer.find('time');
                    var $days = $timer.find('.days');
                    var $hours = $timer.find('.hours');
                    var $min = $timer.find('.minutes');
                    var $sec = $timer.find('.seconds');
        
                    // Set the date we're counting down to
                    var startDate = new Date($timer.data('start')).getTime();
        
                    // Update the count down every 1 second
                    var x = setInterval(function()
                    {
                        // Get the current date and time
                        var now = new Date().getTime();
        
                        // Find the remaining time between now and the count down date
                        var remainingTime = startDate - now;
        
                        // Time calculations for days, hours, minutes and seconds
                        var days = Math.floor(remainingTime / (1000 * 60 * 60 * 24));
                        var hours = Math.floor((remainingTime % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
                        var minutes = Math.floor((remainingTime % (1000 * 60 * 60)) / (1000 * 60));
                        var seconds = Math.floor((remainingTime % (1000 * 60)) / 1000);
        
                        // Output the results
                        $days.text(days);
                        $hours.text(hours);
                        $min.text(minutes);
                        $sec.text(seconds);
        
                        // update the datetime attribute value
                        $time.attr('datetime', 'P' + days + 'D' + hours + 'H' + minutes + 'M' + seconds + 'S')
        
                        // If the count down is over, reload the page
                        if (remainingTime < 0)
                        {
                            clearInterval(x);
                            $timer.find('.countdown-wrap').text('Starting Now…');
                            location.reload();
                        }
                    }, 1000);
                });
            });
        {%- endjavascript -%}
    {%- endif -%}
    </div>
{%- endif -%}

Parameters:

  • scheduleid 0
  • schedulecategoryid 0
  • startearly 0
  • timerprompt Starting in:

Enabled Lava Commands:

No Lava commands required


Please leave a comment or hit me up on Rock Chat if you have questions or find any issues with this recipe. Thanks!