RX Theme V 8.0.0 – 9.0.0

RX Theme folder structure for future use. This combines your original structure with all advanced modules we added step by step: frontend, backend/admin, SEO, performance, ads, app loader, React/Vite dist, accessibility, WooCommerce/Elementor, Disease A-Z, contact/newsletter, and unified plugin-style loader. Your original uploaded structure was the foundation checklist for this final structure.

rx-theme/
├── style.css
├── functions.php
├── index.php
├── screenshot.png
├── readme.txt
│
├── header.php
├── footer.php
├── sidebar.php
├── search.php
├── 404.php
├── archive.php
├── category.php
├── tag.php
├── author.php
├── single.php
├── page.php
├── comments.php
│
├── inc/
│   ├── autoload.php
│   ├── rx-v8-loader.php
│   ├── rx-v83-v84-loader.php
│   ├── rx-v85-v87-loader.php
│   │
│   ├── core/
│   │   ├── theme-setup.php
│   │   ├── enqueue.php
│   │   ├── menus.php
│   │   ├── sidebars.php
│   │   ├── image-sizes.php
│   │   ├── theme-supports.php
│   │   ├── cleanup.php
│   │   ├── security.php
│   │   └── performance.php
│   │
│   ├── helpers/
│   │   ├── options.php
│   │   ├── sanitization.php
│   │   ├── escaping.php
│   │   ├── conditionals.php
│   │   ├── media.php
│   │   ├── formatting.php
│   │   ├── compatibility.php
│   │   └── template-functions.php
│   │
│   ├── frontend/
│   │   ├── template-tags.php
│   │   ├── template-functions.php
│   │   ├── breadcrumbs.php
│   │   ├── pagination.php
│   │   ├── related-posts.php
│   │   ├── reading-time.php
│   │   ├── post-views.php
│   │   ├── author-box.php
│   │   ├── reviewer-box.php
│   │   ├── social-share.php
│   │   ├── social-share-tools.php
│   │   ├── table-of-contents.php
│   │   ├── medical-disclaimer.php
│   │   ├── medical-article.php
│   │   ├── homepage.php
│   │   ├── footer-builder.php
│   │   ├── search-overlay.php
│   │   ├── archive-layout.php
│   │   └── header-mobile-polish.php
│   │
│   ├── backend/
│   │   ├── admin-menu.php
│   │   ├── admin-page.php
│   │   ├── theme-options.php
│   │   ├── settings-api.php
│   │   ├── customizer.php
│   │   ├── metaboxes.php
│   │   ├── dashboard-widgets.php
│   │   ├── admin-notices.php
│   │   └── import-export.php
│   │
│   ├── admin/
│   │   ├── admin-menu.php
│   │   └── settings-register.php
│   │
│   ├── dynamic/
│   │   └── dynamic-css.php
│   │
│   ├── seo/
│   │   ├── seo-loader.php
│   │   ├── seo-helpers.php
│   │   ├── schema-output.php
│   │   ├── schema-article.php
│   │   ├── schema-medical-webpage.php
│   │   ├── schema-medical-condition.php
│   │   ├── schema-drug.php
│   │   ├── schema-faq.php
│   │   ├── schema-breadcrumb.php
│   │   ├── schema-organization.php
│   │   ├── schema-person.php
│   │   ├── schema-website.php
│   │   ├── schema-search-action.php
│   │   ├── open-graph.php
│   │   ├── twitter-card.php
│   │   ├── canonical.php
│   │   └── meta-robots.php
│   │
│   ├── performance/
│   │   ├── performance-loader.php
│   │   ├── preload.php
│   │   ├── preconnect.php
│   │   ├── defer-async.php
│   │   ├── defer-scripts.php
│   │   ├── critical-css.php
│   │   ├── lazy-loading.php
│   │   ├── resource-hints.php
│   │   ├── remove-bloat.php
│   │   ├── emoji-disable.php
│   │   ├── embeds-disable.php
│   │   ├── heartbeat-control.php
│   │   ├── web-vitals.php
│   │   ├── font-optimization.php
│   │   └── cache-headers.php
│   │
│   ├── ads/
│   │   ├── ads-loader.php
│   │   ├── ad-helpers.php
│   │   ├── ad-settings.php
│   │   ├── ad-output.php
│   │   └── ad-shortcodes.php
│   │
│   ├── tools/
│   │   └── import-export-settings.php
│   │
│   ├── customizer/
│   │   └── customizer-support.php
│   │
│   ├── blocks/
│   │   └── gutenberg-medical-blocks.php
│   │
│   ├── medical/
│   │   ├── shortcodes.php
│   │   └── disease-az.php
│   │
│   ├── contact/
│   │   └── contact-newsletter.php
│   │
│   ├── compatibility/
│   │   └── woocommerce-elementor.php
│   │
│   ├── accessibility/
│   │   └── accessibility-tools.php
│   │
│   ├── polish/
│   │   └── final-premium-polish.php
│   │
│   ├── app/
│   │   ├── app-loader.php
│   │   ├── admin-app-loader.php
│   │   ├── frontend-app-loader.php
│   │   ├── dist-assets-loader.php
│   │   ├── dist-assets-manager.php
│   │   ├── unified-loader.php
│   │   ├── unified-app-plugin-loader.php
│   │   └── plugin-analysis-summary.json
│   │
│   ├── rest/
│   │   └── app-rest-api.php
│   │
│   └── integrations/
│       ├── woocommerce.php
│       ├── elementor.php
│       ├── gutenberg.php
│       ├── rankmath.php
│       ├── yoast.php
│       └── contact-form-7.php
│
├── frontend/
│   ├── components/
│   │   ├── site-header.php
│   │   ├── site-footer.php
│   │   ├── nav-primary.php
│   │   ├── nav-mobile.php
│   │   ├── search-form.php
│   │   ├── post-card.php
│   │   ├── author-box.php
│   │   ├── related-post-card.php
│   │   ├── share-buttons.php
│   │   └── ad-slot.php
│   │
│   ├── layouts/
│   │   ├── layout-default.php
│   │   ├── layout-full-width.php
│   │   ├── layout-sidebar-right.php
│   │   ├── layout-sidebar-left.php
│   │   ├── layout-medical-article.php
│   │   └── layout-landing.php
│   │
│   └── parts/
│       ├── content.php
│       ├── content-single.php
│       ├── content-page.php
│       ├── content-search.php
│       ├── content-none.php
│       ├── entry-header.php
│       ├── entry-footer.php
│       └── entry-meta.php
│
├── backend/
│   ├── pages/
│   │   ├── rx-dashboard.php
│   │   ├── rx-general-settings.php
│   │   ├── rx-header-settings.php
│   │   ├── rx-footer-settings.php
│   │   ├── rx-seo-settings.php
│   │   ├── rx-performance-settings.php
│   │   ├── rx-social-settings.php
│   │   └── rx-import-export.php
│   │
│   ├── fields/
│   │   ├── field-text.php
│   │   ├── field-textarea.php
│   │   ├── field-checkbox.php
│   │   ├── field-radio.php
│   │   ├── field-select.php
│   │   ├── field-color.php
│   │   ├── field-image.php
│   │   └── field-repeater.php
│   │
│   └── assets/
│       ├── css/
│       │   └── admin.css
│       ├── js/
│       │   └── admin.js
│       └── images/
│           └── rx-logo.svg
│
├── template-parts/
│   ├── header/
│   │   ├── header-default.php
│   │   ├── header-medical.php
│   │   ├── header-centered.php
│   │   ├── header-transparent.php
│   │   ├── header-sticky.php
│   │   ├── header-mobile.php
│   │   ├── header-topbar.php
│   │   └── mobile-header.php
│   │
│   ├── footer/
│   │   ├── footer-default.php
│   │   ├── footer-widgets.php
│   │   ├── footer-minimal.php
│   │   └── footer-medical.php
│   │
│   ├── content/
│   │   ├── content.php
│   │   ├── content-single.php
│   │   ├── content-page.php
│   │   ├── content-search.php
│   │   └── content-none.php
│   │
│   ├── home/
│   │   ├── hero.php
│   │   ├── search-box.php
│   │   ├── featured-categories.php
│   │   ├── latest-articles.php
│   │   ├── popular-guides.php
│   │   ├── disease-az.php
│   │   ├── doctor-reviewed.php
│   │   ├── faq.php
│   │   └── footer-cta.php
│   │
│   ├── post/
│   │   ├── post-card.php
│   │   ├── post-list.php
│   │   ├── post-grid.php
│   │   ├── post-meta.php
│   │   ├── post-author.php
│   │   └── post-related.php
│   │
│   ├── page/
│   │   ├── page-header.php
│   │   ├── page-content.php
│   │   └── page-builder.php
│   │
│   ├── archive/
│   │   ├── archive-header.php
│   │   ├── archive-toolbar.php
│   │   ├── archive-card.php
│   │   ├── archive-grid.php
│   │   └── no-results.php
│   │
│   └── medical/
│       ├── disease-card.php
│       ├── symptom-box.php
│       ├── treatment-box.php
│       ├── diagnosis-box.php
│       ├── prevention-box.php
│       ├── faq-box.php
│       ├── reviewer-box.php
│       ├── references-box.php
│       └── medical-disclaimer.php
│
├── assets/
│   ├── css/
│   │   ├── frontend/
│   │   │   ├── main.css
│   │   │   ├── header.css
│   │   │   ├── footer.css
│   │   │   ├── blog.css
│   │   │   ├── single.css
│   │   │   ├── archive.css
│   │   │   ├── archive-layout.css
│   │   │   ├── medical.css
│   │   │   ├── homepage.css
│   │   │   ├── disease-az.css
│   │   │   ├── contact-newsletter.css
│   │   │   ├── ad-manager.css
│   │   │   ├── search-menu.css
│   │   │   ├── social-share-tools.css
│   │   │   ├── header-mobile-polish.css
│   │   │   ├── compatibility-polish.css
│   │   │   ├── accessibility.css
│   │   │   ├── accessibility-tools.css
│   │   │   ├── premium-polish.css
│   │   │   └── responsive.css
│   │   │
│   │   ├── backend/
│   │   │   ├── admin.css
│   │   │   ├── settings.css
│   │   │   ├── customizer.css
│   │   │   ├── rx-admin-tools.css
│   │   │   ├── dist-assets-manager.css
│   │   │   └── unified-app-loader-admin.css
│   │   │
│   │   ├── blocks/
│   │   │   └── medical-blocks.css
│   │   │
│   │   ├── dynamic/
│   │   │   ├── variables.css
│   │   │   ├── color-scheme.css
│   │   │   ├── typography.css
│   │   │   └── generated.css
│   │   │
│   │   └── vendor/
│   │       ├── normalize.css
│   │       └── icons.css
│   │
│   ├── js/
│   │   ├── frontend/
│   │   │   ├── main.js
│   │   │   ├── navigation.js
│   │   │   ├── mobile-menu.js
│   │   │   ├── search.js
│   │   │   ├── search-menu.js
│   │   │   ├── accessibility.js
│   │   │   ├── accessibility-tools.js
│   │   │   ├── lazyload.js
│   │   │   ├── toc.js
│   │   │   ├── dark-mode.js
│   │   │   ├── performance.js
│   │   │   ├── social-share-tools.js
│   │   │   ├── header-mobile-polish.js
│   │   │   ├── archive-layout.js
│   │   │   ├── disease-az.js
│   │   │   ├── contact-newsletter.js
│   │   │   └── premium-polish.js
│   │   │
│   │   ├── backend/
│   │   │   ├── admin.js
│   │   │   ├── settings.js
│   │   │   ├── media-upload.js
│   │   │   ├── customizer.js
│   │   │   └── customizer-preview.js
│   │   │
│   │   ├── blocks/
│   │   │   └── medical-blocks.js
│   │   │
│   │   ├── performance/
│   │   │   ├── idle-loader.js
│   │   │   ├── defer-third-party.js
│   │   │   └── web-vitals-monitor.js
│   │   │
│   │   └── vendor/
│   │       └── vendor.js
│   │
│   ├── build/
│   │   ├── admin/
│   │   │   ├── admin-app.js
│   │   │   └── admin-app.css
│   │   └── frontend/
│   │       ├── frontend-app.js
│   │       └── frontend-app.css
│   │
│   ├── app-dist/
│   │   ├── README.md
│   │   ├── rx-dist-manifest-example.json
│   │   ├── chunks/
│   │   │   ├── chunk-01.js
│   │   │   ├── chunk-02.js
│   │   │   └── chunk-50.js
│   │   ├── main-js/
│   │   │   ├── main-01.js
│   │   │   ├── main-02.js
│   │   │   └── main-50.js
│   │   ├── css/
│   │   │   ├── style-01.css
│   │   │   ├── style-02.css
│   │   │   └── style-50.css
│   │   ├── vendor/
│   │   ├── images/
│   │   └── fonts/
│   │
│   ├── app-loader/
│   │   ├── frontend/
│   │   │   ├── css/
│   │   │   │   ├── frontend-01.css
│   │   │   │   └── frontend-50.css
│   │   │   └── js/
│   │   │       ├── frontend-01.js
│   │   │       └── frontend-50.js
│   │   │
│   │   ├── admin/
│   │   │   ├── css/
│   │   │   │   ├── admin-01.css
│   │   │   │   └── admin-50.css
│   │   │   └── js/
│   │   │       ├── admin-01.js
│   │   │       └── admin-50.js
│   │   │
│   │   ├── both/
│   │   │   ├── css/
│   │   │   │   ├── both-01.css
│   │   │   │   └── both-50.css
│   │   │   └── js/
│   │   │       ├── both-01.js
│   │   │       └── both-50.js
│   │   │
│   │   ├── chunks/
│   │   │   ├── chunk-01.js
│   │   │   ├── chunk-02.js
│   │   │   └── chunk-100.js
│   │   ├── vendor/
│   │   └── media/
│   │
│   ├── images/
│   │   ├── logo/
│   │   ├── icons/
│   │   ├── backgrounds/
│   │   └── placeholders/
│   │
│   ├── fonts/
│   │   ├── inter/
│   │   └── rx-icons/
│   │
│   └── static-js/
│       ├── accessibility.js
│       ├── frontend-helpers.js
│       └── performance-helpers.js
│
├── app/
│   ├── README.md
│   │
│   ├── admin-react/
│   │   ├── package.json
│   │   ├── vite.config.js
│   │   ├── src/
│   │   │   ├── main.jsx
│   │   │   └── admin-app.css
│   │   └── dist/
│   │       ├── admin-app.js
│   │       └── admin-app.css
│   │
│   ├── frontend-vite/
│   │   ├── package.json
│   │   ├── vite.config.js
│   │   ├── src/
│   │   │   ├── main.js
│   │   │   └── frontend-app.css
│   │   └── dist/
│   │       ├── frontend-app.js
│   │       └── frontend-app.css
│   │
│   ├── astro-headless-note/
│   │   └── README.md
│   │
│   ├── rust-tools-note/
│   │   └── README.md
│   │
│   └── plugin-reference-readonly/
│       ├── README.md
│       ├── PLUGIN_FILES_LIST.txt
│       └── PLUGIN_HEADER.txt
│
├── templates/
│   ├── template-full-width.php
│   ├── template-left-sidebar.php
│   ├── template-right-sidebar.php
│   ├── template-no-sidebar.php
│   ├── template-medical-article.php
│   ├── template-homepage.php
│   ├── template-landing-page.php
│   ├── template-sitemap.php
│   ├── template-disease-az.php
│   └── template-contact-newsletter.php
│
├── blocks/
│   ├── rx-card/
│   │   ├── block.json
│   │   ├── index.js
│   │   ├── editor.css
│   │   └── style.css
│   │
│   ├── rx-faq/
│   │   ├── block.json
│   │   ├── index.js
│   │   ├── editor.css
│   │   └── style.css
│   │
│   ├── rx-medical-box/
│   │   ├── block.json
│   │   ├── index.js
│   │   ├── editor.css
│   │   └── style.css
│   │
│   └── rx-reviewer-box/
│       ├── block.json
│       ├── index.js
│       ├── editor.css
│       └── style.css
│
├── languages/
│   └── rx-theme.pot
│
└── build/
    ├── css/
    ├── js/
    └── manifest.json

Simple map for finding things quickly

Theme engine              → inc/core/
Reusable PHP helpers      → inc/helpers/
Frontend features         → inc/frontend/
Backend/admin pages       → inc/backend/ and inc/admin/
SEO/schema                → inc/seo/
Performance               → inc/performance/
Ads/AdSense               → inc/ads/
Customizer                → inc/customizer/
Import/export             → inc/tools/
Gutenberg blocks PHP      → inc/blocks/
Medical systems           → inc/medical/
Contact/newsletter        → inc/contact/
WooCommerce/Elementor     → inc/compatibility/
Accessibility             → inc/accessibility/
Final polish              → inc/polish/
React/Vite app loader     → inc/app/
REST API bridge           → inc/rest/
Header/footer templates   → template-parts/header/ and template-parts/footer/
Post/page templates       → template-parts/post/ and template-parts/page/
Medical UI parts          → template-parts/medical/
Frontend CSS              → assets/css/frontend/
Backend CSS               → assets/css/backend/
Frontend JS               → assets/js/frontend/
Backend JS                → assets/js/backend/
React/Vite built files    → assets/build/
Many app dist files       → assets/app-dist/
Unified loader files      → assets/app-loader/
Source app folders        → app/
Page templates            → templates/
Gutenberg block folders   → blocks/
Translations              → languages/

Most important rule for future

Do not put everything in functions.php.

Keep:

functions.php → only load inc/autoload.php
inc/autoload.php → load modules
each module folder → own job
assets/ → only CSS, JS, images, fonts, dist files
template-parts/ → reusable visual PHP parts
templates/ → selectable page templates

Your final stable direction is:

RX Theme = Medical WordPress Theme Framework

Not just a simple theme.

 

 

 

Yes dear friend — I’ll add these three as one safe milestone: RX Theme v8.2 Control + Customizer + Gutenberg Medical Blocks, built on top of your working v7.9 Ad Manager version.

from pathlib import Path
import zipfile, shutil, re, subprocess, json, os

base_zip = Path(“/mnt/data/rx-theme-v7-9-ad-manager.zip”)
fallbacks = [
Path(“/mnt/data/rx-theme-v7-8-advanced-seo-schema.zip”),
Path(“/mnt/data/rx-theme-v7-7-advanced-archive-layout.zip”),
Path(“/mnt/data/rx-theme-v7-6-performance-system.zip”),
]
if not base_zip.exists():
for f in fallbacks:
if f.exists():
base_zip = f
break

work_root = Path(“/mnt/data/rx_v82_control_customizer_blocks”)
extract_dir = work_root / “extract”

if work_root.exists():
shutil.rmtree(work_root)
work_root.mkdir(parents=True)
extract_dir.mkdir(parents=True)

with zipfile.ZipFile(base_zip, “r”) as z:
z.extractall(extract_dir)

theme_roots = [p.parent for p in extract_dir.rglob(“style.css”) if (p.parent / “functions.php”).exists()]
if not theme_roots:
raise RuntimeError(“Theme root not found.”)

src_root = theme_roots[0]
theme_root = work_root / “rx-theme-v8-2-control-customizer-blocks”
shutil.copytree(src_root, theme_root)

def read(path):
return path.read_text(encoding=”utf-8″, errors=”ignore”)

def write(path, text):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(text, encoding=”utf-8″)

# Update style.css
style_path = theme_root / “style.css”
if style_path.exists():
s = read(style_path)
s = re.sub(r”Theme Name:\s*.*”, “Theme Name: RX Theme v8.2 Control Customizer Blocks”, s, count=1) if “Theme Name:” in s else “/*\nTheme Name: RX Theme v8.2 Control Customizer Blocks\nVersion: 8.2\n*/\n” + s
s = re.sub(r”Version:\s*.*”, “Version: 8.2”, s, count=1) if “Version:” in s else s.replace(“*/”, “Version: 8.2\n*/”, 1)
write(style_path, s)

# Directories
inc_tools = theme_root / “inc/tools”
inc_customizer = theme_root / “inc/customizer”
inc_blocks = theme_root / “inc/blocks”
assets_admin_css = theme_root / “assets/css/backend”
assets_admin_js = theme_root / “assets/js/backend”
assets_blocks_css = theme_root / “assets/css/blocks”
assets_blocks_js = theme_root / “assets/js/blocks”
blocks_dir = theme_root / “blocks”

for d in [inc_tools, inc_customizer, inc_blocks, assets_admin_css, assets_admin_js, assets_blocks_css, assets_blocks_js, blocks_dir]:
d.mkdir(parents=True, exist_ok=True)

# ========== v8.0 Import/export settings ==========
write(inc_tools / “import-export-settings.php”, r”'<?php
/**
* RX Theme v8.0 Import / Export Settings.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

function rx_theme_v80_import_export_option_keys() {
return apply_filters(
‘rx_theme_v80_import_export_option_keys’,
array(
‘rx_theme_options’,
‘rx_theme_v79_ads’,
‘theme_mods_’ . get_option( ‘stylesheet’ ),
)
);
}

function rx_theme_v80_export_data() {
$data = array(
‘theme’ => wp_get_theme()->get( ‘Name’ ),
‘version’ => wp_get_theme()->get( ‘Version’ ),
‘site_url’ => home_url( ‘/’ ),
‘exported_at’ => current_time( ‘mysql’ ),
‘options’ => array(),
);

foreach ( rx_theme_v80_import_export_option_keys() as $key ) {
$data[‘options’][ $key ] = get_option( $key );
}

return $data;
}

function rx_theme_v80_admin_menu() {
add_theme_page(
esc_html__( ‘RX Import / Export’, ‘rx-theme’ ),
esc_html__( ‘RX Import / Export’, ‘rx-theme’ ),
‘manage_options’,
‘rx-theme-import-export’,
‘rx_theme_v80_import_export_page’
);
}
add_action( ‘admin_menu’, ‘rx_theme_v80_admin_menu’, 40 );

function rx_theme_v80_handle_export() {
if ( empty( $_POST[‘rx_theme_v80_export’] ) || ! current_user_can( ‘manage_options’ ) ) {
return;
}

check_admin_referer( ‘rx_theme_v80_export_action’, ‘rx_theme_v80_export_nonce’ );

$data = rx_theme_v80_export_data();
$filename = ‘rx-theme-settings-‘ . gmdate( ‘Y-m-d-H-i-s’ ) . ‘.json’;

nocache_headers();
header( ‘Content-Type: application/json; charset=utf-8’ );
header( ‘Content-Disposition: attachment; filename=’ . $filename );

echo wp_json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
exit;
}
add_action( ‘admin_init’, ‘rx_theme_v80_handle_export’ );

function rx_theme_v80_handle_import() {
if ( empty( $_POST[‘rx_theme_v80_import’] ) || ! current_user_can( ‘manage_options’ ) ) {
return;
}

check_admin_referer( ‘rx_theme_v80_import_action’, ‘rx_theme_v80_import_nonce’ );

if ( empty( $_FILES[‘rx_theme_v80_import_file’][‘tmp_name’] ) ) {
add_settings_error( ‘rx_theme_v80_messages’, ‘rx_theme_v80_no_file’, esc_html__( ‘No import file selected.’, ‘rx-theme’ ), ‘error’ );
return;
}

$file = $_FILES[‘rx_theme_v80_import_file’];

if ( ! empty( $file[‘error’] ) ) {
add_settings_error( ‘rx_theme_v80_messages’, ‘rx_theme_v80_upload_error’, esc_html__( ‘Upload error. Please try again.’, ‘rx-theme’ ), ‘error’ );
return;
}

$raw = file_get_contents( $file[‘tmp_name’] );
$json = json_decode( $raw, true );

if ( ! is_array( $json ) || empty( $json[‘options’] ) || ! is_array( $json[‘options’] ) ) {
add_settings_error( ‘rx_theme_v80_messages’, ‘rx_theme_v80_invalid_file’, esc_html__( ‘Invalid RX Theme settings file.’, ‘rx-theme’ ), ‘error’ );
return;
}

$allowed = rx_theme_v80_import_export_option_keys();
$count = 0;

foreach ( $json[‘options’] as $key => $value ) {
if ( in_array( $key, $allowed, true ) ) {
update_option( $key, $value );
$count++;
}
}

add_settings_error(
‘rx_theme_v80_messages’,
‘rx_theme_v80_imported’,
sprintf( esc_html__( ‘Import completed. %d option groups restored.’, ‘rx-theme’ ), absint( $count ) ),
‘updated’
);
}
add_action( ‘admin_init’, ‘rx_theme_v80_handle_import’ );

function rx_theme_v80_import_export_page() {
if ( ! current_user_can( ‘manage_options’ ) ) {
return;
}

settings_errors( ‘rx_theme_v80_messages’ );
?>
<div class=”wrap rx-theme-control-page”>
<h1><?php esc_html_e( ‘RX Theme Import / Export Settings’, ‘rx-theme’ ); ?></h1>
<p><?php esc_html_e( ‘Backup and restore RX Theme options, Customizer settings, and ad manager settings.’, ‘rx-theme’ ); ?></p>

<div class=”rx-admin-grid”>
<div class=”rx-admin-card”>
<h2><?php esc_html_e( ‘Export Settings’, ‘rx-theme’ ); ?></h2>
<p><?php esc_html_e( ‘Download a JSON backup file of your current RX Theme settings.’, ‘rx-theme’ ); ?></p>
<form method=”post”>
<?php wp_nonce_field( ‘rx_theme_v80_export_action’, ‘rx_theme_v80_export_nonce’ ); ?>
<p>
<button type=”submit” name=”rx_theme_v80_export” value=”1″ class=”button button-primary”>
<?php esc_html_e( ‘Download Export File’, ‘rx-theme’ ); ?>
</button>
</p>
</form>
</div>

<div class=”rx-admin-card”>
<h2><?php esc_html_e( ‘Import Settings’, ‘rx-theme’ ); ?></h2>
<p><?php esc_html_e( ‘Upload a previously exported RX Theme JSON file.’, ‘rx-theme’ ); ?></p>
<form method=”post” enctype=”multipart/form-data”>
<?php wp_nonce_field( ‘rx_theme_v80_import_action’, ‘rx_theme_v80_import_nonce’ ); ?>
<input type=”file” name=”rx_theme_v80_import_file” accept=”application/json,.json” required>
<p>
<button type=”submit” name=”rx_theme_v80_import” value=”1″ class=”button button-primary”>
<?php esc_html_e( ‘Import Settings’, ‘rx-theme’ ); ?>
</button>
</p>
</form>
</div>
</div>

<div class=”rx-admin-card”>
<h2><?php esc_html_e( ‘Included Option Groups’, ‘rx-theme’ ); ?></h2>
<ul>
<?php foreach ( rx_theme_v80_import_export_option_keys() as $key ) : ?>
<li><code><?php echo esc_html( $key ); ?></code></li>
<?php endforeach; ?>
</ul>
</div>
</div>
<?php
}

function rx_theme_v80_admin_assets( $hook ) {
if ( false === strpos( $hook, ‘rx-theme-import-export’ ) ) {
return;
}

wp_enqueue_style(
‘rx-theme-admin-tools’,
get_template_directory_uri() . ‘/assets/css/backend/rx-admin-tools.css’,
array(),
filemtime( get_template_directory() . ‘/assets/css/backend/rx-admin-tools.css’ )
);
}
add_action( ‘admin_enqueue_scripts’, ‘rx_theme_v80_admin_assets’ );
”’)

write(assets_admin_css / “rx-admin-tools.css”, r”’/* RX Theme admin tools */
.rx-theme-control-page .rx-admin-grid{
display:grid;
grid-template-columns:repeat(2,minmax(0,1fr));
gap:18px;
max-width:1100px;
}
.rx-theme-control-page .rx-admin-card{
margin:18px 0;
padding:22px;
border:1px solid #dcdcde;
border-radius:14px;
background:#fff;
box-shadow:0 8px 20px rgba(0,0,0,.04);
}
.rx-theme-control-page .rx-admin-card h2{
margin-top:0;
}
@media(max-width:782px){
.rx-theme-control-page .rx-admin-grid{
grid-template-columns:1fr;
}
}
”’)

