Skip to content

Instantly share code, notes, and snippets.

@digisavvy
Created January 15, 2026 14:41
Show Gist options
  • Select an option

  • Save digisavvy/66a0416843fbe7313c88edb60a61337a to your computer and use it in GitHub Desktop.

Select an option

Save digisavvy/66a0416843fbe7313c88edb60a61337a to your computer and use it in GitHub Desktop.
Coming Soon Countdown Timer - WordPress mu-plugin with configurable data attributes for Etch WP patterns
<?php
/**
* Coming Soon Countdown Timer Script
* Loads on pages/patterns with .coming-soon element
*/
add_action('wp_footer', function() {
if (is_admin()) return;
?>
<script>
/**
* Coming Soon Countdown Timer
*
* Configurable via data attributes on .coming-soon:
* - data-target-date: Target date in ISO format (e.g., "2025-03-01T00:00:00")
* - data-show-days: "true" or "false" (default: true)
* - data-show-hours: "true" or "false" (default: true)
* - data-show-minutes: "true" or "false" (default: true)
* - data-show-seconds: "true" or "false" (default: true)
* - data-expired-message: Message when countdown ends (default: "We're Live!")
*/
(function() {
const section = document.querySelector('.coming-soon');
if (!section) return;
// Check if in editor
const isEditor = section.closest('.etch-builder-block') ||
section.closest('.block-editor-block-list__block') ||
document.body.classList.contains('wp-admin');
// Get configuration from data attributes
const config = {
targetDate: section.dataset.targetDate || '2025-12-31T00:00:00',
showDays: section.dataset.showDays !== 'false',
showHours: section.dataset.showHours !== 'false',
showMinutes: section.dataset.showMinutes !== 'false',
showSeconds: section.dataset.showSeconds !== 'false',
expiredMessage: section.dataset.expiredMessage || "We're Live!"
};
// Get countdown elements
const countdown = section.querySelector('.coming-soon__countdown');
const daysUnit = section.querySelector('[data-unit="days"]');
const hoursUnit = section.querySelector('[data-unit="hours"]');
const minutesUnit = section.querySelector('[data-unit="minutes"]');
const secondsUnit = section.querySelector('[data-unit="seconds"]');
const daysValue = section.querySelector('[data-countdown="days"]');
const hoursValue = section.querySelector('[data-countdown="hours"]');
const minutesValue = section.querySelector('[data-countdown="minutes"]');
const secondsValue = section.querySelector('[data-countdown="seconds"]');
// Hide units based on config
if (!config.showDays && daysUnit) daysUnit.style.display = 'none';
if (!config.showHours && hoursUnit) hoursUnit.style.display = 'none';
if (!config.showMinutes && minutesUnit) minutesUnit.style.display = 'none';
if (!config.showSeconds && secondsUnit) secondsUnit.style.display = 'none';
// Update countdown function
function updateCountdown() {
const now = new Date().getTime();
const target = new Date(config.targetDate).getTime();
const diff = target - now;
if (diff <= 0) {
// Countdown expired
if (countdown) {
countdown.innerHTML = '<p style="font-size: var(--h2, 2rem); font-weight: 700; color: var(--primary, #7c3aed);">' + config.expiredMessage + '</p>';
}
return false;
}
// Calculate time units
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((diff % (1000 * 60)) / 1000);
// Update display
if (daysValue) daysValue.textContent = String(days).padStart(2, '0');
if (hoursValue) hoursValue.textContent = String(hours).padStart(2, '0');
if (minutesValue) minutesValue.textContent = String(minutes).padStart(2, '0');
if (secondsValue) secondsValue.textContent = String(seconds).padStart(2, '0');
return true;
}
// Initial update
updateCountdown();
// Don't run interval in editor
if (!isEditor) {
const interval = setInterval(function() {
if (!updateCountdown()) {
clearInterval(interval);
}
}, 1000);
}
})();
</script>
<?php
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment