<?php
/**
* Template Name: ArtKey Holiday Page
* Description: Standalone holiday page with form handler
*
* IMPORTANT: This file must be uploaded to your WordPress theme directory:
* /wp-content/themes/[your-active-theme]/artkey-holiday-page.php
*
* Then create a new WordPress page and select this template from Page Attributes.
* DO NOT paste any PHP code in the WordPress page content editor.
*/
// This is a WordPress template - ABSPATH will be defined when loaded by WordPress
// Handle form submission if POST request
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['artkey_submit'])) {
header('Content-Type: application/json');
$name = isset($_POST['name']) ? strip_tags(trim($_POST['name'])) : '';
$email = isset($_POST['email']) ? filter_var(trim($_POST['email']), FILTER_SANITIZE_EMAIL) : '';
$message = isset($_POST['message']) ? strip_tags(trim($_POST['message'])) : '';
if (empty($name) || empty($email) || empty($message)) {
echo json_encode(['success' => false, 'message' => 'All fields are required']);
exit;
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo json_encode(['success' => false, 'message' => 'Invalid email address']);
exit;
}
$to = 'bcolman@eiag.com';
$subject = 'New ArtKey Message from ' . $name;
$body = "You've received a new message from your ArtKey!\n\n";
$body .= "From: " . $name . "\n";
$body .= "Email: " . $email . "\n\n";
$body .= "Message:\n" . $message . "\n\n";
$body .= "---\n";
$body .= "Sent: " . date('F j, Y, g:i a') . "\n";
$body .= "IP Address: " . $_SERVER['REMOTE_ADDR'];
$headers = "Content-Type: text/plain; charset=UTF-8\r\n";
$headers .= "From: ArtKey <noreply@" . $_SERVER['HTTP_HOST'] . ">\r\n";
$headers .= "Reply-To: " . $name . " <" . $email . ">";
$sent = mail($to, $subject, $body, $headers);
if ($sent) {
echo json_encode(['success' => true, 'message' => 'Message sent successfully']);
} else {
echo json_encode(['success' => false, 'message' => 'Failed to send message']);
}
exit;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<!-- NO INDEX / NO FOLLOW -->
<meta name="robots" content="noindex, nofollow">
<meta name="googlebot" content="noindex, nofollow">
<!-- PWA / App-like -->
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="theme-color" content="#00427e">
<title>Happy Holidays - Bryant & Torrie</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
html, body {
min-height: 100%;
width: 100%;
overflow-x: hidden;
overflow-y: auto;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
body {
background: #F3F3F3;
}
.app-container {
min-height: 100vh;
width: 100%;
display: flex;
flex-direction: column;
-webkit-overflow-scrolling: touch;
}
.safe-area-top {
height: env(safe-area-inset-top);
background: #F3F3F3;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px;
background: #F3F3F3;
width: 100%;
box-sizing: border-box;
}
.admin-btn {
background: #666;
border: 2px solid #666;
color: #ffffff;
padding: 8px 16px;
border-radius: 20px;
font-size: clamp(12px, 2vw, 14px);
font-weight: 600;
text-decoration: none;
transition: all 0.3s;
white-space: nowrap;
}
.admin-btn:hover,
.admin-btn:active {
transform: scale(0.95);
opacity: 0.8;
background: #555;
border-color: #555;
}
.header-buttons {
display: flex;
gap: 10px;
align-items: center;
}
.linktree-btn {
background: #00427e;
border: 2px solid #00427e;
color: #ffffff;
padding: 8px 16px;
border-radius: 20px;
font-size: clamp(12px, 2vw, 14px);
font-weight: 600;
text-decoration: none;
transition: all 0.3s;
white-space: nowrap;
}
.linktree-btn:active {
transform: scale(0.95);
opacity: 0.8;
}
.content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
width: 100%;
max-width: 100%;
margin: 0;
padding: 20px 20px 40px 20px;
box-sizing: border-box;
}
.title {
color: #00427e;
text-align: center;
font-size: clamp(2rem, 8vw, 3rem);
font-weight: 300;
margin-bottom: 40px;
letter-spacing: 2px;
width: 100%;
max-width: 100%;
}
.buttons {
display: flex;
flex-direction: column;
gap: 16px;
width: 100%;
max-width: 600px;
margin: 0 auto;
padding-bottom: 20px;
}
.btn {
background: #00427e;
color: #ffffff;
padding: 20px 24px;
border-radius: 50px;
font-size: clamp(1rem, 2.5vw, 1.1rem);
font-weight: 600;
text-align: center;
border: none;
cursor: pointer;
box-shadow: 0 4px 15px rgba(0, 66, 126, 0.3);
transition: all 0.3s;
width: 100%;
box-sizing: border-box;
}
.btn:active {
transform: scale(0.98);
opacity: 0.9;
}
.overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #000;
z-index: 1000;
display: none;
flex-direction: column;
}
.overlay.active {
display: flex;
}
.close-btn {
position: absolute;
top: calc(env(safe-area-inset-top) + 15px);
left: 20px;
background: #00427e;
border: 2px solid #00427e;
color: #ffffff;
padding: 10px 20px;
border-radius: 25px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
z-index: 1001;
}
.close-btn:active {
transform: scale(0.95);
opacity: 0.8;
}
.video-wrapper {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.video-wrapper video {
width: 100%;
height: 100%;
object-fit: contain;
}
.video-controls-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 20%, rgba(0, 0, 0, 0) 80%, rgba(0, 0, 0, 0.6) 100%);
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
display: flex;
flex-direction: column;
justify-content: flex-end;
padding: 20px;
}
.video-controls-overlay.show {
opacity: 1;
pointer-events: auto;
}
.video-controls {
display: flex;
flex-direction: column;
gap: 15px;
align-items: center;
}
.play-pause-btn {
width: 60px;
height: 60px;
background: rgba(255, 255, 255, 0.9);
border: none;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.play-pause-btn svg {
width: 24px;
height: 24px;
fill: #00427e;
}
.progress-bar-container {
width: 100%;
height: 4px;
background: rgba(255, 255, 255, 0.3);
border-radius: 2px;
cursor: pointer;
position: relative;
}
.progress-bar-fill {
height: 100%;
background: #ffffff;
border-radius: 2px;
width: 0%;
}
.time-display {
color: white;
font-size: 12px;
font-weight: 500;
}
.tap-hint {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
background: rgba(0, 0, 0, 0.7);
padding: 15px 30px;
border-radius: 30px;
font-size: 14px;
pointer-events: none;
opacity: 0;
animation: fadeInOut 3s ease-in-out;
}
@keyframes fadeInOut {
0%, 100% { opacity: 0; }
10%, 90% { opacity: 1; }
}
.viewer {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 60px 20px 20px;
overflow: auto;
touch-action: pan-x pan-y pinch-zoom;
}
.viewer iframe {
width: 100%;
height: 100%;
border: none;
background: white;
border-radius: 10px;
}
.viewer img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
transition: transform 0.3s;
cursor: zoom-in;
}
.viewer img.zoomed {
cursor: zoom-out;
}
.zoom-controls {
position: absolute;
bottom: 80px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
opacity: 0;
transition: opacity 0.3s;
z-index: 100;
}
.overlay.active .zoom-controls {
opacity: 1;
}
.zoom-btn {
background: rgba(0, 66, 126, 0.9);
color: white;
border: none;
padding: 10px 15px;
border-radius: 20px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
}
.zoom-btn:active {
transform: scale(0.95);
}
.form-overlay {
background: #F3F3F3;
overflow-y: auto;
}
.form-content {
padding: 80px 20px 40px;
max-width: 500px;
margin: 0 auto;
}
.form-title {
color: #00427e;
font-size: 2rem;
font-weight: 300;
text-align: center;
margin-bottom: 10px;
}
.form-subtitle {
color: #00427e;
text-align: center;
margin-bottom: 30px;
}
.form-card {
background: #ffffff;
border: 2px solid #e0e0e0;
border-radius: 30px;
padding: 30px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
color: #333;
font-weight: 600;
margin-bottom: 8px;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 15px;
border: 2px solid #e0e0e0;
border-radius: 15px;
font-size: 16px;
font-family: inherit;
}
.form-group input:focus,
.form-group textarea:focus {
outline: none;
border-color: #00427e;
box-shadow: 0 0 0 3px rgba(0, 66, 126, 0.1);
}
.form-group textarea {
min-height: 120px;
resize: vertical;
}
.submit-btn {
width: 100%;
background: #00427e;
color: #ffffff;
border: none;
padding: 16px;
border-radius: 25px;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
box-shadow: 0 4px 15px rgba(0, 66, 126, 0.3);
}
.submit-btn:active {
transform: scale(0.98);
opacity: 0.9;
}
.submit-btn:disabled {
opacity: 0.6;
}
.success-message {
display: none;
background: #4caf50;
color: white;
padding: 15px;
border-radius: 15px;
margin-bottom: 20px;
text-align: center;
}
.success-message.show {
display: block;
}
.error-message {
display: none;
background: #f44336;
color: white;
padding: 15px;
border-radius: 15px;
margin-bottom: 20px;
text-align: center;
}
.error-message.show {
display: block;
}
@media (max-width: 480px) {
.content {
padding: 15px 15px 30px 15px;
}
.btn {
padding: 18px 20px;
}
.title {
font-size: clamp(1.75rem, 7vw, 2.5rem);
margin-bottom: 30px;
}
.buttons {
padding-bottom: 30px;
}
}
@media (min-width: 768px) {
.content {
padding: 40px;
}
.buttons {
max-width: 700px;
}
.btn {
padding: 22px 28px;
}
}
@media (min-width: 1024px) {
.content {
padding: 60px;
}
.buttons {
max-width: 800px;
}
}
</style>
</head>
<body>
<div class="safe-area-top"></div>
<div class="app-container" id="mainPage">
<div class="header">
<?php if (current_user_can('manage_options')): ?>
<a href="<?php echo admin_url(); ?>" class="admin-btn">Admin</a>
<?php endif; ?>
<div class="header-buttons">
<a href="https://linktr.ee/theartfulexperience" class="linktree-btn" target="_blank">ArtKey →</a>
</div>
</div>
<div class="content">
<h1 class="title">Happy Holidays</h1>
<div class="buttons">
<button class="btn" onclick="openVideo()">
Greetings From Bryant & Torrie
</button>
<button class="btn" onclick="openPDF()">
2025 Year In Review
</button>
<button class="btn" onclick="openFavorites()">
Favorites of 2025
</button>
<button class="btn" onclick="openExperience()">
The Artful Experience
</button>
<button class="btn" onclick="openMessage()">
Leave Us A Message
</button>
</div>
</div>
</div>
<div class="overlay" id="videoOverlay">
<button class="close-btn" onclick="closeOverlay('videoOverlay')">← Back</button>
<div class="video-wrapper" id="videoWrapper">
<video id="holidayVideo" playsinline preload="auto">
<source src="https://wp.theartfulexperience.com/wp-content/uploads/2025/12/Holiday-Message-Trim-1.mp4" type="video/mp4">
</video>
<div class="tap-hint" id="tapHint">Tap to show controls</div>
<div class="video-controls-overlay" id="videoControlsOverlay">
<div class="video-controls">
<div class="time-display" id="timeDisplay">0:00 / 0:00</div>
<div class="progress-bar-container" id="progressBarContainer">
<div class="progress-bar-fill" id="progressBarFill"></div>
</div>
<button class="play-pause-btn" id="playPauseBtn">
<svg id="playIcon" viewBox="0 0 24 24">
<path d="M8 5v14l11-7z"/>
</svg>
<svg id="pauseIcon" viewBox="0 0 24 24" style="display:none;">
<path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z"/>
</svg>
</button>
</div>
</div>
</div>
</div>
<div class="overlay" id="pdfOverlay">
<button class="close-btn" onclick="closeOverlay('pdfOverlay')">← Back</button>
<div class="viewer">
<iframe id="pdfFrame" src=""></iframe>
</div>
</div>
<div class="overlay" id="favoritesOverlay">
<button class="close-btn" onclick="closeOverlay('favoritesOverlay')">← Back</button>
<div class="viewer">
<iframe id="favoritesFrame" src=""></iframe>
</div>
</div>
<div class="overlay" id="experienceOverlay">
<button class="close-btn" onclick="closeOverlay('experienceOverlay')">← Back</button>
<div class="viewer">
<img id="experienceImg" src="https://wp.theartfulexperience.com/wp-content/uploads/2025/12/BC-tAE-ArtKey.png" alt="The Artful Experience">
</div>
<div class="zoom-controls">
<button class="zoom-btn" onclick="zoomImage('experienceImg', 0.2)">Zoom In</button>
<button class="zoom-btn" onclick="zoomImage('experienceImg', -0.2)">Zoom Out</button>
<button class="zoom-btn" onclick="resetZoom('experienceImg')">Reset</button>
</div>
</div>
<div class="overlay form-overlay" id="messageOverlay">
<button class="close-btn" onclick="closeOverlay('messageOverlay')">← Back</button>
<div class="form-content">
<h2 class="form-title">Leave a Message</h2>
<p class="form-subtitle">Share your thoughts with Bryant & Torrie</p>
<div class="form-card">
<div class="success-message" id="successMessage">
Thank you! Your message has been sent. 🎉
</div>
<div class="error-message" id="errorMessage">
There was an error. Please try again.
</div>
<form id="messageForm">
<input type="hidden" name="artkey_submit" value="1">
<div class="form-group">
<label for="name">Your Name *</label>
<input type="text" id="name" name="name" required placeholder="Enter your name">
</div>
<div class="form-group">
<label for="email">Your Email *</label>
<input type="email" id="email" name="email" required placeholder="Enter your email">
</div>
<div class="form-group">
<label for="message">Your Message *</label>
<textarea id="message" name="message" required placeholder="Write your message here..."></textarea>
</div>
<button type="submit" class="submit-btn" id="submitBtn">
Send Message
</button>
</form>
</div>
</div>
</div>
<script>
let hideControlsTimeout;
let videoPlaying = false;
let imageScales = {};
function openVideo() {
document.getElementById('videoOverlay').classList.add('active');
const video = document.getElementById('holidayVideo');
video.play();
setTimeout(() => {
const hint = document.getElementById('tapHint');
if (hint) hint.style.animation = 'fadeInOut 3s ease-in-out';
}, 500);
}
function openPDF() {
const pdfUrl = 'https://wp.theartfulexperience.com/wp-content/uploads/2025/12/Red-Aesthetic-Traveling-Gallery-Moodboard-Photo-Collage-Instagram-Post.pdf';
const isAndroid = /Android/.test(navigator.userAgent);
if (isAndroid) {
document.getElementById('pdfFrame').src = `https://docs.google.com/viewer?url=${encodeURIComponent(pdfUrl)}&embedded=true`;
} else {
document.getElementById('pdfFrame').src = pdfUrl + '#toolbar=1&navpanes=0&scrollbar=1';
}
document.getElementById('pdfOverlay').classList.add('active');
}
function openFavorites() {
const favPdfUrl = 'https://wp.theartfulexperience.com/wp-content/uploads/2025/12/Bryant-Torries-Favs.png';
const isAndroid = /Android/.test(navigator.userAgent);
if (isAndroid) {
document.getElementById('favoritesFrame').src = `https://docs.google.com/viewer?url=${encodeURIComponent(favPdfUrl)}&embedded=true`;
} else {
document.getElementById('favoritesFrame').src = favPdfUrl;
}
document.getElementById('favoritesOverlay').classList.add('active');
}
function openExperience() {
document.getElementById('experienceOverlay').classList.add('active');
}
function openMessage() {
document.getElementById('messageOverlay').classList.add('active');
}
function closeOverlay(overlayId) {
document.getElementById(overlayId).classList.remove('active');
if (overlayId === 'videoOverlay') {
const video = document.getElementById('holidayVideo');
video.pause();
video.currentTime = 0;
hideVideoControls();
}
if (overlayId === 'pdfOverlay') document.getElementById('pdfFrame').src = '';
if (overlayId === 'favoritesOverlay') document.getElementById('favoritesFrame').src = '';
if (overlayId === 'experienceOverlay') resetZoom('experienceImg');
}
const video = document.getElementById('holidayVideo');
const videoWrapper = document.getElementById('videoWrapper');
const controlsOverlay = document.getElementById('videoControlsOverlay');
const playPauseBtn = document.getElementById('playPauseBtn');
const playIcon = document.getElementById('playIcon');
const pauseIcon = document.getElementById('pauseIcon');
const progressBarContainer = document.getElementById('progressBarContainer');
const progressBarFill = document.getElementById('progressBarFill');
const timeDisplay = document.getElementById('timeDisplay');
videoWrapper.addEventListener('click', function(e) {
if (e.target === videoWrapper || e.target === video) toggleVideoControls();
});
function toggleVideoControls() {
controlsOverlay.classList.contains('show') ? hideVideoControls() : showVideoControls();
}
function showVideoControls() {
controlsOverlay.classList.add('show');
clearTimeout(hideControlsTimeout);
if (videoPlaying) {
hideControlsTimeout = setTimeout(() => hideVideoControls(), 3000);
}
}
function hideVideoControls() {
controlsOverlay.classList.remove('show');
}
playPauseBtn.addEventListener('click', function(e) {
e.stopPropagation();
video.paused ? video.play() : video.pause();
});
video.addEventListener('play', function() {
videoPlaying = true;
playIcon.style.display = 'none';
pauseIcon.style.display = 'block';
showVideoControls();
});
video.addEventListener('pause', function() {
videoPlaying = false;
playIcon.style.display = 'block';
pauseIcon.style.display = 'none';
showVideoControls();
});
video.addEventListener('timeupdate', function() {
if (video.duration) {
const progress = (video.currentTime / video.duration) * 100;
progressBarFill.style.width = progress + '%';
timeDisplay.textContent = formatTime(video.currentTime) + ' / ' + formatTime(video.duration);
}
});
progressBarContainer.addEventListener('click', function(e) {
e.stopPropagation();
const rect = this.getBoundingClientRect();
const pos = (e.clientX - rect.left) / rect.width;
video.currentTime = pos * video.duration;
showVideoControls();
});
function formatTime(seconds) {
if (isNaN(seconds)) return '0:00';
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return mins + ':' + (secs < 10 ? '0' : '') + secs;
}
function zoomImage(imgId, delta) {
const img = document.getElementById(imgId);
if (!imageScales[imgId]) imageScales[imgId] = 1;
imageScales[imgId] += delta;
imageScales[imgId] = Math.max(1, Math.min(4, imageScales[imgId]));
img.style.transform = `scale(${imageScales[imgId]})`;
if (imageScales[imgId] > 1) {
img.classList.add('zoomed');
img.parentElement.style.overflow = 'auto';
} else {
img.classList.remove('zoomed');
img.parentElement.style.overflow = 'hidden';
}
}
function resetZoom(imgId) {
const img = document.getElementById(imgId);
imageScales[imgId] = 1;
img.style.transform = 'scale(1)';
img.classList.remove('zoomed');
img.parentElement.style.overflow = 'hidden';
}
let initialDistance = 0;
let initialScale = 1;
document.getElementById('experienceImg').addEventListener('touchstart', function(e) {
if (e.touches.length === 2) {
e.preventDefault();
const touch1 = e.touches[0];
const touch2 = e.touches[1];
initialDistance = Math.hypot(touch2.clientX - touch1.clientX, touch2.clientY - touch1.clientY);
initialScale = imageScales['experienceImg'] || 1;
}
}, { passive: false });
document.getElementById('experienceImg').addEventListener('touchmove', function(e) {
if (e.touches.length === 2) {
e.preventDefault();
const touch1 = e.touches[0];
const touch2 = e.touches[1];
const distance = Math.hypot(touch2.clientX - touch1.clientX, touch2.clientY - touch1.clientY);
const scale = initialScale * (distance / initialDistance);
imageScales['experienceImg'] = Math.max(1, Math.min(4, scale));
this.style.transform = `scale(${imageScales['experienceImg']})`;
if (imageScales['experienceImg'] > 1) {
this.classList.add('zoomed');
this.parentElement.style.overflow = 'auto';
} else {
this.classList.remove('zoomed');
this.parentElement.style.overflow = 'hidden';
}
}
}, { passive: false });
let lastTap = 0;
document.getElementById('experienceImg').addEventListener('touchend', function(e) {
const currentTime = new Date().getTime();
const tapLength = currentTime - lastTap;
if (tapLength < 300 && tapLength > 0) {
e.preventDefault();
(imageScales['experienceImg'] || 1) > 1 ? resetZoom('experienceImg') : zoomImage('experienceImg', 1);
}
lastTap = currentTime;
});
document.getElementById('messageForm').addEventListener('submit', async function(e) {
e.preventDefault();
const submitBtn = document.getElementById('submitBtn');
const successMessage = document.getElementById('successMessage');
const errorMessage = document.getElementById('errorMessage');
submitBtn.disabled = true;
submitBtn.textContent = 'Sending...';
errorMessage.classList.remove('show');
const formData = new FormData(this);
try {
const response = await fetch(window.location.href, {
method: 'POST',
body: formData
});
const data = await response.json();
if (data.success) {
successMessage.classList.add('show');
this.reset();
setTimeout(() => {
successMessage.classList.remove('show');
closeOverlay('messageOverlay');
}, 3000);
} else {
errorMessage.textContent = data.message || 'There was an error. Please try again.';
errorMessage.classList.add('show');
}
} catch (error) {
console.error('Error:', error);
errorMessage.textContent = 'Failed to send message. Please try again.';
errorMessage.classList.add('show');
} finally {
submitBtn.disabled = false;
submitBtn.textContent = 'Send Message';
}
});
document.addEventListener('gesturestart', function(e) {
e.preventDefault();
});
video.controls = false;
</script>
</body>
</html>
Good a blog toper