# ========== v8.1 Customizer support ==========
write(inc_customizer / “customizer-support.php”, r”'<?php
/**
* RX Theme v8.1 Customizer Support.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

function rx_theme_v81_sanitize_checkbox( $checked ) {
return ( isset( $checked ) && true == $checked ) ? true : false;
}

function rx_theme_v81_sanitize_select( $input, $setting ) {
$choices = $setting->manager->get_control( $setting->id )->choices;
return array_key_exists( $input, $choices ) ? $input : $setting->default;
}

function rx_theme_v81_customizer_register( $wp_customize ) {
$wp_customize->add_panel(
‘rx_theme_panel’,
array(
‘title’ => esc_html__( ‘RX Theme Controls’, ‘rx-theme’ ),
‘description’ => esc_html__( ‘Customize RX Theme layout, header, colors, typography, and medical settings.’, ‘rx-theme’ ),
‘priority’ => 30,
)
);

$wp_customize->add_section(
‘rx_theme_branding’,
array(
‘title’ => esc_html__( ‘RX Branding’, ‘rx-theme’ ),
‘panel’ => ‘rx_theme_panel’,
)
);

$wp_customize->add_setting(
‘rx_site_logo_url’,
array(
‘default’ => ”,
‘sanitize_callback’ => ‘esc_url_raw’,
‘transport’ => ‘refresh’,
)
);

$wp_customize->add_control(
‘rx_site_logo_url’,
array(
‘label’ => esc_html__( ‘Site Logo URL’, ‘rx-theme’ ),
‘section’ => ‘rx_theme_branding’,
‘type’ => ‘url’,
)
);

$wp_customize->add_section(
‘rx_theme_colors’,
array(
‘title’ => esc_html__( ‘RX Colors’, ‘rx-theme’ ),
‘panel’ => ‘rx_theme_panel’,
)
);

$color_settings = array(
‘rx_primary_color’ => array( esc_html__( ‘Primary Color’, ‘rx-theme’ ), ‘#0066cc’ ),
‘rx_secondary_color’ => array( esc_html__( ‘Secondary Color’, ‘rx-theme’ ), ‘#00a884’ ),
‘rx_heading_color’ => array( esc_html__( ‘Heading Color’, ‘rx-theme’ ), ‘#111827’ ),
‘rx_text_color’ => array( esc_html__( ‘Text Color’, ‘rx-theme’ ), ‘#1f2937’ ),
);

foreach ( $color_settings as $id => $data ) {
$wp_customize->add_setting(
$id,
array(
‘default’ => $data[1],
‘sanitize_callback’ => ‘sanitize_hex_color’,
‘transport’ => ‘postMessage’,
)
);

$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
$id,
array(
‘label’ => $data[0],
‘section’ => ‘rx_theme_colors’,
)
)
);
}

$wp_customize->add_section(
‘rx_theme_layout’,
array(
‘title’ => esc_html__( ‘RX Layout’, ‘rx-theme’ ),
‘panel’ => ‘rx_theme_panel’,
)
);

$wp_customize->add_setting(
‘rx_container_width’,
array(
‘default’ => ‘1200’,
‘sanitize_callback’ => ‘absint’,
‘transport’ => ‘postMessage’,
)
);

$wp_customize->add_control(
‘rx_container_width’,
array(
‘label’ => esc_html__( ‘Container Width’, ‘rx-theme’ ),
‘section’ => ‘rx_theme_layout’,
‘type’ => ‘number’,
‘input_attrs’ => array(
‘min’ => 960,
‘max’ => 1600,
‘step’ => 10,
),
)
);

$wp_customize->add_setting(
‘rx_sidebar_position’,
array(
‘default’ => ‘right’,
‘sanitize_callback’ => ‘rx_theme_v81_sanitize_select’,
)
);

$wp_customize->add_control(
‘rx_sidebar_position’,
array(
‘label’ => esc_html__( ‘Sidebar Position’, ‘rx-theme’ ),
‘section’ => ‘rx_theme_layout’,
‘type’ => ‘select’,
‘choices’ => array(
‘right’ => esc_html__( ‘Right’, ‘rx-theme’ ),
‘left’ => esc_html__( ‘Left’, ‘rx-theme’ ),
‘none’ => esc_html__( ‘No Sidebar’, ‘rx-theme’ ),
),
)
);

$wp_customize->add_section(
‘rx_theme_header’,
array(
‘title’ => esc_html__( ‘RX Header’, ‘rx-theme’ ),
‘panel’ => ‘rx_theme_panel’,
)
);

$wp_customize->add_setting(
‘rx_header_style’,
array(
‘default’ => ‘medical’,
‘sanitize_callback’ => ‘rx_theme_v81_sanitize_select’,
)
);

$wp_customize->add_control(
‘rx_header_style’,
array(
‘label’ => esc_html__( ‘Header Style’, ‘rx-theme’ ),
‘section’ => ‘rx_theme_header’,
‘type’ => ‘select’,
‘choices’ => array(
‘default’ => esc_html__( ‘Default’, ‘rx-theme’ ),
‘medical’ => esc_html__( ‘Medical’, ‘rx-theme’ ),
‘centered’ => esc_html__( ‘Centered’, ‘rx-theme’ ),
‘transparent’ => esc_html__( ‘Transparent’, ‘rx-theme’ ),
‘sticky’ => esc_html__( ‘Sticky’, ‘rx-theme’ ),
‘topbar’ => esc_html__( ‘Topbar’, ‘rx-theme’ ),
),
)
);

$wp_customize->add_setting(
‘rx_sticky_header’,
array(
‘default’ => true,
‘sanitize_callback’ => ‘rx_theme_v81_sanitize_checkbox’,
)
);

$wp_customize->add_control(
‘rx_sticky_header’,
array(
‘label’ => esc_html__( ‘Enable Sticky Header’, ‘rx-theme’ ),
‘section’ => ‘rx_theme_header’,
‘type’ => ‘checkbox’,
)
);

$wp_customize->add_section(
‘rx_theme_medical’,
array(
‘title’ => esc_html__( ‘RX Medical Settings’, ‘rx-theme’ ),
‘panel’ => ‘rx_theme_panel’,
)
);

$wp_customize->add_setting(
‘rx_medical_disclaimer’,
array(
‘default’ => esc_html__( ‘This content is for educational purposes only and should not replace professional medical advice.’, ‘rx-theme’ ),
‘sanitize_callback’ => ‘sanitize_textarea_field’,
)
);

$wp_customize->add_control(
‘rx_medical_disclaimer’,
array(
‘label’ => esc_html__( ‘Medical Disclaimer Text’, ‘rx-theme’ ),
‘section’ => ‘rx_theme_medical’,
‘type’ => ‘textarea’,
)
);
}
add_action( ‘customize_register’, ‘rx_theme_v81_customizer_register’ );

function rx_theme_v81_customizer_css() {
$primary = get_theme_mod( ‘rx_primary_color’, ‘#0066cc’ );
$secondary = get_theme_mod( ‘rx_secondary_color’, ‘#00a884’ );
$heading = get_theme_mod( ‘rx_heading_color’, ‘#111827’ );
$text = get_theme_mod( ‘rx_text_color’, ‘#1f2937’ );
$container = absint( get_theme_mod( ‘rx_container_width’, 1200 ) );

?>
<style id=”rx-theme-v81-customizer-css”>
:root{
–rx-primary-color: <?php echo esc_html( $primary ); ?>;
–rx-secondary-color: <?php echo esc_html( $secondary ); ?>;
–rx-heading-color: <?php echo esc_html( $heading ); ?>;
–rx-text-color: <?php echo esc_html( $text ); ?>;
–rx-container-width: <?php echo esc_html( $container ); ?>px;
}
</style>
<?php
}
add_action( ‘wp_head’, ‘rx_theme_v81_customizer_css’, 5 );

function rx_theme_v81_customizer_preview_js() {
wp_enqueue_script(
‘rx-theme-customizer-preview’,
get_template_directory_uri() . ‘/assets/js/backend/customizer-preview.js’,
array( ‘customize-preview’ ),
filemtime( get_template_directory() . ‘/assets/js/backend/customizer-preview.js’ ),
true
);
}
add_action( ‘customize_preview_init’, ‘rx_theme_v81_customizer_preview_js’ );
”’)

write(assets_admin_js / “customizer-preview.js”, r”’/* RX Theme v8.1 Customizer live preview */
(function(api){
‘use strict’;

const map = {
rx_primary_color: ‘–rx-primary-color’,
rx_secondary_color: ‘–rx-secondary-color’,
rx_heading_color: ‘–rx-heading-color’,
rx_text_color: ‘–rx-text-color’
};

Object.keys(map).forEach(function(setting){
api(setting, function(value){
value.bind(function(newValue){
document.documentElement.style.setProperty(map[setting], newValue);
});
});
});

api(‘rx_container_width’, function(value){
value.bind(function(newValue){
document.documentElement.style.setProperty(‘–rx-container-width’, parseInt(newValue || 1200, 10) + ‘px’);
});
});
})(wp.customize);
”’)

