I’ll build this as a standalone advanced video chunk file for RX Theme: performance-friendly, accessible, lazy-loaded, WordPress-friendly, and safe to enqueue only where video features are needed.
Dear friend, create this file:
assets/static-js/static-chunks-js/chunk-018-video.js
This file is advanced video functionality for RX Theme: lazy video loading, YouTube/Vimeo support, native video support, play/pause buttons, mute, fullscreen, progress bar, keyboard support, accessibility, modal video, scroll pause, reduced-motion respect, and performance-safe initialization.
/*!
* RX Theme - Chunk 018 Video
* File: assets/static-js/static-chunks-js/chunk-018-video.js
* Purpose: Advanced video functionality for RX Theme
* Author: RxHarun
*/
(function () {
'use strict';
/**
* Prevent duplicate loading
*/
if (window.RXVideoChunkLoaded) {
return;
}
window.RXVideoChunkLoaded = true;
/**
* Main namespace
*/
window.RXTheme = window.RXTheme || {};
const RXVideo = {
version: '1.0.0',
selectors: {
root: '[data-rx-video]',
nativeVideo: 'video[data-rx-video-native]',
youtube: '[data-rx-youtube]',
vimeo: '[data-rx-vimeo]',
lazyVideo: '[data-rx-video-lazy]',
playButton: '[data-rx-video-play]',
pauseButton: '[data-rx-video-pause]',
muteButton: '[data-rx-video-mute]',
fullscreenButton: '[data-rx-video-fullscreen]',
progress: '[data-rx-video-progress]',
progressBar: '[data-rx-video-progress-bar]',
timeCurrent: '[data-rx-video-current]',
timeDuration: '[data-rx-video-duration]',
modalTrigger: '[data-rx-video-modal]',
modalClose: '[data-rx-video-modal-close]',
poster: '[data-rx-video-poster]',
iframeWrapper: '[data-rx-video-iframe-wrapper]'
},
classes: {
initialized: 'rx-video-initialized',
loading: 'rx-video-loading',
loaded: 'rx-video-loaded',
playing: 'rx-video-playing',
paused: 'rx-video-paused',
muted: 'rx-video-muted',
error: 'rx-video-error',
modalOpen: 'rx-video-modal-open',
hidden: 'rx-hidden',
active: 'rx-active'
},
settings: {
lazyRootMargin: '300px 0px',
lazyThreshold: 0.01,
autoPauseOnScrollOut: true,
pauseOtherVideos: true,
respectReducedMotion: true,
enableKeyboard: true,
debug: false
},
videos: new Map(),
observer: null,
modal: null,
lastFocusedElement: null,
/**
* Debug logger
*/
log(...args) {
if (this.settings.debug) {
console.log('[RX Video]', ...args);
}
},
/**
* Safe query helpers
*/
qs(selector, context = document) {
return context.querySelector(selector);
},
qsa(selector, context = document) {
return Array.from(context.querySelectorAll(selector));
},
/**
* Check reduced motion
*/
prefersReducedMotion() {
return (
this.settings.respectReducedMotion &&
window.matchMedia &&
window.matchMedia('(prefers-reduced-motion: reduce)').matches
);
},
/**
* Generate unique ID
*/
uid(prefix = 'rx-video') {
return `${prefix}-${Math.random().toString(36).slice(2, 11)}`;
},
/**
* Format seconds to mm:ss
*/
formatTime(seconds) {
if (!Number.isFinite(seconds)) {
return '0:00';
}
const totalSeconds = Math.max(0, Math.floor(seconds));
const minutes = Math.floor(totalSeconds / 60);
const remainingSeconds = totalSeconds % 60;
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
},
/**
* Add ARIA attributes safely
*/
setAria(element, attrs = {}) {
if (!element) return;
Object.entries(attrs).forEach(([key, value]) => {
element.setAttribute(key, value);
});
},
/**
* Dispatch custom event
*/
emit(name, detail = {}) {
document.dispatchEvent(
new CustomEvent(`rxVideo:${name}`, {
detail,
bubbles: true
})
);
},
/**
* Initialize all video features
*/
init(options = {}) {
this.settings = {
...this.settings,
...options
};
this.setupLazyObserver();
this.initNativeVideos();
this.initLazyEmbeds();
this.initVideoControls();
this.initVideoModals();
this.bindGlobalEvents();
this.emit('ready', {
version: this.version
});
this.log('Initialized');
},
/**
* Setup lazy observer
*/
setupLazyObserver() {
if (!('IntersectionObserver' in window)) {
this.loadAllLazyVideos();
return;
}
this.observer = new IntersectionObserver(
entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.loadLazyVideo(entry.target);
if (this.observer) {
this.observer.unobserve(entry.target);
}
}
});
},
{
root: null,
rootMargin: this.settings.lazyRootMargin,
threshold: this.settings.lazyThreshold
}
);
},
/**
* Load all lazy videos fallback
*/
loadAllLazyVideos() {
this.qsa(this.selectors.lazyVideo).forEach(video => {
this.loadLazyVideo(video);
});
this.qsa(this.selectors.youtube).forEach(embed => {
this.loadLazyEmbed(embed);
});
this.qsa(this.selectors.vimeo).forEach(embed => {
this.loadLazyEmbed(embed);
});
},
/**
* Native video initialization
*/
initNativeVideos() {
const videos = this.qsa(this.selectors.nativeVideo);
videos.forEach(video => {
if (video.classList.contains(this.classes.initialized)) {
return;
}
this.prepareNativeVideo(video);
});
},
/**
* Prepare native HTML5 video
*/
prepareNativeVideo(video) {
const id = video.id || this.uid('rx-native-video');
video.id = id;
video.classList.add(this.classes.initialized);
if (!video.hasAttribute('preload')) {
video.setAttribute('preload', 'metadata');
}
if (!video.hasAttribute('playsinline')) {
video.setAttribute('playsinline', '');
}
this.setAria(video, {
tabindex: '0'
});
this.videos.set(id, {
type: 'native',
element: video,
loaded: !video.dataset.src,
playing: false
});
this.bindNativeVideoEvents(video);
if (video.matches(this.selectors.lazyVideo) && this.observer) {
this.observer.observe(video);
} else if (video.matches(this.selectors.lazyVideo)) {
this.loadLazyVideo(video);
}
},
/**
* Bind native video events
*/
bindNativeVideoEvents(video) {
video.addEventListener('loadedmetadata', () => {
this.updateDuration(video);
this.emit('loadedmetadata', { video });
});
video.addEventListener('timeupdate', () => {
this.updateProgress(video);
});
video.addEventListener('play', () => {
this.markPlaying(video);
if (this.settings.pauseOtherVideos) {
this.pauseOtherVideos(video);
}
this.emit('play', { video });
});
video.addEventListener('pause', () => {
this.markPaused(video);
this.emit('pause', { video });
});
video.addEventListener('ended', () => {
this.markPaused(video);
this.emit('ended', { video });
});
video.addEventListener('volumechange', () => {
this.updateMuteState(video);
});
video.addEventListener('error', () => {
this.markError(video);
this.emit('error', { video });
});
if (this.settings.enableKeyboard) {
video.addEventListener('keydown', event => {
this.handleVideoKeyboard(event, video);
});
}
},
/**
* Lazy video loading
*/
loadLazyVideo(video) {
if (!video || video.dataset.rxLoaded === 'true') {
return;
}
video.classList.add(this.classes.loading);
const src = video.dataset.src;
const poster = video.dataset.poster;
if (poster && !video.getAttribute('poster')) {
video.setAttribute('poster', poster);
}
this.qsa('source[data-src]', video).forEach(source => {
source.src = source.dataset.src;
source.removeAttribute('data-src');
});
if (src) {
video.src = src;
video.removeAttribute('data-src');
}
video.load();
video.dataset.rxLoaded = 'true';
video.classList.remove(this.classes.loading);
video.classList.add(this.classes.loaded);
this.emit('lazyloaded', { video });
},
/**
* Lazy YouTube/Vimeo embeds
*/
initLazyEmbeds() {
const embeds = [
...this.qsa(this.selectors.youtube),
...this.qsa(this.selectors.vimeo)
];
embeds.forEach(embed => {
if (embed.classList.contains(this.classes.initialized)) {
return;
}
embed.classList.add(this.classes.initialized);
if (this.observer) {
this.observer.observe(embed);
} else {
this.loadLazyEmbed(embed);
}
});
},
/**
* Load YouTube/Vimeo iframe
*/
loadLazyEmbed(embed) {
if (!embed || embed.dataset.rxLoaded === 'true') {
return;
}
const type = embed.matches(this.selectors.youtube) ? 'youtube' : 'vimeo';
const id =
embed.dataset.rxYoutube ||
embed.dataset.rxVimeo ||
embed.dataset.videoId ||
'';
if (!id) {
this.markError(embed);
return;
}
const title = embed.dataset.title || 'Embedded video';
const autoplay = embed.dataset.autoplay === 'true';
const muted = embed.dataset.muted === 'true';
const controls = embed.dataset.controls !== 'false';
let src = '';
if (type === 'youtube') {
src = this.buildYouTubeURL(id, {
autoplay,
muted,
controls
});
}
if (type === 'vimeo') {
src = this.buildVimeoURL(id, {
autoplay,
muted,
controls
});
}
const iframe = document.createElement('iframe');
iframe.src = src;
iframe.title = title;
iframe.loading = 'lazy';
iframe.allow =
'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share';
iframe.allowFullscreen = true;
iframe.referrerPolicy = 'strict-origin-when-cross-origin';
iframe.setAttribute('frameborder', '0');
embed.classList.add(this.classes.loading);
embed.innerHTML = '';
embed.appendChild(iframe);
iframe.addEventListener('load', () => {
embed.dataset.rxLoaded = 'true';
embed.classList.remove(this.classes.loading);
embed.classList.add(this.classes.loaded);
this.emit('embedloaded', {
embed,
iframe,
type
});
});
iframe.addEventListener('error', () => {
this.markError(embed);
});
},
/**
* Build YouTube privacy-friendly URL
*/
buildYouTubeURL(id, options = {}) {
const params = new URLSearchParams();
params.set('rel', '0');
params.set('modestbranding', '1');
params.set('playsinline', '1');
if (options.autoplay) {
params.set('autoplay', '1');
}
if (options.muted || options.autoplay) {
params.set('mute', '1');
}
if (!options.controls) {
params.set('controls', '0');
}
return `https://www.youtube-nocookie.com/embed/${encodeURIComponent(id)}?${params.toString()}`;
},
/**
* Build Vimeo URL
*/
buildVimeoURL(id, options = {}) {
const params = new URLSearchParams();
params.set('dnt', '1');
params.set('playsinline', '1');
if (options.autoplay) {
params.set('autoplay', '1');
}
if (options.muted || options.autoplay) {
params.set('muted', '1');
}
if (!options.controls) {
params.set('controls', '0');
}
return `https://player.vimeo.com/video/${encodeURIComponent(id)}?${params.toString()}`;
},
/**
* Initialize custom controls
*/
initVideoControls() {
const roots = this.qsa(this.selectors.root);
roots.forEach(root => {
if (root.dataset.rxControlsReady === 'true') {
return;
}
root.dataset.rxControlsReady = 'true';
const video = this.qs('video', root);
if (!video) {
return;
}
this.bindControlButtons(root, video);
this.updateDuration(video);
this.updateProgress(video);
this.updateMuteState(video);
});
},
/**
* Bind control buttons
*/
bindControlButtons(root, video) {
const playButtons = this.qsa(this.selectors.playButton, root);
const pauseButtons = this.qsa(this.selectors.pauseButton, root);
const muteButtons = this.qsa(this.selectors.muteButton, root);
const fullscreenButtons = this.qsa(this.selectors.fullscreenButton, root);
const progress = this.qs(this.selectors.progress, root);
playButtons.forEach(button => {
this.setAria(button, {
type: 'button',
'aria-label': button.getAttribute('aria-label') || 'Play video'
});
button.addEventListener('click', event => {
event.preventDefault();
this.playVideo(video);
});
});
pauseButtons.forEach(button => {
this.setAria(button, {
type: 'button',
'aria-label': button.getAttribute('aria-label') || 'Pause video'
});
button.addEventListener('click', event => {
event.preventDefault();
this.pauseVideo(video);
});
});
muteButtons.forEach(button => {
this.setAria(button, {
type: 'button',
'aria-label': button.getAttribute('aria-label') || 'Mute video'
});
button.addEventListener('click', event => {
event.preventDefault();
this.toggleMute(video);
});
});
fullscreenButtons.forEach(button => {
this.setAria(button, {
type: 'button',
'aria-label': button.getAttribute('aria-label') || 'Fullscreen video'
});
button.addEventListener('click', event => {
event.preventDefault();
this.toggleFullscreen(root);
});
});
if (progress) {
this.setAria(progress, {
role: 'slider',
tabindex: '0',
'aria-valuemin': '0',
'aria-valuemax': '100',
'aria-valuenow': '0',
'aria-label': progress.getAttribute('aria-label') || 'Video progress'
});
progress.addEventListener('click', event => {
this.seekFromPointer(event, progress, video);
});
progress.addEventListener('keydown', event => {
this.handleProgressKeyboard(event, video);
});
}
},
/**
* Play video safely
*/
playVideo(video) {
if (!video) return;
if (video.matches(this.selectors.lazyVideo)) {
this.loadLazyVideo(video);
}
const playPromise = video.play();
if (playPromise && typeof playPromise.catch === 'function') {
playPromise.catch(() => {
this.log('Autoplay or play blocked');
});
}
},
/**
* Pause video
*/
pauseVideo(video) {
if (!video) return;
video.pause();
},
/**
* Toggle play
*/
togglePlay(video) {
if (!video) return;
if (video.paused) {
this.playVideo(video);
} else {
this.pauseVideo(video);
}
},
/**
* Toggle mute
*/
toggleMute(video) {
if (!video) return;
video.muted = !video.muted;
this.updateMuteState(video);
},
/**
* Seek video from pointer
*/
seekFromPointer(event, progress, video) {
if (!video || !progress || !Number.isFinite(video.duration)) {
return;
}
const rect = progress.getBoundingClientRect();
const position = Math.min(Math.max(0, event.clientX - rect.left), rect.width);
const percent = position / rect.width;
video.currentTime = percent * video.duration;
},
/**
* Keyboard controls for video
*/
handleVideoKeyboard(event, video) {
const key = event.key;
if (key === ' ' || key === 'Enter') {
event.preventDefault();
this.togglePlay(video);
}
if (key === 'ArrowRight') {
event.preventDefault();
this.seekBy(video, 5);
}
if (key === 'ArrowLeft') {
event.preventDefault();
this.seekBy(video, -5);
}
if (key.toLowerCase() === 'm') {
event.preventDefault();
this.toggleMute(video);
}
if (key.toLowerCase() === 'f') {
event.preventDefault();
const root = video.closest(this.selectors.root) || video.parentElement;
this.toggleFullscreen(root);
}
},
/**
* Keyboard progress controls
*/
handleProgressKeyboard(event, video) {
if (!video) return;
if (event.key === 'ArrowRight') {
event.preventDefault();
this.seekBy(video, 5);
}
if (event.key === 'ArrowLeft') {
event.preventDefault();
this.seekBy(video, -5);
}
if (event.key === 'Home') {
event.preventDefault();
video.currentTime = 0;
}
if (event.key === 'End' && Number.isFinite(video.duration)) {
event.preventDefault();
video.currentTime = video.duration;
}
},
/**
* Seek by seconds
*/
seekBy(video, seconds) {
if (!video || !Number.isFinite(video.duration)) {
return;
}
video.currentTime = Math.min(
Math.max(0, video.currentTime + seconds),
video.duration
);
},
/**
* Update progress UI
*/
updateProgress(video) {
const root = video.closest(this.selectors.root);
if (!root || !Number.isFinite(video.duration)) {
return;
}
const percent = (video.currentTime / video.duration) * 100;
const progress = this.qs(this.selectors.progress, root);
const progressBar = this.qs(this.selectors.progressBar, root);
const current = this.qs(this.selectors.timeCurrent, root);
if (progressBar) {
progressBar.style.width = `${percent}%`;
}
if (progress) {
progress.setAttribute('aria-valuenow', String(Math.round(percent)));
}
if (current) {
current.textContent = this.formatTime(video.currentTime);
}
},
/**
* Update duration UI
*/
updateDuration(video) {
const root = video.closest(this.selectors.root);
if (!root || !Number.isFinite(video.duration)) {
return;
}
const duration = this.qs(this.selectors.timeDuration, root);
if (duration) {
duration.textContent = this.formatTime(video.duration);
}
},
/**
* Mark playing
*/
markPlaying(video) {
const root = video.closest(this.selectors.root);
video.classList.add(this.classes.playing);
video.classList.remove(this.classes.paused);
if (root) {
root.classList.add(this.classes.playing);
root.classList.remove(this.classes.paused);
}
},
/**
* Mark paused
*/
markPaused(video) {
const root = video.closest(this.selectors.root);
video.classList.add(this.classes.paused);
video.classList.remove(this.classes.playing);
if (root) {
root.classList.add(this.classes.paused);
root.classList.remove(this.classes.playing);
}
},
/**
* Mark error
*/
markError(element) {
if (!element) return;
element.classList.add(this.classes.error);
element.classList.remove(this.classes.loading);
const root = element.closest(this.selectors.root);
if (root) {
root.classList.add(this.classes.error);
}
this.emit('error', {
element
});
},
/**
* Update mute state
*/
updateMuteState(video) {
const root = video.closest(this.selectors.root);
if (!root) return;
const muteButtons = this.qsa(this.selectors.muteButton, root);
if (video.muted || video.volume === 0) {
root.classList.add(this.classes.muted);
muteButtons.forEach(button => {
button.setAttribute('aria-label', 'Unmute video');
button.setAttribute('aria-pressed', 'true');
});
} else {
root.classList.remove(this.classes.muted);
muteButtons.forEach(button => {
button.setAttribute('aria-label', 'Mute video');
button.setAttribute('aria-pressed', 'false');
});
}
},
/**
* Pause other videos
*/
pauseOtherVideos(currentVideo) {
this.qsa('video').forEach(video => {
if (video !== currentVideo && !video.paused) {
video.pause();
}
});
},
/**
* Fullscreen support
*/
toggleFullscreen(element) {
if (!element) return;
if (!document.fullscreenElement) {
if (element.requestFullscreen) {
element.requestFullscreen().catch(() => {});
}
} else if (document.exitFullscreen) {
document.exitFullscreen().catch(() => {});
}
},
/**
* Video modal system
*/
initVideoModals() {
const triggers = this.qsa(this.selectors.modalTrigger);
if (!triggers.length) {
return;
}
this.createModal();
triggers.forEach(trigger => {
if (trigger.dataset.rxModalReady === 'true') {
return;
}
trigger.dataset.rxModalReady = 'true';
trigger.addEventListener('click', event => {
event.preventDefault();
this.openModalFromTrigger(trigger);
});
});
},
/**
* Create reusable modal
*/
createModal() {
if (this.modal) {
return;
}
const modal = document.createElement('div');
modal.className = 'rx-video-modal';
modal.setAttribute('role', 'dialog');
modal.setAttribute('aria-modal', 'true');
modal.setAttribute('aria-label', 'Video player');
modal.setAttribute('hidden', '');
modal.innerHTML = `
<div class="rx-video-modal__overlay" data-rx-video-modal-close></div>
<div class="rx-video-modal__dialog" role="document">
<button class="rx-video-modal__close" type="button" data-rx-video-modal-close aria-label="Close video">
×
</button>
<div class="rx-video-modal__content" data-rx-video-modal-content></div>
</div>
`;
document.body.appendChild(modal);
this.modal = modal;
this.qsa(this.selectors.modalClose, modal).forEach(close => {
close.addEventListener('click', () => {
this.closeModal();
});
});
document.addEventListener('keydown', event => {
if (event.key === 'Escape' && document.body.classList.contains(this.classes.modalOpen)) {
this.closeModal();
}
});
},
/**
* Open modal from trigger
*/
openModalFromTrigger(trigger) {
if (!this.modal) {
return;
}
const content = this.qs('[data-rx-video-modal-content]', this.modal);
if (!content) {
return;
}
this.lastFocusedElement = document.activeElement;
const youtubeId = trigger.dataset.youtube || trigger.dataset.rxYoutube;
const vimeoId = trigger.dataset.vimeo || trigger.dataset.rxVimeo;
const videoSrc = trigger.dataset.videoSrc;
const title = trigger.dataset.title || 'Video player';
let html = '';
if (youtubeId) {
html = `
<iframe
src="${this.buildYouTubeURL(youtubeId, {
autoplay: true,
muted: false,
controls: true
})}"
title="${this.escapeHTML(title)}"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
loading="lazy"
referrerpolicy="strict-origin-when-cross-origin"></iframe>
`;
} else if (vimeoId) {
html = `
<iframe
src="${this.buildVimeoURL(vimeoId, {
autoplay: true,
muted: false,
controls: true
})}"
title="${this.escapeHTML(title)}"
allow="autoplay; fullscreen; picture-in-picture"
allowfullscreen
loading="lazy"></iframe>
`;
} else if (videoSrc) {
html = `
<video controls autoplay playsinline preload="metadata">
<source src="${this.escapeAttribute(videoSrc)}">
</video>
`;
}
if (!html) {
return;
}
content.innerHTML = html;
this.modal.removeAttribute('hidden');
document.body.classList.add(this.classes.modalOpen);
const closeButton = this.qs(this.selectors.modalClose, this.modal);
if (closeButton) {
closeButton.focus();
}
this.emit('modalopen', {
trigger
});
},
/**
* Close modal
*/
closeModal() {
if (!this.modal) {
return;
}
const content = this.qs('[data-rx-video-modal-content]', this.modal);
if (content) {
content.innerHTML = '';
}
this.modal.setAttribute('hidden', '');
document.body.classList.remove(this.classes.modalOpen);
if (this.lastFocusedElement && typeof this.lastFocusedElement.focus === 'function') {
this.lastFocusedElement.focus();
}
this.emit('modalclose');
},
/**
* Escape HTML
*/
escapeHTML(value) {
return String(value)
.replaceAll('&', '&')
.replaceAll('<', '<')
.replaceAll('>', '>')
.replaceAll('"', '"')
.replaceAll("'", ''');
},
/**
* Escape attribute
*/
escapeAttribute(value) {
return this.escapeHTML(value);
},
/**
* Global events
*/
bindGlobalEvents() {
document.addEventListener('click', event => {
const poster = event.target.closest(this.selectors.poster);
if (poster) {
const root = poster.closest(this.selectors.root);
const video = root ? this.qs('video', root) : null;
if (video) {
this.playVideo(video);
}
}
});
if (this.settings.autoPauseOnScrollOut && 'IntersectionObserver' in window) {
this.setupAutoPauseObserver();
}
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
this.pauseAllVideos();
}
});
},
/**
* Pause videos when out of viewport
*/
setupAutoPauseObserver() {
const pauseObserver = new IntersectionObserver(
entries => {
entries.forEach(entry => {
const video = entry.target;
if (!entry.isIntersecting && !video.paused) {
video.pause();
}
});
},
{
threshold: 0.15
}
);
this.qsa('video').forEach(video => {
pauseObserver.observe(video);
});
},
/**
* Pause all native videos
*/
pauseAllVideos() {
this.qsa('video').forEach(video => {
if (!video.paused) {
video.pause();
}
});
},
/**
* Public refresh method for AJAX/Load More
*/
refresh() {
this.initNativeVideos();
this.initLazyEmbeds();
this.initVideoControls();
this.initVideoModals();
this.emit('refresh');
},
/**
* Public destroy method
*/
destroy() {
if (this.observer) {
this.observer.disconnect();
}
this.pauseAllVideos();
this.videos.clear();
if (this.modal) {
this.modal.remove();
this.modal = null;
}
window.RXVideoChunkLoaded = false;
this.emit('destroy');
}
};
/**
* Expose API
*/
window.RXTheme.Video = RXVideo;
/**
* Auto init
*/
const boot = () => {
RXVideo.init();
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', boot, {
once: true
});
} else {
boot();
}
})();
Example HTML for native video
<div class="rx-video-box" data-rx-video>
<video
data-rx-video-native
data-rx-video-lazy
data-src="https://example.com/video.mp4"
data-poster="https://example.com/poster.jpg"
preload="metadata"
playsinline>
</video>
<button data-rx-video-play type="button">Play</button>
<button data-rx-video-pause type="button">Pause</button>
<button data-rx-video-mute type="button">Mute</button>
<button data-rx-video-fullscreen type="button">Fullscreen</button>
<div data-rx-video-progress class="rx-video-progress">
<span data-rx-video-progress-bar class="rx-video-progress-bar"></span>
</div>
<span data-rx-video-current>0:00</span>
<span data-rx-video-duration>0:00</span>
</div>
Example HTML for lazy YouTube
<div
class="rx-video-embed"
data-rx-youtube="YOUTUBE_VIDEO_ID"
data-title="RX Theme Video"
data-autoplay="false"
data-muted="false"
data-controls="true">
</div>
Example HTML for lazy Vimeo
<div
class="rx-video-embed"
data-rx-vimeo="VIMEO_VIDEO_ID"
data-title="RX Theme Vimeo Video"
data-autoplay="false"
data-muted="false"
data-controls="true">
</div>
Example HTML for modal video
<button
type="button"
data-rx-video-modal
data-youtube="YOUTUBE_VIDEO_ID"
data-title="Watch RX Theme Video">
Watch Video
</button>
Enqueue in functions.php
function rx_theme_enqueue_video_chunk() {
wp_enqueue_script(
'rx-theme-video-chunk',
get_template_directory_uri() . '/assets/static-js/static-chunks-js/chunk-018-video.js',
array(),
wp_get_theme()->get('Version'),
true
);
}
add_action('wp_enqueue_scripts', 'rx_theme_enqueue_video_chunk');
Better advanced conditional loading:
function rx_theme_enqueue_video_chunk_conditionally() {
if (is_admin()) {
return;
}
if (is_singular() || is_front_page() || is_home()) {
wp_enqueue_script(
'rx-theme-video-chunk',
get_template_directory_uri() . '/assets/static-js/static-chunks-js/chunk-018-video.js',
array(),
wp_get_theme()->get('Version'),
true
);
}
}
add_action('wp_enqueue_scripts', 'rx_theme_enqueue_video_chunk_conditionally');
Best naming, dear friend
For RX Theme, this file name is good:
chunk-018-video.js
But for a more professional future system, this is also excellent:
chunk-018-rx-video.js
My recommendation:
assets/static-js/static-chunks-js/chunk-018-rx-video.js
Because later you may have many chunks, and every RX Theme chunk will look branded and organized.