I’ll build this as a safe “RX Theme chunks controller” file: performance helpers, lazy loading, accessibility, sticky header, search, dark mode, back-to-top, reading progress, TOC, comments, and small WordPress-friendly utilities.
Below is a large advanced inc/chunks/chunks.js file for your RX Theme. It includes many safe frontend functions: performance, lazy loading, accessibility, dark mode, sticky header, mobile menu, search overlay, reading progress, table of contents, accordion, tabs, copy buttons, back-to-top, external-link handling, smooth scroll, comments helper, share buttons, image lightbox, and more.
Create this file:
rx-theme/inc/chunks/chunks.js
Then paste all code below.
/*!
* RX Theme - chunks.js
* Advanced frontend controller for RX Theme
* Author: RxHarun
* Purpose: Performance, accessibility, UX, SEO-supportive frontend features.
*/
(function () {
'use strict';
/**
* ============================================================
* RX GLOBAL OBJECT
* ============================================================
*/
const RXTheme = {
version: '1.0.0',
selectors: {
body: 'body',
html: 'html',
siteHeader: '.site-header, #site-header, header[role="banner"]',
mainNav: '.main-navigation, .primary-navigation, #site-navigation',
menuToggle: '.menu-toggle, .nav-toggle, .mobile-menu-toggle',
searchToggle: '.search-toggle, .rx-search-toggle',
searchOverlay: '.rx-search-overlay, .search-overlay',
searchClose: '.rx-search-close, .search-close',
backToTop: '.rx-back-to-top, .back-to-top',
readingProgress: '.rx-reading-progress',
toc: '.rx-table-of-contents, .table-of-contents',
content: '.entry-content, .post-content, article',
accordion: '.rx-accordion',
tabs: '.rx-tabs',
copyButton: '.rx-copy-button',
lazyImage: 'img[loading="lazy"], img[data-src]',
lightboxImage: '.entry-content img, .post-content img',
commentForm: '#commentform',
externalLinks: 'a[href^="http"]'
},
settings: {
stickyHeaderOffset: 120,
backToTopOffset: 500,
readingProgressEnabled: true,
smoothScrollOffset: 90,
darkModeStorageKey: 'rx_theme_dark_mode',
fontStorageKey: 'rx_theme_font_size',
animationClass: 'rx-animate-in',
activeClass: 'is-active',
openClass: 'is-open',
fixedClass: 'is-fixed',
hiddenClass: 'is-hidden',
loadedClass: 'is-loaded'
},
state: {
lastScrollY: 0,
ticking: false,
isMobileMenuOpen: false,
isSearchOpen: false,
reducedMotion: false
},
init() {
this.cache();
this.detectPreferences();
this.addBodyClasses();
this.bindGlobalEvents();
this.initNoJS();
this.initStickyHeader();
this.initMobileMenu();
this.initSearchOverlay();
this.initBackToTop();
this.initReadingProgress();
this.initSmoothScroll();
this.initLazyImages();
this.initExternalLinks();
this.initTableOfContents();
this.initAccordions();
this.initTabs();
this.initCopyButtons();
this.initShareButtons();
this.initCommentFormEnhancer();
this.initImageLightbox();
this.initFormValidation();
this.initDarkMode();
this.initFontSizeControls();
this.initScrollAnimations();
this.initPrintHelpers();
this.initResponsiveTables();
this.initVideoEmbeds();
this.initCodeBlocks();
this.initBreadcrumbEnhancer();
this.initKeyboardAccessibility();
this.initSkipLinks();
this.initCookieNotice();
this.initNewsletterBox();
this.initAjaxLoadMorePlaceholder();
this.initServiceWorkerHelper();
this.markLoaded();
},
cache() {
this.html = document.documentElement;
this.body = document.body;
this.header = document.querySelector(this.selectors.siteHeader);
this.mainNav = document.querySelector(this.selectors.mainNav);
},
detectPreferences() {
this.state.reducedMotion = window.matchMedia &&
window.matchMedia('(prefers-reduced-motion: reduce)').matches;
},
addBodyClasses() {
if (!this.body) return;
this.body.classList.add('rx-js-enabled');
if ('IntersectionObserver' in window) {
this.body.classList.add('rx-supports-intersection-observer');
}
if ('localStorage' in window) {
this.body.classList.add('rx-supports-local-storage');
}
if (this.state.reducedMotion) {
this.body.classList.add('rx-reduced-motion');
}
},
bindGlobalEvents() {
window.addEventListener('scroll', () => {
this.requestTick();
}, { passive: true });
window.addEventListener('resize', this.debounce(() => {
this.handleResize();
}, 200));
document.addEventListener('keydown', (event) => {
this.handleGlobalKeydown(event);
});
},
requestTick() {
if (!this.state.ticking) {
window.requestAnimationFrame(() => {
this.handleScroll();
this.state.ticking = false;
});
this.state.ticking = true;
}
},
handleScroll() {
const scrollY = window.scrollY || window.pageYOffset;
this.updateStickyHeader(scrollY);
this.updateBackToTop(scrollY);
this.updateReadingProgress(scrollY);
this.state.lastScrollY = scrollY;
},
handleResize() {
this.closeMobileMenuOnDesktop();
this.refreshReadingProgress();
this.refreshResponsiveTables();
},
handleGlobalKeydown(event) {
if (event.key === 'Escape') {
this.closeSearchOverlay();
this.closeMobileMenu();
this.closeLightbox();
}
},
markLoaded() {
window.addEventListener('load', () => {
this.body.classList.add(this.settings.loadedClass);
});
},
/**
* ============================================================
* BASIC NO-JS SUPPORT
* ============================================================
*/
initNoJS() {
if (!this.html) return;
this.html.classList.remove('no-js');
this.html.classList.add('js');
},
/**
* ============================================================
* STICKY HEADER
* ============================================================
*/
initStickyHeader() {
if (!this.header) return;
this.header.classList.add('rx-sticky-ready');
const placeholder = document.createElement('div');
placeholder.className = 'rx-header-placeholder';
placeholder.style.display = 'none';
this.header.parentNode.insertBefore(placeholder, this.header.nextSibling);
this.headerPlaceholder = placeholder;
},
updateStickyHeader(scrollY) {
if (!this.header) return;
const offset = this.settings.stickyHeaderOffset;
if (scrollY > offset) {
this.header.classList.add(this.settings.fixedClass);
if (this.headerPlaceholder) {
this.headerPlaceholder.style.height = `${this.header.offsetHeight}px`;
this.headerPlaceholder.style.display = 'block';
}
} else {
this.header.classList.remove(this.settings.fixedClass);
if (this.headerPlaceholder) {
this.headerPlaceholder.style.display = 'none';
}
}
if (scrollY > this.state.lastScrollY && scrollY > offset + 100) {
this.header.classList.add('is-scrolling-down');
this.header.classList.remove('is-scrolling-up');
} else {
this.header.classList.add('is-scrolling-up');
this.header.classList.remove('is-scrolling-down');
}
},
/**
* ============================================================
* MOBILE MENU
* ============================================================
*/
initMobileMenu() {
const toggles = document.querySelectorAll(this.selectors.menuToggle);
if (!toggles.length || !this.mainNav) return;
toggles.forEach((toggle) => {
toggle.setAttribute('aria-expanded', 'false');
toggle.setAttribute('aria-controls', this.mainNav.id || 'site-navigation');
if (!this.mainNav.id) {
this.mainNav.id = 'site-navigation';
}
toggle.addEventListener('click', (event) => {
event.preventDefault();
this.toggleMobileMenu(toggle);
});
});
this.initSubMenuToggles();
},
toggleMobileMenu(toggle) {
if (this.state.isMobileMenuOpen) {
this.closeMobileMenu();
} else {
this.openMobileMenu(toggle);
}
},
openMobileMenu(toggle) {
this.state.isMobileMenuOpen = true;
this.body.classList.add('rx-menu-open');
this.mainNav.classList.add(this.settings.openClass);
document.querySelectorAll(this.selectors.menuToggle).forEach((btn) => {
btn.setAttribute('aria-expanded', 'true');
});
if (toggle) {
toggle.classList.add(this.settings.activeClass);
}
},
closeMobileMenu() {
if (!this.mainNav) return;
this.state.isMobileMenuOpen = false;
this.body.classList.remove('rx-menu-open');
this.mainNav.classList.remove(this.settings.openClass);
document.querySelectorAll(this.selectors.menuToggle).forEach((btn) => {
btn.setAttribute('aria-expanded', 'false');
btn.classList.remove(this.settings.activeClass);
});
},
closeMobileMenuOnDesktop() {
if (window.innerWidth >= 992) {
this.closeMobileMenu();
}
},
initSubMenuToggles() {
if (!this.mainNav) return;
const menuItems = this.mainNav.querySelectorAll('.menu-item-has-children');
menuItems.forEach((item, index) => {
const link = item.querySelector('a');
const submenu = item.querySelector('.sub-menu, .children');
if (!link || !submenu) return;
const button = document.createElement('button');
button.className = 'rx-submenu-toggle';
button.setAttribute('aria-expanded', 'false');
button.setAttribute('aria-label', 'Open submenu');
button.innerHTML = '<span aria-hidden="true">+</span>';
const submenuId = submenu.id || `rx-submenu-${index}`;
submenu.id = submenuId;
button.setAttribute('aria-controls', submenuId);
link.insertAdjacentElement('afterend', button);
button.addEventListener('click', () => {
const expanded = button.getAttribute('aria-expanded') === 'true';
button.setAttribute('aria-expanded', expanded ? 'false' : 'true');
button.setAttribute('aria-label', expanded ? 'Open submenu' : 'Close submenu');
item.classList.toggle(this.settings.openClass, !expanded);
submenu.classList.toggle(this.settings.openClass, !expanded);
button.innerHTML = expanded
? '<span aria-hidden="true">+</span>'
: '<span aria-hidden="true">−</span>';
});
});
},
/**
* ============================================================
* SEARCH OVERLAY
* ============================================================
*/
initSearchOverlay() {
const toggles = document.querySelectorAll(this.selectors.searchToggle);
const closes = document.querySelectorAll(this.selectors.searchClose);
const overlay = document.querySelector(this.selectors.searchOverlay);
if (!overlay) return;
this.searchOverlay = overlay;
toggles.forEach((toggle) => {
toggle.setAttribute('aria-expanded', 'false');
toggle.addEventListener('click', (event) => {
event.preventDefault();
this.openSearchOverlay(toggle);
});
});
closes.forEach((close) => {
close.addEventListener('click', (event) => {
event.preventDefault();
this.closeSearchOverlay();
});
});
overlay.addEventListener('click', (event) => {
if (event.target === overlay) {
this.closeSearchOverlay();
}
});
},
openSearchOverlay(toggle) {
if (!this.searchOverlay) return;
this.state.isSearchOpen = true;
this.body.classList.add('rx-search-open');
this.searchOverlay.classList.add(this.settings.openClass);
this.searchOverlay.removeAttribute('hidden');
document.querySelectorAll(this.selectors.searchToggle).forEach((btn) => {
btn.setAttribute('aria-expanded', 'true');
});
if (toggle) {
toggle.classList.add(this.settings.activeClass);
}
const input = this.searchOverlay.querySelector('input[type="search"], input[name="s"]');
if (input) {
setTimeout(() => input.focus(), 80);
}
},
closeSearchOverlay() {
if (!this.searchOverlay) return;
this.state.isSearchOpen = false;
this.body.classList.remove('rx-search-open');
this.searchOverlay.classList.remove(this.settings.openClass);
document.querySelectorAll(this.selectors.searchToggle).forEach((btn) => {
btn.setAttribute('aria-expanded', 'false');
btn.classList.remove(this.settings.activeClass);
});
setTimeout(() => {
if (!this.state.isSearchOpen) {
this.searchOverlay.setAttribute('hidden', 'hidden');
}
}, 250);
},
/**
* ============================================================
* BACK TO TOP BUTTON
* ============================================================
*/
initBackToTop() {
let button = document.querySelector(this.selectors.backToTop);
if (!button) {
button = document.createElement('button');
button.className = 'rx-back-to-top';
button.setAttribute('type', 'button');
button.setAttribute('aria-label', 'Back to top');
button.innerHTML = '↑';
document.body.appendChild(button);
}
this.backToTopButton = button;
button.addEventListener('click', () => {
window.scrollTo({
top: 0,
behavior: this.state.reducedMotion ? 'auto' : 'smooth'
});
});
},
updateBackToTop(scrollY) {
if (!this.backToTopButton) return;
if (scrollY > this.settings.backToTopOffset) {
this.backToTopButton.classList.add(this.settings.activeClass);
} else {
this.backToTopButton.classList.remove(this.settings.activeClass);
}
},
/**
* ============================================================
* READING PROGRESS BAR
* ============================================================
*/
initReadingProgress() {
if (!this.settings.readingProgressEnabled) return;
let bar = document.querySelector(this.selectors.readingProgress);
if (!bar) {
bar = document.createElement('div');
bar.className = 'rx-reading-progress';
bar.setAttribute('aria-hidden', 'true');
const inner = document.createElement('span');
inner.className = 'rx-reading-progress-inner';
bar.appendChild(inner);
document.body.appendChild(bar);
}
this.readingProgress = bar.querySelector('.rx-reading-progress-inner') || bar;
this.refreshReadingProgress();
},
refreshReadingProgress() {
this.documentHeight = Math.max(
document.body.scrollHeight,
document.documentElement.scrollHeight
) - window.innerHeight;
},
updateReadingProgress(scrollY) {
if (!this.readingProgress || !this.documentHeight) return;
const percent = Math.min(100, Math.max(0, (scrollY / this.documentHeight) * 100));
this.readingProgress.style.transform = `scaleX(${percent / 100})`;
},
/**
* ============================================================
* SMOOTH SCROLL
* ============================================================
*/
initSmoothScroll() {
const links = document.querySelectorAll('a[href^="#"]:not([href="#"])');
links.forEach((link) => {
link.addEventListener('click', (event) => {
const targetId = decodeURIComponent(link.getAttribute('href'));
const target = document.querySelector(targetId);
if (!target) return;
event.preventDefault();
const offset = this.settings.smoothScrollOffset;
const top = target.getBoundingClientRect().top + window.scrollY - offset;
window.scrollTo({
top,
behavior: this.state.reducedMotion ? 'auto' : 'smooth'
});
target.setAttribute('tabindex', '-1');
target.focus({ preventScroll: true });
history.pushState(null, '', targetId);
});
});
},
/**
* ============================================================
* LAZY IMAGES
* ============================================================
*/
initLazyImages() {
const images = document.querySelectorAll('img[data-src], img[data-srcset]');
if (!images.length) return;
if ('IntersectionObserver' in window) {
const observer = new IntersectionObserver((entries, obs) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return;
const img = entry.target;
this.loadLazyImage(img);
obs.unobserve(img);
});
}, {
rootMargin: '250px 0px'
});
images.forEach((img) => observer.observe(img));
} else {
images.forEach((img) => this.loadLazyImage(img));
}
},
loadLazyImage(img) {
if (!img) return;
if (img.dataset.src) {
img.src = img.dataset.src;
}
if (img.dataset.srcset) {
img.srcset = img.dataset.srcset;
}
img.classList.add('rx-lazy-loading');
img.addEventListener('load', () => {
img.classList.remove('rx-lazy-loading');
img.classList.add('rx-lazy-loaded');
}, { once: true });
},
/**
* ============================================================
* EXTERNAL LINKS
* ============================================================
*/
initExternalLinks() {
const links = document.querySelectorAll(this.selectors.externalLinks);
const currentHost = window.location.hostname;
links.forEach((link) => {
try {
const url = new URL(link.href);
if (url.hostname !== currentHost) {
link.setAttribute('target', '_blank');
link.setAttribute('rel', 'noopener noreferrer');
if (!link.querySelector('.screen-reader-text')) {
const text = document.createElement('span');
text.className = 'screen-reader-text';
text.textContent = ' opens in a new tab';
link.appendChild(text);
}
}
} catch (error) {
// Ignore invalid URLs.
}
});
},
/**
* ============================================================
* TABLE OF CONTENTS
* ============================================================
*/
initTableOfContents() {
const content = document.querySelector(this.selectors.content);
const toc = document.querySelector(this.selectors.toc);
if (!content || !toc) return;
const headings = content.querySelectorAll('h2, h3');
if (!headings.length) {
toc.style.display = 'none';
return;
}
const list = document.createElement('ol');
list.className = 'rx-toc-list';
headings.forEach((heading, index) => {
if (!heading.id) {
heading.id = this.slugify(heading.textContent || `section-${index + 1}`);
}
const item = document.createElement('li');
item.className = `rx-toc-item rx-toc-${heading.tagName.toLowerCase()}`;
const link = document.createElement('a');
link.href = `#${heading.id}`;
link.textContent = heading.textContent;
item.appendChild(link);
list.appendChild(item);
});
toc.appendChild(list);
this.observeTOCHeadings(headings, toc);
},
observeTOCHeadings(headings, toc) {
if (!('IntersectionObserver' in window)) return;
const links = toc.querySelectorAll('a');
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return;
links.forEach((link) => {
link.classList.toggle(
this.settings.activeClass,
link.getAttribute('href') === `#${entry.target.id}`
);
});
});
}, {
rootMargin: '-20% 0px -70% 0px'
});
headings.forEach((heading) => observer.observe(heading));
},
/**
* ============================================================
* ACCORDIONS
* ============================================================
*/
initAccordions() {
const accordions = document.querySelectorAll(this.selectors.accordion);
accordions.forEach((accordion, accordionIndex) => {
const items = accordion.querySelectorAll('.rx-accordion-item');
items.forEach((item, itemIndex) => {
const header = item.querySelector('.rx-accordion-header');
const panel = item.querySelector('.rx-accordion-panel');
if (!header || !panel) return;
const button = header.tagName.toLowerCase() === 'button'
? header
: header.querySelector('button') || this.wrapHeaderWithButton(header);
const panelId = panel.id || `rx-accordion-panel-${accordionIndex}-${itemIndex}`;
panel.id = panelId;
button.setAttribute('aria-expanded', 'false');
button.setAttribute('aria-controls', panelId);
panel.setAttribute('hidden', 'hidden');
button.addEventListener('click', () => {
const expanded = button.getAttribute('aria-expanded') === 'true';
if (accordion.dataset.single === 'true') {
this.closeAllAccordionItems(accordion);
}
button.setAttribute('aria-expanded', expanded ? 'false' : 'true');
panel.toggleAttribute('hidden', expanded);
item.classList.toggle(this.settings.openClass, !expanded);
});
});
});
},
wrapHeaderWithButton(header) {
const button = document.createElement('button');
button.className = 'rx-accordion-button';
button.type = 'button';
button.innerHTML = header.innerHTML;
header.innerHTML = '';
header.appendChild(button);
return button;
},
closeAllAccordionItems(accordion) {
accordion.querySelectorAll('.rx-accordion-item').forEach((item) => {
const button = item.querySelector('[aria-expanded]');
const panel = item.querySelector('.rx-accordion-panel');
if (button) {
button.setAttribute('aria-expanded', 'false');
}
if (panel) {
panel.setAttribute('hidden', 'hidden');
}
item.classList.remove(this.settings.openClass);
});
},
/**
* ============================================================
* TABS
* ============================================================
*/
initTabs() {
const tabsGroups = document.querySelectorAll(this.selectors.tabs);
tabsGroups.forEach((tabs, groupIndex) => {
const tabButtons = tabs.querySelectorAll('[role="tab"], .rx-tab-button');
const panels = tabs.querySelectorAll('[role="tabpanel"], .rx-tab-panel');
if (!tabButtons.length || !panels.length) return;
tabButtons.forEach((button, index) => {
const panel = panels[index];
if (!panel) return;
const tabId = button.id || `rx-tab-${groupIndex}-${index}`;
const panelId = panel.id || `rx-tab-panel-${groupIndex}-${index}`;
button.id = tabId;
panel.id = panelId;
button.setAttribute('role', 'tab');
button.setAttribute('aria-controls', panelId);
button.setAttribute('aria-selected', index === 0 ? 'true' : 'false');
button.setAttribute('tabindex', index === 0 ? '0' : '-1');
panel.setAttribute('role', 'tabpanel');
panel.setAttribute('aria-labelledby', tabId);
if (index !== 0) {
panel.setAttribute('hidden', 'hidden');
}
button.addEventListener('click', () => {
this.activateTab(tabButtons, panels, index);
});
button.addEventListener('keydown', (event) => {
this.handleTabKeydown(event, tabButtons, panels, index);
});
});
});
},
activateTab(buttons, panels, activeIndex) {
buttons.forEach((button, index) => {
const selected = index === activeIndex;
button.setAttribute('aria-selected', selected ? 'true' : 'false');
button.setAttribute('tabindex', selected ? '0' : '-1');
button.classList.toggle(this.settings.activeClass, selected);
if (panels[index]) {
panels[index].toggleAttribute('hidden', !selected);
panels[index].classList.toggle(this.settings.activeClass, selected);
}
});
buttons[activeIndex].focus();
},
handleTabKeydown(event, buttons, panels, currentIndex) {
let nextIndex = currentIndex;
if (event.key === 'ArrowRight') {
nextIndex = (currentIndex + 1) % buttons.length;
} else if (event.key === 'ArrowLeft') {
nextIndex = (currentIndex - 1 + buttons.length) % buttons.length;
} else if (event.key === 'Home') {
nextIndex = 0;
} else if (event.key === 'End') {
nextIndex = buttons.length - 1;
} else {
return;
}
event.preventDefault();
this.activateTab(buttons, panels, nextIndex);
},
/**
* ============================================================
* COPY BUTTONS
* ============================================================
*/
initCopyButtons() {
const codeBlocks = document.querySelectorAll('pre code');
codeBlocks.forEach((code) => {
const pre = code.parentElement;
if (!pre || pre.classList.contains('rx-copy-ready')) return;
pre.classList.add('rx-copy-ready');
const button = document.createElement('button');
button.type = 'button';
button.className = 'rx-copy-button';
button.textContent = 'Copy';
button.setAttribute('aria-label', 'Copy code');
pre.appendChild(button);
button.addEventListener('click', async () => {
const text = code.innerText;
try {
await navigator.clipboard.writeText(text);
button.textContent = 'Copied';
button.classList.add('is-copied');
setTimeout(() => {
button.textContent = 'Copy';
button.classList.remove('is-copied');
}, 1800);
} catch (error) {
button.textContent = 'Failed';
}
});
});
},
/**
* ============================================================
* SHARE BUTTONS
* ============================================================
*/
initShareButtons() {
const shareButtons = document.querySelectorAll('[data-rx-share]');
shareButtons.forEach((button) => {
button.addEventListener('click', async (event) => {
event.preventDefault();
const title = button.dataset.title || document.title;
const url = button.dataset.url || window.location.href;
const text = button.dataset.text || '';
if (navigator.share) {
try {
await navigator.share({ title, text, url });
} catch (error) {
// User cancelled share.
}
} else {
try {
await navigator.clipboard.writeText(url);
button.classList.add('is-copied');
button.textContent = button.dataset.copiedText || 'Link copied';
setTimeout(() => {
button.classList.remove('is-copied');
button.textContent = button.dataset.defaultText || 'Share';
}, 1800);
} catch (error) {
window.prompt('Copy this link:', url);
}
}
});
});
},
/**
* ============================================================
* COMMENT FORM ENHANCER
* ============================================================
*/
initCommentFormEnhancer() {
const form = document.querySelector(this.selectors.commentForm);
if (!form) return;
const textarea = form.querySelector('textarea');
if (textarea) {
this.addTextareaCounter(textarea, 3000);
this.autoResizeTextarea(textarea);
}
form.addEventListener('submit', (event) => {
const requiredFields = form.querySelectorAll('[required]');
let valid = true;
requiredFields.forEach((field) => {
if (!field.value.trim()) {
valid = false;
field.classList.add('has-error');
field.setAttribute('aria-invalid', 'true');
} else {
field.classList.remove('has-error');
field.removeAttribute('aria-invalid');
}
});
if (!valid) {
event.preventDefault();
const firstError = form.querySelector('.has-error');
if (firstError) firstError.focus();
}
});
},
addTextareaCounter(textarea, max) {
const counter = document.createElement('div');
counter.className = 'rx-character-counter';
counter.setAttribute('aria-live', 'polite');
textarea.insertAdjacentElement('afterend', counter);
const update = () => {
const count = textarea.value.length;
counter.textContent = `${count}/${max} characters`;
if (count > max) {
counter.classList.add('is-over-limit');
} else {
counter.classList.remove('is-over-limit');
}
};
textarea.addEventListener('input', update);
update();
},
autoResizeTextarea(textarea) {
const resize = () => {
textarea.style.height = 'auto';
textarea.style.height = `${textarea.scrollHeight}px`;
};
textarea.addEventListener('input', resize);
resize();
},
/**
* ============================================================
* IMAGE LIGHTBOX
* ============================================================
*/
initImageLightbox() {
const images = document.querySelectorAll(this.selectors.lightboxImage);
if (!images.length) return;
const overlay = document.createElement('div');
overlay.className = 'rx-lightbox';
overlay.setAttribute('hidden', 'hidden');
overlay.innerHTML = `
<button type="button" class="rx-lightbox-close" aria-label="Close image">×</button>
<img class="rx-lightbox-image" alt="">
`;
document.body.appendChild(overlay);
this.lightbox = overlay;
this.lightboxImage = overlay.querySelector('.rx-lightbox-image');
images.forEach((img) => {
if (img.closest('a')) return;
img.classList.add('rx-lightbox-trigger');
img.setAttribute('tabindex', '0');
img.setAttribute('role', 'button');
img.addEventListener('click', () => this.openLightbox(img));
img.addEventListener('keydown', (event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
this.openLightbox(img);
}
});
});
overlay.addEventListener('click', (event) => {
if (
event.target === overlay ||
event.target.classList.contains('rx-lightbox-close')
) {
this.closeLightbox();
}
});
},
openLightbox(img) {
if (!this.lightbox || !this.lightboxImage) return;
this.lightboxImage.src = img.currentSrc || img.src;
this.lightboxImage.alt = img.alt || '';
this.lightbox.removeAttribute('hidden');
this.lightbox.classList.add(this.settings.openClass);
this.body.classList.add('rx-lightbox-open');
const close = this.lightbox.querySelector('.rx-lightbox-close');
if (close) close.focus();
},
closeLightbox() {
if (!this.lightbox) return;
this.lightbox.classList.remove(this.settings.openClass);
this.body.classList.remove('rx-lightbox-open');
setTimeout(() => {
this.lightbox.setAttribute('hidden', 'hidden');
}, 200);
},
/**
* ============================================================
* FORM VALIDATION
* ============================================================
*/
initFormValidation() {
const forms = document.querySelectorAll('form.rx-validate, form[data-rx-validate]');
forms.forEach((form) => {
form.addEventListener('submit', (event) => {
const invalidFields = [];
form.querySelectorAll('input, select, textarea').forEach((field) => {
if (!this.validateField(field)) {
invalidFields.push(field);
}
});
if (invalidFields.length) {
event.preventDefault();
invalidFields[0].focus();
}
});
form.querySelectorAll('input, select, textarea').forEach((field) => {
field.addEventListener('blur', () => this.validateField(field));
field.addEventListener('input', () => {
if (field.classList.contains('has-error')) {
this.validateField(field);
}
});
});
});
},
validateField(field) {
if (!field.willValidate) return true;
const isValid = field.checkValidity();
field.classList.toggle('has-error', !isValid);
field.setAttribute('aria-invalid', isValid ? 'false' : 'true');
let message = field.parentNode.querySelector('.rx-field-error');
if (!isValid) {
if (!message) {
message = document.createElement('span');
message.className = 'rx-field-error';
field.insertAdjacentElement('afterend', message);
}
message.textContent = field.validationMessage;
} else if (message) {
message.remove();
}
return isValid;
},
/**
* ============================================================
* DARK MODE
* ============================================================
*/
initDarkMode() {
const toggles = document.querySelectorAll('[data-rx-dark-toggle], .rx-dark-toggle');
const saved = this.storageGet(this.settings.darkModeStorageKey);
if (saved === 'dark') {
this.html.classList.add('rx-dark-mode');
} else if (saved === 'light') {
this.html.classList.remove('rx-dark-mode');
} else if (
window.matchMedia &&
window.matchMedia('(prefers-color-scheme: dark)').matches
) {
this.html.classList.add('rx-dark-mode');
}
toggles.forEach((toggle) => {
toggle.addEventListener('click', () => {
const isDark = this.html.classList.toggle('rx-dark-mode');
this.storageSet(this.settings.darkModeStorageKey, isDark ? 'dark' : 'light');
toggle.setAttribute('aria-pressed', isDark ? 'true' : 'false');
});
});
},
/**
* ============================================================
* FONT SIZE CONTROLS
* ============================================================
*/
initFontSizeControls() {
const increase = document.querySelectorAll('[data-rx-font-increase]');
const decrease = document.querySelectorAll('[data-rx-font-decrease]');
const reset = document.querySelectorAll('[data-rx-font-reset]');
let size = parseInt(this.storageGet(this.settings.fontStorageKey) || '100', 10);
this.applyFontSize(size);
increase.forEach((btn) => {
btn.addEventListener('click', () => {
size = Math.min(size + 10, 140);
this.applyFontSize(size);
});
});
decrease.forEach((btn) => {
btn.addEventListener('click', () => {
size = Math.max(size - 10, 80);
this.applyFontSize(size);
});
});
reset.forEach((btn) => {
btn.addEventListener('click', () => {
size = 100;
this.applyFontSize(size);
});
});
},
applyFontSize(size) {
this.html.style.setProperty('--rx-user-font-size', `${size}%`);
this.storageSet(this.settings.fontStorageKey, String(size));
},
/**
* ============================================================
* SCROLL ANIMATIONS
* ============================================================
*/
initScrollAnimations() {
const elements = document.querySelectorAll('[data-rx-animate], .rx-animate');
if (!elements.length || this.state.reducedMotion) return;
if ('IntersectionObserver' in window) {
const observer = new IntersectionObserver((entries, obs) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return;
entry.target.classList.add(this.settings.animationClass);
obs.unobserve(entry.target);
});
}, {
threshold: 0.15
});
elements.forEach((el) => observer.observe(el));
} else {
elements.forEach((el) => el.classList.add(this.settings.animationClass));
}
},
/**
* ============================================================
* PRINT HELPERS
* ============================================================
*/
initPrintHelpers() {
const printButtons = document.querySelectorAll('[data-rx-print], .rx-print-button');
printButtons.forEach((button) => {
button.addEventListener('click', (event) => {
event.preventDefault();
window.print();
});
});
},
/**
* ============================================================
* RESPONSIVE TABLES
* ============================================================
*/
initResponsiveTables() {
const content = document.querySelector(this.selectors.content);
if (!content) return;
const tables = content.querySelectorAll('table');
tables.forEach((table) => {
if (table.parentElement.classList.contains('rx-table-wrap')) return;
const wrapper = document.createElement('div');
wrapper.className = 'rx-table-wrap';
wrapper.setAttribute('tabindex', '0');
table.parentNode.insertBefore(wrapper, table);
wrapper.appendChild(table);
});
this.refreshResponsiveTables();
},
refreshResponsiveTables() {
const wrappers = document.querySelectorAll('.rx-table-wrap');
wrappers.forEach((wrapper) => {
const isScrollable = wrapper.scrollWidth > wrapper.clientWidth;
wrapper.classList.toggle('is-scrollable', isScrollable);
});
},
/**
* ============================================================
* VIDEO EMBEDS
* ============================================================
*/
initVideoEmbeds() {
const iframes = document.querySelectorAll(
'iframe[src*="youtube.com"], iframe[src*="youtu.be"], iframe[src*="vimeo.com"]'
);
iframes.forEach((iframe) => {
if (iframe.parentElement.classList.contains('rx-video-wrap')) return;
const wrapper = document.createElement('div');
wrapper.className = 'rx-video-wrap';
iframe.parentNode.insertBefore(wrapper, iframe);
wrapper.appendChild(iframe);
iframe.setAttribute('loading', 'lazy');
});
},
/**
* ============================================================
* CODE BLOCK ENHANCER
* ============================================================
*/
initCodeBlocks() {
const codeBlocks = document.querySelectorAll('pre');
codeBlocks.forEach((pre) => {
pre.classList.add('rx-code-block');
if (!pre.querySelector('.rx-code-label')) {
const code = pre.querySelector('code');
const className = code ? code.className : '';
const match = className.match(/language-([a-z0-9]+)/i);
if (match) {
const label = document.createElement('span');
label.className = 'rx-code-label';
label.textContent = match[1].toUpperCase();
pre.appendChild(label);
}
}
});
},
/**
* ============================================================
* BREADCRUMB ENHANCER
* ============================================================
*/
initBreadcrumbEnhancer() {
const breadcrumbs = document.querySelectorAll('.breadcrumb, .breadcrumbs, .rx-breadcrumbs');
breadcrumbs.forEach((breadcrumb) => {
breadcrumb.setAttribute('aria-label', 'Breadcrumb');
breadcrumb.setAttribute('role', 'navigation');
const links = breadcrumb.querySelectorAll('a');
links.forEach((link, index) => {
if (index === links.length - 1) {
link.setAttribute('aria-current', 'page');
}
});
});
},
/**
* ============================================================
* KEYBOARD ACCESSIBILITY
* ============================================================
*/
initKeyboardAccessibility() {
document.addEventListener('keydown', (event) => {
if (event.key === 'Tab') {
this.body.classList.add('rx-keyboard-user');
}
});
document.addEventListener('mousedown', () => {
this.body.classList.remove('rx-keyboard-user');
});
},
/**
* ============================================================
* SKIP LINKS
* ============================================================
*/
initSkipLinks() {
const skipLink = document.querySelector('.skip-link, .screen-reader-text[href="#content"]');
if (!skipLink) return;
skipLink.addEventListener('click', () => {
const target = document.querySelector(skipLink.getAttribute('href'));
if (target) {
target.setAttribute('tabindex', '-1');
target.focus();
}
});
},
/**
* ============================================================
* COOKIE NOTICE
* ============================================================
*/
initCookieNotice() {
const notice = document.querySelector('[data-rx-cookie-notice], .rx-cookie-notice');
if (!notice) return;
const key = 'rx_cookie_notice_accepted';
if (this.storageGet(key) === 'yes') {
notice.remove();
return;
}
const accept = notice.querySelector('[data-rx-cookie-accept], .rx-cookie-accept');
if (accept) {
accept.addEventListener('click', () => {
this.storageSet(key, 'yes');
notice.classList.add('is-accepted');
setTimeout(() => notice.remove(), 250);
});
}
},
/**
* ============================================================
* NEWSLETTER BOX
* ============================================================
*/
initNewsletterBox() {
const boxes = document.querySelectorAll('[data-rx-newsletter], .rx-newsletter');
boxes.forEach((box) => {
const form = box.querySelector('form');
const email = box.querySelector('input[type="email"]');
if (!form || !email) return;
form.addEventListener('submit', (event) => {
if (!email.checkValidity()) {
event.preventDefault();
email.classList.add('has-error');
email.focus();
}
});
});
},
/**
* ============================================================
* AJAX LOAD MORE PLACEHOLDER
* ============================================================
* This prepares frontend button behavior.
* Real AJAX needs wp_localize_script + admin-ajax.php PHP handler.
*/
initAjaxLoadMorePlaceholder() {
const buttons = document.querySelectorAll('[data-rx-load-more]');
buttons.forEach((button) => {
button.addEventListener('click', () => {
if (!window.rxThemeAjax || !window.rxThemeAjax.ajaxUrl) {
button.classList.add('is-disabled');
button.textContent = 'Load more is not connected';
return;
}
button.classList.add('is-loading');
button.setAttribute('disabled', 'disabled');
});
});
},
/**
* ============================================================
* SERVICE WORKER HELPER
* ============================================================
* Only registers if rx-sw.js exists and browser supports it.
*/
initServiceWorkerHelper() {
if (!('serviceWorker' in navigator)) return;
if (!window.rxThemeSettings || !window.rxThemeSettings.enableServiceWorker) return;
window.addEventListener('load', () => {
navigator.serviceWorker.register('/rx-sw.js').catch(() => {
// Silent fail. Service worker is optional.
});
});
},
/**
* ============================================================
* UTILITIES
* ============================================================
*/
slugify(text) {
return String(text)
.toLowerCase()
.trim()
.replace(/&/g, 'and')
.replace(/[\s\W-]+/g, '-')
.replace(/^-+|-+$/g, '');
},
debounce(callback, delay) {
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => {
callback.apply(this, args);
}, delay);
};
},
throttle(callback, delay) {
let waiting = false;
return function (...args) {
if (waiting) return;
callback.apply(this, args);
waiting = true;
setTimeout(() => {
waiting = false;
}, delay);
};
},
storageGet(key) {
try {
return window.localStorage.getItem(key);
} catch (error) {
return null;
}
},
storageSet(key, value) {
try {
window.localStorage.setItem(key, value);
} catch (error) {
// localStorage may be blocked.
}
}
};
/**
* ============================================================
* DOM READY
* ============================================================
*/
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => RXTheme.init());
} else {
RXTheme.init();
}
window.RXTheme = RXTheme;
})();
Now enqueue it in your functions.php:
function rx_theme_enqueue_chunks_js() {
wp_enqueue_script(
'rx-theme-chunks',
get_template_directory_uri() . '/inc/chunks/chunks.js',
array(),
wp_get_theme()->get('Version'),
true
);
}
add_action('wp_enqueue_scripts', 'rx_theme_enqueue_chunks_js');
For best performance, also create this folder:
rx-theme/inc/chunks/
Your file path should be exactly:
rx-theme/inc/chunks/chunks.js
Below is the clean combined final RX Theme structure. I merged both ideas and removed duplication.
Best decision: keep PHP files inside inc/, and keep CSS/JS/chunks inside assets/.
rx-theme/
├── style.css
├── functions.php
├── index.php
├── header.php
├── footer.php
├── sidebar.php
├── single.php
├── page.php
├── archive.php
├── search.php
├── 404.php
├── comments.php
├── screenshot.png
│
├── inc/
│ ├── core/
│ │ ├── theme-setup.php
│ │ ├── enqueue.php
│ │ ├── menus.php
│ │ ├── sidebars.php
│ │ ├── image-sizes.php
│ │ └── cleanup.php
│ │
│ ├── helpers/
│ │ ├── template-functions.php
│ │ ├── sanitization.php
│ │ ├── breadcrumbs.php
│ │ ├── reading-time.php
│ │ ├── related-posts.php
│ │ ├── pagination.php
│ │ └── schema.php
│ │
│ ├── seo/
│ │ ├── meta-tags.php
│ │ ├── canonical.php
│ │ ├── sitemap.php
│ │ ├── robots.php
│ │ ├── schema-article.php
│ │ └── indexnow.php
│ │
│ ├── performance/
│ │ ├── preload.php
│ │ ├── preconnect.php
│ │ ├── cache-headers.php
│ │ ├── lazy-loading.php
│ │ ├── defer-scripts.php
│ │ └── critical-css.php
│ │
│ ├── security/
│ │ ├── hardening.php
│ │ ├── uploads.php
│ │ ├── rest-api.php
│ │ └── login-security.php
│ │
│ ├── options/
│ │ ├── customizer.php
│ │ ├── theme-options.php
│ │ ├── color-options.php
│ │ ├── typography-options.php
│ │ └── layout-options.php
│ │
│ ├── admin/
│ │ ├── admin-page.php
│ │ ├── dashboard-widgets.php
│ │ ├── system-status.php
│ │ └── notice.php
│ │
│ ├── builders/
│ │ ├── header-builder.php
│ │ ├── footer-builder.php
│ │ ├── layout-builder.php
│ │ ├── sidebar-builder.php
│ │ └── hook-builder.php
│ │
│ ├── post-types/
│ │ ├── portfolio.php
│ │ ├── medical-library.php
│ │ ├── review-board.php
│ │ ├── glossary.php
│ │ └── faq.php
│ │
│ ├── taxonomies/
│ │ ├── medical-category.php
│ │ ├── disease-type.php
│ │ └── article-level.php
│ │
│ ├── shortcodes/
│ │ ├── buttons.php
│ │ ├── alerts.php
│ │ ├── medical-boxes.php
│ │ ├── faq.php
│ │ └── table-of-contents.php
│ │
│ ├── widgets/
│ │ ├── recent-posts-widget.php
│ │ ├── related-posts-widget.php
│ │ ├── medical-toc-widget.php
│ │ └── author-box-widget.php
│ │
│ ├── ajax/
│ │ ├── load-more.php
│ │ ├── live-search.php
│ │ ├── filter-posts.php
│ │ └── newsletter.php
│ │
│ ├── woocommerce/
│ │ ├── woocommerce-setup.php
│ │ ├── product-layout.php
│ │ ├── cart.php
│ │ └── checkout.php
│ │
│ └── integrations/
│ ├── rank-math.php
│ ├── yoast.php
│ ├── elementor.php
│ ├── gutenberg.php
│ └── cloudflare.php
│
├── template-parts/
│ ├── header/
│ │ ├── site-branding.php
│ │ ├── primary-menu.php
│ │ ├── mobile-menu.php
│ │ └── search-toggle.php
│ │
│ ├── footer/
│ │ ├── footer-widgets.php
│ │ ├── footer-menu.php
│ │ └── footer-bottom.php
│ │
│ ├── content/
│ │ ├── content.php
│ │ ├── content-single.php
│ │ ├── content-page.php
│ │ ├── content-archive.php
│ │ ├── content-search.php
│ │ └── content-none.php
│ │
│ ├── post/
│ │ ├── post-meta.php
│ │ ├── author-box.php
│ │ ├── related-posts.php
│ │ └── post-navigation.php
│ │
│ └── components/
│ ├── breadcrumbs.php
│ ├── pagination.php
│ ├── social-share.php
│ ├── table-of-contents.php
│ └── scroll-top.php
│
├── assets/
│ ├── css/
│ │ ├── app.css
│ │ ├── header.css
│ │ ├── footer.css
│ │ ├── layout.css
│ │ ├── blog.css
│ │ ├── single.css
│ │ ├── page.css
│ │ ├── archive.css
│ │ ├── search.css
│ │ ├── medical.css
│ │ ├── citation.css
│ │ ├── wiki.css
│ │ ├── table.css
│ │ ├── forms.css
│ │ ├── widgets.css
│ │ ├── woocommerce.css
│ │ ├── dark-mode.css
│ │ ├── responsive.css
│ │ └── print.css
│ │
│ ├── js/
│ │ ├── app.js
│ │ ├── mobile-menu.js
│ │ ├── dark-mode.js
│ │ ├── search.js
│ │ ├── modal.js
│ │ ├── tabs.js
│ │ ├── accordion.js
│ │ ├── ajax-load-more.js
│ │ ├── single-post.js
│ │ └── woocommerce.js
│ │
│ ├── chunks/
│ │ ├── chunk-001-core.js
│ │ ├── chunk-002-header.js
│ │ ├── chunk-003-mobile-menu.js
│ │ ├── chunk-004-search.js
│ │ ├── chunk-005-dark-mode.js
│ │ ├── chunk-006-back-to-top.js
│ │ ├── chunk-007-reading-progress.js
│ │ ├── chunk-008-lazyload.js
│ │ ├── chunk-009-toc.js
│ │ ├── chunk-010-accordion.js
│ │ ├── chunk-011-tabs.js
│ │ ├── chunk-012-copy-code.js
│ │ ├── chunk-013-lightbox.js
│ │ ├── chunk-014-share.js
│ │ ├── chunk-015-comments.js
│ │ ├── chunk-016-forms.js
│ │ ├── chunk-017-table.js
│ │ ├── chunk-018-video.js
│ │ ├── chunk-019-scroll-animation.js
│ │ ├── chunk-020-print.js
│ │ ├── chunk-021-accessibility.js
│ │ ├── chunk-022-breadcrumb.js
│ │ ├── chunk-023-sticky-sidebar.js
│ │ ├── chunk-024-newsletter.js
│ │ ├── chunk-025-cookie-notice.js
│ │ ├── chunk-026-popup.js
│ │ ├── chunk-027-load-more.js
│ │ ├── chunk-028-filter-posts.js
│ │ ├── chunk-029-pagination.js
│ │ ├── chunk-030-related-posts.js
│ │ ├── chunk-031-schema-helper.js
│ │ ├── chunk-032-font-size.js
│ │ ├── chunk-033-theme-mode.js
│ │ ├── chunk-034-reading-time.js
│ │ ├── chunk-035-progress-circle.js
│ │ ├── chunk-036-notification.js
│ │ ├── chunk-037-marquee.js
│ │ ├── chunk-038-slider.js
│ │ ├── chunk-039-carousel.js
│ │ ├── chunk-040-gallery.js
│ │ ├── chunk-041-medical-card.js
│ │ ├── chunk-042-faq.js
│ │ ├── chunk-043-author-box.js
│ │ ├── chunk-044-scrollspy.js
│ │ ├── chunk-045-ajax-search.js
│ │ ├── chunk-046-pwa.js
│ │ ├── chunk-047-performance.js
│ │ ├── chunk-048-security-ui.js
│ │ ├── chunk-049-seo-ui.js
│ │ └── chunk-050-final.js
│ │
│ ├── dynamic/
│ │ ├── css/
│ │ │ ├── style-001.css
│ │ │ ├── style-002.css
│ │ │ └── style-003.css
│ │ │
│ │ ├── js/
│ │ │ ├── script-001.js
│ │ │ ├── script-002.js
│ │ │ └── script-003.js
│ │ │
│ │ ├── apps/
│ │ │ ├── app-001.js
│ │ │ ├── app-002.js
│ │ │ └── app-003.js
│ │ │
│ │ └── chunks/
│ │ ├── chunk-001.js
│ │ ├── chunk-002.js
│ │ └── chunk-003.js
│ │
│ ├── fonts/
│ │ ├── rx-regular.woff2
│ │ └── rx-bold.woff2
│ │
│ ├── images/
│ │ ├── logo.png
│ │ └── placeholder.png
│ │
│ ├── icons/
│ │ └── rx-icons.svg
│ │
│ ├── vendor/
│ │ ├── vendor.css
│ │ └── vendor.js
│ │
│ ├── generated/
│ │ ├── python/
│ │ ├── go/
│ │ └── rust/
│ │
│ ├── wasm/
│ │ ├── rust-app.js
│ │ ├── rust-app_bg.wasm
│ │ ├── wasm_exec.js
│ │ └── go-app.js
│ │
│ └── critical/
│ ├── critical.css
│ └── critical-inline.css
│
└── languages/
└── rx-theme.pot
Important correction
Do not keep chunks in both places:
inc/chunks/
assets/chunks/
Use only this:
assets/chunks/
Because inc/ is better for PHP logic, and assets/ is better for CSS, JS, images, fonts, chunks, dynamic files, and app files.
Best chunk naming system
Use this style:
chunk-001-core.js
chunk-002-header.js
chunk-003-mobile-menu.js
...
chunk-050-final.js
This is better than:
chunk-1-core.js
chunk-2-header.js
Because 001, 002, 003 keeps files perfectly sorted in Windows, VS Code, cPanel, and Hostinger File Manager.
Final answer
Your final RX Theme should use:
PHP modules: rx-theme/inc/
Template parts: rx-theme/template-parts/
CSS/JS/assets: rx-theme/assets/
JS chunks: rx-theme/assets/chunks/
Dynamic assets: rx-theme/assets/dynamic/
Language file: rx-theme/languages/
This is a very strong professional structure for your RX Theme.
Yes friend — below is the final combined RX Theme structure. I merged your new structure with the first advanced structure, kept the best naming system, and removed confusing duplicate folders where possible. Based on your uploaded theme structure reference:
Best rule:
inc/ = PHP logic
template-parts/ = reusable PHP template sections
templates/ = WordPress page templates
assets/css/ = static CSS
assets/js/ = main JS
assets/app/ = advanced app JS
assets/chunks/ = feature-based chunk JS
assets/dynamic/ = user/admin/generated dynamic assets
Final RX Theme Combined Structure
rx-theme/
├── style.css
├── functions.php
├── index.php
├── header.php
├── footer.php
├── sidebar.php
├── single.php
├── page.php
├── archive.php
├── search.php
├── 404.php
├── comments.php
├── screenshot.png
├── README.md
│
├── assets/
│ ├── css/
│ │ ├── 01-rx-reset.css
│ │ ├── 02-rx-variables.css
│ │ ├── 03-rx-base.css
│ │ ├── 04-rx-layout.css
│ │ ├── 05-rx-header.css
│ │ ├── 06-rx-footer.css
│ │ ├── 07-rx-components.css
│ │ ├── 08-rx-blog.css
│ │ ├── 09-rx-single.css
│ │ ├── 10-rx-page.css
│ │ ├── 11-rx-archive.css
│ │ ├── 12-rx-search.css
│ │ ├── 13-rx-medical.css
│ │ ├── 14-rx-citation.css
│ │ ├── 15-rx-wiki.css
│ │ ├── 16-rx-table.css
│ │ ├── 17-rx-forms.css
│ │ ├── 18-rx-widgets.css
│ │ ├── 19-rx-woocommerce.css
│ │ ├── 20-rx-dark-mode.css
│ │ ├── 21-rx-responsive.css
│ │ └── 22-rx-print.css
│ │
│ ├── js/
│ │ ├── rx-main.js
│ │ ├── rx-navigation.js
│ │ ├── rx-mobile-menu.js
│ │ ├── rx-search.js
│ │ ├── rx-modal.js
│ │ ├── rx-toc.js
│ │ ├── rx-accordion.js
│ │ ├── rx-tabs.js
│ │ ├── rx-dark-mode.js
│ │ ├── rx-ajax-load-more.js
│ │ ├── rx-single-post.js
│ │ └── rx-woocommerce.js
│ │
│ ├── app/
│ │ ├── rx-app.js
│ │ ├── rx-medical-library-app.js
│ │ ├── rx-live-search-app.js
│ │ ├── rx-dashboard-app.js
│ │ └── rx-review-board-app.js
│ │
│ ├── chunks/
│ │ ├── chunk-001-core.js
│ │ ├── chunk-002-header.js
│ │ ├── chunk-003-mobile-menu.js
│ │ ├── chunk-004-search.js
│ │ ├── chunk-005-dark-mode.js
│ │ ├── chunk-006-back-to-top.js
│ │ ├── chunk-007-reading-progress.js
│ │ ├── chunk-008-lazyload.js
│ │ ├── chunk-009-toc.js
│ │ ├── chunk-010-accordion.js
│ │ ├── chunk-011-tabs.js
│ │ ├── chunk-012-copy-code.js
│ │ ├── chunk-013-lightbox.js
│ │ ├── chunk-014-share.js
│ │ ├── chunk-015-comments.js
│ │ ├── chunk-016-forms.js
│ │ ├── chunk-017-table.js
│ │ ├── chunk-018-video.js
│ │ ├── chunk-019-scroll-animation.js
│ │ ├── chunk-020-print.js
│ │ ├── chunk-021-accessibility.js
│ │ ├── chunk-022-breadcrumb.js
│ │ ├── chunk-023-sticky-sidebar.js
│ │ ├── chunk-024-newsletter.js
│ │ ├── chunk-025-cookie-notice.js
│ │ ├── chunk-026-popup.js
│ │ ├── chunk-027-load-more.js
│ │ ├── chunk-028-filter-posts.js
│ │ ├── chunk-029-pagination.js
│ │ ├── chunk-030-related-posts.js
│ │ ├── chunk-031-schema-helper.js
│ │ ├── chunk-032-font-size.js
│ │ ├── chunk-033-theme-mode.js
│ │ ├── chunk-034-reading-time.js
│ │ ├── chunk-035-progress-circle.js
│ │ ├── chunk-036-notification.js
│ │ ├── chunk-037-marquee.js
│ │ ├── chunk-038-slider.js
│ │ ├── chunk-039-carousel.js
│ │ ├── chunk-040-gallery.js
│ │ ├── chunk-041-medical-card.js
│ │ ├── chunk-042-faq.js
│ │ ├── chunk-043-author-box.js
│ │ ├── chunk-044-scrollspy.js
│ │ ├── chunk-045-ajax-search.js
│ │ ├── chunk-046-pwa.js
│ │ ├── chunk-047-performance.js
│ │ ├── chunk-048-security-ui.js
│ │ ├── chunk-049-seo-ui.js
│ │ └── chunk-050-final.js
│ │
│ ├── dynamic/
│ │ ├── css/
│ │ │ ├── style-001.css
│ │ │ ├── style-002.css
│ │ │ └── style-003.css
│ │ │
│ │ ├── js/
│ │ │ ├── script-001.js
│ │ │ ├── script-002.js
│ │ │ └── script-003.js
│ │ │
│ │ ├── apps/
│ │ │ ├── app-001.js
│ │ │ ├── app-002.js
│ │ │ └── app-003.js
│ │ │
│ │ └── chunks/
│ │ ├── chunk-001.js
│ │ ├── chunk-002.js
│ │ └── chunk-003.js
│ │
│ ├── images/
│ │ ├── rx-logo.svg
│ │ ├── rx-logo-dark.svg
│ │ ├── rx-favicon.png
│ │ ├── rx-placeholder.webp
│ │ ├── rx-doctor-avatar.webp
│ │ └── rx-medical-hero.webp
│ │
│ ├── fonts/
│ │ └── .gitkeep
│ │
│ ├── icons/
│ │ └── rx-icons.svg
│ │
│ ├── vendor/
│ │ ├── vendor.css
│ │ └── vendor.js
│ │
│ ├── generated/
│ │ ├── python/
│ │ ├── go/
│ │ └── rust/
│ │
│ ├── wasm/
│ │ ├── rust-app.js
│ │ ├── rust-app_bg.wasm
│ │ ├── wasm_exec.js
│ │ └── go-app.js
│ │
│ └── critical/
│ ├── critical.css
│ └── critical-inline.css
│
├── inc/
│ ├── core/
│ │ ├── theme-setup.php
│ │ ├── enqueue.php
│ │ ├── menus.php
│ │ ├── sidebars.php
│ │ ├── image-sizes.php
│ │ └── cleanup.php
│ │
│ ├── helpers/
│ │ ├── template-functions.php
│ │ ├── sanitization.php
│ │ ├── breadcrumbs.php
│ │ ├── reading-time.php
│ │ ├── related-posts.php
│ │ ├── pagination.php
│ │ └── schema.php
│ │
│ ├── seo/
│ │ ├── meta-tags.php
│ │ ├── canonical.php
│ │ ├── sitemap.php
│ │ ├── robots.php
│ │ ├── schema-article.php
│ │ └── indexnow.php
│ │
│ ├── performance/
│ │ ├── preload.php
│ │ ├── preconnect.php
│ │ ├── resource-hints.php
│ │ ├── font-optimization.php
│ │ ├── cache-headers.php
│ │ ├── lazy-loading.php
│ │ ├── defer-scripts.php
│ │ ├── critical-css.php
│ │ └── web-vitals.php
│ │
│ ├── css/
│ │ ├── dynamic-css.php
│ │ ├── colors-css.php
│ │ ├── typography-css.php
│ │ ├── layout-css.php
│ │ ├── customizer-css.php
│ │ └── critical-css.php
│ │
│ ├── security/
│ │ ├── hardening.php
│ │ ├── uploads.php
│ │ ├── rest-api.php
│ │ └── login-security.php
│ │
│ ├── options/
│ │ ├── customizer.php
│ │ ├── theme-options.php
│ │ ├── color-options.php
│ │ ├── typography-options.php
│ │ └── layout-options.php
│ │
│ ├── admin/
│ │ ├── admin-page.php
│ │ ├── dashboard-widgets.php
│ │ ├── system-status.php
│ │ └── notice.php
│ │
│ ├── builders/
│ │ ├── header-builder.php
│ │ ├── footer-builder.php
│ │ ├── layout-builder.php
│ │ ├── sidebar-builder.php
│ │ └── hook-builder.php
│ │
│ ├── post-types/
│ │ ├── portfolio.php
│ │ ├── medical-library.php
│ │ ├── review-board.php
│ │ ├── glossary.php
│ │ └── faq.php
│ │
│ ├── taxonomies/
│ │ ├── medical-category.php
│ │ ├── disease-type.php
│ │ └── article-level.php
│ │
│ ├── shortcodes/
│ │ ├── buttons.php
│ │ ├── alerts.php
│ │ ├── medical-boxes.php
│ │ ├── faq.php
│ │ └── table-of-contents.php
│ │
│ ├── widgets/
│ │ ├── recent-posts-widget.php
│ │ ├── related-posts-widget.php
│ │ ├── medical-toc-widget.php
│ │ └── author-box-widget.php
│ │
│ ├── ajax/
│ │ ├── load-more.php
│ │ ├── live-search.php
│ │ ├── filter-posts.php
│ │ └── newsletter.php
│ │
│ ├── woocommerce/
│ │ ├── woocommerce-setup.php
│ │ ├── product-layout.php
│ │ ├── cart.php
│ │ └── checkout.php
│ │
│ └── integrations/
│ ├── rank-math.php
│ ├── yoast.php
│ ├── elementor.php
│ ├── gutenberg.php
│ └── cloudflare.php
│
├── template-parts/
│ ├── header/
│ │ ├── site-branding.php
│ │ ├── primary-menu.php
│ │ ├── mobile-menu.php
│ │ └── search-toggle.php
│ │
│ ├── footer/
│ │ ├── footer-widgets.php
│ │ ├── footer-menu.php
│ │ └── footer-bottom.php
│ │
│ ├── content/
│ │ ├── content.php
│ │ ├── content-single.php
│ │ ├── content-page.php
│ │ ├── content-archive.php
│ │ ├── content-search.php
│ │ └── content-none.php
│ │
│ ├── post/
│ │ ├── post-meta.php
│ │ ├── author-box.php
│ │ ├── related-posts.php
│ │ └── post-navigation.php
│ │
│ ├── sidebar/
│ │ ├── sidebar-primary.php
│ │ ├── sidebar-single.php
│ │ └── sidebar-medical.php
│ │
│ ├── medical/
│ │ ├── medical-card.php
│ │ ├── disease-summary.php
│ │ ├── evidence-box.php
│ │ ├── citation-box.php
│ │ └── review-board-box.php
│ │
│ ├── blocks/
│ │ ├── block-alert.php
│ │ ├── block-faq.php
│ │ ├── block-table.php
│ │ ├── block-medical-note.php
│ │ └── block-reference.php
│ │
│ └── components/
│ ├── breadcrumbs.php
│ ├── pagination.php
│ ├── social-share.php
│ ├── table-of-contents.php
│ └── scroll-top.php
│
├── templates/
│ ├── template-full-width.php
│ ├── template-left-sidebar.php
│ ├── template-right-sidebar.php
│ ├── template-medical-library.php
│ ├── template-review-board.php
│ └── template-contact.php
│
└── languages/
└── rx-theme.pot
Most important correction
Do not use both of these for normal chunks:
assets/chunks/
assets/dynamic/chunks/
Use them differently:
assets/chunks/
For your real theme feature chunks.
assets/dynamic/chunks/
Only for admin-generated, future, optional, or CDN-created dynamic chunk files.
Best final naming system
For static CSS:
01-rx-reset.css
02-rx-variables.css
03-rx-base.css
For normal JS:
rx-main.js
rx-navigation.js
rx-search.js
For chunks:
chunk-001-core.js
chunk-002-header.js
chunk-003-mobile-menu.js
For dynamic generated files:
style-001.css
script-001.js
app-001.js
chunk-001.js
This final structure is clean, advanced, scalable, and good for your RX Theme dream project.
Yes dear friend — in assets/dynamic/ you can use real meaningful file names, not only style-001.css, script-001.js, etc. This will be easier to understand later.
Below is the updated full final RX Theme structure, with the dynamic/ section expanded using 5–10 real names. I kept your previous final structure and improved only the dynamic part. Your original uploaded structure is used as the base reference.
rx-theme/
├── style.css
├── functions.php
├── index.php
├── header.php
├── footer.php
├── sidebar.php
├── single.php
├── page.php
├── archive.php
├── search.php
├── 404.php
├── comments.php
├── screenshot.png
├── README.md
│
├── assets/
│ ├── css/
│ │ ├── 01-rx-reset.css
│ │ ├── 02-rx-variables.css
│ │ ├── 03-rx-base.css
│ │ ├── 04-rx-layout.css
│ │ ├── 05-rx-header.css
│ │ ├── 06-rx-footer.css
│ │ ├── 07-rx-components.css
│ │ ├── 08-rx-blog.css
│ │ ├── 09-rx-single.css
│ │ ├── 10-rx-page.css
│ │ ├── 11-rx-archive.css
│ │ ├── 12-rx-search.css
│ │ ├── 13-rx-medical.css
│ │ ├── 14-rx-citation.css
│ │ ├── 15-rx-wiki.css
│ │ ├── 16-rx-table.css
│ │ ├── 17-rx-forms.css
│ │ ├── 18-rx-widgets.css
│ │ ├── 19-rx-woocommerce.css
│ │ ├── 20-rx-dark-mode.css
│ │ ├── 21-rx-responsive.css
│ │ └── 22-rx-print.css
│ │
│ ├── js/
│ │ ├── rx-main.js
│ │ ├── rx-navigation.js
│ │ ├── rx-mobile-menu.js
│ │ ├── rx-search.js
│ │ ├── rx-modal.js
│ │ ├── rx-toc.js
│ │ ├── rx-accordion.js
│ │ ├── rx-tabs.js
│ │ ├── rx-dark-mode.js
│ │ ├── rx-ajax-load-more.js
│ │ ├── rx-single-post.js
│ │ └── rx-woocommerce.js
│ │
│ ├── app/
│ │ ├── rx-app.js
│ │ ├── rx-medical-library-app.js
│ │ ├── rx-live-search-app.js
│ │ ├── rx-dashboard-app.js
│ │ └── rx-review-board-app.js
│ │
│ ├── chunks/
│ │ ├── chunk-001-core.js
│ │ ├── chunk-002-header.js
│ │ ├── chunk-003-mobile-menu.js
│ │ ├── chunk-004-search.js
│ │ ├── chunk-005-dark-mode.js
│ │ ├── chunk-006-back-to-top.js
│ │ ├── chunk-007-reading-progress.js
│ │ ├── chunk-008-lazyload.js
│ │ ├── chunk-009-toc.js
│ │ ├── chunk-010-accordion.js
│ │ ├── chunk-011-tabs.js
│ │ ├── chunk-012-copy-code.js
│ │ ├── chunk-013-lightbox.js
│ │ ├── chunk-014-share.js
│ │ ├── chunk-015-comments.js
│ │ ├── chunk-016-forms.js
│ │ ├── chunk-017-table.js
│ │ ├── chunk-018-video.js
│ │ ├── chunk-019-scroll-animation.js
│ │ ├── chunk-020-print.js
│ │ ├── chunk-021-accessibility.js
│ │ ├── chunk-022-breadcrumb.js
│ │ ├── chunk-023-sticky-sidebar.js
│ │ ├── chunk-024-newsletter.js
│ │ ├── chunk-025-cookie-notice.js
│ │ ├── chunk-026-popup.js
│ │ ├── chunk-027-load-more.js
│ │ ├── chunk-028-filter-posts.js
│ │ ├── chunk-029-pagination.js
│ │ ├── chunk-030-related-posts.js
│ │ ├── chunk-031-schema-helper.js
│ │ ├── chunk-032-font-size.js
│ │ ├── chunk-033-theme-mode.js
│ │ ├── chunk-034-reading-time.js
│ │ ├── chunk-035-progress-circle.js
│ │ ├── chunk-036-notification.js
│ │ ├── chunk-037-marquee.js
│ │ ├── chunk-038-slider.js
│ │ ├── chunk-039-carousel.js
│ │ ├── chunk-040-gallery.js
│ │ ├── chunk-041-medical-card.js
│ │ ├── chunk-042-faq.js
│ │ ├── chunk-043-author-box.js
│ │ ├── chunk-044-scrollspy.js
│ │ ├── chunk-045-ajax-search.js
│ │ ├── chunk-046-pwa.js
│ │ ├── chunk-047-performance.js
│ │ ├── chunk-048-security-ui.js
│ │ ├── chunk-049-seo-ui.js
│ │ └── chunk-050-final.js
│ │
│ ├── dynamic/
│ │ ├── css/
│ │ │ ├── dynamic-global.css
│ │ │ ├── dynamic-colors.css
│ │ │ ├── dynamic-typography.css
│ │ │ ├── dynamic-layout.css
│ │ │ ├── dynamic-header.css
│ │ │ ├── dynamic-footer.css
│ │ │ ├── dynamic-medical.css
│ │ │ ├── dynamic-dark-mode.css
│ │ │ ├── dynamic-customizer.css
│ │ │ └── dynamic-critical.css
│ │ │
│ │ ├── js/
│ │ │ ├── dynamic-global.js
│ │ │ ├── dynamic-customizer.js
│ │ │ ├── dynamic-header.js
│ │ │ ├── dynamic-footer.js
│ │ │ ├── dynamic-layout.js
│ │ │ ├── dynamic-live-search.js
│ │ │ ├── dynamic-filter-posts.js
│ │ │ ├── dynamic-medical-tools.js
│ │ │ ├── dynamic-dark-mode.js
│ │ │ └── dynamic-performance.js
│ │ │
│ │ ├── apps/
│ │ │ ├── dynamic-medical-library-app.js
│ │ │ ├── dynamic-live-search-app.js
│ │ │ ├── dynamic-review-board-app.js
│ │ │ ├── dynamic-dashboard-app.js
│ │ │ ├── dynamic-glossary-app.js
│ │ │ ├── dynamic-faq-app.js
│ │ │ ├── dynamic-calculator-app.js
│ │ │ ├── dynamic-citation-app.js
│ │ │ ├── dynamic-author-app.js
│ │ │ └── dynamic-admin-panel-app.js
│ │ │
│ │ └── chunks/
│ │ ├── dynamic-search.chunk.js
│ │ ├── dynamic-filter.chunk.js
│ │ ├── dynamic-table.chunk.js
│ │ ├── dynamic-chart.chunk.js
│ │ ├── dynamic-medical-card.chunk.js
│ │ ├── dynamic-faq.chunk.js
│ │ ├── dynamic-toc.chunk.js
│ │ ├── dynamic-citation.chunk.js
│ │ ├── dynamic-load-more.chunk.js
│ │ └── dynamic-review-board.chunk.js
│ │
│ ├── images/
│ │ ├── rx-logo.svg
│ │ ├── rx-logo-dark.svg
│ │ ├── rx-favicon.png
│ │ ├── rx-placeholder.webp
│ │ ├── rx-doctor-avatar.webp
│ │ └── rx-medical-hero.webp
│ │
│ ├── fonts/
│ │ └── .gitkeep
│ │
│ ├── icons/
│ │ └── rx-icons.svg
│ │
│ ├── vendor/
│ │ ├── vendor.css
│ │ └── vendor.js
│ │
│ ├── generated/
│ │ ├── python/
│ │ ├── go/
│ │ └── rust/
│ │
│ ├── wasm/
│ │ ├── rust-app.js
│ │ ├── rust-app_bg.wasm
│ │ ├── wasm_exec.js
│ │ └── go-app.js
│ │
│ └── critical/
│ ├── critical.css
│ └── critical-inline.css
│
├── inc/
│ ├── core/
│ │ ├── theme-setup.php
│ │ ├── enqueue.php
│ │ ├── menus.php
│ │ ├── sidebars.php
│ │ ├── image-sizes.php
│ │ └── cleanup.php
│ │
│ ├── helpers/
│ │ ├── template-functions.php
│ │ ├── sanitization.php
│ │ ├── breadcrumbs.php
│ │ ├── reading-time.php
│ │ ├── related-posts.php
│ │ ├── pagination.php
│ │ └── schema.php
│ │
│ ├── seo/
│ │ ├── meta-tags.php
│ │ ├── canonical.php
│ │ ├── sitemap.php
│ │ ├── robots.php
│ │ ├── schema-article.php
│ │ └── indexnow.php
│ │
│ ├── performance/
│ │ ├── preload.php
│ │ ├── preconnect.php
│ │ ├── resource-hints.php
│ │ ├── font-optimization.php
│ │ ├── cache-headers.php
│ │ ├── lazy-loading.php
│ │ ├── defer-scripts.php
│ │ ├── critical-css.php
│ │ └── web-vitals.php
│ │
│ ├── css/
│ │ ├── dynamic-css.php
│ │ ├── colors-css.php
│ │ ├── typography-css.php
│ │ ├── layout-css.php
│ │ ├── customizer-css.php
│ │ └── critical-css.php
│ │
│ ├── security/
│ │ ├── hardening.php
│ │ ├── uploads.php
│ │ ├── rest-api.php
│ │ └── login-security.php
│ │
│ ├── options/
│ │ ├── customizer.php
│ │ ├── theme-options.php
│ │ ├── color-options.php
│ │ ├── typography-options.php
│ │ └── layout-options.php
│ │
│ ├── admin/
│ │ ├── admin-page.php
│ │ ├── dashboard-widgets.php
│ │ ├── system-status.php
│ │ └── notice.php
│ │
│ ├── builders/
│ │ ├── header-builder.php
│ │ ├── footer-builder.php
│ │ ├── layout-builder.php
│ │ ├── sidebar-builder.php
│ │ └── hook-builder.php
│ │
│ ├── post-types/
│ │ ├── portfolio.php
│ │ ├── medical-library.php
│ │ ├── review-board.php
│ │ ├── glossary.php
│ │ └── faq.php
│ │
│ ├── taxonomies/
│ │ ├── medical-category.php
│ │ ├── disease-type.php
│ │ └── article-level.php
│ │
│ ├── shortcodes/
│ │ ├── buttons.php
│ │ ├── alerts.php
│ │ ├── medical-boxes.php
│ │ ├── faq.php
│ │ └── table-of-contents.php
│ │
│ ├── widgets/
│ │ ├── recent-posts-widget.php
│ │ ├── related-posts-widget.php
│ │ ├── medical-toc-widget.php
│ │ └── author-box-widget.php
│ │
│ ├── ajax/
│ │ ├── load-more.php
│ │ ├── live-search.php
│ │ ├── filter-posts.php
│ │ └── newsletter.php
│ │
│ ├── woocommerce/
│ │ ├── woocommerce-setup.php
│ │ ├── product-layout.php
│ │ ├── cart.php
│ │ └── checkout.php
│ │
│ └── integrations/
│ ├── rank-math.php
│ ├── yoast.php
│ ├── elementor.php
│ ├── gutenberg.php
│ └── cloudflare.php
│
├── template-parts/
│ ├── header/
│ │ ├── site-branding.php
│ │ ├── primary-menu.php
│ │ ├── mobile-menu.php
│ │ └── search-toggle.php
│ │
│ ├── footer/
│ │ ├── footer-widgets.php
│ │ ├── footer-menu.php
│ │ └── footer-bottom.php
│ │
│ ├── content/
│ │ ├── content.php
│ │ ├── content-single.php
│ │ ├── content-page.php
│ │ ├── content-archive.php
│ │ ├── content-search.php
│ │ └── content-none.php
│ │
│ ├── post/
│ │ ├── post-meta.php
│ │ ├── author-box.php
│ │ ├── related-posts.php
│ │ └── post-navigation.php
│ │
│ ├── sidebar/
│ │ ├── sidebar-primary.php
│ │ ├── sidebar-single.php
│ │ └── sidebar-medical.php
│ │
│ ├── medical/
│ │ ├── medical-card.php
│ │ ├── disease-summary.php
│ │ ├── evidence-box.php
│ │ ├── citation-box.php
│ │ └── review-board-box.php
│ │
│ ├── blocks/
│ │ ├── block-alert.php
│ │ ├── block-faq.php
│ │ ├── block-table.php
│ │ ├── block-medical-note.php
│ │ └── block-reference.php
│ │
│ └── components/
│ ├── breadcrumbs.php
│ ├── pagination.php
│ ├── social-share.php
│ ├── table-of-contents.php
│ └── scroll-top.php
│
├── templates/
│ ├── template-full-width.php
│ ├── template-left-sidebar.php
│ ├── template-right-sidebar.php
│ ├── template-medical-library.php
│ ├── template-review-board.php
│ └── template-contact.php
│
└── languages/
└── rx-theme.pot
My recommendation: use this naming style for dynamic files:
dynamic-global.css
dynamic-customizer.js
dynamic-medical-library-app.js
dynamic-search.chunk.js
This is clearer than only:
style-001.css
script-001.js
app-001.js
chunk-001.js