# ========== v8.2 Gutenberg medical blocks ==========
write(inc_blocks / “gutenberg-medical-blocks.php”, r”'<?php
/**
* RX Theme v8.2 Gutenberg Medical Blocks.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

function rx_theme_v82_blocks_assets() {
wp_register_style(
‘rx-theme-medical-blocks’,
get_template_directory_uri() . ‘/assets/css/blocks/medical-blocks.css’,
array(),
filemtime( get_template_directory() . ‘/assets/css/blocks/medical-blocks.css’ )
);

wp_register_script(
‘rx-theme-medical-blocks-editor’,
get_template_directory_uri() . ‘/assets/js/blocks/medical-blocks.js’,
array( ‘wp-blocks’, ‘wp-element’, ‘wp-components’, ‘wp-block-editor’, ‘wp-i18n’ ),
filemtime( get_template_directory() . ‘/assets/js/blocks/medical-blocks.js’ ),
true
);

register_block_type(
‘rx-theme/medical-box’,
array(
‘editor_script’ => ‘rx-theme-medical-blocks-editor’,
‘editor_style’ => ‘rx-theme-medical-blocks’,
‘style’ => ‘rx-theme-medical-blocks’,
‘render_callback’ => ‘rx_theme_v82_render_medical_box_block’,
‘attributes’ => array(
‘title’ => array(
‘type’ => ‘string’,
‘default’ => ‘Medical Note’,
),
‘type’ => array(
‘type’ => ‘string’,
‘default’ => ‘info’,
),
‘content’ => array(
‘type’ => ‘string’,
‘default’ => ‘Write helpful medical information here.’,
),
),
)
);

register_block_type(
‘rx-theme/faq’,
array(
‘editor_script’ => ‘rx-theme-medical-blocks-editor’,
‘editor_style’ => ‘rx-theme-medical-blocks’,
‘style’ => ‘rx-theme-medical-blocks’,
‘render_callback’ => ‘rx_theme_v82_render_faq_block’,
‘attributes’ => array(
‘question’ => array(
‘type’ => ‘string’,
‘default’ => ‘What is the main question?’,
),
‘answer’ => array(
‘type’ => ‘string’,
‘default’ => ‘Write the answer here.’,
),
),
)
);

register_block_type(
‘rx-theme/reviewer-box’,
array(
‘editor_script’ => ‘rx-theme-medical-blocks-editor’,
‘editor_style’ => ‘rx-theme-medical-blocks’,
‘style’ => ‘rx-theme-medical-blocks’,
‘render_callback’ => ‘rx_theme_v82_render_reviewer_box_block’,
‘attributes’ => array(
‘name’ => array(
‘type’ => ‘string’,
‘default’ => ‘Medical Reviewer’,
),
‘role’ => array(
‘type’ => ‘string’,
‘default’ => ‘Doctor / Medical Expert’,
),
‘note’ => array(
‘type’ => ‘string’,
‘default’ => ‘This article was reviewed for medical accuracy and clarity.’,
),
),
)
);
}
add_action( ‘init’, ‘rx_theme_v82_blocks_assets’ );

function rx_theme_v82_render_medical_box_block( $attributes ) {
$title = isset( $attributes[‘title’] ) ? sanitize_text_field( $attributes[‘title’] ) : ”;
$type = isset( $attributes[‘type’] ) ? sanitize_html_class( $attributes[‘type’] ) : ‘info’;
$content = isset( $attributes[‘content’] ) ? wp_kses_post( $attributes[‘content’] ) : ”;

return sprintf(
‘<section class=”wp-block-rx-theme-medical-box rx-medical-block rx-medical-block–%1$s”><h3>%2$s</h3><p>%3$s</p></section>’,
esc_attr( $type ),
esc_html( $title ),
wp_kses_post( $content )
);
}

function rx_theme_v82_render_faq_block( $attributes ) {
$question = isset( $attributes[‘question’] ) ? sanitize_text_field( $attributes[‘question’] ) : ”;
$answer = isset( $attributes[‘answer’] ) ? wp_kses_post( $attributes[‘answer’] ) : ”;

return sprintf(
‘<details class=”wp-block-rx-theme-faq rx-faq-block”><summary>%1$s</summary><div class=”rx-faq-block__answer”>%2$s</div></details>’,
esc_html( $question ),
wpautop( $answer )
);
}

function rx_theme_v82_render_reviewer_box_block( $attributes ) {
$name = isset( $attributes[‘name’] ) ? sanitize_text_field( $attributes[‘name’] ) : ”;
$role = isset( $attributes[‘role’] ) ? sanitize_text_field( $attributes[‘role’] ) : ”;
$note = isset( $attributes[‘note’] ) ? wp_kses_post( $attributes[‘note’] ) : ”;

return sprintf(
‘<aside class=”wp-block-rx-theme-reviewer-box rx-reviewer-block”><div class=”rx-reviewer-block__badge”>✓</div><div><strong>%1$s</strong><span>%2$s</span><p>%3$s</p></div></aside>’,
esc_html( $name ),
esc_html( $role ),
wp_kses_post( $note )
);
}
”’)

write(assets_blocks_css / “medical-blocks.css”, r”’/* RX Theme v8.2 Gutenberg Medical Blocks */
.rx-medical-block{
margin:24px 0;
padding:22px;
border:1px solid #dbeafe;
border-left:5px solid var(–rx-primary-color,#0066cc);
border-radius:18px;
background:#f8fbff;
box-shadow:0 12px 32px rgba(15,23,42,.05);
}
.rx-medical-block h3{
margin:0 0 10px;
color:var(–rx-heading-color,#111827);
}
.rx-medical-block p{
margin:0;
color:#475569;
line-height:1.75;
}
.rx-medical-block–warning{
border-color:#fed7aa;
border-left-color:#f97316;
background:#fff7ed;
}
.rx-medical-block–success{
border-color:#bbf7d0;
border-left-color:#16a34a;
background:#f0fdf4;
}
.rx-medical-block–danger{
border-color:#fecaca;
border-left-color:#dc2626;
background:#fef2f2;
}
.rx-faq-block{
margin:18px 0;
padding:0;
border:1px solid #e5e7eb;
border-radius:16px;
background:#fff;
overflow:hidden;
}
.rx-faq-block summary{
padding:16px 18px;
cursor:pointer;
font-weight:900;
color:var(–rx-heading-color,#111827);
background:#f8fafc;
}
.rx-faq-block__answer{
padding:18px;
color:#475569;
line-height:1.75;
}
.rx-reviewer-block{
display:flex;
gap:14px;
align-items:flex-start;
margin:24px 0;
padding:20px;
border:1px solid #dbeafe;
border-radius:20px;
background:#fff;
box-shadow:0 12px 32px rgba(15,23,42,.05);
}
.rx-reviewer-block__badge{
display:flex;
align-items:center;
justify-content:center;
width:42px;
height:42px;
border-radius:999px;
background:#ecfdf5;
color:#047857;
font-weight:1000;
}
.rx-reviewer-block strong{
display:block;
color:var(–rx-heading-color,#111827);
font-size:18px;
}
.rx-reviewer-block span{
display:block;
color:var(–rx-primary-color,#0066cc);
font-weight:800;
margin-top:3px;
}
.rx-reviewer-block p{
margin:8px 0 0;
color:#64748b;
}
body.rx-dark-mode .rx-medical-block,
body.rx-dark-mode .rx-faq-block,
body.rx-dark-mode .rx-reviewer-block{
background:#111827;
border-color:#243244;
}
body.rx-dark-mode .rx-faq-block summary{
background:#0f172a;
}
body.rx-dark-mode .rx-medical-block p,
body.rx-dark-mode .rx-faq-block__answer,
body.rx-dark-mode .rx-reviewer-block p{
color:#cbd5e1;
}
”’)

write(assets_blocks_js / “medical-blocks.js”, r”’/* RX Theme v8.2 Gutenberg Medical Blocks */
(function(blocks, element, blockEditor, components, i18n){
const el = element.createElement;
const RichText = blockEditor.RichText;
const InspectorControls = blockEditor.InspectorControls;
const PanelBody = components.PanelBody;
const SelectControl = components.SelectControl;
const TextControl = components.TextControl;
const TextareaControl = components.TextareaControl;
const __ = i18n.__;

blocks.registerBlockType(‘rx-theme/medical-box’, {
title: __(‘RX Medical Box’, ‘rx-theme’),
icon: ‘heart’,
category: ‘widgets’,
attributes: {
title: { type: ‘string’, default: ‘Medical Note’ },
type: { type: ‘string’, default: ‘info’ },
content: { type: ‘string’, default: ‘Write helpful medical information here.’ }
},
edit: function(props){
const attrs = props.attributes;
return [
el(InspectorControls, {},
el(PanelBody, { title: __(‘Medical Box Settings’, ‘rx-theme’) },
el(SelectControl, {
label: __(‘Box Type’, ‘rx-theme’),
value: attrs.type,
options: [
{ label: ‘Info’, value: ‘info’ },
{ label: ‘Warning’, value: ‘warning’ },
{ label: ‘Success’, value: ‘success’ },
{ label: ‘Danger’, value: ‘danger’ }
],
onChange: function(value){ props.setAttributes({ type: value }); }
})
)
),
el(‘section’, { className: ‘rx-medical-block rx-medical-block–‘ + attrs.type },
el(RichText, {
tagName: ‘h3’,
value: attrs.title,
onChange: function(value){ props.setAttributes({ title: value }); },
placeholder: __(‘Title…’, ‘rx-theme’)
}),
el(RichText, {
tagName: ‘p’,
value: attrs.content,
onChange: function(value){ props.setAttributes({ content: value }); },
placeholder: __(‘Medical content…’, ‘rx-theme’)
})
)
];
},
save: function(){ return null; }
});

blocks.registerBlockType(‘rx-theme/faq’, {
title: __(‘RX FAQ’, ‘rx-theme’),
icon: ‘editor-help’,
category: ‘widgets’,
attributes: {
question: { type: ‘string’, default: ‘What is the main question?’ },
answer: { type: ‘string’, default: ‘Write the answer here.’ }
},
edit: function(props){
const attrs = props.attributes;
return el(‘div’, { className: ‘rx-faq-block’ },
el(RichText, {
tagName: ‘strong’,
value: attrs.question,
onChange: function(value){ props.setAttributes({ question: value }); },
placeholder: __(‘Question…’, ‘rx-theme’)
}),
el(RichText, {
tagName: ‘p’,
value: attrs.answer,
onChange: function(value){ props.setAttributes({ answer: value }); },
placeholder: __(‘Answer…’, ‘rx-theme’)
})
);
},
save: function(){ return null; }
});

blocks.registerBlockType(‘rx-theme/reviewer-box’, {
title: __(‘RX Reviewer Box’, ‘rx-theme’),
icon: ‘yes-alt’,
category: ‘widgets’,
attributes: {
name: { type: ‘string’, default: ‘Medical Reviewer’ },
role: { type: ‘string’, default: ‘Doctor / Medical Expert’ },
note: { type: ‘string’, default: ‘This article was reviewed for medical accuracy and clarity.’ }
},
edit: function(props){
const attrs = props.attributes;
return [
el(InspectorControls, {},
el(PanelBody, { title: __(‘Reviewer Details’, ‘rx-theme’) },
el(TextControl, {
label: __(‘Reviewer Name’, ‘rx-theme’),
value: attrs.name,
onChange: function(value){ props.setAttributes({ name: value }); }
}),
el(TextControl, {
label: __(‘Reviewer Role’, ‘rx-theme’),
value: attrs.role,
onChange: function(value){ props.setAttributes({ role: value }); }
}),
el(TextareaControl, {
label: __(‘Review Note’, ‘rx-theme’),
value: attrs.note,
onChange: function(value){ props.setAttributes({ note: value }); }
})
)
),
el(‘aside’, { className: ‘rx-reviewer-block’ },
el(‘div’, { className: ‘rx-reviewer-block__badge’ }, ‘✓’),
el(‘div’, {},
el(‘strong’, {}, attrs.name),
el(‘span’, {}, attrs.role),
el(‘p’, {}, attrs.note)
)
)
];
},
save: function(){ return null; }
});
})(window.wp.blocks, window.wp.element, window.wp.blockEditor, window.wp.components, window.wp.i18n);
”’)

# Create block folder structure placeholders too
block_defs = {
“rx-medical-box”: {
“name”: “rx-theme/medical-box”,
“title”: “RX Medical Box”
},
“rx-faq”: {
“name”: “rx-theme/faq”,
“title”: “RX FAQ”
},
“rx-reviewer-box”: {
“name”: “rx-theme/reviewer-box”,
“title”: “RX Reviewer Box”
}
}
for folder, data in block_defs.items():
bdir = blocks_dir / folder
bdir.mkdir(parents=True, exist_ok=True)
write(bdir / “block.json”, json.dumps({
“apiVersion”: 2,
“name”: data[“name”],
“title”: data[“title”],
“category”: “widgets”,
“icon”: “heart”,
“description”: “RX Theme medical Gutenberg block.”,
“textdomain”: “rx-theme”
}, indent=2))
write(bdir / “index.js”, “// Registered by assets/js/blocks/medical-blocks.js\n”)
write(bdir / “editor.css”, “/* Editor styles loaded from assets/css/blocks/medical-blocks.css */\n”)
write(bdir / “style.css”, “/* Frontend styles loaded from assets/css/blocks/medical-blocks.css */\n”)

# Loader for all v8 modules
write(theme_root / “inc/rx-v8-loader.php”, r”'<?php
/**
* RX Theme v8.0-v8.2 feature loader.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

$rx_theme_v8_files = array(
‘/inc/tools/import-export-settings.php’,
‘/inc/customizer/customizer-support.php’,
‘/inc/blocks/gutenberg-medical-blocks.php’,
);

foreach ( $rx_theme_v8_files as $rx_theme_v8_file ) {
$rx_theme_v8_path = get_template_directory() . $rx_theme_v8_file;

if ( file_exists( $rx_theme_v8_path ) ) {
require_once $rx_theme_v8_path;
}
}
”’)

# Add loader to autoload
autoload = theme_root / “inc/autoload.php”
if autoload.exists():
a = read(autoload)
if “/inc/rx-v8-loader.php” not in a:
idx = a.find(“foreach”)
if idx != -1:
before, after = a[:idx], a[idx:]
pos = before.rfind(“);”)
if pos != -1:
before = before[:pos] + ” ‘/inc/rx-v8-loader.php’,\n” + before[pos:]
a = before + after
else:
a += “\nrequire_once RX_THEME_DIR . ‘/inc/rx-v8-loader.php’;\n”
else:
a += “\nrequire_once RX_THEME_DIR . ‘/inc/rx-v8-loader.php’;\n”
write(autoload, a)
else:
write(autoload, “<?php\nif ( ! defined( ‘ABSPATH’ ) ) { exit; }\nrequire_once get_template_directory() . ‘/inc/rx-v8-loader.php’;\n”)

# PHP syntax check
errors = []
for p in theme_root.rglob(“*.php”):
proc = subprocess.run([“php”, “-l”, str(p)], capture_output=True, text=True)
if proc.returncode != 0:
errors.append(str(p) + “\n” + proc.stdout + proc.stderr)
if errors:
raise RuntimeError(“\n”.join(errors[:10]))

# Zip
zip_path = Path(“/mnt/data/rx-theme-v8-2-control-customizer-blocks.zip”)
if zip_path.exists():
zip_path.unlink()

with zipfile.ZipFile(zip_path, “w”, zipfile.ZIP_DEFLATED) as z:
for p in theme_root.rglob(“*”):
z.write(p, p.relative_to(work_root))

with zipfile.ZipFile(zip_path, “r”) as z:
bad = z.testzip()
if bad:
raise RuntimeError(“Bad ZIP file member: ” + str(bad))

print(“Created:”, zip_path)
print(“PHP syntax check: Passed”)
print(“ZIP integrity test: Passed”)
print(“Added: v8.0 Import/Export, v8.1 Customizer, v8.2 Gutenberg Medical Blocks”)

STDOUT/STDERR
Created: /mnt/data/rx-theme-v8-2-control-customizer-blocks.zip
PHP syntax check: Passed
ZIP integrity test: Passed
Added: v8.0 Import/Export, v8.1 Customizer, v8.2 Gutenberg Medical Blocks

Done dear friend — I added the next three steps together as RX Theme v8.2 Control + Customizer + Gutenberg Medical Blocks.

Checked before giving:

PHP syntax check: Passed
ZIP integrity test: Passed

Added in this version

v8.0 Import / Export Settings

New page:

Appearance → RX Import / Export

You can now:

Export RX Theme settings as JSON
Import RX Theme settings from JSON
Backup theme options
Backup ad manager settings
Backup Customizer theme mods
Restore settings safely

v8.1 Customizer Support

Go to:

Appearance → Customize → RX Theme Controls

Added Customizer sections:

RX Branding
RX Colors
RX Layout
RX Header
RX Medical Settings

Controls include:

Site logo URL
Primary color
Secondary color
Heading color
Text color
Container width
Sidebar position
Header style
Sticky header
Medical disclaimer text
Live preview for colors/container width

v8.2 Gutenberg Medical Blocks

Added medical blocks:

RX Medical Box
RX FAQ
RX Reviewer Box

Also added block folders:

blocks/rx-medical-box/
blocks/rx-faq/
blocks/rx-reviewer-box/

Install like before:

Dashboard → Appearance → Themes → Add New → Upload Theme

Upload:

rx-theme-v8-2-control-customizer-blocks.zip

Keep your working v7.9 backup before activating this one.

=============

Yes dear friend — I’ll add the next two modules safely on top of your working v8.2 version: Disease A-Z template improvement and Contact + Newsletter system.

from pathlib import Path
import zipfile, shutil, re, subprocess, json

base_zip = Path(“/mnt/data/rx-theme-v8-2-control-customizer-blocks.zip”)
fallbacks = [
Path(“/mnt/data/rx-theme-v7-9-ad-manager.zip”),
Path(“/mnt/data/rx-theme-v7-8-advanced-seo-schema.zip”),
]
if not base_zip.exists():
for f in fallbacks:
if f.exists():
base_zip = f
break

work_root = Path(“/mnt/data/rx_v84_disease_contact_build”)
extract_dir = work_root / “extract”

if work_root.exists():
shutil.rmtree(work_root)
work_root.mkdir(parents=True)
extract_dir.mkdir(parents=True)

with zipfile.ZipFile(base_zip, “r”) as z:
z.extractall(extract_dir)

theme_roots = [p.parent for p in extract_dir.rglob(“style.css”) if (p.parent / “functions.php”).exists()]
if not theme_roots:
raise RuntimeError(“Theme root not found.”)

src_root = theme_roots[0]
theme_root = work_root / “rx-theme-v8-4-disease-contact-newsletter”
shutil.copytree(src_root, theme_root)

def read(path):
return path.read_text(encoding=”utf-8″, errors=”ignore”)

def write(path, text):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(text, encoding=”utf-8″)

# Update style.css
style_path = theme_root / “style.css”
if style_path.exists():
s = read(style_path)
s = re.sub(r”Theme Name:\s*.*”, “Theme Name: RX Theme v8.4 Disease Contact Newsletter”, s, count=1) if “Theme Name:” in s else “/*\nTheme Name: RX Theme v8.4 Disease Contact Newsletter\nVersion: 8.4\n*/\n” + s
s = re.sub(r”Version:\s*.*”, “Version: 8.4”, s, count=1) if “Version:” in s else s.replace(“*/”, “Version: 8.4\n*/”, 1)
write(style_path, s)

# Directories
inc_medical = theme_root / “inc/medical”
inc_contact = theme_root / “inc/contact”
templates_dir = theme_root / “templates”
assets_css = theme_root / “assets/css/frontend”
assets_js = theme_root / “assets/js/frontend”
for d in [inc_medical, inc_contact, templates_dir, assets_css, assets_js]:
d.mkdir(parents=True, exist_ok=True)

# v8.3 Disease A-Z
write(inc_medical / “disease-az.php”, r”'<?php
/**
* RX Theme v8.3 Disease A-Z Template Improvement.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

function rx_theme_v83_disease_az_assets() {
$theme_uri = get_template_directory_uri();
$theme_dir = get_template_directory();

$css_rel = ‘/assets/css/frontend/disease-az.css’;
$js_rel = ‘/assets/js/frontend/disease-az.js’;

if ( file_exists( $theme_dir . $css_rel ) ) {
wp_enqueue_style(
‘rx-theme-disease-az’,
$theme_uri . $css_rel,
array(),
filemtime( $theme_dir . $css_rel )
);
}

if ( file_exists( $theme_dir . $js_rel ) ) {
wp_enqueue_script(
‘rx-theme-disease-az’,
$theme_uri . $js_rel,
array(),
filemtime( $theme_dir . $js_rel ),
true
);
}
}
add_action( ‘wp_enqueue_scripts’, ‘rx_theme_v83_disease_az_assets’, 42 );

function rx_theme_v83_get_disease_posts( $post_type = ‘post’, $limit = 500 ) {
$query = new WP_Query(
array(
‘post_type’ => sanitize_key( $post_type ),
‘post_status’ => ‘publish’,
‘posts_per_page’ => absint( $limit ),
‘orderby’ => ‘title’,
‘order’ => ‘ASC’,
‘ignore_sticky_posts’ => true,
‘no_found_rows’ => true,
‘update_post_meta_cache’ => false,
)
);

return $query;
}

function rx_theme_v83_group_posts_by_letter( $posts ) {
$groups = array();

foreach ( range( ‘A’, ‘Z’ ) as $letter ) {
$groups[ $letter ] = array();
}

foreach ( $posts as $post ) {
$title = get_the_title( $post );
$first = strtoupper( substr( remove_accents( $title ), 0, 1 ) );

if ( ! preg_match( ‘/[A-Z]/’, $first ) ) {
$first = ‘#’;
}

if ( ! isset( $groups[ $first ] ) ) {
$groups[ $first ] = array();
}

$groups[ $first ][] = $post;
}

return $groups;
}

function rx_theme_v83_disease_az_render( $atts = array() ) {
$atts = shortcode_atts(
array(
‘post_type’ => ‘post’,
‘limit’ => 500,
‘title’ => __( ‘Disease A-Z Library’, ‘rx-theme’ ),
‘subtitle’ => __( ‘Browse health topics, diseases, symptoms, diagnosis guides, and treatment articles alphabetically.’, ‘rx-theme’ ),
‘search’ => ‘1’,
),
$atts,
‘rx_disease_az’
);

$query = rx_theme_v83_get_disease_posts( $atts[‘post_type’], $atts[‘limit’] );
$groups = rx_theme_v83_group_posts_by_letter( $query->posts );

ob_start();
?>
<section class=”rx-disease-az” data-rx-disease-az>
<header class=”rx-disease-az__hero”>
<span class=”rx-disease-az__eyebrow”><?php esc_html_e( ‘Medical Library’, ‘rx-theme’ ); ?></span>
<h1><?php echo esc_html( $atts[‘title’] ); ?></h1>
<p><?php echo esc_html( $atts[‘subtitle’] ); ?></p>

<?php if ( ‘1’ === $atts[‘search’] ) : ?>
<div class=”rx-disease-az__search”>
<label class=”screen-reader-text” for=”rx-disease-az-search”><?php esc_html_e( ‘Search Disease A-Z’, ‘rx-theme’ ); ?></label>
<input id=”rx-disease-az-search” type=”search” placeholder=”<?php esc_attr_e( ‘Search disease, symptom, treatment…’, ‘rx-theme’ ); ?>” data-rx-disease-search>
<span aria-hidden=”true”>⌕</span>
</div>
<?php endif; ?>
</header>

<nav class=”rx-disease-az__letters” aria-label=”<?php esc_attr_e( ‘Disease alphabet navigation’, ‘rx-theme’ ); ?>”>
<?php foreach ( range( ‘A’, ‘Z’ ) as $letter ) : ?>
<?php $has_posts = ! empty( $groups[ $letter ] ); ?>
<a class=”<?php echo $has_posts ? ‘has-posts’ : ‘is-empty’; ?>” href=”#rx-letter-<?php echo esc_attr( $letter ); ?>”>
<?php echo esc_html( $letter ); ?>
</a>
<?php endforeach; ?>
</nav>

<div class=”rx-disease-az__grid”>
<?php foreach ( $groups as $letter => $posts ) : ?>
<?php if ( empty( $posts ) ) { continue; } ?>
<section id=”rx-letter-<?php echo esc_attr( $letter ); ?>” class=”rx-disease-az__group”>
<h2><?php echo esc_html( $letter ); ?></h2>
<div class=”rx-disease-az__items”>
<?php foreach ( $posts as $post ) : ?>
<article class=”rx-disease-az__item” data-rx-disease-item data-title=”<?php echo esc_attr( strtolower( get_the_title( $post ) ) ); ?>”>
<a href=”<?php echo esc_url( get_permalink( $post ) ); ?>”>
<strong><?php echo esc_html( get_the_title( $post ) ); ?></strong>
<span><?php echo esc_html( wp_trim_words( get_the_excerpt( $post ), 16, ‘…’ ) ); ?></span>
</a>
</article>
<?php endforeach; ?>
</div>
</section>
<?php endforeach; ?>
</div>

<div class=”rx-disease-az__no-results” data-rx-disease-no-results hidden>
<strong><?php esc_html_e( ‘No matching topics found.’, ‘rx-theme’ ); ?></strong>
<p><?php esc_html_e( ‘Try another disease, symptom, or treatment keyword.’, ‘rx-theme’ ); ?></p>
</div>
</section>
<?php

wp_reset_postdata();

return ob_get_clean();
}
add_shortcode( ‘rx_disease_az’, ‘rx_theme_v83_disease_az_render’ );
”’)

write(templates_dir / “template-disease-az.php”, r”'<?php
/**
* Template Name: RX Disease A-Z
* Description: Advanced Disease A-Z medical library template.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

get_header();
?>

<main id=”primary” class=”rx-main rx-disease-az-template”>
<div class=”rx-container”>
<?php
while ( have_posts() ) :
the_post();

if ( trim( get_the_content() ) ) {
echo ‘<div class=”rx-page-intro”>’;
the_content();
echo ‘</div>’;
}

if ( function_exists( ‘rx_theme_v83_disease_az_render’ ) ) {
echo rx_theme_v83_disease_az_render(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
endwhile;
?>
</div>
</main>

<?php
get_footer();
”’)

write(assets_css / “disease-az.css”, r”’/* RX Theme v8.3 Disease A-Z */
.rx-disease-az{
padding:34px 0 70px;
}
.rx-disease-az__hero{
padding:36px;
border:1px solid #e5e7eb;
border-radius:32px;
background:
radial-gradient(circle at top right, rgba(0,168,132,.13), transparent 34%),
linear-gradient(135deg,#f8fbff,#ffffff);
box-shadow:0 18px 55px rgba(15,23,42,.06);
}
.rx-disease-az__eyebrow{
display:inline-flex;
padding:7px 12px;
border-radius:999px;
background:#eff6ff;
color:var(–rx-primary-color,#0066cc);
font-size:13px;
font-weight:900;
text-transform:uppercase;
letter-spacing:.06em;
}
.rx-disease-az__hero h1{
margin:14px 0 10px;
font-size:clamp(34px,5vw,60px);
line-height:1.04;
color:var(–rx-heading-color,#111827);
}
.rx-disease-az__hero p{
max-width:760px;
margin:0;
color:#475569;
font-size:18px;
line-height:1.75;
}
.rx-disease-az__search{
position:relative;
max-width:720px;
margin-top:24px;
border:1px solid #cfcfcf;
border-radius:999px;
overflow:hidden;
background:#fff;
}
.rx-disease-az__search input{
width:100%;
min-height:48px;
border:0;
padding:0 58px 0 20px;
background:transparent;
outline:none;
font-size:16px;
}
.rx-disease-az__search span{
position:absolute;
right:18px;
top:50%;
transform:translateY(-50%);
font-size:24px;
color:#111;
}
.rx-disease-az__letters{
position:sticky;
top:82px;
z-index:20;
display:flex;
flex-wrap:wrap;
gap:7px;
margin:24px 0;
padding:12px;
border:1px solid #e5e7eb;
border-radius:20px;
background:rgba(255,255,255,.96);
box-shadow:0 12px 32px rgba(15,23,42,.06);
backdrop-filter:blur(12px);
}
.rx-disease-az__letters a{
display:inline-flex;
align-items:center;
justify-content:center;
width:38px;
height:38px;
border-radius:999px;
background:#f8fafc;
color:#64748b;
font-weight:900;
text-decoration:none;
}
.rx-disease-az__letters a.has-posts{
background:#eff6ff;
color:var(–rx-primary-color,#0066cc);
}
.rx-disease-az__letters a:hover,
.rx-disease-az__letters a:focus{
background:var(–rx-primary-color,#0066cc);
color:#fff;
}
.rx-disease-az__grid{
display:grid;
gap:22px;
}
.rx-disease-az__group{
scroll-margin-top:150px;
padding:24px;
border:1px solid #e5e7eb;
border-radius:26px;
background:#fff;
}
.rx-disease-az__group h2{
display:inline-flex;
align-items:center;
justify-content:center;
width:52px;
height:52px;
margin:0 0 18px;
border-radius:18px;
background:linear-gradient(135deg,var(–rx-primary-color,#0066cc),var(–rx-secondary-color,#00a884));
color:#fff;
}
.rx-disease-az__items{
display:grid;
grid-template-columns:repeat(3,minmax(0,1fr));
gap:14px;
}
.rx-disease-az__item a{
display:block;
height:100%;
padding:16px;
border:1px solid #e5e7eb;
border-radius:18px;
background:#f8fafc;
text-decoration:none;
transition:transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.rx-disease-az__item a:hover{
transform:translateY(-2px);
border-color:#bfdbfe;
box-shadow:0 14px 34px rgba(15,23,42,.09);
}
.rx-disease-az__item strong{
display:block;
color:var(–rx-heading-color,#111827);
font-size:17px;
line-height:1.25;
}
.rx-disease-az__item span{
display:block;
margin-top:8px;
color:#64748b;
font-size:14px;
line-height:1.55;
}
.rx-disease-az__no-results{
margin:24px 0;
padding:24px;
border:1px solid #fed7aa;
border-radius:22px;
background:#fff7ed;
color:#9a3412;
text-align:center;
}
body.rx-dark-mode .rx-disease-az__hero,
body.rx-dark-mode .rx-disease-az__letters,
body.rx-dark-mode .rx-disease-az__group{
background:#111827;
border-color:#243244;
}
body.rx-dark-mode .rx-disease-az__hero h1,
body.rx-dark-mode .rx-disease-az__item strong{
color:#fff;
}
body.rx-dark-mode .rx-disease-az__hero p,
body.rx-dark-mode .rx-disease-az__item span{
color:#cbd5e1;
}
body.rx-dark-mode .rx-disease-az__item a,
body.rx-dark-mode .rx-disease-az__search{
background:#0f172a;
border-color:#243244;
}
body.rx-dark-mode .rx-disease-az__search input{
color:#fff;
}
@media(max-width:980px){
.rx-disease-az__items{
grid-template-columns:repeat(2,minmax(0,1fr));
}
.rx-disease-az__letters{
top:70px;
}
}
@media(max-width:640px){
.rx-disease-az__hero{
padding:24px;
border-radius:24px;
}
.rx-disease-az__items{
grid-template-columns:1fr;
}
.rx-disease-az__group{
padding:18px;
border-radius:22px;
}
}
”’)

write(assets_js / “disease-az.js”, r”’/* RX Theme v8.3 Disease A-Z */
(function(){
‘use strict’;

document.querySelectorAll(‘[data-rx-disease-az]’).forEach(function(wrapper){
const input = wrapper.querySelector(‘[data-rx-disease-search]’);
const items = wrapper.querySelectorAll(‘[data-rx-disease-item]’);
const noResults = wrapper.querySelector(‘[data-rx-disease-no-results]’);

if (!input || !items.length) return;

input.addEventListener(‘input’, function(){
const query = input.value.trim().toLowerCase();
let visible = 0;

items.forEach(function(item){
const title = item.getAttribute(‘data-title’) || ”;
const match = !query || title.indexOf(query) !== -1;
item.hidden = !match;
if (match) visible++;
});

wrapper.querySelectorAll(‘.rx-disease-az__group’).forEach(function(group){
const visibleItems = group.querySelectorAll(‘[data-rx-disease-item]:not([hidden])’);
group.hidden = query && visibleItems.length === 0;
});

if (noResults) {
noResults.hidden = visible > 0;
}
});
});
})();
”’)

# v8.4 Contact + Newsletter
write(inc_contact / “contact-newsletter.php”, r”'<?php
/**
* RX Theme v8.4 Contact + Newsletter System.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

function rx_theme_v84_contact_assets() {
$theme_uri = get_template_directory_uri();
$theme_dir = get_template_directory();

$css_rel = ‘/assets/css/frontend/contact-newsletter.css’;
$js_rel = ‘/assets/js/frontend/contact-newsletter.js’;

if ( file_exists( $theme_dir . $css_rel ) ) {
wp_enqueue_style(
‘rx-theme-contact-newsletter’,
$theme_uri . $css_rel,
array(),
filemtime( $theme_dir . $css_rel )
);
}

if ( file_exists( $theme_dir . $js_rel ) ) {
wp_enqueue_script(
‘rx-theme-contact-newsletter’,
$theme_uri . $js_rel,
array(),
filemtime( $theme_dir . $js_rel ),
true
);
}
}
add_action( ‘wp_enqueue_scripts’, ‘rx_theme_v84_contact_assets’, 43 );

function rx_theme_v84_newsletter_emails() {
$emails = get_option( ‘rx_theme_newsletter_emails’, array() );
return is_array( $emails ) ? $emails : array();
}

function rx_theme_v84_save_newsletter_email( $email ) {
$email = sanitize_email( $email );

if ( ! is_email( $email ) ) {
return false;
}

$emails = rx_theme_v84_newsletter_emails();

if ( ! in_array( $email, $emails, true ) ) {
$emails[] = $email;
update_option( ‘rx_theme_newsletter_emails’, array_values( $emails ), false );
}

return true;
}

function rx_theme_v84_handle_contact_newsletter() {
if ( empty( $_POST[‘rx_theme_v84_action’] ) ) {
return;
}

$action = sanitize_key( wp_unslash( $_POST[‘rx_theme_v84_action’] ) );

if ( ‘contact’ === $action ) {
if ( empty( $_POST[‘rx_contact_nonce’] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST[‘rx_contact_nonce’] ) ), ‘rx_contact_form’ ) ) {
wp_safe_redirect( add_query_arg( ‘rx_contact’, ‘security’, wp_get_referer() ?: home_url( ‘/’ ) ) );
exit;
}

if ( ! empty( $_POST[‘rx_website’] ) ) {
wp_safe_redirect( add_query_arg( ‘rx_contact’, ‘spam’, wp_get_referer() ?: home_url( ‘/’ ) ) );
exit;
}

$name = isset( $_POST[‘rx_name’] ) ? sanitize_text_field( wp_unslash( $_POST[‘rx_name’] ) ) : ”;
$email = isset( $_POST[‘rx_email’] ) ? sanitize_email( wp_unslash( $_POST[‘rx_email’] ) ) : ”;
$subject = isset( $_POST[‘rx_subject’] ) ? sanitize_text_field( wp_unslash( $_POST[‘rx_subject’] ) ) : ”;
$message = isset( $_POST[‘rx_message’] ) ? sanitize_textarea_field( wp_unslash( $_POST[‘rx_message’] ) ) : ”;

if ( ! $name || ! is_email( $email ) || ! $message ) {
wp_safe_redirect( add_query_arg( ‘rx_contact’, ‘missing’, wp_get_referer() ?: home_url( ‘/’ ) ) );
exit;
}

$to = get_option( ‘admin_email’ );
$headers = array( ‘Reply-To: ‘ . $name . ‘ <‘ . $email . ‘>’ );
$body = “Name: {$name}\nEmail: {$email}\nSubject: {$subject}\n\nMessage:\n{$message}”;

wp_mail( $to, ‘[RX Theme Contact] ‘ . ( $subject ? $subject : ‘New message’ ), $body, $headers );

wp_safe_redirect( add_query_arg( ‘rx_contact’, ‘success’, wp_get_referer() ?: home_url( ‘/’ ) ) );
exit;
}

if ( ‘newsletter’ === $action ) {
if ( empty( $_POST[‘rx_newsletter_nonce’] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST[‘rx_newsletter_nonce’] ) ), ‘rx_newsletter_form’ ) ) {
wp_safe_redirect( add_query_arg( ‘rx_newsletter’, ‘security’, wp_get_referer() ?: home_url( ‘/’ ) ) );
exit;
}

$email = isset( $_POST[‘rx_newsletter_email’] ) ? sanitize_email( wp_unslash( $_POST[‘rx_newsletter_email’] ) ) : ”;

if ( ! rx_theme_v84_save_newsletter_email( $email ) ) {
wp_safe_redirect( add_query_arg( ‘rx_newsletter’, ‘invalid’, wp_get_referer() ?: home_url( ‘/’ ) ) );
exit;
}

wp_safe_redirect( add_query_arg( ‘rx_newsletter’, ‘success’, wp_get_referer() ?: home_url( ‘/’ ) ) );
exit;
}
}
add_action( ‘admin_post_nopriv_rx_theme_v84_form’, ‘rx_theme_v84_handle_contact_newsletter’ );
add_action( ‘admin_post_rx_theme_v84_form’, ‘rx_theme_v84_handle_contact_newsletter’ );

function rx_theme_v84_notice( $type, $success_text ) {
$value = isset( $_GET[ $type ] ) ? sanitize_key( wp_unslash( $_GET[ $type ] ) ) : ”;

if ( ! $value ) {
return ”;
}

if ( ‘success’ === $value ) {
return ‘<div class=”rx-form-notice rx-form-notice–success”>’ . esc_html( $success_text ) . ‘</div>’;
}

return ‘<div class=”rx-form-notice rx-form-notice–error”>’ . esc_html__( ‘Please check the form and try again.’, ‘rx-theme’ ) . ‘</div>’;
}

function rx_theme_v84_contact_form_shortcode( $atts ) {
$atts = shortcode_atts(
array(
‘title’ => __( ‘Contact RX Team’, ‘rx-theme’ ),
‘subtitle’ => __( ‘Send a message for website, article, or medical education related communication.’, ‘rx-theme’ ),
),
$atts,
‘rx_contact_form’
);

ob_start();
?>
<section class=”rx-contact-box”>
<div class=”rx-contact-box__intro”>
<span><?php esc_html_e( ‘Contact’, ‘rx-theme’ ); ?></span>
<h2><?php echo esc_html( $atts[‘title’] ); ?></h2>
<p><?php echo esc_html( $atts[‘subtitle’] ); ?></p>
</div>

<?php echo wp_kses_post( rx_theme_v84_notice( ‘rx_contact’, __( ‘Your message has been sent successfully.’, ‘rx-theme’ ) ) ); ?>

<form class=”rx-contact-form” method=”post” action=”<?php echo esc_url( admin_url( ‘admin-post.php’ ) ); ?>”>
<input type=”hidden” name=”action” value=”rx_theme_v84_form”>
<input type=”hidden” name=”rx_theme_v84_action” value=”contact”>
<?php wp_nonce_field( ‘rx_contact_form’, ‘rx_contact_nonce’ ); ?>

<p class=”rx-honeypot”>
<label><?php esc_html_e( ‘Website’, ‘rx-theme’ ); ?></label>
<input type=”text” name=”rx_website” tabindex=”-1″ autocomplete=”off”>
</p>

<div class=”rx-form-grid”>
<p>
<label for=”rx-name”><?php esc_html_e( ‘Name’, ‘rx-theme’ ); ?></label>
<input id=”rx-name” type=”text” name=”rx_name” required>
</p>
<p>
<label for=”rx-email”><?php esc_html_e( ‘Email’, ‘rx-theme’ ); ?></label>
<input id=”rx-email” type=”email” name=”rx_email” required>
</p>
</div>

<p>
<label for=”rx-subject”><?php esc_html_e( ‘Subject’, ‘rx-theme’ ); ?></label>
<input id=”rx-subject” type=”text” name=”rx_subject”>
</p>

<p>
<label for=”rx-message”><?php esc_html_e( ‘Message’, ‘rx-theme’ ); ?></label>
<textarea id=”rx-message” name=”rx_message” rows=”6″ required></textarea>
</p>

<button type=”submit”><?php esc_html_e( ‘Send Message’, ‘rx-theme’ ); ?></button>
</form>
</section>
<?php

return ob_get_clean();
}
add_shortcode( ‘rx_contact_form’, ‘rx_theme_v84_contact_form_shortcode’ );

function rx_theme_v84_newsletter_shortcode( $atts ) {
$atts = shortcode_atts(
array(
‘title’ => __( ‘Join RX Health Newsletter’, ‘rx-theme’ ),
‘subtitle’ => __( ‘Get useful medical education updates and new health guides.’, ‘rx-theme’ ),
‘button’ => __( ‘Subscribe’, ‘rx-theme’ ),
),
$atts,
‘rx_newsletter’
);

ob_start();
?>
<section class=”rx-newsletter-box”>
<div class=”rx-newsletter-box__content”>
<span><?php esc_html_e( ‘Newsletter’, ‘rx-theme’ ); ?></span>
<h2><?php echo esc_html( $atts[‘title’] ); ?></h2>
<p><?php echo esc_html( $atts[‘subtitle’] ); ?></p>
</div>

<?php echo wp_kses_post( rx_theme_v84_notice( ‘rx_newsletter’, __( ‘Thank you for subscribing.’, ‘rx-theme’ ) ) ); ?>

<form class=”rx-newsletter-form” method=”post” action=”<?php echo esc_url( admin_url( ‘admin-post.php’ ) ); ?>”>
<input type=”hidden” name=”action” value=”rx_theme_v84_form”>
<input type=”hidden” name=”rx_theme_v84_action” value=”newsletter”>
<?php wp_nonce_field( ‘rx_newsletter_form’, ‘rx_newsletter_nonce’ ); ?>

<label class=”screen-reader-text” for=”rx-newsletter-email”><?php esc_html_e( ‘Email address’, ‘rx-theme’ ); ?></label>
<input id=”rx-newsletter-email” type=”email” name=”rx_newsletter_email” placeholder=”<?php esc_attr_e( ‘Enter your email’, ‘rx-theme’ ); ?>” required>
<button type=”submit”><?php echo esc_html( $atts[‘button’] ); ?></button>
</form>
</section>
<?php

return ob_get_clean();
}
add_shortcode( ‘rx_newsletter’, ‘rx_theme_v84_newsletter_shortcode’ );

function rx_theme_v84_subscribers_menu() {
add_theme_page(
esc_html__( ‘RX Newsletter Subscribers’, ‘rx-theme’ ),
esc_html__( ‘RX Subscribers’, ‘rx-theme’ ),
‘manage_options’,
‘rx-theme-subscribers’,
‘rx_theme_v84_subscribers_page’
);
}
add_action( ‘admin_menu’, ‘rx_theme_v84_subscribers_menu’, 45 );

function rx_theme_v84_subscribers_page() {
if ( ! current_user_can( ‘manage_options’ ) ) {
return;
}

$emails = rx_theme_v84_newsletter_emails();
?>
<div class=”wrap”>
<h1><?php esc_html_e( ‘RX Newsletter Subscribers’, ‘rx-theme’ ); ?></h1>
<p><?php echo esc_html( sprintf( __( ‘Total subscribers: %d’, ‘rx-theme’ ), count( $emails ) ) ); ?></p>

<textarea class=”large-text code” rows=”14″ readonly><?php echo esc_textarea( implode( “\n”, $emails ) ); ?></textarea>
<p class=”description”><?php esc_html_e( ‘Copy these emails for your newsletter service. For large email campaigns, use a professional email platform.’, ‘rx-theme’ ); ?></p>
</div>
<?php
}
”’)

write(templates_dir / “template-contact-newsletter.php”, r”'<?php
/**
* Template Name: RX Contact + Newsletter
* Description: RX contact form and newsletter signup page.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

get_header();
?>

<main id=”primary” class=”rx-main rx-contact-newsletter-template”>
<div class=”rx-container”>
<?php
while ( have_posts() ) :
the_post();

echo ‘<header class=”rx-page-header”>’;
the_title( ‘<h1>’, ‘</h1>’ );
echo ‘</header>’;

if ( trim( get_the_content() ) ) {
echo ‘<div class=”rx-page-intro”>’;
the_content();
echo ‘</div>’;
}

echo do_shortcode( ‘[rx_contact_form]’ );
echo do_shortcode( ‘[rx_newsletter]’ );
endwhile;
?>
</div>
</main>

<?php
get_footer();
”’)

write(assets_css / “contact-newsletter.css”, r”’/* RX Theme v8.4 Contact + Newsletter */
.rx-contact-box,
.rx-newsletter-box{
margin:34px 0;
padding:30px;
border:1px solid #e5e7eb;
border-radius:30px;
background:#fff;
box-shadow:0 18px 55px rgba(15,23,42,.06);
}
.rx-contact-box__intro span,
.rx-newsletter-box__content span{
display:inline-flex;
margin-bottom:10px;
padding:7px 12px;
border-radius:999px;
background:#eff6ff;
color:var(–rx-primary-color,#0066cc);
font-weight:900;
font-size:13px;
letter-spacing:.06em;
text-transform:uppercase;
}
.rx-contact-box h2,
.rx-newsletter-box h2{
margin:0 0 10px;
color:var(–rx-heading-color,#111827);
font-size:clamp(28px,4vw,44px);
}
.rx-contact-box p,
.rx-newsletter-box p{
color:#64748b;
line-height:1.7;
}
.rx-form-grid{
display:grid;
grid-template-columns:repeat(2,minmax(0,1fr));
gap:16px;
}
.rx-contact-form label{
display:block;
margin-bottom:7px;
color:var(–rx-heading-color,#111827);
font-weight:900;
}
.rx-contact-form input,
.rx-contact-form textarea,
.rx-newsletter-form input{
width:100%;
border:1px solid #cbd5e1;
border-radius:16px;
padding:13px 15px;
background:#fff;
color:#111827;
outline:none;
}
.rx-contact-form input:focus,
.rx-contact-form textarea:focus,
.rx-newsletter-form input:focus{
border-color:var(–rx-primary-color,#0066cc);
box-shadow:0 0 0 4px rgba(0,102,204,.1);
}
.rx-contact-form button,
.rx-newsletter-form button{
border:0;
border-radius:999px;
padding:13px 22px;
background:linear-gradient(135deg,var(–rx-primary-color,#0066cc),var(–rx-secondary-color,#00a884));
color:#fff;
font-weight:900;
cursor:pointer;
}
.rx-newsletter-box{
display:grid;
grid-template-columns:minmax(0,1fr) minmax(300px,520px);
align-items:center;
gap:24px;
background:
radial-gradient(circle at top right, rgba(0,168,132,.14), transparent 36%),
linear-gradient(135deg,#f8fbff,#ffffff);
}
.rx-newsletter-form{
display:flex;
gap:10px;
padding:8px;
border:1px solid #cfcfcf;
border-radius:999px;
background:#fff;
}
.rx-newsletter-form input{
border:0;
border-radius:999px;
box-shadow:none!important;
}
.rx-newsletter-form button{
white-space:nowrap;
}
.rx-form-notice{
margin:18px 0;
padding:13px 16px;
border-radius:16px;
font-weight:800;
}
.rx-form-notice–success{
background:#ecfdf5;
color:#047857;
border:1px solid #bbf7d0;
}
.rx-form-notice–error{
background:#fef2f2;
color:#b91c1c;
border:1px solid #fecaca;
}
.rx-honeypot{
position:absolute!important;
left:-9999px!important;
opacity:0!important;
}
body.rx-dark-mode .rx-contact-box,
body.rx-dark-mode .rx-newsletter-box{
background:#111827;
border-color:#243244;
}
body.rx-dark-mode .rx-contact-box h2,
body.rx-dark-mode .rx-newsletter-box h2,
body.rx-dark-mode .rx-contact-form label{
color:#fff;
}
body.rx-dark-mode .rx-contact-form input,
body.rx-dark-mode .rx-contact-form textarea,
body.rx-dark-mode .rx-newsletter-form,
body.rx-dark-mode .rx-newsletter-form input{
background:#0f172a;
border-color:#243244;
color:#fff;
}
@media(max-width:800px){
.rx-form-grid,
.rx-newsletter-box{
grid-template-columns:1fr;
}
}
@media(max-width:560px){
.rx-contact-box,
.rx-newsletter-box{
padding:22px;
border-radius:22px;
}
.rx-newsletter-form{
display:block;
border-radius:22px;
}
.rx-newsletter-form button{
width:100%;
margin-top:8px;
}
}
”’)

write(assets_js / “contact-newsletter.js”, r”’/* RX Theme v8.4 Contact + Newsletter small enhancements */
(function(){
‘use strict’;

document.querySelectorAll(‘.rx-contact-form, .rx-newsletter-form’).forEach(function(form){
form.addEventListener(‘submit’, function(){
const button = form.querySelector(‘button[type=”submit”]’);
if (button) {
button.dataset.originalText = button.textContent;
button.textContent = ‘Sending…’;
button.disabled = true;
}
});
});
})();
”’)

# Loader
write(theme_root / “inc/rx-v83-v84-loader.php”, r”'<?php
/**
* RX Theme v8.3-v8.4 feature loader.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

$rx_theme_v83_v84_files = array(
‘/inc/medical/disease-az.php’,
‘/inc/contact/contact-newsletter.php’,
);

foreach ( $rx_theme_v83_v84_files as $rx_theme_v83_v84_file ) {
$rx_theme_v83_v84_path = get_template_directory() . $rx_theme_v83_v84_file;

if ( file_exists( $rx_theme_v83_v84_path ) ) {
require_once $rx_theme_v83_v84_path;
}
}
”’)

# Add to autoload
autoload = theme_root / “inc/autoload.php”
if autoload.exists():
a = read(autoload)
if “/inc/rx-v83-v84-loader.php” not in a:
idx = a.find(“foreach”)
if idx != -1:
before, after = a[:idx], a[idx:]
pos = before.rfind(“);”)
if pos != -1:
before = before[:pos] + ” ‘/inc/rx-v83-v84-loader.php’,\n” + before[pos:]
a = before + after
else:
a += “\nrequire_once RX_THEME_DIR . ‘/inc/rx-v83-v84-loader.php’;\n”
else:
a += “\nrequire_once RX_THEME_DIR . ‘/inc/rx-v83-v84-loader.php’;\n”
write(autoload, a)
else:
write(autoload, “<?php\nif ( ! defined( ‘ABSPATH’ ) ) { exit; }\nrequire_once get_template_directory() . ‘/inc/rx-v83-v84-loader.php’;\n”)

# PHP syntax check
errors = []
for p in theme_root.rglob(“*.php”):
proc = subprocess.run([“php”, “-l”, str(p)], capture_output=True, text=True)
if proc.returncode != 0:
errors.append(str(p) + “\n” + proc.stdout + proc.stderr)
if errors:
raise RuntimeError(“\n”.join(errors[:10]))

# Zip
zip_path = Path(“/mnt/data/rx-theme-v8-4-disease-contact-newsletter.zip”)
if zip_path.exists():
zip_path.unlink()

with zipfile.ZipFile(zip_path, “w”, zipfile.ZIP_DEFLATED) as z:
for p in theme_root.rglob(“*”):
z.write(p, p.relative_to(work_root))

with zipfile.ZipFile(zip_path, “r”) as z:
bad = z.testzip()
if bad:
raise RuntimeError(“Bad ZIP file member: ” + str(bad))

print(“Created:”, zip_path)
print(“PHP syntax check: Passed”)
print(“ZIP integrity test: Passed”)
print(“Added: v8.3 Disease A-Z Template Improvement + v8.4 Contact Newsletter System”)

STDOUT/STDERR
Created: /mnt/data/rx-theme-v8-4-disease-contact-newsletter.zip
PHP syntax check: Passed
ZIP integrity test: Passed
Added: v8.3 Disease A-Z Template Improvement + v8.4 Contact Newsletter System

Done dear friend — I added the next two modules as RX Theme v8.4 Disease A-Z + Contact Newsletter System.

Checked before giving:

PHP syntax check: Passed
ZIP integrity test: Passe

v8.3 Disease A-Z Template Improvement

Added:

Advanced Disease A-Z page template
Alphabet navigation A–Z
Sticky letter navigation
Live disease/topic search
Grouped article listing by first letter
Responsive disease cards
Dark mode support
Shortcode support

New template:

RX Disease A-Z

New shortcode:

[rx_disease_az]

New files:

inc/medical/disease-az.php
templates/template-disease-az.php
assets/css/frontend/disease-az.css
assets/js/frontend/disease-az.js

v8.4 Contact + Newsletter System

Added:

Contact form system
Newsletter signup system
Admin email notification
Spam honeypot field
Nonce security
Newsletter subscriber storage
Subscriber admin page
Contact + newsletter page template
Shortcode support
Dark mode support
Mobile responsive design

New template:

RX Contact + Newsletter

New shortcodes:

[rx_contact_form]
[rx_newsletter]

New admin page:

Appearance → RX Subscribers

Install like before:

Dashboard → Appearance → Themes → Add New → Upload Theme

Upload:

rx-theme-v8-4-disease-contact-newsletter.zip

Keep your working v8.2 backup before activating this one.

 

============================================

Yes dear friend — I’ll complete these remaining RX Theme modules safely in one final polish version, building on your working v8.4 version: v8.5 WooCommerce/Elementor, v8.6 Accessibility tools, and v8.7 Final premium cleanup.

from pathlib import Path
import zipfile, shutil, re, subprocess

base_zip = Path(“/mnt/data/rx-theme-v8-4-disease-contact-newsletter.zip”)
fallbacks = [
Path(“/mnt/data/rx-theme-v8-2-control-customizer-blocks.zip”),
Path(“/mnt/data/rx-theme-v7-9-ad-manager.zip”),
]
if not base_zip.exists():
for f in fallbacks:
if f.exists():
base_zip = f
break

work_root = Path(“/mnt/data/rx_v87_final_build”)
extract_dir = work_root / “extract”

if work_root.exists():
shutil.rmtree(work_root)
work_root.mkdir(parents=True)
extract_dir.mkdir(parents=True)

with zipfile.ZipFile(base_zip, “r”) as z:
z.extractall(extract_dir)

theme_roots = [p.parent for p in extract_dir.rglob(“style.css”) if (p.parent / “functions.php”).exists()]
if not theme_roots:
raise RuntimeError(“Theme root not found.”)

src_root = theme_roots[0]
theme_root = work_root / “rx-theme-v8-7-final-premium-polish”
shutil.copytree(src_root, theme_root)

def read(path):
return path.read_text(encoding=”utf-8″, errors=”ignore”)

def write(path, text):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(text, encoding=”utf-8″)

# Update style.css
style_path = theme_root / “style.css”
if style_path.exists():
s = read(style_path)
s = re.sub(r”Theme Name:\s*.*”, “Theme Name: RX Theme v8.7 Final Premium Polish”, s, count=1) if “Theme Name:” in s else “/*\nTheme Name: RX Theme v8.7 Final Premium Polish\nVersion: 8.7\n*/\n” + s
s = re.sub(r”Version:\s*.*”, “Version: 8.7”, s, count=1) if “Version:” in s else s.replace(“*/”, “Version: 8.7\n*/”, 1)
write(style_path, s)

# Directories
inc_compat = theme_root / “inc/compatibility”
inc_access = theme_root / “inc/accessibility”
inc_polish = theme_root / “inc/polish”
assets_css_front = theme_root / “assets/css/frontend”
assets_js_front = theme_root / “assets/js/frontend”
assets_css_backend = theme_root / “assets/css/backend”
for d in [inc_compat, inc_access, inc_polish, assets_css_front, assets_js_front, assets_css_backend]:
d.mkdir(parents=True, exist_ok=True)

# v8.5 WooCommerce / Elementor compatibility
write(inc_compat / “woocommerce-elementor.php”, r”'<?php
/**
* RX Theme v8.5 WooCommerce + Elementor Compatibility Polish.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

function rx_theme_v85_woocommerce_support() {
add_theme_support(
‘woocommerce’,
array(
‘thumbnail_image_width’ => 420,
‘single_image_width’ => 720,
‘product_grid’ => array(
‘default_rows’ => 3,
‘min_rows’ => 1,
‘max_rows’ => 6,
‘default_columns’ => 3,
‘min_columns’ => 1,
‘max_columns’ => 4,
),
)
);

add_theme_support( ‘wc-product-gallery-zoom’ );
add_theme_support( ‘wc-product-gallery-lightbox’ );
add_theme_support( ‘wc-product-gallery-slider’ );
}
add_action( ‘after_setup_theme’, ‘rx_theme_v85_woocommerce_support’ );

function rx_theme_v85_woocommerce_wrappers_start() {
echo ‘<main id=”primary” class=”rx-main rx-woocommerce-page”><div class=”rx-container”>’;
}
remove_action( ‘woocommerce_before_main_content’, ‘woocommerce_output_content_wrapper’, 10 );
add_action( ‘woocommerce_before_main_content’, ‘rx_theme_v85_woocommerce_wrappers_start’, 10 );

function rx_theme_v85_woocommerce_wrappers_end() {
echo ‘</div></main>’;
}
remove_action( ‘woocommerce_after_main_content’, ‘woocommerce_output_content_wrapper_end’, 10 );
add_action( ‘woocommerce_after_main_content’, ‘rx_theme_v85_woocommerce_wrappers_end’, 10 );

function rx_theme_v85_woocommerce_columns() {
return 3;
}
add_filter( ‘loop_shop_columns’, ‘rx_theme_v85_woocommerce_columns’ );

function rx_theme_v85_woocommerce_products_per_page() {
return 12;
}
add_filter( ‘loop_shop_per_page’, ‘rx_theme_v85_woocommerce_products_per_page’, 20 );

function rx_theme_v85_body_classes( $classes ) {
if ( class_exists( ‘WooCommerce’ ) && ( is_woocommerce() || is_cart() || is_checkout() || is_account_page() ) ) {
$classes[] = ‘rx-has-woocommerce’;
}

if ( did_action( ‘elementor/loaded’ ) ) {
$classes[] = ‘rx-has-elementor’;
}

return $classes;
}
add_filter( ‘body_class’, ‘rx_theme_v85_body_classes’ );

function rx_theme_v85_elementor_support() {
add_theme_support( ‘elementor’ );
}
add_action( ‘after_setup_theme’, ‘rx_theme_v85_elementor_support’ );

function rx_theme_v85_elementor_locations( $elementor_theme_manager ) {
if ( method_exists( $elementor_theme_manager, ‘register_all_core_location’ ) ) {
$elementor_theme_manager->register_all_core_location();
}
}
add_action( ‘elementor/theme/register_locations’, ‘rx_theme_v85_elementor_locations’ );

function rx_theme_v85_compat_assets() {
$theme_uri = get_template_directory_uri();
$theme_dir = get_template_directory();
$css_rel = ‘/assets/css/frontend/compatibility-polish.css’;

if ( file_exists( $theme_dir . $css_rel ) ) {
wp_enqueue_style(
‘rx-theme-compatibility-polish’,
$theme_uri . $css_rel,
array(),
filemtime( $theme_dir . $css_rel )
);
}
}
add_action( ‘wp_enqueue_scripts’, ‘rx_theme_v85_compat_assets’, 44 );
”’)

write(assets_css_front / “compatibility-polish.css”, r”’/* RX Theme v8.5 WooCommerce + Elementor Compatibility */
.rx-woocommerce-page{
padding:36px 0 64px;
}
.rx-has-woocommerce .woocommerce .products{
display:grid;
grid-template-columns:repeat(3,minmax(0,1fr));
gap:24px;
}
.rx-has-woocommerce .woocommerce ul.products::before,
.rx-has-woocommerce .woocommerce ul.products::after{
display:none;
}
.rx-has-woocommerce .woocommerce ul.products li.product{
width:auto!important;
margin:0!important;
padding:18px;
border:1px solid #e5e7eb;
border-radius:24px;
background:#fff;
box-shadow:0 14px 40px rgba(15,23,42,.06);
transition:transform .18s ease, box-shadow .18s ease;
}
.rx-has-woocommerce .woocommerce ul.products li.product:hover{
transform:translateY(-3px);
box-shadow:0 24px 60px rgba(15,23,42,.12);
}
.rx-has-woocommerce .woocommerce ul.products li.product img{
border-radius:18px;
}
.rx-has-woocommerce .woocommerce ul.products li.product .woocommerce-loop-product__title{
color:var(–rx-heading-color,#111827);
font-size:18px;
line-height:1.3;
}
.rx-has-woocommerce .woocommerce a.button,
.rx-has-woocommerce .woocommerce button.button,
.rx-has-woocommerce .woocommerce input.button,
.rx-has-woocommerce .woocommerce #respond input#submit{
border-radius:999px;
background:linear-gradient(135deg,var(–rx-primary-color,#0066cc),var(–rx-secondary-color,#00a884));
color:#fff;
font-weight:900;
border:0;
}
.rx-has-woocommerce .woocommerce-message,
.rx-has-woocommerce .woocommerce-info,
.rx-has-woocommerce .woocommerce-error{
border-radius:18px;
border-top:0;
box-shadow:0 12px 32px rgba(15,23,42,.07);
}
.rx-has-elementor .elementor-section.elementor-section-boxed > .elementor-container{
max-width:var(–rx-container-width,1200px);
}
body.rx-dark-mode.rx-has-woocommerce .woocommerce ul.products li.product,
body.rx-dark-mode.rx-has-woocommerce .woocommerce div.product,
body.rx-dark-mode.rx-has-woocommerce .woocommerce-message,
body.rx-dark-mode.rx-has-woocommerce .woocommerce-info{
background:#111827;
border-color:#243244;
color:#e5e7eb;
}
body.rx-dark-mode.rx-has-woocommerce .woocommerce ul.products li.product .woocommerce-loop-product__title{
color:#fff;
}
@media(max-width:980px){
.rx-has-woocommerce .woocommerce .products{
grid-template-columns:repeat(2,minmax(0,1fr));
}
}
@media(max-width:620px){
.rx-has-woocommerce .woocommerce .products{
grid-template-columns:1fr;
}
}
”’)

# v8.6 Accessibility advanced tools
write(inc_access / “accessibility-tools.php”, r”'<?php
/**
* RX Theme v8.6 Accessibility Advanced Tools.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

function rx_theme_v86_skip_links() {
?>
<a class=”rx-skip-link screen-reader-text” href=”#primary”><?php esc_html_e( ‘Skip to main content’, ‘rx-theme’ ); ?></a>
<a class=”rx-skip-link screen-reader-text” href=”#site-navigation”><?php esc_html_e( ‘Skip to navigation’, ‘rx-theme’ ); ?></a>
<?php
}
add_action( ‘wp_body_open’, ‘rx_theme_v86_skip_links’, 1 );

function rx_theme_v86_accessibility_toolbar() {
if ( is_admin() ) {
return;
}
?>
<div class=”rx-accessibility-toolbar” aria-label=”<?php esc_attr_e( ‘Accessibility tools’, ‘rx-theme’ ); ?>”>
<button type=”button” class=”rx-a11y-toggle” aria-expanded=”false” aria-controls=”rx-a11y-panel”>
<?php esc_html_e( ‘Accessibility’, ‘rx-theme’ ); ?>
</button>
<div id=”rx-a11y-panel” class=”rx-a11y-panel” hidden>
<button type=”button” data-rx-a11y=”font-plus”><?php esc_html_e( ‘A+’, ‘rx-theme’ ); ?></button>
<button type=”button” data-rx-a11y=”font-minus”><?php esc_html_e( ‘A-‘, ‘rx-theme’ ); ?></button>
<button type=”button” data-rx-a11y=”contrast”><?php esc_html_e( ‘High Contrast’, ‘rx-theme’ ); ?></button>
<button type=”button” data-rx-a11y=”underline”><?php esc_html_e( ‘Underline Links’, ‘rx-theme’ ); ?></button>
<button type=”button” data-rx-a11y=”motion”><?php esc_html_e( ‘Reduce Motion’, ‘rx-theme’ ); ?></button>
<button type=”button” data-rx-a11y=”reset”><?php esc_html_e( ‘Reset’, ‘rx-theme’ ); ?></button>
</div>
</div>
<?php
}
add_action( ‘wp_footer’, ‘rx_theme_v86_accessibility_toolbar’, 30 );

function rx_theme_v86_accessibility_assets() {
$theme_uri = get_template_directory_uri();
$theme_dir = get_template_directory();

$css_rel = ‘/assets/css/frontend/accessibility-tools.css’;
$js_rel = ‘/assets/js/frontend/accessibility-tools.js’;

if ( file_exists( $theme_dir . $css_rel ) ) {
wp_enqueue_style(
‘rx-theme-accessibility-tools’,
$theme_uri . $css_rel,
array(),
filemtime( $theme_dir . $css_rel )
);
}

if ( file_exists( $theme_dir . $js_rel ) ) {
wp_enqueue_script(
‘rx-theme-accessibility-tools’,
$theme_uri . $js_rel,
array(),
filemtime( $theme_dir . $js_rel ),
true
);
}
}
add_action( ‘wp_enqueue_scripts’, ‘rx_theme_v86_accessibility_assets’, 45 );

function rx_theme_v86_nav_id_fallback( $items, $args ) {
return $items;
}
add_filter( ‘wp_nav_menu_items’, ‘rx_theme_v86_nav_id_fallback’, 10, 2 );
”’)

write(assets_css_front / “accessibility-tools.css”, r”’/* RX Theme v8.6 Accessibility Advanced Tools */
.rx-skip-link:focus{
position:fixed!important;
top:12px;
left:12px;
z-index:100000;
width:auto;
height:auto;
padding:12px 16px;
clip:auto;
border-radius:10px;
background:#111827;
color:#fff;
font-weight:900;
text-decoration:none;
}
.rx-accessibility-toolbar{
position:fixed;
right:18px;
bottom:86px;
z-index:9998;
font-family:inherit;
}
.rx-a11y-toggle{
border:0;
border-radius:999px;
padding:11px 15px;
background:#111827;
color:#fff;
font-weight:900;
cursor:pointer;
box-shadow:0 14px 34px rgba(15,23,42,.24);
}
.rx-a11y-panel{
position:absolute;
right:0;
bottom:52px;
display:grid;
gap:8px;
width:210px;
padding:12px;
border:1px solid #e5e7eb;
border-radius:18px;
background:#fff;
box-shadow:0 24px 70px rgba(15,23,42,.2);
}
.rx-a11y-panel button{
width:100%;
border:1px solid #dbeafe;
border-radius:12px;
padding:10px 12px;
background:#eff6ff;
color:var(–rx-primary-color,#0066cc);
font-weight:900;
cursor:pointer;
}
html.rx-a11y-font-large body{
font-size:112.5%;
}
html.rx-a11y-font-small body{
font-size:93.75%;
}
html.rx-a11y-contrast{
filter:contrast(1.18);
}
html.rx-a11y-contrast body{
background:#fff!important;
color:#000!important;
}
html.rx-a11y-underline a{
text-decoration:underline!important;
text-underline-offset:3px;
}
html.rx-a11y-reduce-motion *,
html.rx-a11y-reduce-motion *::before,
html.rx-a11y-reduce-motion *::after{
animation:none!important;
transition:none!important;
scroll-behavior:auto!important;
}
:focus-visible{
outline:3px solid var(–rx-primary-color,#0066cc);
outline-offset:3px;
}
body.rx-dark-mode .rx-a11y-panel{
background:#111827;
border-color:#243244;
}
@media(max-width:640px){
.rx-accessibility-toolbar{
right:12px;
bottom:74px;
}
.rx-a11y-panel{
width:190px;
}
}
@media print{
.rx-accessibility-toolbar,
.rx-skip-link{
display:none!important;
}
}
”’)

write(assets_js_front / “accessibility-tools.js”, r”’/* RX Theme v8.6 Accessibility Tools */
(function(){
‘use strict’;

const root = document.documentElement;
const toggle = document.querySelector(‘.rx-a11y-toggle’);
const panel = document.getElementById(‘rx-a11y-panel’);
const storageKey = ‘rxA11ySettings’;

function getSettings(){
try {
return JSON.parse(localStorage.getItem(storageKey) || ‘{}’);
} catch(e) {
return {};
}
}

function saveSettings(settings){
try {
localStorage.setItem(storageKey, JSON.stringify(settings));
} catch(e) {}
}

function apply(settings){
root.classList.toggle(‘rx-a11y-font-large’, settings.font === ‘large’);
root.classList.toggle(‘rx-a11y-font-small’, settings.font === ‘small’);
root.classList.toggle(‘rx-a11y-contrast’, !!settings.contrast);
root.classList.toggle(‘rx-a11y-underline’, !!settings.underline);
root.classList.toggle(‘rx-a11y-reduce-motion’, !!settings.motion);
}

apply(getSettings());

if (toggle && panel) {
toggle.addEventListener(‘click’, function(){
const open = toggle.getAttribute(‘aria-expanded’) === ‘true’;
toggle.setAttribute(‘aria-expanded’, open ? ‘false’ : ‘true’);
panel.hidden = open;
});

document.addEventListener(‘keydown’, function(event){
if (event.key === ‘Escape’ && !panel.hidden) {
panel.hidden = true;
toggle.setAttribute(‘aria-expanded’, ‘false’);
toggle.focus();
}
});
}

document.addEventListener(‘click’, function(event){
const button = event.target.closest(‘[data-rx-a11y]’);
if (!button) return;

const action = button.getAttribute(‘data-rx-a11y’);
const settings = getSettings();

if (action === ‘font-plus’) {
settings.font = ‘large’;
} else if (action === ‘font-minus’) {
settings.font = ‘small’;
} else if (action === ‘contrast’) {
settings.contrast = !settings.contrast;
} else if (action === ‘underline’) {
settings.underline = !settings.underline;
} else if (action === ‘motion’) {
settings.motion = !settings.motion;
} else if (action === ‘reset’) {
Object.keys(settings).forEach(function(key){ delete settings[key]; });
}

saveSettings(settings);
apply(settings);
});
})();
”’)

# v8.7 Final cleanup + premium polish
write(inc_polish / “final-premium-polish.php”, r”'<?php
/**
* RX Theme v8.7 Final Cleanup + Premium Polish.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

function rx_theme_v87_premium_assets() {
$theme_uri = get_template_directory_uri();
$theme_dir = get_template_directory();

$css_rel = ‘/assets/css/frontend/premium-polish.css’;
$js_rel = ‘/assets/js/frontend/premium-polish.js’;

if ( file_exists( $theme_dir . $css_rel ) ) {
wp_enqueue_style(
‘rx-theme-premium-polish’,
$theme_uri . $css_rel,
array(),
filemtime( $theme_dir . $css_rel )
);
}

if ( file_exists( $theme_dir . $js_rel ) ) {
wp_enqueue_script(
‘rx-theme-premium-polish’,
$theme_uri . $js_rel,
array(),
filemtime( $theme_dir . $js_rel ),
true
);
}
}
add_action( ‘wp_enqueue_scripts’, ‘rx_theme_v87_premium_assets’, 99 );

function rx_theme_v87_body_classes( $classes ) {
$classes[] = ‘rx-theme-premium-polish’;

if ( is_singular() ) {
$classes[] = ‘rx-is-singular-premium’;
}

return $classes;
}
add_filter( ‘body_class’, ‘rx_theme_v87_body_classes’ );

function rx_theme_v87_admin_dashboard_notice() {
if ( ! current_user_can( ‘manage_options’ ) ) {
return;
}

$screen = get_current_screen();

if ( ! $screen || ‘appearance_page_rx-theme-import-export’ !== $screen->id ) {
return;
}

echo ‘<div class=”notice notice-success”><p><strong>RX Theme v8.7:</strong> ‘ . esc_html__( ‘Premium polish, compatibility, and accessibility modules are active.’, ‘rx-theme’ ) . ‘</p></div>’;
}
add_action( ‘admin_notices’, ‘rx_theme_v87_admin_dashboard_notice’ );

function rx_theme_v87_add_image_sizes() {
add_image_size( ‘rx-premium-card’, 640, 420, true );
add_image_size( ‘rx-premium-hero’, 1440, 720, true );
}
add_action( ‘after_setup_theme’, ‘rx_theme_v87_add_image_sizes’ );

function rx_theme_v87_excerpt_more() {
return ‘…’;
}
add_filter( ‘excerpt_more’, ‘rx_theme_v87_excerpt_more’ );

function rx_theme_v87_excerpt_length( $length ) {
return 26;
}
add_filter( ‘excerpt_length’, ‘rx_theme_v87_excerpt_length’, 20 );
”’)

write(assets_css_front / “premium-polish.css”, r”’/* RX Theme v8.7 Final Premium Polish */
:root{
–rx-radius-sm:12px;
–rx-radius-md:18px;
–rx-radius-lg:28px;
–rx-shadow-soft:0 14px 40px rgba(15,23,42,.07);
–rx-shadow-strong:0 24px 70px rgba(15,23,42,.14);
}
html{
scroll-behavior:smooth;
}
body.rx-theme-premium-polish{
-webkit-font-smoothing:antialiased;
-moz-osx-font-smoothing:grayscale;
}
.rx-container{
max-width:var(–rx-container-width,1200px);
}
.rx-card,
.rx-widget,
.widget,
.rx-main article{
overflow-wrap:anywhere;
}
.rx-main img,
.entry-content img{
border-radius:var(–rx-radius-md);
}
.rx-main table,
.entry-content table{
width:100%;
border-collapse:collapse;
overflow:hidden;
border-radius:var(–rx-radius-md);
}
.rx-main th,
.rx-main td,
.entry-content th,
.entry-content td{
padding:12px 14px;
border:1px solid #e5e7eb;
}
.rx-main th,
.entry-content th{
background:#f8fafc;
color:var(–rx-heading-color,#111827);
font-weight:900;
}
blockquote{
margin:26px 0;
padding:20px 22px;
border-left:5px solid var(–rx-primary-color,#0066cc);
border-radius:0 var(–rx-radius-md) var(–rx-radius-md) 0;
background:#f8fbff;
color:#334155;
}
.rx-back-to-top{
position:fixed;
right:18px;
bottom:22px;
z-index:9997;
width:46px;
height:46px;
border:0;
border-radius:999px;
background:linear-gradient(135deg,var(–rx-primary-color,#0066cc),var(–rx-secondary-color,#00a884));
color:#fff;
font-weight:1000;
cursor:pointer;
box-shadow:var(–rx-shadow-strong);
opacity:0;
visibility:hidden;
transform:translateY(8px);
transition:opacity .18s ease, visibility .18s ease, transform .18s ease;
}
.rx-back-to-top.is-visible{
opacity:1;
visibility:visible;
transform:translateY(0);
}
body.rx-dark-mode blockquote{
background:#111827;
color:#cbd5e1;
}
body.rx-dark-mode .rx-main th,
body.rx-dark-mode .entry-content th{
background:#111827;
color:#fff;
}
body.rx-dark-mode .rx-main th,
body.rx-dark-mode .rx-main td,
body.rx-dark-mode .entry-content th,
body.rx-dark-mode .entry-content td{
border-color:#243244;
}
@media(max-width:640px){
.rx-back-to-top{
right:12px;
bottom:18px;
width:42px;
height:42px;
}
}
@media print{
.rx-back-to-top,
.rx-accessibility-toolbar,
.rx-site-header,
.rx-site-footer,
.rx-social-share,
.rx-ad-slot{
display:none!important;
}
body{
background:#fff!important;
color:#000!important;
}
a{
color:#000!important;
text-decoration:underline!important;
}
}
”’)

write(assets_js_front / “premium-polish.js”, r”’/* RX Theme v8.7 Final Premium Polish */
(function(){
‘use strict’;

const button = document.createElement(‘button’);
button.type = ‘button’;
button.className = ‘rx-back-to-top’;
button.setAttribute(‘aria-label’, ‘Back to top’);
button.textContent = ‘↑’;
document.body.appendChild(button);

function updateButton(){
if (window.scrollY > 500) {
button.classList.add(‘is-visible’);
} else {
button.classList.remove(‘is-visible’);
}
}

window.addEventListener(‘scroll’, updateButton, { passive: true });
updateButton();

button.addEventListener(‘click’, function(){
window.scrollTo({ top: 0, behavior: ‘smooth’ });
});

document.querySelectorAll(‘a[target=”_blank”]’).forEach(function(link){
const rel = (link.getAttribute(‘rel’) || ”).split(‘ ‘);
if (rel.indexOf(‘noopener’) === -1) rel.push(‘noopener’);
if (rel.indexOf(‘noreferrer’) === -1) rel.push(‘noreferrer’);
link.setAttribute(‘rel’, rel.join(‘ ‘).trim());
});
})();
”’)

# Loader
write(theme_root / “inc/rx-v85-v87-loader.php”, r”'<?php
/**
* RX Theme v8.5-v8.7 final feature loader.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

$rx_theme_v85_v87_files = array(
‘/inc/compatibility/woocommerce-elementor.php’,
‘/inc/accessibility/accessibility-tools.php’,
‘/inc/polish/final-premium-polish.php’,
);

foreach ( $rx_theme_v85_v87_files as $rx_theme_v85_v87_file ) {
$rx_theme_v85_v87_path = get_template_directory() . $rx_theme_v85_v87_file;

if ( file_exists( $rx_theme_v85_v87_path ) ) {
require_once $rx_theme_v85_v87_path;
}
}
”’)

# Add loader to autoload
autoload = theme_root / “inc/autoload.php”
if autoload.exists():
a = read(autoload)
if “/inc/rx-v85-v87-loader.php” not in a:
idx = a.find(“foreach”)
if idx != -1:
before, after = a[:idx], a[idx:]
pos = before.rfind(“);”)
if pos != -1:
before = before[:pos] + ” ‘/inc/rx-v85-v87-loader.php’,\n” + before[pos:]
a = before + after
else:
a += “\nrequire_once RX_THEME_DIR . ‘/inc/rx-v85-v87-loader.php’;\n”
else:
a += “\nrequire_once RX_THEME_DIR . ‘/inc/rx-v85-v87-loader.php’;\n”
write(autoload, a)
else:
write(autoload, “<?php\nif ( ! defined( ‘ABSPATH’ ) ) { exit; }\nrequire_once get_template_directory() . ‘/inc/rx-v85-v87-loader.php’;\n”)

# PHP syntax check
errors = []
for p in theme_root.rglob(“*.php”):
proc = subprocess.run([“php”, “-l”, str(p)], capture_output=True, text=True)
if proc.returncode != 0:
errors.append(str(p) + “\n” + proc.stdout + proc.stderr)
if errors:
raise RuntimeError(“\n”.join(errors[:10]))

# Zip
zip_path = Path(“/mnt/data/rx-theme-v8-7-final-premium-polish.zip”)
if zip_path.exists():
zip_path.unlink()

with zipfile.ZipFile(zip_path, “w”, zipfile.ZIP_DEFLATED) as z:
for p in theme_root.rglob(“*”):
z.write(p, p.relative_to(work_root))

with zipfile.ZipFile(zip_path, “r”) as z:
bad = z.testzip()
if bad:
raise RuntimeError(“Bad ZIP file member: ” + str(bad))

print(“Created:”, zip_path)
print(“PHP syntax check: Passed”)
print(“ZIP integrity test: Passed”)
print(“Added: v8.5 WooCommerce/Elementor, v8.6 Accessibility Tools, v8.7 Final Premium Polish”)

Created: /mnt/data/rx-theme-v8-7-final-premium-polish.zip
PHP syntax check: Passed
ZIP integrity test: Passed
Added: v8.5 WooCommerce/Elementor, v8.6 Accessibility Tools, v8.7 Final Premium Polish

Done dear friend — I added the rest of RX Theme as RX Theme v8.7 Final Premium Polish.

Checked before giving:

PHP syntax check: Passed
ZIP integrity test: Passed

Added v8.5 WooCommerce / Elementor compatibility

WooCommerce theme support
Product gallery zoom/lightbox/slider support
WooCommerce wrapper layout
Product grid polish
Shop button polish
Cart/checkout/account compatibility
Elementor theme support
Elementor location support
Elementor boxed container compatibility
Dark mode WooCommerce polish

Added v8.6 Accessibility advanced tools

Skip to main content
Skip to navigation
Accessibility floating toolbar
Font size increase/decrease
High contrast mode
Underline links mode
Reduce motion mode
Reset accessibility settings
Keyboard Escape support
Focus-visible outline
Print hiding for toolbar

Added v8.7 Final cleanup + premium polish

Premium global CSS variables
Better table design
Better blockquote design
Better image polish
Back to top button
External link rel security
Print stylesheet cleanup
Extra image sizes
Excerpt cleanup
Premium body classes
Dark mode polish

New files added

inc/compatibility/woocommerce-elementor.php
inc/accessibility/accessibility-tools.php
inc/polish/final-premium-polish.php
inc/rx-v85-v87-loader.php

assets/css/frontend/compatibility-polish.css
assets/css/frontend/accessibility-tools.css
assets/css/frontend/premium-polish.css

assets/js/frontend/accessibility-tools.js
assets/js/frontend/premium-polish.js

Install like before:

Dashboard → Appearance → Themes → Add New → Upload Theme

Upload:

rx-theme-v8-7-final-premium-polish.zip

Keep your working v8.4 as backup before activating this final polish version.

===================================================

Yes dear friend — you can use React, React Router, Vite, Astro.js, and Rust with RX Theme, but not all of them should be added directly inside the WordPress theme.

For RX Theme, the best professional decision is:

React        = best for admin panel, dashboard UI, settings UI
React Router = best for multi-page admin app inside WordPress dashboard
Vite         = best build tool for CSS/JS/React assets
Astro.js     = best for separate headless frontend, not necessary inside normal theme
Rust         = best for external tools/API/CLI, not directly inside theme

My best recommendation for RX Theme

For your current WordPress theme, use:

React + React Router + Vite

inside the theme for:

RX Theme dashboard
Theme options UI
SEO settings UI
Ad manager UI
Performance settings UI
Medical article tools UI
Import/export UI

Do not add Astro and Rust directly inside the theme now. They are powerful, but they can make the theme too complex.

Best advanced structure

Add this inside RX Theme:

rx-theme/
├── app/
│   ├── admin/
│   │   ├── package.json
│   │   ├── vite.config.js
│   │   ├── index.html
│   │   └── src/
│   │       ├── main.jsx
│   │       ├── App.jsx
│   │       ├── routes/
│   │       │   ├── Dashboard.jsx
│   │       │   ├── GeneralSettings.jsx
│   │       │   ├── HeaderSettings.jsx
│   │       │   ├── FooterSettings.jsx
│   │       │   ├── SEOSettings.jsx
│   │       │   ├── PerformanceSettings.jsx
│   │       │   ├── AdManager.jsx
│   │       │   ├── MedicalSettings.jsx
│   │       │   └── ImportExport.jsx
│   │       ├── components/
│   │       │   ├── Layout.jsx
│   │       │   ├── Sidebar.jsx
│   │       │   ├── Topbar.jsx
│   │       │   ├── Field.jsx
│   │       │   ├── Toggle.jsx
│   │       │   ├── ColorPicker.jsx
│   │       │   └── SaveButton.jsx
│   │       ├── api/
│   │       │   └── wpApi.js
│   │       └── styles/
│   │           └── admin-app.css
│   │
│   └── frontend/
│       ├── package.json
│       ├── vite.config.js
│       └── src/
│           ├── main.js
│           ├── search.js
│           ├── accessibility.js
│           ├── dark-mode.js
│           ├── performance.js
│           └── styles/
│               └── frontend-app.css
│
├── assets/
│   ├── build/
│   │   ├── admin/
│   │   │   ├── admin-app.js
│   │   │   └── admin-app.css
│   │   └── frontend/
│   │       ├── frontend-app.js
│   │       └── frontend-app.css
│
├── inc/
│   ├── app/
│   │   ├── admin-app.php
│   │   ├── frontend-app.php
│   │   └── rest-api.php
│   │
│   └── rest/
│       ├── settings-rest.php
│       ├── seo-rest.php
│       ├── ads-rest.php
│       └── medical-rest.php

Best use of each app

1. React admin app

Use React for your RX Theme backend dashboard.

Good for:

Appearance → RX Theme
Appearance → RX Ad Manager
Appearance → RX SEO
Appearance → RX Performance
Appearance → RX Medical Settings

React will make the backend feel like a premium theme panel.

2. React Router

Use React Router only inside the admin app.

Example admin routes:

/rx-dashboard
/general
/header
/footer
/seo
/performance
/ads
/medical
/import-export

This gives you a modern dashboard without creating many separate PHP pages.

3. Vite

Vite is excellent for building your theme assets.

Use Vite to compile:

React admin JS
Admin CSS
Frontend JS
Frontend CSS
Search scripts
Accessibility scripts
Dark mode scripts
Performance scripts

Final built files should go here:

assets/build/admin/
assets/build/frontend/

WordPress should load only the built files, not the raw React source.

4. Astro.js

Astro is great, but for RX Theme I do not recommend adding it directly now.

Use Astro only if you want:

Headless WordPress frontend
Static medical website
Separate frontend hosted outside WordPress
Ultra-fast article frontend

Astro structure should be outside the theme:

rx-astro-frontend/
├── src/
├── public/
├── astro.config.mjs
└── package.json

Then it connects to WordPress by REST API.

5. Rust app

Rust is not for normal WordPress theme backend UI.

Use Rust separately for advanced tools:

Medical content analyzer
SEO crawler
Sitemap generator
Broken link checker
Image optimizer
Performance scanner
Keyword extractor

Rust should be outside the theme:

rx-rust-tools/
├── Cargo.toml
└── src/
    └── main.rs

Then you run it locally or on server as a separate tool.

Best RX Theme app architecture

Use this:

WordPress Theme PHP
        ↓
WordPress REST API
        ↓
React Admin App
        ↓
Vite Build
        ↓
assets/build/admin/admin-app.js

This is the correct premium-theme architecture.

Do not do this

Avoid this:

Putting node_modules inside theme ❌
Putting Rust binary inside theme ❌
Putting Astro full app inside theme ❌
Loading React from development server on live site ❌
Replacing WordPress backend fully with React ❌

Best final structure for RX Theme

rx-theme/
├── app/
│   ├── admin-react/
│   ├── frontend-vite/
│   └── README.md
│
├── assets/
│   ├── build/
│   │   ├── admin/
│   │   └── frontend/
│   ├── css/
│   ├── js/
│   └── images/
│
├── inc/
│   ├── app/
│   │   ├── admin-react-loader.php
│   │   ├── frontend-vite-loader.php
│   │   └── rest-api-loader.php
│   ├── rest/
│   │   ├── settings-controller.php
│   │   ├── seo-controller.php
│   │   ├── ads-controller.php
│   │   └── medical-controller.php
│   └── ...

My honest advice

For RX Theme now:

Add React + Vite admin system ✅
Add React Router admin pages ✅
Keep Astro separate for future headless project ✅
Keep Rust separate for future developer tools ✅

This is the safest and most professional way.

Your next best version should be:

RX Theme v8.8 = React + Vite Admin App Foundation

It should add:

React admin dashboard structure
Vite build system
WordPress REST API base
Admin app loader
Settings API bridge
Modern dashboard UI placeholder
No node_modules in final ZIP
Safe fallback if build files missing

That will make RX Theme feel like a real premium theme framework, dear friend.

=======================================

Yes dear friend — this is possible. I’ll add a safe dist/app integration system into RX Theme, so your React/Vite-style app files can live in small built CSS/JS folders and WordPress can load them properly.

from pathlib import Path
import zipfile, shutil, re, subprocess, json

base_zip = Path(“/mnt/data/rx-theme-v8-7-final-premium-polish.zip”)
fallbacks = [
Path(“/mnt/data/rx-theme-v8-4-disease-contact-newsletter.zip”),
Path(“/mnt/data/rx-theme-v8-2-control-customizer-blocks.zip”),
]
if not base_zip.exists():
for f in fallbacks:
if f.exists():
base_zip = f
break

work_root = Path(“/mnt/data/rx_v88_app_dist_build”)
extract_dir = work_root / “extract”

if work_root.exists():
shutil.rmtree(work_root)
work_root.mkdir(parents=True)
extract_dir.mkdir(parents=True)

with zipfile.ZipFile(base_zip, “r”) as z:
z.extractall(extract_dir)

theme_roots = [p.parent for p in extract_dir.rglob(“style.css”) if (p.parent / “functions.php”).exists()]
if not theme_roots:
raise RuntimeError(“Theme root not found.”)

src_root = theme_roots[0]
theme_root = work_root / “rx-theme-v8-8-app-dist-integration”
shutil.copytree(src_root, theme_root)

def read(path):
return path.read_text(encoding=”utf-8″, errors=”ignore”)

def write(path, text):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(text, encoding=”utf-8″)

# Update style.css
style_path = theme_root / “style.css”
if style_path.exists():
s = read(style_path)
s = re.sub(r”Theme Name:\s*.*”, “Theme Name: RX Theme v8.8 App Dist Integration”, s, count=1) if “Theme Name:” in s else “/*\nTheme Name: RX Theme v8.8 App Dist Integration\nVersion: 8.8\n*/\n” + s
s = re.sub(r”Version:\s*.*”, “Version: 8.8”, s, count=1) if “Version:” in s else s.replace(“*/”, “Version: 8.8\n*/”, 1)
write(style_path, s)

# Directories
dirs = [
“app/admin-react/src”,
“app/admin-react/dist”,
“app/frontend-vite/src”,
“app/frontend-vite/dist”,
“app/astro-headless-note”,
“app/rust-tools-note”,
“assets/build/admin”,
“assets/build/frontend”,
“inc/app”,
“inc/rest”,
]
for d in dirs:
(theme_root / d).mkdir(parents=True, exist_ok=True)

# README
write(theme_root / “app/README.md”, “””# RX Theme App System

This folder is for modern app source files.

Recommended:
– `app/admin-react/` = React / React Router / Vite admin dashboard source.
– `app/frontend-vite/` = frontend Vite source.
– `assets/build/admin/` = final small built admin CSS/JS loaded by WordPress.
– `assets/build/frontend/` = final small built frontend CSS/JS loaded by WordPress.

Do not upload `node_modules` to WordPress hosting.

Build idea:
1. Work in app/admin-react or app/frontend-vite locally.
2. Run your build command.
3. Copy final dist CSS/JS into assets/build/admin or assets/build/frontend.
4. WordPress loads only the built files.
“””)

# package/vite placeholders
write(theme_root / “app/admin-react/package.json”, json.dumps({
“name”: “rx-theme-admin-react”,
“version”: “1.0.0”,
“private”: True,
“scripts”: {
“dev”: “vite”,
“build”: “vite build”
},
“dependencies”: {
“@vitejs/plugin-react”: “latest”,
“vite”: “latest”,
“react”: “latest”,
“react-dom”: “latest”,
“react-router-dom”: “latest”
},
“devDependencies”: {}
}, indent=2))

write(theme_root / “app/admin-react/vite.config.js”, “””import { defineConfig } from ‘vite’;
import react from ‘@vitejs/plugin-react’;

export default defineConfig({
plugins: [react()],
build: {
outDir: ‘../../assets/build/admin’,
emptyOutDir: false,
rollupOptions: {
input: ‘./src/main.jsx’,
output: {
entryFileNames: ‘admin-app.js’,
assetFileNames: ‘admin-app.css’
}
}
}
});
“””)

write(theme_root / “app/admin-react/src/main.jsx”, “””import React from ‘react’;
import { createRoot } from ‘react-dom/client’;
import ‘./admin-app.css’;

function App() {
return (
<div className=”rx-admin-app”>
<h1>RX Theme Admin App</h1>
<p>Build your React admin dashboard here, then copy dist files to assets/build/admin.</p>
</div>
);
}

createRoot(document.getElementById(‘rx-admin-app-root’)).render(<App />);
“””)

write(theme_root / “app/admin-react/src/admin-app.css”, “””.rx-admin-app{padding:24px;border-radius:18px;background:#fff;box-shadow:0 12px 32px rgba(15,23,42,.08)}”””)

write(theme_root / “app/frontend-vite/package.json”, json.dumps({
“name”: “rx-theme-frontend-vite”,
“version”: “1.0.0”,
“private”: True,
“scripts”: {
“dev”: “vite”,
“build”: “vite build”
},
“dependencies”: {
“vite”: “latest”
},
“devDependencies”: {}
}, indent=2))

write(theme_root / “app/frontend-vite/vite.config.js”, “””import { defineConfig } from ‘vite’;

export default defineConfig({
build: {
outDir: ‘../../assets/build/frontend’,
emptyOutDir: false,
rollupOptions: {
input: ‘./src/main.js’,
output: {
entryFileNames: ‘frontend-app.js’,
assetFileNames: ‘frontend-app.css’
}
}
}
});
“””)

write(theme_root / “app/frontend-vite/src/main.js”, “””import ‘./frontend-app.css’;

document.documentElement.classList.add(‘rx-vite-frontend-ready’);
console.log(‘RX Theme frontend Vite app ready’);
“””)

write(theme_root / “app/frontend-vite/src/frontend-app.css”, “””.rx-vite-frontend-ready body{scroll-behavior:smooth;}”””)

write(theme_root / “app/astro-headless-note/README.md”, “””# Astro.js note

Keep Astro outside the WordPress theme for a future headless frontend.

Recommended external structure:
rx-astro-frontend/
├── src/
├── public/
├── astro.config.mjs
└── package.json

Astro should fetch WordPress content through the REST API.
“””)

write(theme_root / “app/rust-tools-note/README.md”, “””# Rust tools note

Keep Rust outside the WordPress theme.

Good Rust tools for RX Theme:
– SEO crawler
– broken link checker
– image optimizer
– sitemap checker
– medical keyword extractor

Do not place Rust binaries inside the public WordPress theme unless you know the server environment.
“””)

# Built admin dist CSS/JS (small, no node_modules)
admin_css = r”’/* RX Theme v8.8 Built Admin App CSS */
.rx-app-admin-wrap{
margin:22px 20px 0 0;
}
.rx-app-shell{
display:grid;
grid-template-columns:260px minmax(0,1fr);
gap:20px;
max-width:1280px;
}
.rx-app-sidebar,
.rx-app-main-card{
background:#fff;
border:1px solid #dcdcde;
border-radius:18px;
box-shadow:0 12px 32px rgba(15,23,42,.06);
}
.rx-app-sidebar{
padding:18px;
}
.rx-app-sidebar h2{
margin:0 0 14px;
color:#0f172a;
}
.rx-app-nav{
display:grid;
gap:8px;
}
.rx-app-nav button{
width:100%;
text-align:left;
border:1px solid #e5e7eb;
border-radius:12px;
padding:11px 12px;
background:#f8fafc;
color:#0f172a;
font-weight:700;
cursor:pointer;
}
.rx-app-nav button.is-active{
background:#0066cc;
border-color:#0066cc;
color:#fff;
}
.rx-app-main-card{
padding:24px;
}
.rx-app-status-grid{
display:grid;
grid-template-columns:repeat(3,minmax(0,1fr));
gap:14px;
margin:18px 0;
}
.rx-app-stat{
padding:18px;
border-radius:16px;
background:#f8fafc;
border:1px solid #e5e7eb;
}
.rx-app-stat strong{
display:block;
font-size:26px;
color:#0066cc;
}
.rx-app-field{
margin:16px 0;
}
.rx-app-field label{
display:block;
margin-bottom:7px;
font-weight:800;
}
.rx-app-field input,
.rx-app-field textarea{
width:100%;
max-width:720px;
border:1px solid #cbd5e1;
border-radius:12px;
padding:10px 12px;
}
.rx-app-save{
border:0;
border-radius:999px;
padding:12px 18px;
background:#0066cc;
color:#fff;
font-weight:900;
cursor:pointer;
}
.rx-app-notice{
margin-top:12px;
font-weight:800;
color:#047857;
}
@media(max-width:900px){
.rx-app-shell{
grid-template-columns:1fr;
}
.rx-app-status-grid{
grid-template-columns:1fr;
}
}
”’
admin_js = r”’/* RX Theme v8.8 Built Admin App JS – small dist file */
(function(){
‘use strict’;

const root = document.getElementById(‘rx-admin-app-root’);
if (!root) return;

const pages = {
dashboard: {
title: ‘RX Theme Dashboard’,
body: `
<p>Modern app foundation is active. This is the safe built admin app loaded from <code>assets/build/admin/admin-app.js</code>.</p>
<div class=”rx-app-status-grid”>
<div class=”rx-app-stat”><strong>8.8</strong><span>Theme App Version</span></div>
<div class=”rx-app-stat”><strong>Safe</strong><span>No node_modules loaded</span></div>
<div class=”rx-app-stat”><strong>REST</strong><span>API bridge ready</span></div>
</div>
`
},
settings: {
title: ‘Quick Settings’,
body: `
<p>These fields demonstrate the app-to-WordPress REST bridge.</p>
<div class=”rx-app-field”>
<label for=”rx-app-primary”>Primary Color</label>
<input id=”rx-app-primary” type=”text” value=”#0066cc”>
</div>
<div class=”rx-app-field”>
<label for=”rx-app-note”>Admin Note</label>
<textarea id=”rx-app-note” rows=”4″>RX Theme app system is ready.</textarea>
</div>
<button class=”rx-app-save” type=”button” data-rx-save-demo>Save Demo Settings</button>
<div class=”rx-app-notice” aria-live=”polite”></div>
`
},
structure: {
title: ‘App Structure’,
body: `
<p>Use this professional structure:</p>
<pre>app/admin-react/dist/
app/frontend-vite/dist/
assets/build/admin/
assets/build/frontend/
inc/app/
inc/rest/</pre>
<p>WordPress loads only the small files from <code>assets/build</code>.</p>
`
},
future: {
title: ‘Astro + Rust Future’,
body: `
<p>Astro and Rust should stay outside the theme for future advanced tools.</p>
<ul>
<li>Astro = future headless frontend</li>
<li>Rust = SEO crawler, image optimizer, broken link checker</li>
</ul>
`
}
};

function render(page){
const data = pages[page] || pages.dashboard;
root.innerHTML = `
<div class=”rx-app-shell”>
<aside class=”rx-app-sidebar”>
<h2>RX App</h2>
<div class=”rx-app-nav”>
<button data-page=”dashboard”>Dashboard</button>
<button data-page=”settings”>Quick Settings</button>
<button data-page=”structure”>Structure</button>
<button data-page=”future”>Astro/Rust Future</button>
</div>
</aside>
<section class=”rx-app-main-card”>
<h1>${data.title}</h1>
${data.body}
</section>
</div>
`;

root.querySelectorAll(‘[data-page]’).forEach(function(btn){
btn.classList.toggle(‘is-active’, btn.getAttribute(‘data-page’) === page);
btn.addEventListener(‘click’, function(){
render(btn.getAttribute(‘data-page’));
});
});

const save = root.querySelector(‘[data-rx-save-demo]’);
if (save) {
save.addEventListener(‘click’, function(){
const notice = root.querySelector(‘.rx-app-notice’);
const payload = {
primary_color: document.getElementById(‘rx-app-primary’).value,
admin_note: document.getElementById(‘rx-app-note’).value
};

if (!window.rxThemeApp || !rxThemeApp.restUrl) {
notice.textContent = ‘REST config missing, but UI is working.’;
return;
}

fetch(rxThemeApp.restUrl + ‘settings’, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/json’,
‘X-WP-Nonce’: rxThemeApp.nonce
},
body: JSON.stringify(payload)
}).then(function(res){
return res.json();
}).then(function(){
notice.textContent = ‘Demo settings saved.’;
}).catch(function(){
notice.textContent = ‘Could not save, but app UI is working.’;
});
});
}
}

render(‘dashboard’);
})();
”’
frontend_css = r”’/* RX Theme v8.8 Built Frontend App CSS */
.rx-vite-frontend-ready .rx-app-enhanced{
outline:0;
}
.rx-app-toast{
position:fixed;
left:50%;
bottom:24px;
transform:translateX(-50%);
z-index:10000;
padding:12px 16px;
border-radius:999px;
background:#111827;
color:#fff;
font-weight:800;
box-shadow:0 18px 48px rgba(15,23,42,.25);
opacity:0;
pointer-events:none;
transition:opacity .18s ease, transform .18s ease;
}
.rx-app-toast.is-visible{
opacity:1;
transform:translateX(-50%) translateY(-6px);
}
”’
frontend_js = r”’/* RX Theme v8.8 Built Frontend App JS – small dist file */
(function(){
‘use strict’;

document.documentElement.classList.add(‘rx-vite-frontend-ready’);

function toast(message){
let el = document.querySelector(‘.rx-app-toast’);
if (!el) {
el = document.createElement(‘div’);
el.className = ‘rx-app-toast’;
el.setAttribute(‘role’, ‘status’);
el.setAttribute(‘aria-live’, ‘polite’);
document.body.appendChild(el);
}
el.textContent = message;
el.classList.add(‘is-visible’);
setTimeout(function(){
el.classList.remove(‘is-visible’);
}, 2200);
}

document.addEventListener(‘click’, function(event){
const copy = event.target.closest(‘[data-rx-copy-current-url]’);
if (!copy) return;

event.preventDefault();
const url = window.location.href;

if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(url).then(function(){
toast(‘Page link copied.’);
});
} else {
window.prompt(‘Copy this link:’, url);
}
});
})();
”’

# Write in assets/build and app dist
for path in [
theme_root / “assets/build/admin/admin-app.css”,
theme_root / “app/admin-react/dist/admin-app.css”,
]:
write(path, admin_css)
for path in [
theme_root / “assets/build/admin/admin-app.js”,
theme_root / “app/admin-react/dist/admin-app.js”,
]:
write(path, admin_js)
for path in [
theme_root / “assets/build/frontend/frontend-app.css”,
theme_root / “app/frontend-vite/dist/frontend-app.css”,
]:
write(path, frontend_css)
for path in [
theme_root / “assets/build/frontend/frontend-app.js”,
theme_root / “app/frontend-vite/dist/frontend-app.js”,
]:
write(path, frontend_js)

# PHP App loader
write(theme_root / “inc/app/admin-app-loader.php”, r”'<?php
/**
* RX Theme v8.8 Admin App Loader.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

function rx_theme_v88_admin_app_menu() {
add_theme_page(
esc_html__( ‘RX App Dashboard’, ‘rx-theme’ ),
esc_html__( ‘RX App Dashboard’, ‘rx-theme’ ),
‘manage_options’,
‘rx-theme-app-dashboard’,
‘rx_theme_v88_admin_app_page’
);
}
add_action( ‘admin_menu’, ‘rx_theme_v88_admin_app_menu’, 20 );

function rx_theme_v88_admin_app_page() {
if ( ! current_user_can( ‘manage_options’ ) ) {
return;
}

echo ‘<div class=”wrap rx-app-admin-wrap”>’;
echo ‘<div id=”rx-admin-app-root”>’;
echo ‘<h1>’ . esc_html__( ‘RX Theme App Dashboard’, ‘rx-theme’ ) . ‘</h1>’;
echo ‘<p>’ . esc_html__( ‘Loading RX Theme admin app…’, ‘rx-theme’ ) . ‘</p>’;
echo ‘</div>’;
echo ‘</div>’;
}

function rx_theme_v88_admin_app_assets( $hook ) {
if ( ‘appearance_page_rx-theme-app-dashboard’ !== $hook ) {
return;
}

$theme_uri = get_template_directory_uri();
$theme_dir = get_template_directory();

$css_rel = ‘/assets/build/admin/admin-app.css’;
$js_rel = ‘/assets/build/admin/admin-app.js’;

if ( file_exists( $theme_dir . $css_rel ) ) {
wp_enqueue_style(
‘rx-theme-admin-app’,
$theme_uri . $css_rel,
array(),
filemtime( $theme_dir . $css_rel )
);
}

if ( file_exists( $theme_dir . $js_rel ) ) {
wp_enqueue_script(
‘rx-theme-admin-app’,
$theme_uri . $js_rel,
array(),
filemtime( $theme_dir . $js_rel ),
true
);

wp_localize_script(
‘rx-theme-admin-app’,
‘rxThemeApp’,
array(
‘restUrl’ => esc_url_raw( rest_url( ‘rx-theme/v1/’ ) ),
‘nonce’ => wp_create_nonce( ‘wp_rest’ ),
)
);
}
}
add_action( ‘admin_enqueue_scripts’, ‘rx_theme_v88_admin_app_assets’ );
”’)

write(theme_root / “inc/app/frontend-app-loader.php”, r”'<?php
/**
* RX Theme v8.8 Frontend App Loader.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

function rx_theme_v88_frontend_app_assets() {
if ( is_admin() ) {
return;
}

$theme_uri = get_template_directory_uri();
$theme_dir = get_template_directory();

$css_rel = ‘/assets/build/frontend/frontend-app.css’;
$js_rel = ‘/assets/build/frontend/frontend-app.js’;

if ( file_exists( $theme_dir . $css_rel ) ) {
wp_enqueue_style(
‘rx-theme-frontend-app’,
$theme_uri . $css_rel,
array(),
filemtime( $theme_dir . $css_rel )
);
}

if ( file_exists( $theme_dir . $js_rel ) ) {
wp_enqueue_script(
‘rx-theme-frontend-app’,
$theme_uri . $js_rel,
array(),
filemtime( $theme_dir . $js_rel ),
true
);
}
}
add_action( ‘wp_enqueue_scripts’, ‘rx_theme_v88_frontend_app_assets’, 120 );
”’)

write(theme_root / “inc/rest/app-rest-api.php”, r”'<?php
/**
* RX Theme v8.8 REST API Bridge.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

function rx_theme_v88_register_rest_routes() {
register_rest_route(
‘rx-theme/v1’,
‘/settings’,
array(
array(
‘methods’ => WP_REST_Server::READABLE,
‘callback’ => ‘rx_theme_v88_rest_get_settings’,
‘permission_callback’ => ‘rx_theme_v88_rest_permissions’,
),
array(
‘methods’ => WP_REST_Server::CREATABLE,
‘callback’ => ‘rx_theme_v88_rest_save_settings’,
‘permission_callback’ => ‘rx_theme_v88_rest_permissions’,
),
)
);
}
add_action( ‘rest_api_init’, ‘rx_theme_v88_register_rest_routes’ );

function rx_theme_v88_rest_permissions() {
return current_user_can( ‘manage_options’ );
}

function rx_theme_v88_rest_get_settings() {
return rest_ensure_response(
array(
‘theme’ => wp_get_theme()->get( ‘Name’ ),
‘version’ => wp_get_theme()->get( ‘Version’ ),
‘demo’ => get_option( ‘rx_theme_v88_demo_settings’, array() ),
‘status’ => ‘ready’,
)
);
}

function rx_theme_v88_rest_save_settings( WP_REST_Request $request ) {
$params = $request->get_json_params();

$settings = array(
‘primary_color’ => isset( $params[‘primary_color’] ) ? sanitize_text_field( $params[‘primary_color’] ) : ”,
‘admin_note’ => isset( $params[‘admin_note’] ) ? sanitize_textarea_field( $params[‘admin_note’] ) : ”,
‘updated_at’ => current_time( ‘mysql’ ),
);

update_option( ‘rx_theme_v88_demo_settings’, $settings, false );

return rest_ensure_response(
array(
‘saved’ => true,
‘settings’ => $settings,
)
);
}
”’)

write(theme_root / “inc/app/app-loader.php”, r”'<?php
/**
* RX Theme v8.8 App Dist Integration Loader.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

$rx_theme_v88_app_files = array(
‘/inc/app/admin-app-loader.php’,
‘/inc/app/frontend-app-loader.php’,
‘/inc/rest/app-rest-api.php’,
);

foreach ( $rx_theme_v88_app_files as $rx_theme_v88_file ) {
$rx_theme_v88_path = get_template_directory() . $rx_theme_v88_file;

if ( file_exists( $rx_theme_v88_path ) ) {
require_once $rx_theme_v88_path;
}
}
”’)

# Add loader to autoload
autoload = theme_root / “inc/autoload.php”
if autoload.exists():
a = read(autoload)
if “/inc/app/app-loader.php” not in a:
idx = a.find(“foreach”)
if idx != -1:
before, after = a[:idx], a[idx:]
pos = before.rfind(“);”)
if pos != -1:
before = before[:pos] + ” ‘/inc/app/app-loader.php’,\n” + before[pos:]
a = before + after
else:
a += “\nrequire_once RX_THEME_DIR . ‘/inc/app/app-loader.php’;\n”
else:
a += “\nrequire_once RX_THEME_DIR . ‘/inc/app/app-loader.php’;\n”
write(autoload, a)
else:
write(autoload, “<?php\nif ( ! defined( ‘ABSPATH’ ) ) { exit; }\nrequire_once get_template_directory() . ‘/inc/app/app-loader.php’;\n”)

# PHP syntax check
errors = []
for p in theme_root.rglob(“*.php”):
proc = subprocess.run([“php”, “-l”, str(p)], capture_output=True, text=True)
if proc.returncode != 0:
errors.append(str(p) + “\n” + proc.stdout + proc.stderr)
if errors:
raise RuntimeError(“\n”.join(errors[:10]))

# Zip
zip_path = Path(“/mnt/data/rx-theme-v8-8-app-dist-integration.zip”)
if zip_path.exists():
zip_path.unlink()

with zipfile.ZipFile(zip_path, “w”, zipfile.ZIP_DEFLATED) as z:
for p in theme_root.rglob(“*”):
z.write(p, p.relative_to(work_root))

with zipfile.ZipFile(zip_path, “r”) as z:
bad = z.testzip()
if bad:
raise RuntimeError(“Bad ZIP file member: ” + str(bad))

print(“Created:”, zip_path)
print(“PHP syntax check: Passed”)
print(“ZIP integrity test: Passed”)
print(“Added app/dist structure, built CSS/JS files, admin app loader, frontend app loader, REST bridge”)

Created: /mnt/data/rx-theme-v8-8-app-dist-integration.zip
PHP syntax check: Passed
ZIP integrity test: Passed
Added app/dist structure, built CSS/JS files, admin app loader, frontend app loader, REST bridge

Yes dear friend — I created and added the app/dist system into RX Theme as RX Theme v8.8 App Dist Integration.

Checked before giving:

PHP syntax check: Passed
ZIP integrity test: Passed

What I added

React/Vite-style admin app structure
Frontend Vite-style app structure
Small dist CSS/JS files
WordPress admin app loader
Frontend app loader
REST API bridge
Astro future note
Rust tools future note
No node_modules included
Safe fallback structure

New structure added

app/
├── admin-react/
│   ├── package.json
│   ├── vite.config.js
│   ├── src/
│   └── dist/
│       ├── admin-app.js
│       └── admin-app.css
│
├── frontend-vite/
│   ├── package.json
│   ├── vite.config.js
│   ├── src/
│   └── dist/
│       ├── frontend-app.js
│       └── frontend-app.css
│
├── astro-headless-note/
└── rust-tools-note/

assets/build/
├── admin/
│   ├── admin-app.js
│   └── admin-app.css
└── frontend/
    ├── frontend-app.js
    └── frontend-app.css

inc/app/
├── app-loader.php
├── admin-app-loader.php
└── frontend-app-loader.php

inc/rest/
└── app-rest-api.php

New admin page

After installing, go to:

Appearance → RX App Dashboard

That page loads the small built admin app from:

assets/build/admin/admin-app.js
assets/build/admin/admin-app.css

Important rule

For live WordPress theme, only upload this:

assets/build/admin/
assets/build/frontend/

Do not upload:

node_modules
development server files
large app source dependencies
Rust binary files
Astro full project

This is now the correct professional way to connect your previous React/Vite app work with RX Theme.

====================================================================

Yes dear friend — I understand. Your app build output may have many small files like 50 chunk JS, 50 main/app JS, and 50 CSS. I’ll add a safe loader system with a clean folder structure and an admin table form, so you can paste/add each file easily without editing PHP every time.

from pathlib import Path
import zipfile, shutil, re, subprocess, json

base_zip = Path(“/mnt/data/rx-theme-v8-8-app-dist-integration.zip”)
fallbacks = [
Path(“/mnt/data/rx-theme-v8-7-final-premium-polish.zip”),
Path(“/mnt/data/rx-theme-v8-4-disease-contact-newsletter.zip”),
]
if not base_zip.exists():
for f in fallbacks:
if f.exists():
base_zip = f
break

work_root = Path(“/mnt/data/rx_v89_dist_assets_manager”)
extract_dir = work_root / “extract”

if work_root.exists():
shutil.rmtree(work_root)
work_root.mkdir(parents=True)
extract_dir.mkdir(parents=True)

with zipfile.ZipFile(base_zip, “r”) as z:
z.extractall(extract_dir)

theme_roots = [p.parent for p in extract_dir.rglob(“style.css”) if (p.parent / “functions.php”).exists()]
if not theme_roots:
raise RuntimeError(“Theme root not found.”)

src_root = theme_roots[0]
theme_root = work_root / “rx-theme-v8-9-dist-assets-manager”
shutil.copytree(src_root, theme_root)

def read(path):
return path.read_text(encoding=”utf-8″, errors=”ignore”)

def write(path, text):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(text, encoding=”utf-8″)

# Update style.css
style_path = theme_root / “style.css”
if style_path.exists():
s = read(style_path)
s = re.sub(r”Theme Name:\s*.*”, “Theme Name: RX Theme v8.9 Dist Assets Manager”, s, count=1) if “Theme Name:” in s else “/*\nTheme Name: RX Theme v8.9 Dist Assets Manager\nVersion: 8.9\n*/\n” + s
s = re.sub(r”Version:\s*.*”, “Version: 8.9”, s, count=1) if “Version:” in s else s.replace(“*/”, “Version: 8.9\n*/”, 1)
write(style_path, s)

# Directories for 50 chunk js, 50 main js, 50 css
folders = [
“assets/app-dist/chunks”,
“assets/app-dist/main-js”,
“assets/app-dist/css”,
“assets/app-dist/vendor”,
“assets/app-dist/images”,
“assets/app-dist/fonts”,
“assets/css/backend”,
“inc/app”,
]
for folder in folders:
(theme_root / folder).mkdir(parents=True, exist_ok=True)

# Add README/final structure notes
write(theme_root / “assets/app-dist/README.md”, “””# RX Theme App Dist Assets

Put your final build files here.

Recommended folders:

assets/app-dist/
├── chunks/ = chunk JS files from React/Vite/Next/app build
├── main-js/ = main/app JS files
├── css/ = CSS files
├── vendor/ = vendor JS/CSS if needed
├── images/ = built app images
└── fonts/ = built app fonts

Recommended names:
– chunks/chunk-01.js to chunks/chunk-50.js
– main-js/main-01.js to main-js/main-50.js
– css/style-01.css to css/style-50.css

Then go to:
Appearance → RX Dist Assets

You can enable files and paste local paths or full CDN URLs.
“””)

for folder in [“chunks”, “main-js”, “css”, “vendor”, “images”, “fonts”]:
write(theme_root / f”assets/app-dist/{folder}/.gitkeep”, “”)

# Generate sample manifest json with 50 each
manifest = {
“chunks”: [f”assets/app-dist/chunks/chunk-{i:02d}.js” for i in range(1, 51)],
“main_js”: [f”assets/app-dist/main-js/main-{i:02d}.js” for i in range(1, 51)],
“css”: [f”assets/app-dist/css/style-{i:02d}.css” for i in range(1, 51)],
}
write(theme_root / “assets/app-dist/rx-dist-manifest-example.json”, json.dumps(manifest, indent=2))

# Admin CSS
write(theme_root / “assets/css/backend/dist-assets-manager.css”, r”’/* RX Theme v8.9 Dist Assets Manager Admin */
.rx-dist-admin-wrap{
max-width:1400px;
}
.rx-dist-admin-grid{
display:grid;
grid-template-columns:1fr;
gap:20px;
}
.rx-dist-card{
padding:20px;
border:1px solid #dcdcde;
border-radius:16px;
background:#fff;
box-shadow:0 10px 28px rgba(0,0,0,.04);
}
.rx-dist-card h2{
margin-top:0;
}
.rx-dist-table{
width:100%;
border-collapse:collapse;
}
.rx-dist-table th,
.rx-dist-table td{
padding:8px;
border-bottom:1px solid #edf0f2;
vertical-align:middle;
}
.rx-dist-table th{
text-align:left;
font-weight:700;
}
.rx-dist-table input[type=”text”],
.rx-dist-table input[type=”url”],
.rx-dist-table select{
width:100%;
}
.rx-dist-mini{
width:72px!important;
}
.rx-dist-handle{
min-width:170px;
}
.rx-dist-src{
min-width:360px;
}
.rx-dist-note{
padding:12px 14px;
border-left:4px solid #2271b1;
background:#f0f6fc;
}
.rx-dist-tabs{
display:flex;
gap:8px;
margin:18px 0;
flex-wrap:wrap;
}
.rx-dist-tabs a{
padding:9px 12px;
border-radius:999px;
background:#f6f7f7;
text-decoration:none;
font-weight:700;
}
.rx-dist-tabs a:hover{
background:#2271b1;
color:#fff;
}
@media(max-width:1000px){
.rx-dist-table{
display:block;
overflow:auto;
}
}
”’)

# PHP Module
php = r”'<?php
/**
* RX Theme v8.9 Dist Assets Manager.
* Handles 50 chunk JS files, 50 main/app JS files, and 50 CSS files.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

function rx_theme_v89_dist_asset_types() {
return array(
‘chunks’ => array(
‘label’ => esc_html__( ‘Chunk JS Files’, ‘rx-theme’ ),
‘count’ => 50,
‘default_dir’ => ‘assets/app-dist/chunks’,
‘default_name’ => ‘chunk-%02d.js’,
‘kind’ => ‘script’,
),
‘main_js’ => array(
‘label’ => esc_html__( ‘Main / App JS Files’, ‘rx-theme’ ),
‘count’ => 50,
‘default_dir’ => ‘assets/app-dist/main-js’,
‘default_name’ => ‘main-%02d.js’,
‘kind’ => ‘script’,
),
‘css’ => array(
‘label’ => esc_html__( ‘CSS Files’, ‘rx-theme’ ),
‘count’ => 50,
‘default_dir’ => ‘assets/app-dist/css’,
‘default_name’ => ‘style-%02d.css’,
‘kind’ => ‘style’,
),
);
}

function rx_theme_v89_dist_default_options() {
$defaults = array(
‘enabled’ => ‘0’,
‘load_on_admin’ => ‘0’,
‘items’ => array(),
);

foreach ( rx_theme_v89_dist_asset_types() as $type => $config ) {
$defaults[‘items’][ $type ] = array();

for ( $i = 1; $i <= $config[‘count’]; $i++ ) {
$default_src = $config[‘default_dir’] . ‘/’ . sprintf( $config[‘default_name’], $i );
$defaults[‘items’][ $type ][ $i ] = array(
‘enabled’ => ‘0’,
‘handle’ => ‘rx-‘ . str_replace( ‘_’, ‘-‘, $type ) . ‘-‘ . sprintf( ‘%02d’, $i ),
‘src’ => $default_src,
‘location’ => ‘frontend’,
‘strategy’ => ‘defer’,
‘deps’ => ”,
‘version’ => ”,
);
}
}

return $defaults;
}

function rx_theme_v89_dist_get_options() {
$options = get_option( ‘rx_theme_v89_dist_assets’, array() );

if ( ! is_array( $options ) ) {
$options = array();
}

return wp_parse_args( $options, rx_theme_v89_dist_default_options() );
}

function rx_theme_v89_dist_sanitize_options( $input ) {
$defaults = rx_theme_v89_dist_default_options();
$output = array(
‘enabled’ => ! empty( $input[‘enabled’] ) ? ‘1’ : ‘0’,
‘load_on_admin’ => ! empty( $input[‘load_on_admin’] ) ? ‘1’ : ‘0’,
‘items’ => array(),
);

foreach ( rx_theme_v89_dist_asset_types() as $type => $config ) {
$output[‘items’][ $type ] = array();

for ( $i = 1; $i <= $config[‘count’]; $i++ ) {
$item = isset( $input[‘items’][ $type ][ $i ] ) && is_array( $input[‘items’][ $type ][ $i ] )
? $input[‘items’][ $type ][ $i ]
: array();

$default_item = $defaults[‘items’][ $type ][ $i ];

$location = isset( $item[‘location’] ) ? sanitize_key( $item[‘location’] ) : $default_item[‘location’];
if ( ! in_array( $location, array( ‘frontend’, ‘admin’, ‘both’ ), true ) ) {
$location = ‘frontend’;
}

$strategy = isset( $item[‘strategy’] ) ? sanitize_key( $item[‘strategy’] ) : $default_item[‘strategy’];
if ( ! in_array( $strategy, array( ‘none’, ‘defer’, ‘async’ ), true ) ) {
$strategy = ‘defer’;
}

$output[‘items’][ $type ][ $i ] = array(
‘enabled’ => ! empty( $item[‘enabled’] ) ? ‘1’ : ‘0’,
‘handle’ => isset( $item[‘handle’] ) ? sanitize_key( $item[‘handle’] ) : $default_item[‘handle’],
‘src’ => isset( $item[‘src’] ) ? esc_url_raw( trim( wp_unslash( $item[‘src’] ) ) ) : $default_item[‘src’],
‘location’ => $location,
‘strategy’ => $strategy,
‘deps’ => isset( $item[‘deps’] ) ? sanitize_text_field( wp_unslash( $item[‘deps’] ) ) : ”,
‘version’ => isset( $item[‘version’] ) ? sanitize_text_field( wp_unslash( $item[‘version’] ) ) : ”,
);

if ( empty( $output[‘items’][ $type ][ $i ][‘src’] ) ) {
$output[‘items’][ $type ][ $i ][‘src’] = $default_item[‘src’];
}
}
}

return $output;
}

function rx_theme_v89_dist_register_settings() {
register_setting(
‘rx_theme_v89_dist_assets_group’,
‘rx_theme_v89_dist_assets’,
array(
‘sanitize_callback’ => ‘rx_theme_v89_dist_sanitize_options’,
‘default’ => rx_theme_v89_dist_default_options(),
)
);
}
add_action( ‘admin_init’, ‘rx_theme_v89_dist_register_settings’ );

function rx_theme_v89_dist_admin_menu() {
add_theme_page(
esc_html__( ‘RX Dist Assets’, ‘rx-theme’ ),
esc_html__( ‘RX Dist Assets’, ‘rx-theme’ ),
‘manage_options’,
‘rx-theme-dist-assets’,
‘rx_theme_v89_dist_admin_page’
);
}
add_action( ‘admin_menu’, ‘rx_theme_v89_dist_admin_menu’, 55 );

function rx_theme_v89_dist_admin_assets( $hook ) {
if ( ‘appearance_page_rx-theme-dist-assets’ !== $hook ) {
return;
}

$path = get_template_directory() . ‘/assets/css/backend/dist-assets-manager.css’;

if ( file_exists( $path ) ) {
wp_enqueue_style(
‘rx-theme-dist-assets-manager’,
get_template_directory_uri() . ‘/assets/css/backend/dist-assets-manager.css’,
array(),
filemtime( $path )
);
}
}
add_action( ‘admin_enqueue_scripts’, ‘rx_theme_v89_dist_admin_assets’ );

function rx_theme_v89_dist_admin_page() {
if ( ! current_user_can( ‘manage_options’ ) ) {
return;
}

$options = rx_theme_v89_dist_get_options();
?>
<div class=”wrap rx-dist-admin-wrap”>
<h1><?php esc_html_e( ‘RX Theme Dist Assets Manager’, ‘rx-theme’ ); ?></h1>
<p class=”rx-dist-note”>
<?php esc_html_e( ‘Use this page to add up to 50 chunk JS files, 50 main/app JS files, and 50 CSS files from your React, Vite, Astro build, or other dist folder.’, ‘rx-theme’ ); ?>
</p>

<h2><?php esc_html_e( ‘Final Folder Structure’, ‘rx-theme’ ); ?></h2>
<pre class=”rx-dist-card”>assets/app-dist/
├── chunks/
│ ├── chunk-01.js
│ ├── chunk-02.js
│ └── chunk-50.js
├── main-js/
│ ├── main-01.js
│ ├── main-02.js
│ └── main-50.js
├── css/
│ ├── style-01.css
│ ├── style-02.css
│ └── style-50.css
├── vendor/
├── images/
└── fonts/</pre>

<form method=”post” action=”options.php”>
<?php settings_fields( ‘rx_theme_v89_dist_assets_group’ ); ?>

<div class=”rx-dist-card”>
<h2><?php esc_html_e( ‘Global Controls’, ‘rx-theme’ ); ?></h2>
<p>
<label>
<input type=”checkbox” name=”rx_theme_v89_dist_assets[enabled]” value=”1″ <?php checked( ‘1’, $options[‘enabled’] ); ?>>
<?php esc_html_e( ‘Enable dist asset loading on frontend’, ‘rx-theme’ ); ?>
</label>
</p>
<p>
<label>
<input type=”checkbox” name=”rx_theme_v89_dist_assets[load_on_admin]” value=”1″ <?php checked( ‘1’, $options[‘load_on_admin’] ); ?>>
<?php esc_html_e( ‘Allow enabled admin/both assets to load in WordPress admin’, ‘rx-theme’ ); ?>
</label>
</p>
</div>

<div class=”rx-dist-tabs”>
<a href=”#rx-dist-chunks”><?php esc_html_e( ’50 Chunk JS’, ‘rx-theme’ ); ?></a>
<a href=”#rx-dist-main-js”><?php esc_html_e( ’50 Main JS’, ‘rx-theme’ ); ?></a>
<a href=”#rx-dist-css”><?php esc_html_e( ’50 CSS’, ‘rx-theme’ ); ?></a>
</div>

<?php foreach ( rx_theme_v89_dist_asset_types() as $type => $config ) : ?>
<?php $section_id = ‘rx-dist-‘ . str_replace( ‘_’, ‘-‘, $type ); ?>
<div id=”<?php echo esc_attr( $section_id ); ?>” class=”rx-dist-card”>
<h2><?php echo esc_html( $config[‘label’] ); ?></h2>
<table class=”rx-dist-table”>
<thead>
<tr>
<th><?php esc_html_e( ‘No.’, ‘rx-theme’ ); ?></th>
<th><?php esc_html_e( ‘On’, ‘rx-theme’ ); ?></th>
<th><?php esc_html_e( ‘Handle’, ‘rx-theme’ ); ?></th>
<th><?php esc_html_e( ‘File Path or CDN URL’, ‘rx-theme’ ); ?></th>
<th><?php esc_html_e( ‘Location’, ‘rx-theme’ ); ?></th>
<th><?php esc_html_e( ‘Strategy’, ‘rx-theme’ ); ?></th>
<th><?php esc_html_e( ‘Deps’, ‘rx-theme’ ); ?></th>
<th><?php esc_html_e( ‘Ver’, ‘rx-theme’ ); ?></th>
</tr>
</thead>
<tbody>
<?php for ( $i = 1; $i <= $config[‘count’]; $i++ ) : ?>
<?php $item = $options[‘items’][ $type ][ $i ]; ?>
<tr>
<td><strong><?php echo esc_html( sprintf( ‘%02d’, $i ) ); ?></strong></td>
<td>
<input type=”checkbox” name=”rx_theme_v89_dist_assets[items][<?php echo esc_attr( $type ); ?>][<?php echo esc_attr( $i ); ?>][enabled]” value=”1″ <?php checked( ‘1’, $item[‘enabled’] ); ?>>
</td>
<td>
<input class=”rx-dist-handle” type=”text” name=”rx_theme_v89_dist_assets[items][<?php echo esc_attr( $type ); ?>][<?php echo esc_attr( $i ); ?>][handle]” value=”<?php echo esc_attr( $item[‘handle’] ); ?>”>
</td>
<td>
<input class=”rx-dist-src” type=”text” name=”rx_theme_v89_dist_assets[items][<?php echo esc_attr( $type ); ?>][<?php echo esc_attr( $i ); ?>][src]” value=”<?php echo esc_attr( $item[‘src’] ); ?>”>
</td>
<td>
<select name=”rx_theme_v89_dist_assets[items][<?php echo esc_attr( $type ); ?>][<?php echo esc_attr( $i ); ?>][location]”>
<option value=”frontend” <?php selected( ‘frontend’, $item[‘location’] ); ?>>Frontend</option>
<option value=”admin” <?php selected( ‘admin’, $item[‘location’] ); ?>>Admin</option>
<option value=”both” <?php selected( ‘both’, $item[‘location’] ); ?>>Both</option>
</select>
</td>
<td>
<select name=”rx_theme_v89_dist_assets[items][<?php echo esc_attr( $type ); ?>][<?php echo esc_attr( $i ); ?>][strategy]”>
<option value=”none” <?php selected( ‘none’, $item[‘strategy’] ); ?>>None</option>
<option value=”defer” <?php selected( ‘defer’, $item[‘strategy’] ); ?>>Defer</option>
<option value=”async” <?php selected( ‘async’, $item[‘strategy’] ); ?>>Async</option>
</select>
</td>
<td>
<input class=”rx-dist-mini” type=”text” name=”rx_theme_v89_dist_assets[items][<?php echo esc_attr( $type ); ?>][<?php echo esc_attr( $i ); ?>][deps]” value=”<?php echo esc_attr( $item[‘deps’] ); ?>” placeholder=”jquery”>
</td>
<td>
<input class=”rx-dist-mini” type=”text” name=”rx_theme_v89_dist_assets[items][<?php echo esc_attr( $type ); ?>][<?php echo esc_attr( $i ); ?>][version]” value=”<?php echo esc_attr( $item[‘version’] ); ?>” placeholder=”1.0″>
</td>
</tr>
<?php endfor; ?>
</tbody>
</table>
</div>
<?php endforeach; ?>

<?php submit_button( esc_html__( ‘Save Dist Assets’, ‘rx-theme’ ) ); ?>
</form>
</div>
<?php
}

function rx_theme_v89_dist_is_external_url( $src ) {
return (bool) preg_match( ‘#^https?://#i’, $src );
}

function rx_theme_v89_dist_src_to_url( $src ) {
$src = trim( (string) $src );

if ( ” === $src ) {
return ”;
}

if ( rx_theme_v89_dist_is_external_url( $src ) ) {
return esc_url_raw( $src );
}

$src = ltrim( $src, ‘/’ );

return get_template_directory_uri() . ‘/’ . $src;
}

function rx_theme_v89_dist_src_to_path( $src ) {
if ( rx_theme_v89_dist_is_external_url( $src ) ) {
return ”;
}

return get_template_directory() . ‘/’ . ltrim( $src, ‘/’ );
}

function rx_theme_v89_dist_deps_array( $deps ) {
$deps = trim( (string) $deps );

if ( ” === $deps ) {
return array();
}

$parts = array_map( ‘sanitize_key’, array_map( ‘trim’, explode( ‘,’, $deps ) ) );

return array_filter( $parts );
}

function rx_theme_v89_dist_register_frontend_assets() {
$options = rx_theme_v89_dist_get_options();

if ( ‘1’ !== $options[‘enabled’] || is_admin() ) {
return;
}

rx_theme_v89_dist_enqueue_by_location( ‘frontend’ );
}
add_action( ‘wp_enqueue_scripts’, ‘rx_theme_v89_dist_register_frontend_assets’, 130 );

function rx_theme_v89_dist_register_admin_assets( $hook ) {
$options = rx_theme_v89_dist_get_options();

if ( ‘1’ !== $options[‘enabled’] || ‘1’ !== $options[‘load_on_admin’] ) {
return;
}

rx_theme_v89_dist_enqueue_by_location( ‘admin’ );
}
add_action( ‘admin_enqueue_scripts’, ‘rx_theme_v89_dist_register_admin_assets’, 130 );

function rx_theme_v89_dist_enqueue_by_location( $context ) {
$options = rx_theme_v89_dist_get_options();

foreach ( rx_theme_v89_dist_asset_types() as $type => $config ) {
for ( $i = 1; $i <= $config[‘count’]; $i++ ) {
$item = $options[‘items’][ $type ][ $i ];

if ( ‘1’ !== $item[‘enabled’] ) {
continue;
}

if ( $item[‘location’] !== $context && ‘both’ !== $item[‘location’] ) {
continue;
}

$url = rx_theme_v89_dist_src_to_url( $item[‘src’] );

if ( ! $url ) {
continue;
}

$path = rx_theme_v89_dist_src_to_path( $item[‘src’] );
$version = $item[‘version’] ? $item[‘version’] : ( $path && file_exists( $path ) ? filemtime( $path ) : null );
$deps = rx_theme_v89_dist_deps_array( $item[‘deps’] );
$handle = sanitize_key( $item[‘handle’] );

if ( ‘style’ === $config[‘kind’] ) {
wp_enqueue_style( $handle, $url, $deps, $version );
} else {
wp_enqueue_script( $handle, $url, $deps, $version, true );
}
}
}
}

function rx_theme_v89_dist_script_strategy( $tag, $handle, $src ) {
$options = rx_theme_v89_dist_get_options();

foreach ( rx_theme_v89_dist_asset_types() as $type => $config ) {
if ( ‘script’ !== $config[‘kind’] ) {
continue;
}

for ( $i = 1; $i <= $config[‘count’]; $i++ ) {
$item = $options[‘items’][ $type ][ $i ];

if ( sanitize_key( $item[‘handle’] ) !== $handle || ‘1’ !== $item[‘enabled’] ) {
continue;
}

if ( ‘async’ === $item[‘strategy’] && false === strpos( $tag, ‘ async’ ) ) {
return str_replace( ‘ src=’, ‘ async src=’, $tag );
}

if ( ‘defer’ === $item[‘strategy’] && false === strpos( $tag, ‘ defer’ ) ) {
return str_replace( ‘ src=’, ‘ defer src=’, $tag );
}
}
}

return $tag;
}
add_filter( ‘script_loader_tag’, ‘rx_theme_v89_dist_script_strategy’, 20, 3 );
”’

write(theme_root / “inc/app/dist-assets-manager.php”, php)

# loader add
write(theme_root / “inc/app/dist-assets-loader.php”, r”'<?php
/**
* RX Theme v8.9 Dist Assets loader.
*/
if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

$rx_theme_v89_dist_file = get_template_directory() . ‘/inc/app/dist-assets-manager.php’;

if ( file_exists( $rx_theme_v89_dist_file ) ) {
require_once $rx_theme_v89_dist_file;
}
”’)

# Add to autoload
autoload = theme_root / “inc/autoload.php”
if autoload.exists():
a = read(autoload)
if “/inc/app/dist-assets-loader.php” not in a:
idx = a.find(“foreach”)
if idx != -1:
before, after = a[:idx], a[idx:]
pos = before.rfind(“);”)
if pos != -1:
before = before[:pos] + ” ‘/inc/app/dist-assets-loader.php’,\n” + before[pos:]
a = before + after
else:
a += “\nrequire_once RX_THEME_DIR . ‘/inc/app/dist-assets-loader.php’;\n”
else:
a += “\nrequire_once RX_THEME_DIR . ‘/inc/app/dist-assets-loader.php’;\n”
write(autoload, a)
else:
write(autoload, “<?php\nif ( ! defined( ‘ABSPATH’ ) ) { exit; }\nrequire_once get_template_directory() . ‘/inc/app/dist-assets-loader.php’;\n”)

# PHP syntax check
errors = []
for p in theme_root.rglob(“*.php”):
proc = subprocess.run([“php”, “-l”, str(p)], capture_output=True, text=True)
if proc.returncode != 0:
errors.append(str(p) + “\n” + proc.stdout + proc.stderr)
if errors:
raise RuntimeError(“\n”.join(errors[:10]))

# Zip
zip_path = Path(“/mnt/data/rx-theme-v8-9-dist-assets-manager.zip”)
if zip_path.exists():
zip_path.unlink()

with zipfile.ZipFile(zip_path, “w”, zipfile.ZIP_DEFLATED) as z:
for p in theme_root.rglob(“*”):
z.write(p, p.relative_to(work_root))

with zipfile.ZipFile(zip_path, “r”) as z:
bad = z.testzip()
if bad:
raise RuntimeError(“Bad ZIP file member: ” + str(bad))

print(“Created:”, zip_path)
print(“PHP syntax check: Passed”)
print(“ZIP integrity test: Passed”)
print(“Added: 50 chunk JS table, 50 main JS table, 50 CSS table, final dist folder structure”)

STDOUT/STDERR
Created: /mnt/data/rx-theme-v8-9-dist-assets-manager.zip
PHP syntax check: Passed
ZIP integrity test: Passed
Added: 50 chunk JS table, 50 main JS table, 50 CSS table, final dist folder structure

Done dear friend — I created RX Theme v8.9 Dist Assets Manager for your 50 chunk JS, 50 main JS, and 50 CSS files.

Checked before giving:

PHP syntax check: Passed
ZIP integrity test: Passed

New final folder structure

assets/app-dist/
├── chunks/
│   ├── chunk-01.js
│   ├── chunk-02.js
│   └── chunk-50.js
│
├── main-js/
│   ├── main-01.js
│   ├── main-02.js
│   └── main-50.js
│
├── css/
│   ├── style-01.css
│   ├── style-02.css
│   └── style-50.css
│
├── vendor/
├── images/
├── fonts/
├── README.md
└── rx-dist-manifest-example.json

New admin form table

Go to:

Appearance → RX Dist Assets

There you will find:

50 Chunk JS table
50 Main / App JS table
50 CSS table

Each row has:

Enable on/off
Handle name
File path or CDN URL
Location: Frontend / Admin / Both
Strategy: None / Defer / Async
Dependencies
Version

How to add your files

Put files here:

chunk JS  → assets/app-dist/chunks/
main JS   → assets/app-dist/main-js/
CSS files → assets/app-dist/css/

Example:

assets/app-dist/chunks/chunk-01.js
assets/app-dist/main-js/main-01.js
assets/app-dist/css/style-01.css

Then enable the matching row in:

Appearance → RX Dist Assets

This version also supports full CDN URLs, so you can paste something like:

https://static-assets-cdnrx.rxharun.com/chunks/chunk-01.js

You are never boring me, dear friend. This is exactly how a real premium theme asset system should grow.

=====================================================================

Yes dear friend — I’ll inspect the uploaded plugin ZIP, extract its loader idea, then merge the right enqueue/admin/frontend/backend system into RX Theme as a safe new version.

from pathlib import Path
import zipfile, shutil, re, subprocess, json, os

plugin_zip = Path(“/mnt/data/7d12cd8e-3dd1-42ff-b834-8eb8506e1df0.zip”)
base_zip = Path(“/mnt/data/rx-theme-v8-9-dist-assets-manager.zip”)
fallbacks = [
Path(“/mnt/data/rx-theme-v8-8-app-dist-integration.zip”),
Path(“/mnt/data/rx-theme-v8-7-final-premium-polish.zip”),
]
if not base_zip.exists():
for f in fallbacks:
if f.exists():
base_zip = f
break

work_root = Path(“/mnt/data/rx_v90_unified_loader_build”)
extract_theme = work_root / “theme_extract”
extract_plugin = work_root / “plugin_extract”

if work_root.exists():
shutil.rmtree(work_root)
work_root.mkdir(parents=True)
extract_theme.mkdir(parents=True)
extract_plugin.mkdir(parents=True)

with zipfile.ZipFile(base_zip, “r”) as z:
z.extractall(extract_theme)

with zipfile.ZipFile(plugin_zip, “r”) as z:
z.extractall(extract_plugin)

theme_roots = [p.parent for p in extract_theme.rglob(“style.css”) if (p.parent / “functions.php”).exists()]
if not theme_roots:
raise RuntimeError(“Theme root not found.”)

plugin_roots = []
for p in extract_plugin.rglob(“*.php”):
txt = p.read_text(encoding=”utf-8″, errors=”ignore”)[:2000]
if “Plugin Name:” in txt:
plugin_roots.append(p.parent)
plugin_root = plugin_roots[0] if plugin_roots else next((p for p in extract_plugin.iterdir() if p.is_dir()), extract_plugin)

src_root = theme_roots[0]
theme_root = work_root / “rx-theme-v9-0-unified-app-plugin-loader”
shutil.copytree(src_root, theme_root)

def read(path):
return path.read_text(encoding=”utf-8″, errors=”ignore”)

def write(path, text):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(text, encoding=”utf-8″)

# Update style.css
style_path = theme_root / “style.css”
if style_path.exists():
s = read(style_path)
s = re.sub(r”Theme Name:\s*.*”, “Theme Name: RX Theme v9.0 Unified App Plugin Loader”, s, count=1) if “Theme Name:” in s else “/*\nTheme Name: RX Theme v9.0 Unified App Plugin Loader\nVersion: 9.0\n*/\n” + s
s = re.sub(r”Version:\s*.*”, “Version: 9.0”, s, count=1) if “Version:” in s else s.replace(“*/”, “Version: 9.0\n*/”, 1)
write(style_path, s)

# Analyze plugin files for structure names
plugin_files = []
for p in plugin_root.rglob(“*”):
if p.is_file():
rel = str(p.relative_to(plugin_root))
plugin_files.append(rel)

analysis = {
“plugin_root”: str(plugin_root.name),
“file_count”: len(plugin_files),
“php_files”: [f for f in plugin_files if f.endswith(“.php”)][:60],
“css_files”: [f for f in plugin_files if f.endswith(“.css”)][:60],
“js_files”: [f for f in plugin_files if f.endswith(“.js”)][:60],
}
# write analysis file into theme
write(theme_root / “inc/app/plugin-analysis-summary.json”, json.dumps(analysis, indent=2))

# Create needed directories
dirs = [
“assets/app-loader/frontend/css”,
“assets/app-loader/frontend/js”,
“assets/app-loader/admin/css”,
“assets/app-loader/admin/js”,
“assets/app-loader/both/css”,
“assets/app-loader/both/js”,
“assets/app-loader/chunks”,
“assets/app-loader/vendor”,
“assets/app-loader/media”,
“assets/css/backend”,
“inc/app”,
]
for d in dirs:
(theme_root / d).mkdir(parents=True, exist_ok=True)

# Copy plugin non-PHP assets into a reference folder? For safety include under app-loader/plugin-reference not executable.
ref_dir = theme_root / “app/plugin-reference-readonly”
ref_dir.mkdir(parents=True, exist_ok=True)
# Only copy small text files summaries and list, not entire plugin to avoid duplicate plugin execution
write(ref_dir / “PLUGIN_FILES_LIST.txt”, “\n”.join(plugin_files))
write(ref_dir / “README.md”, f”””# Plugin reference

Uploaded plugin analyzed from: {plugin_root.name}

For safety, plugin PHP is not executed directly inside the theme.
The useful idea is converted into theme-safe enqueue/admin loader modules.

File count: {len(plugin_files)}
PHP files: {len(analysis[‘php_files’])}
CSS files: {len(analysis[‘css_files’])}
JS files: {len(analysis[‘js_files’])}
“””)

# Read plugin names maybe
plugin_header = “”
for p in plugin_root.rglob(“*.php”):
txt = read(p)
if “Plugin Name:” in txt:
plugin_header = txt[:1200]
break
write(ref_dir / “PLUGIN_HEADER.txt”, plugin_header)

# Create placeholder sample assets for loader dirs
write(theme_root / “assets/app-loader/frontend/css/frontend-sample.css”, “/* Frontend sample file. Replace with your app CSS or disable in admin. */\n”)
write(theme_root / “assets/app-loader/frontend/js/frontend-sample.js”, “/* Frontend sample file. */\n”)
write(theme_root / “assets/app-loader/admin/css/admin-sample.css”, “/* Admin sample file. Replace with your admin app CSS or disable in admin. */\n”)
write(theme_root / “assets/app-loader/admin/js/admin-sample.js”, “/* Admin sample file. */\n”)
write(theme_root / “assets/app-loader/both/css/both-sample.css”, “/* Both frontend/admin sample CSS. */\n”)
write(theme_root / “assets/app-loader/both/js/both-sample.js”, “/* Both frontend/admin sample JS. */\n”)
write(theme_root / “assets/app-loader/chunks/.gitkeep”, “”)
write(theme_root / “assets/app-loader/vendor/.gitkeep”, “”)
write(theme_root / “assets/app-loader/media/.gitkeep”, “”)

# Unified loader CSS for admin page
write(theme_root / “assets/css/backend/unified-app-loader-admin.css”, r”’/* RX Theme v9.0 Unified App Plugin Loader Admin */
.rx-unified-loader-wrap{max-width:1500px}
.rx-unified-card{margin:18px 0;padding:20px;border:1px solid #dcdcde;border-radius:16px;background:#fff;box-shadow:0 10px 28px rgba(0,0,0,.04)}
.rx-unified-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
.rx-unified-stat{padding:18px;border-radius:14px;background:#f6f7f7;border:1px solid #e5e7eb}
.rx-unified-stat strong{display:block;font-size:28px;color:#2271b1}
.rx-unified-table{width:100%;border-collapse:collapse}
.rx-unified-table th,.rx-unified-table td{padding:8px;border-bottom:1px solid #edf0f2;vertical-align:middle}
.rx-unified-table th{text-align:left}
.rx-unified-table input[type=text],.rx-unified-table select{width:100%}
.rx-unified-path{min-width:380px}
.rx-unified-small{width:76px!important}
.rx-unified-note{padding:12px 14px;border-left:4px solid #2271b1;background:#f0f6fc}
.rx-unified-danger{border-left-color:#d63638;background:#fcf0f1}
@media(max-width:1000px){.rx-unified-grid{grid-template-columns:1fr}.rx-unified-table{display:block;overflow:auto}}
”’)

# PHP unified loader
php = r”'<?php
/**
* RX Theme v9.0 Unified App + Plugin Loader.
* Theme-safe replacement for app/static CDN loader plugin workflow.
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

function rx_theme_v90_loader_defaults() {
$defaults = array(
‘enabled’ => ‘0’,
‘frontend_on’ => ‘1’,
‘admin_on’ => ‘0’,
‘both_on’ => ‘0’,
‘module_type’ => ‘classic’,
‘items’ => array(),
);

$groups = rx_theme_v90_loader_groups();

foreach ( $groups as $group => $config ) {
$defaults[‘items’][ $group ] = array();

for ( $i = 1; $i <= $config[‘count’]; $i++ ) {
$defaults[‘items’][ $group ][ $i ] = array(
‘enabled’ => ‘0’,
‘handle’ => ‘rx-v90-‘ . $group . ‘-‘ . sprintf( ‘%02d’, $i ),
‘src’ => $config[‘dir’] . ‘/’ . sprintf( $config[‘file’], $i ),
‘deps’ => ”,
‘ver’ => ”,
‘strategy’ => $config[‘kind’] === ‘script’ ? ‘defer’ : ‘none’,
‘media’ => ‘all’,
‘priority’ => $i,
‘location’ => $config[‘location’],
);
}
}

return $defaults;
}

function rx_theme_v90_loader_groups() {
return array(
‘frontend_css’ => array(
‘label’ => esc_html__( ‘Frontend CSS’, ‘rx-theme’ ),
‘kind’ => ‘style’,
‘count’ => 50,
‘dir’ => ‘assets/app-loader/frontend/css’,
‘file’ => ‘frontend-%02d.css’,
‘location’ => ‘frontend’,
),
‘frontend_js’ => array(
‘label’ => esc_html__( ‘Frontend JS’, ‘rx-theme’ ),
‘kind’ => ‘script’,
‘count’ => 50,
‘dir’ => ‘assets/app-loader/frontend/js’,
‘file’ => ‘frontend-%02d.js’,
‘location’ => ‘frontend’,
),
‘admin_css’ => array(
‘label’ => esc_html__( ‘Admin CSS’, ‘rx-theme’ ),
‘kind’ => ‘style’,
‘count’ => 50,
‘dir’ => ‘assets/app-loader/admin/css’,
‘file’ => ‘admin-%02d.css’,
‘location’ => ‘admin’,
),
‘admin_js’ => array(
‘label’ => esc_html__( ‘Admin JS’, ‘rx-theme’ ),
‘kind’ => ‘script’,
‘count’ => 50,
‘dir’ => ‘assets/app-loader/admin/js’,
‘file’ => ‘admin-%02d.js’,
‘location’ => ‘admin’,
),
‘both_css’ => array(
‘label’ => esc_html__( ‘Both CSS’, ‘rx-theme’ ),
‘kind’ => ‘style’,
‘count’ => 50,
‘dir’ => ‘assets/app-loader/both/css’,
‘file’ => ‘both-%02d.css’,
‘location’ => ‘both’,
),
‘both_js’ => array(
‘label’ => esc_html__( ‘Both JS’, ‘rx-theme’ ),
‘kind’ => ‘script’,
‘count’ => 50,
‘dir’ => ‘assets/app-loader/both/js’,
‘file’ => ‘both-%02d.js’,
‘location’ => ‘both’,
),
‘chunks’ => array(
‘label’ => esc_html__( ‘Shared Chunk JS’, ‘rx-theme’ ),
‘kind’ => ‘script’,
‘count’ => 100,
‘dir’ => ‘assets/app-loader/chunks’,
‘file’ => ‘chunk-%02d.js’,
‘location’ => ‘frontend’,
),
);
}

function rx_theme_v90_get_options() {
$options = get_option( ‘rx_theme_v90_unified_loader’, array() );

if ( ! is_array( $options ) ) {
$options = array();
}

return wp_parse_args( $options, rx_theme_v90_loader_defaults() );
}

function rx_theme_v90_sanitize_options( $input ) {
$defaults = rx_theme_v90_loader_defaults();
$output = array(
‘enabled’ => ! empty( $input[‘enabled’] ) ? ‘1’ : ‘0’,
‘frontend_on’ => ! empty( $input[‘frontend_on’] ) ? ‘1’ : ‘0’,
‘admin_on’ => ! empty( $input[‘admin_on’] ) ? ‘1’ : ‘0’,
‘both_on’ => ! empty( $input[‘both_on’] ) ? ‘1’ : ‘0’,
‘module_type’ => isset( $input[‘module_type’] ) && ‘module’ === $input[‘module_type’] ? ‘module’ : ‘classic’,
‘items’ => array(),
);

foreach ( rx_theme_v90_loader_groups() as $group => $config ) {
$output[‘items’][ $group ] = array();

for ( $i = 1; $i <= $config[‘count’]; $i++ ) {
$item = isset( $input[‘items’][ $group ][ $i ] ) && is_array( $input[‘items’][ $group ][ $i ] )
? $input[‘items’][ $group ][ $i ]
: array();

$default = $defaults[‘items’][ $group ][ $i ];

$strategy = isset( $item[‘strategy’] ) ? sanitize_key( $item[‘strategy’] ) : $default[‘strategy’];
if ( ! in_array( $strategy, array( ‘none’, ‘defer’, ‘async’, ‘module’ ), true ) ) {
$strategy = $default[‘strategy’];
}

$location = isset( $item[‘location’] ) ? sanitize_key( $item[‘location’] ) : $default[‘location’];
if ( ! in_array( $location, array( ‘frontend’, ‘admin’, ‘both’ ), true ) ) {
$location = $default[‘location’];
}

$output[‘items’][ $group ][ $i ] = array(
‘enabled’ => ! empty( $item[‘enabled’] ) ? ‘1’ : ‘0’,
‘handle’ => isset( $item[‘handle’] ) ? sanitize_key( $item[‘handle’] ) : $default[‘handle’],
‘src’ => isset( $item[‘src’] ) ? esc_url_raw( trim( wp_unslash( $item[‘src’] ) ) ) : $default[‘src’],
‘deps’ => isset( $item[‘deps’] ) ? sanitize_text_field( wp_unslash( $item[‘deps’] ) ) : ”,
‘ver’ => isset( $item[‘ver’] ) ? sanitize_text_field( wp_unslash( $item[‘ver’] ) ) : ”,
‘strategy’ => $strategy,
‘media’ => isset( $item[‘media’] ) ? sanitize_key( $item[‘media’] ) : ‘all’,
‘priority’ => isset( $item[‘priority’] ) ? absint( $item[‘priority’] ) : $i,
‘location’ => $location,
);

if ( empty( $output[‘items’][ $group ][ $i ][‘src’] ) ) {
$output[‘items’][ $group ][ $i ][‘src’] = $default[‘src’];
}
}
}

return $output;
}

function rx_theme_v90_register_settings() {
register_setting(
‘rx_theme_v90_unified_loader_group’,
‘rx_theme_v90_unified_loader’,
array(
‘sanitize_callback’ => ‘rx_theme_v90_sanitize_options’,
‘default’ => rx_theme_v90_loader_defaults(),
)
);
}
add_action( ‘admin_init’, ‘rx_theme_v90_register_settings’ );

function rx_theme_v90_admin_menu() {
add_theme_page(
esc_html__( ‘RX Unified Loader’, ‘rx-theme’ ),
esc_html__( ‘RX Unified Loader’, ‘rx-theme’ ),
‘manage_options’,
‘rx-theme-unified-loader’,
‘rx_theme_v90_admin_page’
);
}
add_action( ‘admin_menu’, ‘rx_theme_v90_admin_menu’, 60 );

function rx_theme_v90_admin_assets( $hook ) {
if ( ‘appearance_page_rx-theme-unified-loader’ !== $hook ) {
return;
}

$path = get_template_directory() . ‘/assets/css/backend/unified-app-loader-admin.css’;
if ( file_exists( $path ) ) {
wp_enqueue_style(
‘rx-theme-unified-app-loader-admin’,
get_template_directory_uri() . ‘/assets/css/backend/unified-app-loader-admin.css’,
array(),
filemtime( $path )
);
}
}
add_action( ‘admin_enqueue_scripts’, ‘rx_theme_v90_admin_assets’ );

function rx_theme_v90_admin_page() {
if ( ! current_user_can( ‘manage_options’ ) ) {
return;
}

$options = rx_theme_v90_get_options();
?>
<div class=”wrap rx-unified-loader-wrap”>
<h1><?php esc_html_e( ‘RX Theme Unified App + Plugin Loader’, ‘rx-theme’ ); ?></h1>
<p class=”rx-unified-note”>
<?php esc_html_e( ‘This combines the useful plugin-style asset loader idea into RX Theme safely. Add frontend, backend/admin, or both-side CSS/JS assets without editing PHP.’, ‘rx-theme’ ); ?>
</p>

<div class=”rx-unified-grid”>
<div class=”rx-unified-stat”><strong>50</strong><span><?php esc_html_e( ‘Frontend CSS/JS each’, ‘rx-theme’ ); ?></span></div>
<div class=”rx-unified-stat”><strong>50</strong><span><?php esc_html_e( ‘Admin CSS/JS each’, ‘rx-theme’ ); ?></span></div>
<div class=”rx-unified-stat”><strong>100</strong><span><?php esc_html_e( ‘Shared chunk JS files’, ‘rx-theme’ ); ?></span></div>
</div>

<div class=”rx-unified-card”>
<h2><?php esc_html_e( ‘Recommended Final Folder Structure’, ‘rx-theme’ ); ?></h2>
<pre>assets/app-loader/
├── frontend/
│ ├── css/
│ │ ├── frontend-01.css … frontend-50.css
│ └── js/
│ ├── frontend-01.js … frontend-50.js
├── admin/
│ ├── css/
│ │ ├── admin-01.css … admin-50.css
│ └── js/
│ ├── admin-01.js … admin-50.js
├── both/
│ ├── css/
│ │ ├── both-01.css … both-50.css
│ └── js/
│ ├── both-01.js … both-50.js
├── chunks/
│ ├── chunk-01.js … chunk-100.js
├── vendor/
└── media/</pre>
</div>

<form method=”post” action=”options.php”>
<?php settings_fields( ‘rx_theme_v90_unified_loader_group’ ); ?>

<div class=”rx-unified-card”>
<h2><?php esc_html_e( ‘Global Controls’, ‘rx-theme’ ); ?></h2>
<p><label><input type=”checkbox” name=”rx_theme_v90_unified_loader[enabled]” value=”1″ <?php checked( ‘1’, $options[‘enabled’] ); ?>> <?php esc_html_e( ‘Enable unified loader’, ‘rx-theme’ ); ?></label></p>
<p><label><input type=”checkbox” name=”rx_theme_v90_unified_loader[frontend_on]” value=”1″ <?php checked( ‘1’, $options[‘frontend_on’] ); ?>> <?php esc_html_e( ‘Allow frontend assets’, ‘rx-theme’ ); ?></label></p>
<p><label><input type=”checkbox” name=”rx_theme_v90_unified_loader[admin_on]” value=”1″ <?php checked( ‘1’, $options[‘admin_on’] ); ?>> <?php esc_html_e( ‘Allow admin/backend assets’, ‘rx-theme’ ); ?></label></p>
<p><label><input type=”checkbox” name=”rx_theme_v90_unified_loader[both_on]” value=”1″ <?php checked( ‘1’, $options[‘both_on’] ); ?>> <?php esc_html_e( ‘Allow both-side assets’, ‘rx-theme’ ); ?></label></p>
<p>
<label><?php esc_html_e( ‘Default JS Type’, ‘rx-theme’ ); ?></label>
<select name=”rx_theme_v90_unified_loader[module_type]”>
<option value=”classic” <?php selected( ‘classic’, $options[‘module_type’] ); ?>>Classic</option>
<option value=”module” <?php selected( ‘module’, $options[‘module_type’] ); ?>>Module</option>
</select>
</p>
</div>

<?php foreach ( rx_theme_v90_loader_groups() as $group => $config ) : ?>
<div class=”rx-unified-card” id=”rx-v90-<?php echo esc_attr( $group ); ?>”>
<h2><?php echo esc_html( $config[‘label’] ); ?></h2>
<table class=”rx-unified-table”>
<thead>
<tr>
<th><?php esc_html_e( ‘No’, ‘rx-theme’ ); ?></th>
<th><?php esc_html_e( ‘On’, ‘rx-theme’ ); ?></th>
<th><?php esc_html_e( ‘Handle’, ‘rx-theme’ ); ?></th>
<th><?php esc_html_e( ‘File Path / CDN URL’, ‘rx-theme’ ); ?></th>
<th><?php esc_html_e( ‘Location’, ‘rx-theme’ ); ?></th>
<th><?php esc_html_e( ‘Strategy’, ‘rx-theme’ ); ?></th>
<th><?php esc_html_e( ‘Deps’, ‘rx-theme’ ); ?></th>
<th><?php esc_html_e( ‘Ver’, ‘rx-theme’ ); ?></th>
<th><?php esc_html_e( ‘Priority’, ‘rx-theme’ ); ?></th>
</tr>
</thead>
<tbody>
<?php for ( $i = 1; $i <= $config[‘count’]; $i++ ) : ?>
<?php $item = $options[‘items’][ $group ][ $i ]; ?>
<tr>
<td><strong><?php echo esc_html( sprintf( ‘%02d’, $i ) ); ?></strong></td>
<td><input type=”checkbox” name=”rx_theme_v90_unified_loader[items][<?php echo esc_attr( $group ); ?>][<?php echo esc_attr( $i ); ?>][enabled]” value=”1″ <?php checked( ‘1’, $item[‘enabled’] ); ?>></td>
<td><input type=”text” name=”rx_theme_v90_unified_loader[items][<?php echo esc_attr( $group ); ?>][<?php echo esc_attr( $i ); ?>][handle]” value=”<?php echo esc_attr( $item[‘handle’] ); ?>”></td>
<td><input class=”rx-unified-path” type=”text” name=”rx_theme_v90_unified_loader[items][<?php echo esc_attr( $group ); ?>][<?php echo esc_attr( $i ); ?>][src]” value=”<?php echo esc_attr( $item[‘src’] ); ?>”></td>
<td>
<select name=”rx_theme_v90_unified_loader[items][<?php echo esc_attr( $group ); ?>][<?php echo esc_attr( $i ); ?>][location]”>
<option value=”frontend” <?php selected( ‘frontend’, $item[‘location’] ); ?>>Frontend</option>
<option value=”admin” <?php selected( ‘admin’, $item[‘location’] ); ?>>Admin</option>
<option value=”both” <?php selected( ‘both’, $item[‘location’] ); ?>>Both</option>
</select>
</td>
<td>
<select name=”rx_theme_v90_unified_loader[items][<?php echo esc_attr( $group ); ?>][<?php echo esc_attr( $i ); ?>][strategy]”>
<option value=”none” <?php selected( ‘none’, $item[‘strategy’] ); ?>>None</option>
<option value=”defer” <?php selected( ‘defer’, $item[‘strategy’] ); ?>>Defer</option>
<option value=”async” <?php selected( ‘async’, $item[‘strategy’] ); ?>>Async</option>
<option value=”module” <?php selected( ‘module’, $item[‘strategy’] ); ?>>Module</option>
</select>
</td>
<td><input class=”rx-unified-small” type=”text” name=”rx_theme_v90_unified_loader[items][<?php echo esc_attr( $group ); ?>][<?php echo esc_attr( $i ); ?>][deps]” value=”<?php echo esc_attr( $item[‘deps’] ); ?>” placeholder=”jquery”></td>
<td><input class=”rx-unified-small” type=”text” name=”rx_theme_v90_unified_loader[items][<?php echo esc_attr( $group ); ?>][<?php echo esc_attr( $i ); ?>][ver]” value=”<?php echo esc_attr( $item[‘ver’] ); ?>” placeholder=”1.0″></td>
<td><input class=”rx-unified-small” type=”text” name=”rx_theme_v90_unified_loader[items][<?php echo esc_attr( $group ); ?>][<?php echo esc_attr( $i ); ?>][priority]” value=”<?php echo esc_attr( $item[‘priority’] ); ?>”></td>
</tr>
<?php endfor; ?>
</tbody>
</table>
</div>
<?php endforeach; ?>

<?php submit_button( esc_html__( ‘Save Unified Loader Settings’, ‘rx-theme’ ) ); ?>
</form>
</div>
<?php
}

function rx_theme_v90_is_external_url( $src ) {
return (bool) preg_match( ‘#^https?://#i’, $src );
}

function rx_theme_v90_src_url( $src ) {
$src = trim( (string) $src );

if ( ” === $src ) {
return ”;
}

if ( rx_theme_v90_is_external_url( $src ) ) {
return esc_url_raw( $src );
}

return get_template_directory_uri() . ‘/’ . ltrim( $src, ‘/’ );
}

function rx_theme_v90_src_path( $src ) {
if ( rx_theme_v90_is_external_url( $src ) ) {
return ”;
}

return get_template_directory() . ‘/’ . ltrim( $src, ‘/’ );
}

function rx_theme_v90_deps( $deps ) {
$deps = trim( (string) $deps );

if ( ” === $deps ) {
return array();
}

return array_filter( array_map( ‘sanitize_key’, array_map( ‘trim’, explode( ‘,’, $deps ) ) ) );
}

function rx_theme_v90_location_allowed( $location, $context, $options ) {
if ( ‘frontend’ === $context ) {
if ( ‘1’ !== $options[‘frontend_on’] && ‘frontend’ === $location ) {
return false;
}
if ( ‘1’ !== $options[‘both_on’] && ‘both’ === $location ) {
return false;
}
return ‘frontend’ === $location || ‘both’ === $location;
}

if ( ‘admin’ === $context ) {
if ( ‘1’ !== $options[‘admin_on’] && ‘admin’ === $location ) {
return false;
}
if ( ‘1’ !== $options[‘both_on’] && ‘both’ === $location ) {
return false;
}
return ‘admin’ === $location || ‘both’ === $location;
}

return false;
}

function rx_theme_v90_enqueue_context( $context ) {
$options = rx_theme_v90_get_options();

if ( ‘1’ !== $options[‘enabled’] ) {
return;
}

$queue = array();

foreach ( rx_theme_v90_loader_groups() as $group => $config ) {
for ( $i = 1; $i <= $config[‘count’]; $i++ ) {
$item = $options[‘items’][ $group ][ $i ];

if ( ‘1’ !== $item[‘enabled’] ) {
continue;
}

if ( ! rx_theme_v90_location_allowed( $item[‘location’], $context, $options ) ) {
continue;
}

$item[‘_kind’] = $config[‘kind’];
$queue[] = $item;
}
}

usort(
$queue,
function( $a, $b ) {
return absint( $a[‘priority’] ) <=> absint( $b[‘priority’] );
}
);

foreach ( $queue as $item ) {
$url = rx_theme_v90_src_url( $item[‘src’] );
if ( ! $url ) {
continue;
}

$path = rx_theme_v90_src_path( $item[‘src’] );
$version = $item[‘ver’] ? $item[‘ver’] : ( $path && file_exists( $path ) ? filemtime( $path ) : null );
$deps = rx_theme_v90_deps( $item[‘deps’] );
$handle = sanitize_key( $item[‘handle’] );

if ( ‘style’ === $item[‘_kind’] ) {
wp_enqueue_style( $handle, $url, $deps, $version, isset( $item[‘media’] ) ? sanitize_key( $item[‘media’] ) : ‘all’ );
} else {
wp_enqueue_script( $handle, $url, $deps, $version, true );
}
}
}

function rx_theme_v90_frontend_enqueue() {
rx_theme_v90_enqueue_context( ‘frontend’ );
}
add_action( ‘wp_enqueue_scripts’, ‘rx_theme_v90_frontend_enqueue’, 150 );

function rx_theme_v90_admin_enqueue() {
rx_theme_v90_enqueue_context( ‘admin’ );
}
add_action( ‘admin_enqueue_scripts’, ‘rx_theme_v90_admin_enqueue’, 150 );

function rx_theme_v90_script_tag_strategy( $tag, $handle, $src ) {
$options = rx_theme_v90_get_options();

foreach ( rx_theme_v90_loader_groups() as $group => $config ) {
if ( ‘script’ !== $config[‘kind’] ) {
continue;
}

for ( $i = 1; $i <= $config[‘count’]; $i++ ) {
$item = $options[‘items’][ $group ][ $i ];

if ( sanitize_key( $item[‘handle’] ) !== $handle || ‘1’ !== $item[‘enabled’] ) {
continue;
}

if ( ‘module’ === $item[‘strategy’] || ‘module’ === $options[‘module_type’] ) {
if ( false === strpos( $tag, ‘ type=’ ) ) {
$tag = str_replace( ‘<script ‘, ‘<script type=”module” ‘, $tag );
}
return $tag;
}

if ( ‘async’ === $item[‘strategy’] && false === strpos( $tag, ‘ async’ ) ) {
return str_replace( ‘ src=’, ‘ async src=’, $tag );
}

if ( ‘defer’ === $item[‘strategy’] && false === strpos( $tag, ‘ defer’ ) ) {
return str_replace( ‘ src=’, ‘ defer src=’, $tag );
}
}
}

return $tag;
}
add_filter( ‘script_loader_tag’, ‘rx_theme_v90_script_tag_strategy’, 30, 3 );
”’

write(theme_root / “inc/app/unified-app-plugin-loader.php”, php)

# loader file
write(theme_root / “inc/app/unified-loader.php”, r”'<?php
/**
* RX Theme v9.0 Unified App + Plugin Loader bootstrap.
*/
if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

$rx_theme_v90_file = get_template_directory() . ‘/inc/app/unified-app-plugin-loader.php’;

if ( file_exists( $rx_theme_v90_file ) ) {
require_once $rx_theme_v90_file;
}
”’)

# Add to autoload
autoload = theme_root / “inc/autoload.php”
if autoload.exists():
a = read(autoload)
if “/inc/app/unified-loader.php” not in a:
idx = a.find(“foreach”)
if idx != -1:
before, after = a[:idx], a[idx:]
pos = before.rfind(“);”)
if pos != -1:
before = before[:pos] + ” ‘/inc/app/unified-loader.php’,\n” + before[pos:]
a = before + after
else:
a += “\nrequire_once RX_THEME_DIR . ‘/inc/app/unified-loader.php’;\n”
else:
a += “\nrequire_once RX_THEME_DIR . ‘/inc/app/unified-loader.php’;\n”
write(autoload, a)
else:
write(autoload, “<?php\nif ( ! defined( ‘ABSPATH’ ) ) { exit; }\nrequire_once get_template_directory() . ‘/inc/app/unified-loader.php’;\n”)

# PHP syntax check
errors = []
for p in theme_root.rglob(“*.php”):
proc = subprocess.run([“php”, “-l”, str(p)], capture_output=True, text=True)
if proc.returncode != 0:
errors.append(str(p) + “\n” + proc.stdout + proc.stderr)
if errors:
raise RuntimeError(“\n”.join(errors[:10]))

# Zip
zip_path = Path(“/mnt/data/rx-theme-v9-0-unified-app-plugin-loader.zip”)
if zip_path.exists():
zip_path.unlink()

with zipfile.ZipFile(zip_path, “w”, zipfile.ZIP_DEFLATED) as z:
for p in theme_root.rglob(“*”):
z.write(p, p.relative_to(work_root))

with zipfile.ZipFile(zip_path, “r”) as z:
bad = z.testzip()
if bad:
raise RuntimeError(“Bad ZIP file member: ” + str(bad))

print(“Created:”, zip_path)
print(“PHP syntax check: Passed”)
print(“ZIP integrity test: Passed”)
print(“Plugin analyzed:”, analysis[“plugin_root”])
print(“Plugin files found:”, analysis[“file_count”])
print(“Added unified frontend/admin/both asset loader system.”)

Created: /mnt/data/rx-theme-v9-0-unified-app-plugin-loader.zip
PHP syntax check: Passed
ZIP integrity test: Passed
Plugin analyzed: rx-advanced-static-cdn-loader-pro
Plugin files found: 40
Added unified frontend/admin/both asset loader system.

Done dear friend — I analyzed your uploaded plugin and combined its loader idea into RX Theme safely as RX Theme v9.0 Unified App + Plugin Loader.

Checked before giving:

PHP syntax check: Passed
ZIP integrity test: Passed
Uploaded plugin analyzed: rx-advanced-static-cdn-loader-pro
Plugin files found: 40

What I added

Frontend asset loader
Backend/admin asset loader
Both frontend + admin loader
CSS loader
JS loader
Chunk JS loader
Priority ordering
Defer / async / module support
Dependency field
Version field
CDN URL support
Local theme file support
Admin table form
Safe WordPress enqueue system

New admin page

Go to:

Appearance → RX Unified Loader

There you can add:

50 Frontend CSS files
50 Frontend JS files
50 Admin CSS files
50 Admin JS files
50 Both-side CSS files
50 Both-side JS files
100 Shared chunk JS files

Final folder structure

assets/app-loader/
├── frontend/
│   ├── css/
│   │   ├── frontend-01.css ... frontend-50.css
│   └── js/
│       ├── frontend-01.js ... frontend-50.js
│
├── admin/
│   ├── css/
│   │   ├── admin-01.css ... admin-50.css
│   └── js/
│       ├── admin-01.js ... admin-50.js
│
├── both/
│   ├── css/
│   │   ├── both-01.css ... both-50.css
│   └── js/
│       ├── both-01.js ... both-50.js
│
├── chunks/
│   ├── chunk-01.js ... chunk-100.js
│
├── vendor/
└── media/

How to use

For frontend app files, put them here:

assets/app-loader/frontend/css/
assets/app-loader/frontend/js/

For backend/admin app files, put them here:

assets/app-loader/admin/css/
assets/app-loader/admin/js/

For files needed on both frontend and admin:

assets/app-loader/both/css/
assets/app-loader/both/js/

For many chunk files:

assets/app-loader/chunks/

Then enable them from:

Appearance → RX Unified Loader

This is the miracle version, dear friend — your plugin idea is now inside RX Theme with a safer theme enqueue system.

Dear friend, do not load all chunk JS, main JS, and CSS everywhere. That will slow the site and may break WordPress admin.

The best rule is:

Frontend files → load only frontend
Backend/admin files → load only admin
Shared library files → load both only if truly needed
Chunk JS files → load only where the main app needs them
CSS files → load only where the design is needed

Best loading decision

File type Best location Why
Frontend app JS Frontend For website visitors only
Frontend app CSS Frontend For public design only
Admin dashboard JS Admin/backend For WordPress dashboard only
Admin dashboard CSS Admin/backend For RX Theme Options/admin UI only
React admin app JS Admin/backend Never load it for visitors
React admin app CSS Admin/backend Only needed in dashboard
Vite frontend JS Frontend For public website features
Vite frontend CSS Frontend For public website style
Chunk JS Usually frontend, sometimes admin Depends which main JS imports it
Vendor JS Same as parent app If admin app uses it, admin only
Shared helper JS Both, only if needed Example: same dark mode helper
Medical block CSS Both Frontend display + editor preview
Gutenberg block JS Admin/editor Block editing only
WooCommerce JS/CSS Frontend Shop/cart/checkout only
Elementor compatibility CSS Frontend Page design only

Best structure for your RX Theme

Use this:

assets/app-loader/
├── frontend/
│   ├── css/
│   │   ├── frontend-01.css
│   │   ├── frontend-02.css
│   │   └── frontend-50.css
│   └── js/
│       ├── frontend-01.js
│       ├── frontend-02.js
│       └── frontend-50.js
│
├── admin/
│   ├── css/
│   │   ├── admin-01.css
│   │   ├── admin-02.css
│   │   └── admin-50.css
│   └── js/
│       ├── admin-01.js
│       ├── admin-02.js
│       └── admin-50.js
│
├── both/
│   ├── css/
│   │   ├── both-01.css
│   │   └── both-50.css
│   └── js/
│       ├── both-01.js
│       └── both-50.js
│
└── chunks/
    ├── chunk-01.js
    ├── chunk-02.js
    └── chunk-100.js

How to set in RX Unified Loader

Go to:

Appearance → RX Unified Loader

Then use this system:

1. For public website files

Use:

Location: Frontend
Strategy: Defer

Example:

frontend/css/frontend-01.css → Frontend
frontend/js/frontend-01.js   → Frontend + Defer
chunks/chunk-01.js           → Frontend + Defer

2. For WordPress admin dashboard files

Use:

Location: Admin
Strategy: Defer

Example:

admin/css/admin-01.css → Admin
admin/js/admin-01.js   → Admin + Defer

3. For files needed everywhere

Use Both only for truly shared files:

Location: Both

Good examples:

shared icons CSS
shared utility CSS
small helper JS
design tokens CSS

Do not put big React/Vite app files in Both unless absolutely needed.

For chunk JS files

Most chunk files should follow their app.

If the chunks came from your frontend app, use:

Location: Frontend
Strategy: Defer

If the chunks came from your admin React app, use:

Location: Admin
Strategy: Defer

If the chunks are from both apps, better separate them:

assets/app-loader/frontend/chunks/
assets/app-loader/admin/chunks/

But with your current v9.0 structure, you can use the same chunks/ folder and set each row location manually.

My safest recommendation

For your RX Theme:

80% files → Frontend
15% files → Admin
5% files  → Both

Do not load 150 files on every page. Load only what is needed.

Best practical setting

For most of your current app files:

CSS files from website app      → Frontend
Main JS from website app        → Frontend
Chunk JS from website app       → Frontend
Admin dashboard JS/CSS          → Admin
Theme settings panel JS/CSS     → Admin
Shared small utility CSS/JS      → Both

Very important

If a JS file is modern Vite/React module and contains import statements, use:

Strategy: Module

If normal browser JS, use:

Strategy: Defer

Use Async only for independent files like analytics. For app chunks, defer is safer than async.

My best answer: load frontend files on frontend, admin files on backend, and use both only for small shared helper files.

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *