Make WordPress Themes

Changeset 357886


Ignore:
Timestamp:
11/07/2026 12:35:45 PM (less than one hour ago)
Author:
themedropbox
Message:

New version of Nexversal - 3.5.9

Location:
nexversal/3.5.9
Files:
9 added
21 edited
1 copied

Legend:

Unmodified
Added
Removed
  • nexversal/3.5.9/404.php

    r357433 r357886  
    11<?php
    22/**
    3  * Security: Prevent direct script access
     3 * 404 template (Page Not Found - Enhanced Traffic Retention) for Nexversal Theme
     4 *
     5 * @package Nexversal
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
    410 */
     11
    512if (!defined('ABSPATH')) {
    613    exit;
    714}
    815
    9 /**
    10  * 404 template (Page Not Found - Enhanced Traffic Retention)
    11  *
    12  * @package Nexversal
    13  */
     16// Failsafe auto-redirect: If visitor hits ?page_id=2 or legacy sample/about URLs, 301 redirect immediately to About Us
     17$requested_page_id = isset($_GET['page_id']) ? (int) $_GET['page_id'] : 0;
     18$req_uri           = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
     19if ($requested_page_id === 2 || strpos($req_uri, 'page_id=2') !== false || strpos($req_uri, 'sample-page') !== false || strpos($req_uri, 'aboutAbout') !== false) {
     20    $dest = function_exists('nexversal_get_about_page_url') ? nexversal_get_about_page_url() : home_url('/about/');
     21    wp_safe_redirect($dest, 301);
     22    exit;
     23}
     24
     25// Master 301 Redirect Record evaluation
     26$clean_path = parse_url($req_uri, PHP_URL_PATH);
     27$clean_path = $clean_path ? rtrim($clean_path, '/') : '';
     28if (!empty($clean_path)) {
     29    $blog_url = function_exists('nexversal_get_blogs_page_url') ? nexversal_get_blogs_page_url() : home_url('/blog/');
     30    $redirects = array(
     31        '/aboutAbout'                                              => function_exists('nexversal_get_about_page_url') ? nexversal_get_about_page_url() : home_url('/about/'),
     32        '/contactContact'                                          => function_exists('nexversal_get_contact_page_url') ? nexversal_get_contact_page_url() : home_url('/contact/'),
     33        '/Home'                                                    => home_url('/'),
     34        '/category/comparisonsComparisons'                         => home_url('/category/comparisons/'),
     35        '/sample-page'                                             => function_exists('nexversal_get_about_page_url') ? nexversal_get_about_page_url() : home_url('/about/'),
     36        '/blogs'                                                   => $blog_url,
     37        '/kepler-vs-github-copilot'                                => home_url('/blog/kepler-ai-coding'),
     38        '/gitkraken-kepler'                                        => home_url('/blog/setup-gitkraken-kepler'),
     39        '/seo-in-the-age-of-answer-engines'                        => home_url('/blog/best-ai-seo-tools'),
     40        '/search-marketing-course'                                 => home_url('/blog/best-ai-seo-tools'),
     41        '/category/artificial-intelligence'                        => home_url('/blog'),
     42        '/future-of-artificial-intelligence-2026'                  => home_url('/blog'),
     43        '/the-self-taught-engineers-curriculum'                     => home_url('/blog/best-free-ai-tools-for-coding-2026'),
     44        '/the-anatomy-of-a-supply-chain-attack'                    => home_url('/blog'),
     45        '/the-quiet-revolution-of-agentic-llms'                    => home_url('/blog/chatgpt-vs-claude-vs-gemini-which-should-you-use'),
     46        '/designing-with-restraint'                                => home_url('/blog'),
     47        '/best-ai-video-generators-for-creators-in-2026'          => home_url('/blog/ai-tools-for-a-video-generator'),
     48        '/category/education'                                      => home_url('/blog/best-ai-tools-for-students'),
     49        '/why-pricing-is-strategy-not-a-number'                    => home_url('/blog/ai-tools-for-small-business'),
     50        '/how-to-learn-seo-at-home-for-free-complete-2026-roadmap' => home_url('/blog/best-ai-seo-tools'),
     51        '/key-takeaways-for-mastering-rankings'                    => home_url('/blog/best-ai-seo-tools'),
     52        '/the-best-chatgpt-alternatives-worth-trying'              => home_url('/blog/chatgpt-alternatives'),
     53        '/best-ai-tools-for-text-to-video-generators'              => home_url('/blog/ai-tools-for-a-video-generator'),
     54        '/ai-tools-for-text-to-video-generators'                   => home_url('/blog/ai-tools-for-a-video-generator'),
     55    );
     56
     57    if (isset($redirects[$clean_path])) {
     58        wp_safe_redirect($redirects[$clean_path], 301);
     59        exit;
     60    }
     61}
     62
     63// Failsafe virtual ads.txt interceptor if server routed request to 404
     64if (preg_match('#^/ads\.txt(\?.*)?$#i', $req_uri)) {
     65    if (function_exists('nexversal_render_virtual_ads_txt_output')) {
     66        nexversal_render_virtual_ads_txt_output();
     67    }
     68}
    1469
    1570get_header();
  • nexversal/3.5.9/archive.php

    r357433 r357886  
    11<?php
    22/**
    3  * Security: Prevent direct script access
     3 * Archive template (Categories, Tags, Authors, Dates) for Nexversal Theme
     4 *
     5 * @package Nexversal
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
    410 */
     11
    512if (!defined('ABSPATH')) {
    613    exit;
    714}
    8 
    9 /**
    10  * Archive template (Categories, Tags, Authors, Dates)
    11  *
    12  * @package Nexversal
    13  */
    1415
    1516get_header();
    … …  
    5253        </div>
    5354
    54         <?php get_sidebar(); ?>
     55        <?php
     56        if (!function_exists('nexversal_is_meta_disabled') || !nexversal_is_meta_disabled('disable_sidebar')) {
     57            get_sidebar();
     58        }
     59        ?>
    5560    </div>
    5661</main>
  • nexversal/3.5.9/assets/css/editor-style.css

    r357433 r357886  
    177177}
    178178
     179/* ==========================================================================
     180   Hero Banner Block Styles inside Gutenberg Block Editor
     181   ========================================================================== */
     182.nx-hero-section {
     183  padding: 36px 20px;
     184  background: #f8fafc;
     185  border: 1px solid #e2e8f0;
     186  border-radius: 12px;
     187  margin-bottom: 30px;
     188}
     189
     190.nx-hero-badge {
     191  display: inline-block;
     192  font-size: 0.75rem;
     193  font-weight: 700;
     194  letter-spacing: 0.08em;
     195  text-transform: uppercase;
     196  color: #4f46e5;
     197  background: #eef2ff;
     198  padding: 5px 14px;
     199  border-radius: 20px;
     200  margin-bottom: 14px;
     201}
     202
     203.nx-hero-title {
     204  font-size: 2.2rem;
     205  font-weight: 900;
     206  line-height: 1.2;
     207  letter-spacing: -0.03em;
     208  color: #0f172a;
     209  margin-bottom: 14px;
     210}
     211
     212.nx-hero-description {
     213  font-size: 1.1rem;
     214  line-height: 1.65;
     215  color: #64748b;
     216  max-width: 780px;
     217  margin-bottom: 20px;
     218}
     219
     220.nx-hero-btn .wp-block-button__link {
     221  display: inline-flex;
     222  align-items: center;
     223  padding: 12px 28px;
     224  background-color: #4f46e5 !important;
     225  color: #ffffff !important;
     226  border-radius: 30px !important;
     227  font-weight: 700;
     228  font-size: 0.95rem;
     229  text-decoration: none;
     230}
     231
     232/* Newsletter Card Styles in Gutenberg Editor */
     233.nx-newsletter-card {
     234  background: linear-gradient(135deg, rgba(79, 70, 229, 0.06) 0%, rgba(6, 182, 212, 0.06) 100%);
     235  border: 1px solid #e2e8f0;
     236  border-radius: 12px;
     237  padding: 30px 24px;
     238  margin: 32px 0;
     239}
     240
     241.nx-newsletter-badge {
     242  display: inline-flex;
     243  align-items: center;
     244  gap: 6px;
     245  padding: 4px 12px;
     246  background: #eef2ff;
     247  color: #4f46e5;
     248  border-radius: 20px;
     249  font-size: 0.75rem;
     250  font-weight: 700;
     251  letter-spacing: 0.06em;
     252  text-transform: uppercase;
     253  margin-bottom: 12px;
     254}
     255
     256.nx-newsletter-title {
     257  font-size: 1.5rem !important;
     258  font-weight: 800 !important;
     259  color: #0f172a !important;
     260  margin: 0 0 8px 0 !important;
     261}
     262
     263.nx-newsletter-desc {
     264  font-size: 0.95rem;
     265  color: #64748b;
     266  margin-bottom: 18px;
     267}
     268
     269.nx-newsletter-input-group {
     270  display: flex;
     271  gap: 10px;
     272  max-width: 500px;
     273}
     274
     275.nx-newsletter-input {
     276  flex: 1;
     277  padding: 10px 16px;
     278  border: 1px solid #cbd5e1;
     279  border-radius: 8px;
     280  font-size: 0.9rem;
     281}
     282
     283.nx-newsletter-btn {
     284  padding: 10px 22px;
     285  background: #4f46e5;
     286  color: #ffffff;
     287  border: none;
     288  border-radius: 8px;
     289  font-weight: 700;
     290  cursor: pointer;
     291}
     292
     293.nx-newsletter-privacy {
     294  font-size: 0.8rem;
     295  color: #94a3b8;
     296  margin-top: 8px;
     297}
     298
     299/* Contact Details in Editor */
     300.nx-contact-details {
     301  display: flex;
     302  flex-direction: column;
     303  gap: 16px;
     304  margin-top: 16px;
     305}
     306
     307.nx-contact-item {
     308  margin-bottom: 8px;
     309}
     310
     311.nx-contact-label {
     312  font-size: 0.78rem !important;
     313  font-weight: 700 !important;
     314  color: #64748b !important;
     315  text-transform: uppercase !important;
     316  letter-spacing: 0.05em !important;
     317  margin-bottom: 2px !important;
     318}
     319
     320.nx-contact-val {
     321  font-weight: 600 !important;
     322  font-size: 0.95rem !important;
     323  color: #0f172a !important;
     324  margin-top: 0 !important;
     325  margin-bottom: 0 !important;
     326}
     327
     328
     329
  • nexversal/3.5.9/assets/js/main.js

    r357433 r357886  
    228228        }
    229229    }
     230
     231    // 8. Newsletter Subscription Persistence on Load (Logged-in or Previously Subscribed)
     232    try {
     233        if (localStorage.getItem('nx_newsletter_subscribed') === 'true') {
     234            document.querySelectorAll('.nx-newsletter-v2').forEach(function (box) {
     235                var f = box.querySelector('.nx-newsletter-form-v2');
     236                var s = box.querySelector('.nx-nl-success-card');
     237                if (f && s) {
     238                    f.style.display = 'none';
     239                    s.style.display = 'block';
     240                }
     241            });
     242        }
     243    } catch (err) {}
     244
     245    // 9. Newsletter AJAX Subscription Handler with Validation & WP-Admin Storage
     246    document.addEventListener('submit', function (e) {
     247        var form = e.target.closest('.nx-newsletter-form, .nx-newsletter-form-v2');
     248        if (!form) return;
     249        e.preventDefault();
     250
     251        var input = form.querySelector('.nx-newsletter-input') || form.querySelector('input[type="email"]');
     252        var btn = form.querySelector('.nx-newsletter-btn') || form.querySelector('button[type="submit"]');
     253        var email = input ? input.value.trim() : '';
     254
     255        if (!email) {
     256            alert('Please enter your email address to subscribe.');
     257            if (input) input.focus();
     258            return;
     259        }
     260
     261        // Email validation regex
     262        var emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
     263        if (!emailRegex.test(email)) {
     264            alert('Please enter a valid email format (e.g. name@company.com).');
     265            if (input) input.focus();
     266            return;
     267        }
     268
     269        // Disable button while processing
     270        var originalBtnHtml = btn ? btn.innerHTML : '';
     271        if (btn) {
     272            btn.disabled = true;
     273            btn.innerHTML = '<span>Subscribing...</span>';
     274        }
     275
     276        var ajaxUrl = (typeof nexversal_ajax !== 'undefined' && nexversal_ajax.ajax_url) ? nexversal_ajax.ajax_url : '/wp-admin/admin-ajax.php';
     277        var nonce = (typeof nexversal_ajax !== 'undefined' && nexversal_ajax.nonce) ? nexversal_ajax.nonce : '';
     278
     279        var formData = new FormData();
     280        formData.append('action', 'nexversal_subscribe');
     281        formData.append('nonce', nonce);
     282        formData.append('email', email);
     283
     284        fetch(ajaxUrl, {
     285            method: 'POST',
     286            body: formData
     287        })
     288        .then(function (res) { return res.json(); })
     289        .then(function (data) {
     290            if (data.success) {
     291                try {
     292                    localStorage.setItem('nx_newsletter_subscribed', 'true');
     293                } catch (e) {}
     294
     295                var v2Container = form.closest('.nx-newsletter-v2');
     296                if (v2Container) {
     297                    var successCard = v2Container.querySelector('.nx-nl-success-card');
     298                    if (successCard) {
     299                        form.style.display = 'none';
     300                        successCard.style.display = 'block';
     301                        return;
     302                    }
     303                }
     304
     305                if (btn) {
     306                    btn.innerHTML = '<span>✓ ' + data.data.message + '</span>';
     307                    btn.style.background = '#10b981';
     308                }
     309                if (input) {
     310                    input.disabled = true;
     311                    input.style.borderColor = '#10b981';
     312                }
     313            } else {
     314                if (btn) {
     315                    btn.disabled = false;
     316                    btn.innerHTML = originalBtnHtml || '<span>Subscribe &rarr;</span>';
     317                }
     318                alert(data.data ? data.data.message : 'Error subscribing. Please try again.');
     319            }
     320        })
     321        .catch(function () {
     322            if (btn) {
     323                btn.disabled = false;
     324                btn.innerHTML = originalBtnHtml || '<span>Subscribe &rarr;</span>';
     325            }
     326            alert('Unable to process subscription right now. Please try again later.');
     327        });
     328    });
     329
     330    // 10. Built-in Ad Engine: Impressions Tracking, Click Tracker & Ad-Blocker Bypass
     331    var adSlots = document.querySelectorAll('.nx-ad-slot');
     332    if (adSlots.length > 0) {
     333        var ajaxUrl = (typeof nexversal_ajax !== 'undefined' && nexversal_ajax.ajax_url) ? nexversal_ajax.ajax_url : '/wp-admin/admin-ajax.php';
     334
     335        // A. Record Impressions on load
     336        adSlots.forEach(function (slot) {
     337            var slotName = slot.getAttribute('data-ad-slot');
     338            if (slotName) {
     339                var fd = new FormData();
     340                fd.append('action', 'nexversal_ad_beacon');
     341                fd.append('slot', slotName);
     342                fd.append('type', 'impression');
     343                if (navigator.sendBeacon) {
     344                    navigator.sendBeacon(ajaxUrl, fd);
     345                } else {
     346                    fetch(ajaxUrl, { method: 'POST', body: fd, keepalive: true }).catch(function () {});
     347                }
     348            }
     349        });
     350
     351        // B. Record Clicks on Ad Links
     352        document.addEventListener('click', function (e) {
     353            var adLink = e.target.closest('.nx-ad-slot a');
     354            if (!adLink) return;
     355            var slot = adLink.closest('.nx-ad-slot');
     356            var slotName = slot ? slot.getAttribute('data-ad-slot') : '';
     357            if (slotName) {
     358                var fd = new FormData();
     359                fd.append('action', 'nexversal_ad_beacon');
     360                fd.append('slot', slotName);
     361                fd.append('type', 'click');
     362                if (navigator.sendBeacon) {
     363                    navigator.sendBeacon(ajaxUrl, fd);
     364                } else {
     365                    fetch(ajaxUrl, { method: 'POST', body: fd, keepalive: true }).catch(function () {});
     366                }
     367            }
     368        });
     369
     370        // C. Ad-Blocker Bypass Detection & Fallback Switcher
     371        var bypassElements = document.querySelectorAll('.nx-ad-blocker-bypass');
     372        if (bypassElements.length > 0) {
     373            var bait = document.createElement('div');
     374            bait.className = 'ads ad adsense ad-banner sponsor pub_300x250 text-ad';
     375            bait.style.cssText = 'position:absolute;left:-9999px;top:-9999px;width:1px;height:1px;';
     376            document.body.appendChild(bait);
     377
     378            window.setTimeout(function () {
     379                var isBlocked = (bait.offsetParent === null || bait.offsetHeight === 0 || bait.clientHeight === 0);
     380                if (isBlocked) {
     381                    bypassElements.forEach(function (bypass) {
     382                        var parentSlot = bypass.closest('.nx-ad-slot');
     383                        if (parentSlot) {
     384                            var content = parentSlot.querySelector('.nx-ad-content');
     385                            if (content) content.style.display = 'none';
     386                            bypass.style.display = 'block';
     387                        }
     388                    });
     389                }
     390                if (bait && bait.parentNode) {
     391                    bait.parentNode.removeChild(bait);
     392                }
     393            }, 120);
     394        }
     395    }
    230396});
  • nexversal/3.5.9/author.php

    r357433 r357886  
    11<?php
    22/**
    3  * Security: Prevent direct script access
     3 * Author Archive Template for Nexversal Theme
     4 *
     5 * @package Nexversal
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
    410 */
     11
    512if (!defined('ABSPATH')) {
    613    exit;
    714}
    8 
    9 /**
    10  * Author Archive Template
    11  *
    12  * @package Nexversal
    13  */
    1415
    1516get_header();
    … …  
    7071                <?php endif; ?>
    7172            </div>
    72             <?php get_sidebar(); ?>
     73            <?php
     74            if (!function_exists('nexversal_is_meta_disabled') || !nexversal_is_meta_disabled('disable_sidebar')) {
     75                get_sidebar();
     76            }
     77            ?>
    7378        </div>
    7479    </div>
  • nexversal/3.5.9/comments.php

    r357433 r357886  
    11<?php
    22/**
    3  * Security: Prevent direct script access
     3 * Comments template for Nexversal Theme
     4 *
     5 * @package Nexversal
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
    410 */
     11
    512if (!defined('ABSPATH')) {
    613    exit;
    714}
    8 
    9 /**
    10  * Modern Comments Template
    11  *
    12  * @package Nexversal
    13  */
    1415
    1516if (post_password_required()) {
  • nexversal/3.5.9/footer.php

    r357433 r357886  
    11<?php
    22/**
    3  * Security: Prevent direct script access
     3 * Footer template for Nexversal Theme
     4 *
     5 * @package Nexversal
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
    410 */
     11
    512if (!defined('ABSPATH')) {
    613    exit;
    714}
    8 
    9 /**
    10  * Footer template
    11  *
    12  * @package Nexversal
    13  */
    1415?>
     16<?php if (!function_exists('nexversal_is_meta_disabled') || !nexversal_is_meta_disabled('disable_footer')) : ?>
    1517<footer id="colophon" class="site-footer">
    1618    <div class="container">
    … …  
    3032                <div class="footer-widget">
    3133                    <h4 class="widget-title"><?php bloginfo('name'); ?></h4>
    32                     <p style="line-height:1.6;"><?php bloginfo('description'); ?></p>
    33                     <p style="font-size:0.85rem;color:#64748b;"><?php esc_html_e('Empowering creators, developers, and businesses with actionable technology insights.', 'nexversal'); ?></p>
     34                    <?php
     35                    $site_desc = get_bloginfo('description');
     36                    if (!empty($site_desc)) :
     37                        ?>
     38                        <p style="line-height: 1.6; color: #94a3b8; font-size: 0.92rem; margin-top: 8px;"><?php echo esc_html($site_desc); ?></p>
     39                    <?php endif; ?>
    3440                </div>
    3541                <div class="footer-widget">
    … …  
    96102                    ?>
    97103                    <p class="nx-footer-credits">
    98                         &copy; <?php echo esc_html(gmdate('Y')); ?>. <?php esc_html_e('All rights reserved.', 'nexversal'); ?>
     104                        <?php
     105                        $site_name = get_bloginfo('name');
     106                        if (empty($site_name)) {
     107                            $site_name = 'Nexversal';
     108                        }
     109                        $site_year = gmdate('Y');
     110                        ?>
     111                        &copy; <?php echo esc_html($site_year); ?> <?php echo esc_html($site_name); ?>. <?php esc_html_e('All rights reserved.', 'nexversal'); ?>
    99112                        <span class="nx-footer-sep">&bull;</span>
    100113                        <?php
    … …  
    119132    </div>
    120133</footer>
     134<?php endif; // End disable_footer check ?>
    121135
    122136<button type="button" id="nx-back-to-top" aria-label="<?php esc_attr_e('Back to top', 'nexversal'); ?>">
  • nexversal/3.5.9/functions.php

    r357433 r357886  
    11<?php
    22/**
    3  * Nexversal Theme Functions & Definitions
     3 * Nexversal WordPress Theme functions and definitions
    44 *
    55 * @package Nexversal
    6  * @version 2.5.2
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
     10 * @version 3.3.0
    711 */
    812
    … …  
    6872        add_theme_support('wp-block-styles');
    6973
    70         // Custom Header support.
     74        // Custom background support.
     75        add_theme_support('custom-background', apply_filters('nexversal_custom_background_args', array(
     76            'default-color' => 'ffffff',
     77            'default-image' => '',
     78        )));
     79
     80        // Custom header support.
    7181        add_theme_support('custom-header', apply_filters('nexversal_custom_header_args', array(
    7282            'default-image' => '',
    7383            'width'         => 1200,
    74             'height'        => 300,
     84            'height'        => 280,
    7585            'flex-height'   => true,
    7686            'flex-width'    => true,
    7787            'header-text'   => false,
    78         )));
    79 
    80         // Custom Background support.
    81         add_theme_support('custom-background', apply_filters('nexversal_custom_background_args', array(
    82             'default-color' => 'ffffff',
    8388        )));
    8489    }
    … …  
    99104        register_block_pattern_category('nexversal', array(
    100105            'label' => esc_html__('Nexversal', 'nexversal'),
     106        ));
     107    }
     108    if (function_exists('register_block_pattern')) {
     109        register_block_pattern('nexversal/hero-banner', array(
     110            'title'       => esc_html__('Homepage Hero Banner', 'nexversal'),
     111            'description' => esc_html__('High-impact hero banner with badge, headline, description, and CTA button.', 'nexversal'),
     112            'categories'  => array('nexversal'),
     113            'content'     => '<!-- wp:group {"className":"nx-hero-section","layout":{"type":"constrained"}} -->
     114<div class="wp-block-group nx-hero-section"><div class="container">
     115<!-- wp:paragraph {"className":"nx-hero-badge"} -->
     116<p class="nx-hero-badge">MASTER AI WITH POWERFUL &amp; READY-TO-USE PROMPTS</p>
     117<!-- /wp:paragraph -->
     118
     119<!-- wp:heading {"level":1,"className":"nx-hero-title"} -->
     120<h1 class="wp-block-heading nx-hero-title">Copy, paste, and customize high-performing prompts for modern AI tools and workflows.</h1>
     121<!-- /wp:heading -->
     122
     123<!-- wp:paragraph {"className":"nx-hero-description"} -->
     124<p class="nx-hero-description">Discover the ultimate AI prompt library. Copy, paste, and customize expert-tested ChatGPT, Midjourney, and Claude prompts to boost your productivity instantly.</p>
     125<!-- /wp:paragraph -->
     126
     127<!-- wp:buttons {"className":"nx-hero-actions"} -->
     128<div class="wp-block-buttons nx-hero-actions">
     129<!-- wp:button {"className":"nx-hero-btn"} -->
     130<div class="wp-block-button nx-hero-btn"><a class="wp-block-button__link wp-element-button" href="#primary">Explore Articles &rarr;</a></div>
     131<!-- /wp:button -->
     132</div>
     133<!-- /wp:buttons -->
     134</div></div>
     135<!-- /wp:group -->',
    101136        ));
    102137    }
    … …  
    132167
    133168/**
     169 * GDPR & Google AdSense Cookie Consent Manager
     170 */
     171require_once get_template_directory() . '/inc/cookie-consent.php';
     172
     173/**
    134174 * Set the content width in pixels, based on the theme's design and stylesheet.
    135175 */
    … …  
    202242    );
    203243
     244    wp_localize_script('nexversal-main', 'nexversal_ajax', array(
     245        'ajax_url' => admin_url('admin-ajax.php'),
     246        'nonce'    => wp_create_nonce('nexversal_newsletter_nonce'),
     247    ));
     248
    204249    if (is_singular() && comments_open() && get_option('thread_comments')) {
    205250        wp_enqueue_script('comment-reply');
    206251    }
    207252
    208     // Dynamic customizer accent color injection
    209     $accent = get_theme_mod('nexversal_accent_color', '#4f46e5');
    210     if ($accent && $accent !== '#4f46e5') {
    211         $custom_css = ":root { --nx-primary: {$accent}; --nx-primary-hover: {$accent}; }";
    212         wp_add_inline_style('nexversal-style', $custom_css);
    213     }
     253    // Dynamic customizer color injection for theme & all buttons
     254    $accent       = get_theme_mod('nexversal_accent_color', '#4f46e5');
     255    $btn_bg       = get_theme_mod('nexversal_btn_bg_color', '');
     256    $btn_text     = get_theme_mod('nexversal_btn_text_color', '#ffffff');
     257    $btn_hover_bg = get_theme_mod('nexversal_btn_hover_bg_color', '');
     258
     259    if (empty($btn_bg)) {
     260        $btn_bg = $accent ? $accent : '#4f46e5';
     261    }
     262    if (empty($btn_text)) {
     263        $btn_text = '#ffffff';
     264    }
     265    if (empty($btn_hover_bg)) {
     266        $btn_hover_bg = $btn_bg;
     267    }
     268
     269    $custom_css = "
     270        :root {
     271            --nx-primary: {$accent};
     272            --nx-primary-hover: {$accent};
     273            --nx-btn-bg: {$btn_bg};
     274            --nx-btn-text: {$btn_text};
     275            --nx-btn-hover: {$btn_hover_bg};
     276        }
     277        .nx-hero-btn,
     278        .nx-btn,
     279        .nx-btn-primary,
     280        .nx-card-cta,
     281        .nx-newsletter-btn,
     282        .nx-contact-submit,
     283        .wp-block-button__link,
     284        .wp-element-button,
     285        button[type=\"submit\"],
     286        input[type=\"submit\"],
     287        .comment-form .submit,
     288        #commentform #submit,
     289        .search-submit {
     290            background-color: var(--nx-btn-bg, {$btn_bg}) !important;
     291            color: var(--nx-btn-text, {$btn_text}) !important;
     292            border-color: var(--nx-btn-bg, {$btn_bg}) !important;
     293        }
     294        .nx-hero-btn:hover,
     295        .nx-btn:hover,
     296        .nx-btn-primary:hover,
     297        .nx-card-cta:hover,
     298        .nx-newsletter-btn:hover,
     299        .nx-contact-submit:hover,
     300        .wp-block-button__link:hover,
     301        .wp-element-button:hover,
     302        button[type=\"submit\"]:hover,
     303        input[type=\"submit\"]:hover,
     304        .comment-form .submit:hover,
     305        #commentform #submit:hover,
     306        .search-submit:hover {
     307            background-color: var(--nx-btn-hover, {$btn_hover_bg}) !important;
     308            border-color: var(--nx-btn-hover, {$btn_hover_bg}) !important;
     309        }
     310    ";
     311    wp_add_inline_style('nexversal-style', $custom_css);
    214312}
    215313add_action('wp_enqueue_scripts', 'nexversal_scripts');
    216314
    217315/**
     316 * Enqueue live preview scripts in WordPress Customizer.
     317 */
     318function nexversal_customize_preview_js() {
     319    wp_enqueue_script(
     320        'nexversal-customize-preview',
     321        get_template_directory_uri() . '/assets/js/customize-preview.js',
     322        array('customize-preview', 'jquery'),
     323        '2.8.0',
     324        true
     325    );
     326}
     327add_action('customize_preview_init', 'nexversal_customize_preview_js');
     328
     329/**
     330 * Render callback for hero button partial selective refresh.
     331 */
     332function nexversal_render_hero_button() {
     333    $hero_btn_text = get_theme_mod('nexversal_hero_btn_text', 'Explore Articles');
     334    $hero_btn_url  = get_theme_mod('nexversal_hero_btn_url', '#primary');
     335    if (!empty($hero_btn_text)) :
     336        ?>
     337        <div class="nx-hero-actions nx-hero-btn-wrap" style="margin-bottom: 22px;">
     338            <a href="<?php echo esc_url($hero_btn_url); ?>" class="nx-btn nx-btn-primary nx-hero-btn" data-nx-setting="nexversal_hero_btn_text">
     339                <span class="nx-hero-btn-label"><?php echo esc_html($hero_btn_text); ?></span>
     340                <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="margin-left: 6px;"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>
     341            </a>
     342        </div>
     343        <?php
     344    endif;
     345}
     346
     347/**
    218348 * Customizer options.
    219349 */
    220350function nexversal_customize_register($wp_customize) {
    221     // Styling Section
     351    // Remove default Background Image and Header Image sections
     352    $wp_customize->remove_section('background_image');
     353    $wp_customize->remove_section('header_image');
     354
     355    // Styling Section - Colors for theme and all buttons
    222356    $wp_customize->add_section('nexversal_styling', array(
    223         'title'    => esc_html__('Theme Styling & Colors', 'nexversal'),
    224         'priority' => 30,
    225     ));
    226 
     357        'title'       => esc_html__('Theme Styling & Colors', 'nexversal'),
     358        'priority'    => 30,
     359        'description' => esc_html__('Customize colors for the theme and all buttons across your entire website.', 'nexversal'),
     360    ));
     361
     362    // Accent / Primary Color
    227363    $wp_customize->add_setting('nexversal_accent_color', array(
    228364        'default'           => '#4f46e5',
    229365        'sanitize_callback' => 'sanitize_hex_color',
    230     ));
    231 
     366        'transport'         => 'postMessage',
     367    ));
    232368    $wp_customize->add_control(new WP_Customize_Color_Control($wp_customize, 'nexversal_accent_color', array(
    233         'label'    => esc_html__('Accent / Primary Color', 'nexversal'),
     369        'label'    => esc_html__('Theme Accent / Primary Color', 'nexversal'),
    234370        'section'  => 'nexversal_styling',
    235371        'settings' => 'nexversal_accent_color',
     372        'priority' => 10,
     373    )));
     374
     375    // Buttons Background Color
     376    $wp_customize->add_setting('nexversal_btn_bg_color', array(
     377        'default'           => '#4f46e5',
     378        'sanitize_callback' => 'sanitize_hex_color',
     379        'transport'         => 'postMessage',
     380    ));
     381    $wp_customize->add_control(new WP_Customize_Color_Control($wp_customize, 'nexversal_btn_bg_color', array(
     382        'label'       => esc_html__('All Buttons Background Color', 'nexversal'),
     383        'description' => esc_html__('Sets background color for hero CTA, cards, forms, blocks, and all site buttons.', 'nexversal'),
     384        'section'     => 'nexversal_styling',
     385        'settings'    => 'nexversal_btn_bg_color',
     386        'priority'    => 20,
     387    )));
     388
     389    // Buttons Text Color
     390    $wp_customize->add_setting('nexversal_btn_text_color', array(
     391        'default'           => '#ffffff',
     392        'sanitize_callback' => 'sanitize_hex_color',
     393        'transport'         => 'postMessage',
     394    ));
     395    $wp_customize->add_control(new WP_Customize_Color_Control($wp_customize, 'nexversal_btn_text_color', array(
     396        'label'       => esc_html__('All Buttons Text Color', 'nexversal'),
     397        'description' => esc_html__('Sets text and icon color inside all website buttons.', 'nexversal'),
     398        'section'     => 'nexversal_styling',
     399        'settings'    => 'nexversal_btn_text_color',
     400        'priority'    => 30,
     401    )));
     402
     403    // Buttons Hover Background Color
     404    $wp_customize->add_setting('nexversal_btn_hover_bg_color', array(
     405        'default'           => '#4338ca',
     406        'sanitize_callback' => 'sanitize_hex_color',
     407        'transport'         => 'postMessage',
     408    ));
     409    $wp_customize->add_control(new WP_Customize_Color_Control($wp_customize, 'nexversal_btn_hover_bg_color', array(
     410        'label'       => esc_html__('All Buttons Hover Background Color', 'nexversal'),
     411        'description' => esc_html__('Hover state background color for all website buttons.', 'nexversal'),
     412        'section'     => 'nexversal_styling',
     413        'settings'    => 'nexversal_btn_hover_bg_color',
     414        'priority'    => 40,
    236415    )));
    237416
    … …  
    254433
    255434    $wp_customize->add_setting('nexversal_hero_badge', array(
    256         'default'           => 'Tech & Trends 2026',
     435        'default'           => 'MASTER AI WITH POWERFUL & READY-TO-USE PROMPTS',
    257436        'sanitize_callback' => 'sanitize_text_field',
    258437    ));
    … …  
    265444
    266445    $wp_customize->add_setting('nexversal_hero_title', array(
    267         'default'           => 'Discover In-Depth Tech Reviews, Guides & Insights',
     446        'default'           => 'Copy, paste, and customize high-performing prompts for modern AI tools and workflows.',
    268447        'sanitize_callback' => 'sanitize_text_field',
    269448    ));
    … …  
    276455
    277456    $wp_customize->add_setting('nexversal_hero_desc', array(
    278         'default'           => 'Explore curated articles on software, AI tools, comparisons, and modern web development.',
     457        'default'           => 'Discover the ultimate AI prompt library. Copy, paste, and customize expert-tested ChatGPT, Midjourney, and Claude prompts to boost your productivity instantly.',
    279458        'sanitize_callback' => 'sanitize_textarea_field',
    280459    ));
    … …  
    289468        'default'           => 'Explore Articles',
    290469        'sanitize_callback' => 'sanitize_text_field',
     470        'transport'         => 'postMessage',
    291471    ));
    292472    $wp_customize->add_control('nexversal_hero_btn_text', array(
    293473        'label'       => esc_html__('Hero Button Text', 'nexversal'),
    294         'description' => esc_html__('Text for the primary CTA button in the hero banner. Leave empty to hide button.', 'nexversal'),
     474        'description' => esc_html__('Text for the primary CTA button in the hero banner. Click button in preview to edit.', 'nexversal'),
    295475        'section'     => 'nexversal_hero',
    296476        'type'        => 'text',
    … …  
    301481        'default'           => '#primary',
    302482        'sanitize_callback' => 'esc_url_raw',
     483        'transport'         => 'postMessage',
    303484    ));
    304485    $wp_customize->add_control('nexversal_hero_btn_url', array(
    … …  
    310491    ));
    311492
    312     // Custom Buttons & CTAs Section
    313     $wp_customize->add_section('nexversal_buttons', array(
    314         'title'       => esc_html__('Buttons & CTA Customization', 'nexversal'),
    315         'priority'    => 38,
    316         'description' => esc_html__('Customize the wording on buttons across cards, newsletters, and system pages.', 'nexversal'),
    317     ));
    318 
    319     $wp_customize->add_setting('nexversal_card_btn_text', array(
    320         'default'           => 'Read Article',
    321         'sanitize_callback' => 'sanitize_text_field',
    322     ));
    323     $wp_customize->add_control('nexversal_card_btn_text', array(
    324         'label'       => esc_html__('Post Card "Read More" Button Text', 'nexversal'),
    325         'description' => esc_html__('Text displayed on article cards in grids (e.g. Read Article, Continue Reading, Learn More). Leave empty to hide.', 'nexversal'),
    326         'section'     => 'nexversal_buttons',
    327         'type'        => 'text',
    328         'priority'    => 10,
    329     ));
    330 
    331     $wp_customize->add_setting('nexversal_newsletter_btn_text', array(
    332         'default'           => 'Subscribe',
    333         'sanitize_callback' => 'sanitize_text_field',
    334     ));
    335     $wp_customize->add_control('nexversal_newsletter_btn_text', array(
    336         'label'       => esc_html__('Newsletter Submit Button Text', 'nexversal'),
    337         'description' => esc_html__('Text on the subscription form button (e.g. Subscribe, Join Now, Get Updates).', 'nexversal'),
    338         'section'     => 'nexversal_buttons',
    339         'type'        => 'text',
    340         'priority'    => 20,
    341     ));
    342 
    343     $wp_customize->add_setting('nexversal_404_btn_text', array(
    344         'default'           => 'Back to Homepage',
    345         'sanitize_callback' => 'sanitize_text_field',
    346     ));
    347     $wp_customize->add_control('nexversal_404_btn_text', array(
    348         'label'       => esc_html__('404 Page Return Button Text', 'nexversal'),
    349         'description' => esc_html__('Text on the error page button returning visitors to home.', 'nexversal'),
    350         'section'     => 'nexversal_buttons',
    351         'type'        => 'text',
    352         'priority'    => 30,
    353     ));
     493    // Selective refresh for Hero Button (Shortcut pencil in preview)
     494    if (isset($wp_customize->selective_refresh)) {
     495        $wp_customize->selective_refresh->add_partial('nexversal_hero_btn_partial', array(
     496            'selector'            => '.nx-hero-btn-wrap',
     497            'settings'            => array('nexversal_hero_btn_text', 'nexversal_hero_btn_url'),
     498            'render_callback'     => 'nexversal_render_hero_button',
     499            'container_inclusive' => true,
     500        ));
     501    }
    354502
    355503    // Social Media Section
    … …  
    382530    }
    383531
     532    // Contact Page Settings Section
     533    $wp_customize->add_section('nexversal_contact', array(
     534        'title'       => esc_html__('Contact Page Settings', 'nexversal'),
     535        'priority'    => 42,
     536        'description' => esc_html__('Customize the contact information card, support email, headquarters location, and response times on your Contact page.', 'nexversal'),
     537    ));
     538
     539    // Enable/Disable Contact Info Card
     540    $wp_customize->add_setting('nexversal_show_contact_info', array(
     541        'default'           => true,
     542        'sanitize_callback' => 'nexversal_sanitize_checkbox',
     543    ));
     544    $wp_customize->add_control('nexversal_show_contact_info', array(
     545        'label'       => esc_html__('Show Contact Information Card', 'nexversal'),
     546        'description' => esc_html__('Display the contact details card alongside the message form.', 'nexversal'),
     547        'section'     => 'nexversal_contact',
     548        'type'        => 'checkbox',
     549    ));
     550
     551    // Contact Title
     552    $wp_customize->add_setting('nexversal_contact_title', array(
     553        'default'           => 'Contact Information',
     554        'sanitize_callback' => 'sanitize_text_field',
     555    ));
     556    $wp_customize->add_control('nexversal_contact_title', array(
     557        'label'   => esc_html__('Card Heading', 'nexversal'),
     558        'section' => 'nexversal_contact',
     559        'type'    => 'text',
     560    ));
     561
     562    // Contact Description
     563    $wp_customize->add_setting('nexversal_contact_desc', array(
     564        'default'           => 'We are dedicated to fast response times and transparent communication.',
     565        'sanitize_callback' => 'sanitize_textarea_field',
     566    ));
     567    $wp_customize->add_control('nexversal_contact_desc', array(
     568        'label'   => esc_html__('Card Description', 'nexversal'),
     569        'section' => 'nexversal_contact',
     570        'type'    => 'textarea',
     571    ));
     572
     573    // Support Email
     574    $wp_customize->add_setting('nexversal_contact_email', array(
     575        'default'           => get_option('admin_email', 'contact@nexversal.com'),
     576        'sanitize_callback' => 'sanitize_email',
     577    ));
     578    $wp_customize->add_control('nexversal_contact_email', array(
     579        'label'       => esc_html__('Support Email Address', 'nexversal'),
     580        'description' => esc_html__('The public email address visitors can write to.', 'nexversal'),
     581        'section'     => 'nexversal_contact',
     582        'type'        => 'email',
     583    ));
     584
     585    // Headquarters Text
     586    $wp_customize->add_setting('nexversal_contact_hq_text', array(
     587        'default'           => 'nexversal.com/contact',
     588        'sanitize_callback' => 'sanitize_text_field',
     589    ));
     590    $wp_customize->add_control('nexversal_contact_hq_text', array(
     591        'label'   => esc_html__('Official Headquarters Text / City', 'nexversal'),
     592        'section' => 'nexversal_contact',
     593        'type'    => 'text',
     594    ));
     595
     596    // Headquarters URL
     597    $wp_customize->add_setting('nexversal_contact_hq_url', array(
     598        'default'           => 'https://nexversal.com/contact',
     599        'sanitize_callback' => 'esc_url_raw',
     600    ));
     601    $wp_customize->add_control('nexversal_contact_hq_url', array(
     602        'label'   => esc_html__('Headquarters Link / Maps URL', 'nexversal'),
     603        'section' => 'nexversal_contact',
     604        'type'    => 'url',
     605    ));
     606
     607    // Custom Social Links (One URL per line)
     608    $wp_customize->add_setting('nexversal_custom_social_links', array(
     609        'default'           => "https://facebook.com/nexversal\nhttps://twitter.com/nexversal\nhttps://linkedin.com/company/nexversal\nhttps://github.com/nexversal\nhttps://youtube.com/@nexversal",
     610        'sanitize_callback' => 'sanitize_textarea_field',
     611    ));
     612    $wp_customize->add_control('nexversal_custom_social_links', array(
     613        'label'       => esc_html__('Social & Website Links (One URL per line)', 'nexversal'),
     614        'description' => esc_html__('Add your Facebook, X/Twitter, LinkedIn, Instagram, YouTube, GitHub, TikTok, Discord, Telegram, or personal website links. Logos are auto-detected!', 'nexversal'),
     615        'section'     => 'nexversal_contact',
     616        'type'        => 'textarea',
     617    ));
     618
     619    // Homepage Author Section (Image 3)
     620    $wp_customize->add_section('nexversal_homepage_author', array(
     621        'title'    => esc_html__('Homepage Author Box', 'nexversal'),
     622        'priority' => 38,
     623    ));
     624
     625    $wp_customize->add_setting('nexversal_author_name', array(
     626        'default'           => 'Muhammad Shahid',
     627        'sanitize_callback' => 'sanitize_text_field',
     628    ));
     629    $wp_customize->add_control('nexversal_author_name', array(
     630        'label'   => esc_html__('Author Name', 'nexversal'),
     631        'section' => 'nexversal_homepage_author',
     632        'type'    => 'text',
     633    ));
     634
     635    $wp_customize->add_setting('nexversal_author_role', array(
     636        'default'           => 'Founder & Editor',
     637        'sanitize_callback' => 'sanitize_text_field',
     638    ));
     639    $wp_customize->add_control('nexversal_author_role', array(
     640        'label'   => esc_html__('Author Role / Title', 'nexversal'),
     641        'section' => 'nexversal_homepage_author',
     642        'type'    => 'text',
     643    ));
     644
     645    $wp_customize->add_setting('nexversal_author_link', array(
     646        'default'           => home_url('/about/'),
     647        'sanitize_callback' => 'esc_url_raw',
     648    ));
     649    $wp_customize->add_control('nexversal_author_link', array(
     650        'label'       => esc_html__('Author Profile / Website Link (Clickable URL)', 'nexversal'),
     651        'description' => esc_html__('Enter the link destination when users click the author name, role, or avatar.', 'nexversal'),
     652        'section'     => 'nexversal_homepage_author',
     653        'type'        => 'url',
     654    ));
     655
     656    $wp_customize->add_setting('nexversal_author_avatar', array(
     657        'default'           => '',
     658        'sanitize_callback' => 'esc_url_raw',
     659    ));
     660    $wp_customize->add_control(new WP_Customize_Image_Control($wp_customize, 'nexversal_author_avatar', array(
     661        'label'       => esc_html__('Author Profile Photo / Avatar', 'nexversal'),
     662        'description' => esc_html__('Upload a profile picture. If left empty, the first initial of the author name will be displayed in the gradient circle.', 'nexversal'),
     663        'section'     => 'nexversal_homepage_author',
     664    )));
     665
     666    $wp_customize->add_setting('nexversal_author_bio', array(
     667        'default'           => 'Researches and writes every review and comparison on Nexversal.',
     668        'sanitize_callback' => 'sanitize_textarea_field',
     669    ));
     670    $wp_customize->add_control('nexversal_author_bio', array(
     671        'label'   => esc_html__('Author Bio', 'nexversal'),
     672        'section' => 'nexversal_homepage_author',
     673        'type'    => 'textarea',
     674    ));
     675
     676    // Homepage Newsletter Box Customization (Image 2 Design & Success State)
     677    $wp_customize->add_section('nexversal_newsletter', array(
     678        'title'    => esc_html__('Homepage Newsletter Box', 'nexversal'),
     679        'priority' => 39,
     680    ));
     681
     682    $wp_customize->add_setting('nexversal_newsletter_title', array(
     683        'default'           => 'New AI tool reviews,',
     684        'sanitize_callback' => 'sanitize_text_field',
     685    ));
     686    $wp_customize->add_control('nexversal_newsletter_title', array(
     687        'label'   => esc_html__('Title', 'nexversal'),
     688        'section' => 'nexversal_newsletter',
     689        'type'    => 'text',
     690    ));
     691
     692    $wp_customize->add_setting('nexversal_newsletter_highlight', array(
     693        'default'           => 'in your inbox.',
     694        'sanitize_callback' => 'sanitize_text_field',
     695    ));
     696    $wp_customize->add_control('nexversal_newsletter_highlight', array(
     697        'label'   => esc_html__('Title Highlight Text', 'nexversal'),
     698        'section' => 'nexversal_newsletter',
     699        'type'    => 'text',
     700    ));
     701
     702    $wp_customize->add_setting('nexversal_newsletter_desc', array(
     703        'default'           => 'Get new reviews and comparisons in your inbox. No spam, unsubscribe anytime.',
     704        'sanitize_callback' => 'sanitize_textarea_field',
     705    ));
     706    $wp_customize->add_control('nexversal_newsletter_desc', array(
     707        'label'   => esc_html__('Description', 'nexversal'),
     708        'section' => 'nexversal_newsletter',
     709        'type'    => 'textarea',
     710    ));
     711
     712    $wp_customize->add_setting('nexversal_newsletter_btn_text', array(
     713        'default'           => 'Subscribe',
     714        'sanitize_callback' => 'sanitize_text_field',
     715    ));
     716    $wp_customize->add_control('nexversal_newsletter_btn_text', array(
     717        'label'   => esc_html__('Button Text', 'nexversal'),
     718        'section' => 'nexversal_newsletter',
     719        'type'    => 'text',
     720    ));
     721
     722    $wp_customize->add_setting('nexversal_newsletter_success_title', array(
     723        'default'           => "You're in. ✨",
     724        'sanitize_callback' => 'sanitize_text_field',
     725    ));
     726    $wp_customize->add_control('nexversal_newsletter_success_title', array(
     727        'label'   => esc_html__('Subscribed / Logged-in Success Title', 'nexversal'),
     728        'section' => 'nexversal_newsletter',
     729        'type'    => 'text',
     730    ));
     731
     732    $wp_customize->add_setting('nexversal_newsletter_success_desc', array(
     733        'default'           => "We'll email you new reviews and comparisons as we publish them.",
     734        'sanitize_callback' => 'sanitize_textarea_field',
     735    ));
     736    $wp_customize->add_control('nexversal_newsletter_success_desc', array(
     737        'label'   => esc_html__('Subscribed / Logged-in Success Message', 'nexversal'),
     738        'section' => 'nexversal_newsletter',
     739        'type'    => 'textarea',
     740    ));
     741
    384742    // Footer Customization Section
    385743    $wp_customize->add_section('nexversal_footer', array(
    … …  
    448806    switch ($network) {
    449807        case 'twitter':
     808        case 'x':
    450809            return '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>';
    451810        case 'linkedin':
    … …  
    459818        case 'youtube':
    460819            return '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/></svg>';
     820        case 'tiktok':
     821            return '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12.525.02c1.31-.02 2.61-.01 3.91-.02.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.08-1.03-2.02-1.19-3.44-3.37-3.65-5.71-.02-.5-.03-1-.01-1.49.18-1.9 1.12-3.72 2.58-4.96 1.66-1.44 3.98-2.13 6.15-1.72.02 1.48-.04 2.96-.04 4.44-.99-.32-2.15-.23-3.02.37-.63.41-1.11 1.04-1.36 1.75-.21.51-.24 1.07-.14 1.61.24 1.16 1.18 2.09 2.35 2.29.97.16 1.98-.07 2.74-.69.64-.51 1.05-1.27 1.13-2.09.06-2.58.02-5.16.03-7.74.01-4.45-.02-8.9.02-13.35z"/></svg>';
     822        case 'discord':
     823            return '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994.021-.041.001-.09-.041-.106a13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.929 1.793 8.18 1.793 12.061 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.894.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.028zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/></svg>';
     824        case 'telegram':
     825            return '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4.64 6.8c-.15 1.58-.8 5.42-1.13 7.19-.14.75-.42 1-.68 1.03-.58.05-1.02-.38-1.58-.75-.88-.58-1.38-.94-2.23-1.5-.99-.65-.35-1.01.22-1.59.15-.15 2.71-2.48 2.76-2.69a.2.2 0 0 0-.05-.18c-.06-.05-.14-.03-.21-.02-.09.02-1.49.95-4.22 2.79-.4.27-.76.41-1.08.4-.36-.01-1.04-.2-1.55-.37-.63-.2-1.12-.31-1.08-.66.02-.18.27-.36.75-.55 2.92-1.27 4.86-2.11 5.83-2.51 2.78-1.16 3.35-1.36 3.73-1.36.08 0 .27.02.39.12.1.08.13.19.14.27-.01.06.01.24 0 .38z"/></svg>';
     826        case 'website':
     827            return '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>';
    461828        default:
    462             return '';
    463     }
     829            return '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>';
     830    }
     831}
     832
     833/**
     834 * Parse any list of custom URLs and auto-detect social networks with corresponding official logos.
     835 */
     836function nexversal_get_smart_social_links() {
     837    $raw_links = get_theme_mod('nexversal_custom_social_links', '');
     838    $urls = array();
     839
     840    if (!empty(trim($raw_links))) {
     841        $lines = preg_split('/[\r\n,]+/', $raw_links);
     842        foreach ($lines as $line) {
     843            $u = trim($line);
     844            if (!empty($u) && filter_var($u, FILTER_VALIDATE_URL)) {
     845                $urls[] = $u;
     846            }
     847        }
     848    } else {
     849        $platforms = array('facebook', 'twitter', 'linkedin', 'instagram', 'youtube', 'github');
     850        foreach ($platforms as $p) {
     851            $u = get_theme_mod('nexversal_social_' . $p, '');
     852            if (!empty($u)) {
     853                $urls[] = $u;
     854            }
     855        }
     856        if (empty($urls)) {
     857            $urls = array(
     858                'https://facebook.com/nexversal',
     859                'https://twitter.com/nexversal',
     860                'https://linkedin.com/company/nexversal',
     861                'https://github.com/nexversal',
     862                'https://youtube.com/@nexversal',
     863            );
     864        }
     865    }
     866
     867    $parsed = array();
     868    foreach ($urls as $url) {
     869        $host = strtolower(parse_url($url, PHP_URL_HOST) ?? '');
     870        $host = preg_replace('/^www\./', '', $host);
     871
     872        if (strpos($host, 'facebook.com') !== false || strpos($host, 'fb.com') !== false) {
     873            $parsed[] = array('platform' => 'facebook', 'title' => 'Facebook', 'url' => $url);
     874        } elseif (strpos($host, 'twitter.com') !== false || strpos($host, 'x.com') !== false) {
     875            $parsed[] = array('platform' => 'twitter', 'title' => 'X (Twitter)', 'url' => $url);
     876        } elseif (strpos($host, 'linkedin.com') !== false) {
     877            $parsed[] = array('platform' => 'linkedin', 'title' => 'LinkedIn', 'url' => $url);
     878        } elseif (strpos($host, 'instagram.com') !== false) {
     879            $parsed[] = array('platform' => 'instagram', 'title' => 'Instagram', 'url' => $url);
     880        } elseif (strpos($host, 'youtube.com') !== false || strpos($host, 'youtu.be') !== false) {
     881            $parsed[] = array('platform' => 'youtube', 'title' => 'YouTube', 'url' => $url);
     882        } elseif (strpos($host, 'github.com') !== false) {
     883            $parsed[] = array('platform' => 'github', 'title' => 'GitHub', 'url' => $url);
     884        } elseif (strpos($host, 'tiktok.com') !== false) {
     885            $parsed[] = array('platform' => 'tiktok', 'title' => 'TikTok', 'url' => $url);
     886        } elseif (strpos($host, 'discord.gg') !== false || strpos($host, 'discord.com') !== false) {
     887            $parsed[] = array('platform' => 'discord', 'title' => 'Discord', 'url' => $url);
     888        } elseif (strpos($host, 't.me') !== false || strpos($host, 'telegram.org') !== false) {
     889            $parsed[] = array('platform' => 'telegram', 'title' => 'Telegram', 'url' => $url);
     890        } else {
     891            $parsed[] = array('platform' => 'website', 'title' => !empty($host) ? $host : 'Website', 'url' => $url);
     892        }
     893    }
     894
     895    return $parsed;
    464896}
    465897
    … …  
    7121144add_action('admin_init', 'nexversal_add_privacy_policy_content');
    7131145
    714 
    715 
     1146/**
     1147 * Automatically configure default pages (Home, Blogs, About Us, Contact) and navigation menu.
     1148 */
     1149function nexversal_setup_default_content() {
     1150    // 1. Setup Home Page with Editable Hero Blocks & Newsletter Box
     1151    $home_content = '<!-- wp:group {"className":"nx-hero-section","layout":{"type":"constrained"}} -->
     1152<div class="wp-block-group nx-hero-section"><div class="container">
     1153<!-- wp:paragraph {"className":"nx-hero-badge"} -->
     1154<p class="nx-hero-badge">MASTER AI WITH POWERFUL &amp; READY-TO-USE PROMPTS</p>
     1155<!-- /wp:paragraph -->
     1156
     1157<!-- wp:heading {"level":1,"className":"nx-hero-title"} -->
     1158<h1 class="wp-block-heading nx-hero-title">Copy, paste, and customize high-performing prompts for modern AI tools and workflows.</h1>
     1159<!-- /wp:heading -->
     1160
     1161<!-- wp:paragraph {"className":"nx-hero-description"} -->
     1162<p class="nx-hero-description">Discover the ultimate AI prompt library. Copy, paste, and customize expert-tested ChatGPT, Midjourney, and Claude prompts to boost your productivity instantly.</p>
     1163<!-- /wp:paragraph -->
     1164
     1165<!-- wp:buttons {"className":"nx-hero-actions"} -->
     1166<div class="wp-block-buttons nx-hero-actions">
     1167<!-- wp:button {"className":"nx-hero-btn"} -->
     1168<div class="wp-block-button nx-hero-btn"><a class="wp-block-button__link wp-element-button" href="#primary">Explore Articles &rarr;</a></div>
     1169<!-- /wp:button -->
     1170</div>
     1171<!-- /wp:buttons -->
     1172</div></div>
     1173<!-- /wp:group -->
     1174
     1175<!-- wp:group {"className":"nx-newsletter-card","layout":{"type":"constrained"}} -->
     1176<div class="wp-block-group nx-newsletter-card">
     1177<div class="nx-newsletter-content">
     1178<!-- wp:paragraph {"className":"nx-newsletter-badge"} -->
     1179<p class="nx-newsletter-badge">✉ NEXVERSAL TECH DISPATCH</p>
     1180<!-- /wp:paragraph -->
     1181
     1182<!-- wp:heading {"level":3,"className":"nx-newsletter-title"} -->
     1183<h3 class="wp-block-heading nx-newsletter-title">Stay Ahead in Tech &amp; Modern Software</h3>
     1184<!-- /wp:heading -->
     1185
     1186<!-- wp:paragraph {"className":"nx-newsletter-desc"} -->
     1187<p class="nx-newsletter-desc">Join developers, engineers, and digital innovators getting our weekly deep-dives on AI tools, cloud architectures, and development strategies.</p>
     1188<!-- /wp:paragraph -->
     1189</div>
     1190
     1191<!-- wp:html -->
     1192<form class="nx-newsletter-form" onsubmit="event.preventDefault(); var btn=this.querySelector(\'button\'); btn.innerText=\'Subscribed!\'; btn.style.background=\'#10b981\'; this.querySelector(\'input\').disabled=true;">
     1193    <div class="nx-newsletter-input-group">
     1194        <input type="email" placeholder="Enter your work email..." required class="nx-newsletter-input" />
     1195        <button type="submit" class="nx-newsletter-btn">
     1196            <span>Subscribe &rarr;</span>
     1197        </button>
     1198    </div>
     1199    <p class="nx-newsletter-privacy">
     1200        🔒 No spam. Unsubscribe anytime with 1-click.
     1201    </p>
     1202</form>
     1203<!-- /wp:html -->
     1204</div>
     1205<!-- /wp:group -->';
     1206
     1207    $home = get_page_by_path('home');
     1208    if (!$home) {
     1209        $home_id = wp_insert_post(array(
     1210            'post_title'   => 'Home',
     1211            'post_name'    => 'home',
     1212            'post_status'  => 'publish',
     1213            'post_type'    => 'page',
     1214            'post_content' => $home_content,
     1215        ));
     1216    } else {
     1217        $home_id = $home->ID;
     1218        $current_content = $home->post_content;
     1219        if (empty(trim($current_content)) || strpos($current_content, 'Welcome to Nexversal') !== false || strpos($current_content, 'nx-newsletter-card') === false) {
     1220            wp_update_post(array(
     1221                'ID'           => $home_id,
     1222                'post_content' => $home_content,
     1223            ));
     1224        }
     1225    }
     1226    if ($home_id && !is_wp_error($home_id)) {
     1227        update_post_meta($home_id, '_wp_page_template', 'template-home.php');
     1228        update_option('show_on_front', 'page');
     1229        update_option('page_on_front', $home_id);
     1230    }
     1231
     1232    // 2. Setup Blogs Page with Editable Blocks
     1233    $blog_content = '<!-- wp:paragraph {"className":"nx-hero-badge"} -->
     1234<p class="nx-hero-badge">ARTICLES &amp; GUIDES</p>
     1235<!-- /wp:paragraph -->
     1236
     1237<!-- wp:heading {"level":1} -->
     1238<h1 class="wp-block-heading">Explore All Blogs &amp; Tech Insights</h1>
     1239<!-- /wp:heading -->
     1240
     1241<!-- wp:paragraph {"fontSize":"medium"} -->
     1242<p class="has-medium-font-size">Discover our complete collection of expert tutorials, software comparisons, AI guides, and modern engineering practices.</p>
     1243<!-- /wp:paragraph -->';
     1244
     1245    $blog = get_page_by_path('blog') ?: get_page_by_path('blogs');
     1246    if (!$blog) {
     1247        $blog_id = wp_insert_post(array(
     1248            'post_title'   => 'Blogs',
     1249            'post_name'    => 'blog',
     1250            'post_status'  => 'publish',
     1251            'post_type'    => 'page',
     1252            'post_content' => $blog_content,
     1253        ));
     1254    } else {
     1255        $blog_id = $blog->ID;
     1256        $current_content = $blog->post_content;
     1257        if (empty(trim($current_content)) || strpos($current_content, 'nx-hero-badge') === false) {
     1258            wp_update_post(array(
     1259                'ID'           => $blog_id,
     1260                'post_content' => $blog_content,
     1261            ));
     1262        }
     1263    }
     1264    if ($blog_id && !is_wp_error($blog_id)) {
     1265        update_post_meta($blog_id, '_wp_page_template', 'template-blog.php');
     1266        update_option('page_for_posts', $blog_id);
     1267    }
     1268
     1269    // 3. Setup About Us with Editable Blocks
     1270    $about_content = '<!-- wp:paragraph {"className":"nx-hero-badge"} -->
     1271<p class="nx-hero-badge">WHO WE ARE</p>
     1272<!-- /wp:paragraph -->
     1273
     1274<!-- wp:heading {"level":1} -->
     1275<h1 class="wp-block-heading">About Nexversal</h1>
     1276<!-- /wp:heading -->
     1277
     1278<!-- wp:paragraph {"fontSize":"medium"} -->
     1279<p class="has-medium-font-size">Empowering developers, creators, and modern businesses with actionable technology insights, high-speed software reviews, and engineering excellence.</p>
     1280<!-- /wp:paragraph -->
     1281
     1282<!-- wp:heading {"level":2} -->
     1283<h2 class="wp-block-heading">Our Mission &amp; Philosophy</h2>
     1284<!-- /wp:heading -->
     1285
     1286<!-- wp:paragraph -->
     1287<p>Nexversal was created with a clear objective: cut through the digital noise and deliver high-impact, transparent, and technically rigorous technology journalism. We explore modern artificial intelligence, high-performance web engineering, cloud infrastructure, and modern software tools.</p>
     1288<!-- /wp:paragraph -->
     1289
     1290<!-- wp:columns -->
     1291<div class="wp-block-columns">
     1292<!-- wp:column -->
     1293<div class="wp-block-column" style="padding:20px;background:var(--nx-bg);border-radius:10px;">
     1294<!-- wp:heading {"level":4} -->
     1295<h4 class="wp-block-heading">⚡ Speed &amp; Performance</h4>
     1296<!-- /wp:heading -->
     1297<!-- wp:paragraph -->
     1298<p>We prioritize lightweight architecture, zero bloated dependencies, and pristine Core Web Vitals.</p>
     1299<!-- /wp:paragraph -->
     1300</div>
     1301<!-- /wp:column -->
     1302
     1303<!-- wp:column -->
     1304<div class="wp-block-column" style="padding:20px;background:var(--nx-bg);border-radius:10px;">
     1305<!-- wp:heading {"level":4} -->
     1306<h4 class="wp-block-heading">👑 Independent Editorial</h4>
     1307<!-- /wp:heading -->
     1308<!-- wp:paragraph -->
     1309<p>Every software comparison, AI model evaluation, and tutorial is independently verified and fact-checked.</p>
     1310<!-- /wp:paragraph -->
     1311</div>
     1312<!-- /wp:column -->
     1313
     1314<!-- wp:column -->
     1315<div class="wp-block-column" style="padding:20px;background:var(--nx-bg);border-radius:10px;">
     1316<!-- wp:heading {"level":4} -->
     1317<h4 class="wp-block-heading">🛠️ Developer-Centric</h4>
     1318<!-- /wp:heading -->
     1319<!-- wp:paragraph -->
     1320<p>Built by engineers for engineers, offering real reproducible benchmarks and practical architectures.</p>
     1321<!-- /wp:paragraph -->
     1322</div>
     1323<!-- /wp:column -->
     1324</div>
     1325<!-- /wp:columns -->';
     1326
     1327    $about = get_page_by_path('about') ?: get_page_by_path('about-us');
     1328    if (!$about) {
     1329        $sample = get_page_by_path('sample-page');
     1330        if ($sample) {
     1331            wp_update_post(array(
     1332                'ID'           => $sample->ID,
     1333                'post_title'   => 'About Us',
     1334                'post_name'    => 'about',
     1335                'post_content' => $about_content,
     1336            ));
     1337            $about_id = $sample->ID;
     1338        } else {
     1339            $about_id = wp_insert_post(array(
     1340                'post_title'   => 'About Us',
     1341                'post_name'    => 'about',
     1342                'post_status'  => 'publish',
     1343                'post_type'    => 'page',
     1344                'post_content' => $about_content,
     1345            ));
     1346        }
     1347    } else {
     1348        $about_id = $about->ID;
     1349        $current_content = $about->post_content;
     1350        if (empty(trim($current_content)) || strpos($current_content, 'Welcome to Nexversal') !== false || strpos($current_content, 'nx-hero-badge') === false) {
     1351            wp_update_post(array(
     1352                'ID'           => $about_id,
     1353                'post_content' => $about_content,
     1354            ));
     1355        }
     1356    }
     1357    if ($about_id && !is_wp_error($about_id)) {
     1358        update_post_meta($about_id, '_wp_page_template', 'template-about.php');
     1359    }
     1360
     1361    // 4. Setup Contact Page (managed seamlessly via Appearance > Customize > Contact Page Settings)
     1362    $contact = get_page_by_path('contact') ?: get_page_by_path('contact-us');
     1363    if (!$contact) {
     1364        $contact_id = wp_insert_post(array(
     1365            'post_title'   => 'Contact Us',
     1366            'post_name'    => 'contact',
     1367            'post_status'  => 'publish',
     1368            'post_type'    => 'page',
     1369            'post_content' => '',
     1370        ));
     1371    } else {
     1372        $contact_id = $contact->ID;
     1373    }
     1374    if ($contact_id && !is_wp_error($contact_id)) {
     1375        update_post_meta($contact_id, '_wp_page_template', 'template-contact.php');
     1376    }
     1377
     1378    // 5. Setup Primary Nav Menu with all 4 pages
     1379    $menu_name = 'Main Menu';
     1380    $menu_obj  = wp_get_nav_menu_object($menu_name);
     1381    $menu_id   = $menu_obj ? $menu_obj->term_id : wp_create_nav_menu($menu_name);
     1382
     1383    if ($menu_id && !is_wp_error($menu_id)) {
     1384        $existing_items = wp_get_nav_menu_items($menu_id);
     1385        if (!empty($existing_items)) {
     1386            $seen_titles = array();
     1387            foreach ($existing_items as $item) {
     1388                $t = trim(strtolower($item->title));
     1389                if (isset($seen_titles[$t]) || $t === 'sample page' || strpos((string)$item->url, 'sample-page') !== false) {
     1390                    wp_delete_post($item->ID, true);
     1391                } else {
     1392                    $seen_titles[$t] = true;
     1393                }
     1394            }
     1395            $existing_items = wp_get_nav_menu_items($menu_id);
     1396        }
     1397
     1398        if (empty($existing_items)) {
     1399            if ($home_id) {
     1400                wp_update_nav_menu_item($menu_id, 0, array(
     1401                    'menu-item-title'     => 'Home',
     1402                    'menu-item-object'    => 'page',
     1403                    'menu-item-object-id' => $home_id,
     1404                    'menu-item-type'      => 'post_type',
     1405                    'menu-item-status'    => 'publish',
     1406                ));
     1407            }
     1408            if ($blog_id) {
     1409                wp_update_nav_menu_item($menu_id, 0, array(
     1410                    'menu-item-title'     => 'Blogs',
     1411                    'menu-item-object'    => 'page',
     1412                    'menu-item-object-id' => $blog_id,
     1413                    'menu-item-type'      => 'post_type',
     1414                    'menu-item-status'    => 'publish',
     1415                ));
     1416            }
     1417            if ($about_id) {
     1418                wp_update_nav_menu_item($menu_id, 0, array(
     1419                    'menu-item-title'     => 'About Us',
     1420                    'menu-item-object'    => 'page',
     1421                    'menu-item-object-id' => $about_id,
     1422                    'menu-item-type'      => 'post_type',
     1423                    'menu-item-status'    => 'publish',
     1424                ));
     1425            }
     1426            if ($contact_id) {
     1427                wp_update_nav_menu_item($menu_id, 0, array(
     1428                    'menu-item-title'     => 'Contact',
     1429                    'menu-item-object'    => 'page',
     1430                    'menu-item-object-id' => $contact_id,
     1431                    'menu-item-type'      => 'post_type',
     1432                    'menu-item-status'    => 'publish',
     1433                ));
     1434            }
     1435        }
     1436
     1437        $locations = get_theme_mod('nav_menu_locations');
     1438        if (!is_array($locations)) {
     1439            $locations = array();
     1440        }
     1441        if (empty($locations['primary'])) {
     1442            $locations['primary'] = $menu_id;
     1443            $locations['footer']  = $menu_id;
     1444            set_theme_mod('nav_menu_locations', $locations);
     1445        }
     1446    }
     1447}
     1448add_action('after_switch_theme', 'nexversal_setup_default_content');
     1449
     1450/**
     1451 * Run setup automatically once after update to ensure Home, Blogs, About, Contact pages exist in DB.
     1452 */
     1453function nexversal_auto_setup_pages_once() {
     1454    if (!get_option('nexversal_v330_blocks_synced')) {
     1455        nexversal_setup_default_content();
     1456        update_option('nexversal_v330_blocks_synced', 1);
     1457    }
     1458}
     1459add_action('admin_init', 'nexversal_auto_setup_pages_once');
     1460add_action('after_setup_theme', 'nexversal_auto_setup_pages_once');
     1461
     1462/**
     1463 * ==========================================================================
     1464 * URL Resolvers & Permalinks Resiliency (About, Blogs, Contact)
     1465 * ==========================================================================
     1466 */
     1467
     1468/**
     1469 * Resolve the dynamic, validated URL of the About page across all configurations.
     1470 *
     1471 * @return string
     1472 */
     1473function nexversal_get_about_page_url() {
     1474    static $resolved_url = null;
     1475    if ($resolved_url !== null) {
     1476        return $resolved_url;
     1477    }
     1478
     1479    // 1. Path lookup
     1480    $about = get_page_by_path('about');
     1481    if (!$about) {
     1482        $about = get_page_by_path('about-us');
     1483    }
     1484
     1485    // 2. Page template lookup
     1486    if (!$about) {
     1487        $pages = get_posts(array(
     1488            'post_type'        => 'page',
     1489            'post_status'      => 'publish',
     1490            'numberposts'      => 1,
     1491            'meta_key'         => '_wp_page_template',
     1492            'meta_value'       => 'template-about.php',
     1493            'suppress_filters' => true,
     1494        ));
     1495        if (!empty($pages)) {
     1496            $about = $pages[0];
     1497        }
     1498    }
     1499
     1500    // 3. Title lookup
     1501    if (!$about) {
     1502        $pages = get_posts(array(
     1503            'post_type'        => 'page',
     1504            'post_status'      => 'publish',
     1505            'numberposts'      => 1,
     1506            'title'            => 'About Us',
     1507            'suppress_filters' => true,
     1508        ));
     1509        if (empty($pages)) {
     1510            $pages = get_posts(array(
     1511                'post_type'        => 'page',
     1512                'post_status'      => 'publish',
     1513                'numberposts'      => 1,
     1514                'title'            => 'About',
     1515                'suppress_filters' => true,
     1516            ));
     1517        }
     1518        if (!empty($pages)) {
     1519            $about = $pages[0];
     1520        }
     1521    }
     1522
     1523    if ($about) {
     1524        $resolved_url = get_permalink($about->ID);
     1525        return $resolved_url;
     1526    }
     1527
     1528    $resolved_url = home_url('/about/');
     1529    return $resolved_url;
     1530}
     1531
     1532/**
     1533 * Resolve the dynamic, validated URL of the Blogs page across all configurations.
     1534 *
     1535 * @return string
     1536 */
     1537function nexversal_get_blogs_page_url() {
     1538    static $resolved_url = null;
     1539    if ($resolved_url !== null) {
     1540        return $resolved_url;
     1541    }
     1542
     1543    $page = get_page_by_path('blog') ?: get_page_by_path('blogs');
     1544    if (!$page) {
     1545        $pages = get_posts(array(
     1546            'post_type'        => 'page',
     1547            'post_status'      => 'publish',
     1548            'numberposts'      => 1,
     1549            'meta_key'         => '_wp_page_template',
     1550            'meta_value'       => array('template-blog.php', 'template-blogs.php'),
     1551            'suppress_filters' => true,
     1552        ));
     1553        if (!empty($pages)) {
     1554            $page = $pages[0];
     1555        }
     1556    }
     1557
     1558    if ($page) {
     1559        $resolved_url = get_permalink($page->ID);
     1560        return $resolved_url;
     1561    }
     1562
     1563    $page_for_posts = get_option('page_for_posts');
     1564    if ($page_for_posts) {
     1565        $resolved_url = get_permalink($page_for_posts);
     1566        return $resolved_url;
     1567    }
     1568
     1569    $resolved_url = home_url('/blog/');
     1570    return $resolved_url;
     1571}
     1572
     1573/**
     1574 * Resolve the dynamic, validated URL of the Contact page across all configurations.
     1575 *
     1576 * @return string
     1577 */
     1578function nexversal_get_contact_page_url() {
     1579    static $resolved_url = null;
     1580    if ($resolved_url !== null) {
     1581        return $resolved_url;
     1582    }
     1583
     1584    $contact = get_page_by_path('contact') ?: get_page_by_path('contact-us');
     1585    if (!$contact) {
     1586        $pages = get_posts(array(
     1587            'post_type'        => 'page',
     1588            'post_status'      => 'publish',
     1589            'numberposts'      => 1,
     1590            'meta_key'         => '_wp_page_template',
     1591            'meta_value'       => 'template-contact.php',
     1592            'suppress_filters' => true,
     1593        ));
     1594        if (!empty($pages)) {
     1595            $contact = $pages[0];
     1596        }
     1597    }
     1598
     1599    if ($contact) {
     1600        $resolved_url = get_permalink($contact->ID);
     1601        return $resolved_url;
     1602    }
     1603
     1604    $resolved_url = home_url('/contact/');
     1605    return $resolved_url;
     1606}
     1607
     1608/**
     1609 * Filter nav menu objects to replace any leftover "Sample Page", broken "?page_id=2" links,
     1610 * and deduplicate menu items.
     1611 */
     1612function nexversal_filter_and_deduplicate_nav_menu($items) {
     1613    if (!is_array($items)) {
     1614        return $items;
     1615    }
     1616    $seen = array();
     1617    $clean_items = array();
     1618
     1619    foreach ($items as $item) {
     1620        if (!is_object($item) || !isset($item->title)) {
     1621            continue;
     1622        }
     1623
     1624        $title_raw = trim(strtolower($item->title));
     1625        $item_url  = isset($item->url) ? (string)$item->url : '';
     1626
     1627        // Clean up sample page or broken About link (including ?page_id=2)
     1628        if ($title_raw === 'sample page' || strpos($item_url, 'sample-page') !== false || strpos($item_url, 'page_id=2') !== false || $title_raw === 'about' || $title_raw === 'about us') {
     1629            $item->title = esc_html__('About Us', 'nexversal');
     1630            $item->url   = nexversal_get_about_page_url();
     1631        }
     1632
     1633        // Clean up Blogs link if pointing to invalid URL or plain page_id
     1634        if ($title_raw === 'blogs' || $title_raw === 'blog') {
     1635            $item->title = esc_html__('Blogs', 'nexversal');
     1636            $item->url   = nexversal_get_blogs_page_url();
     1637        }
     1638
     1639        // Clean up Contact link
     1640        if ($title_raw === 'contact' || $title_raw === 'contact us') {
     1641            $item->title = esc_html__('Contact', 'nexversal');
     1642            $item->url   = nexversal_get_contact_page_url();
     1643        }
     1644
     1645        // Clean up Home link
     1646        if ($title_raw === 'home') {
     1647            $item->title = esc_html__('Home', 'nexversal');
     1648            $item->url   = home_url('/');
     1649        }
     1650
     1651        // Deduplicate key by lowercased title
     1652        $title_key = trim(strtolower($item->title));
     1653        if (isset($seen[$title_key])) {
     1654            continue;
     1655        }
     1656
     1657        $seen[$title_key] = true;
     1658        $clean_items[] = $item;
     1659    }
     1660
     1661    return $clean_items;
     1662}
     1663add_filter('wp_nav_menu_objects', 'nexversal_filter_and_deduplicate_nav_menu', 20);
     1664
     1665/**
     1666 * Redirect legacy URLs, dead sample pages, ?page_id=2, and GSC 404s gracefully (301 Permanent Redirect)
     1667 */
     1668function nexversal_redirect_legacy_and_about_urls() {
     1669    $requested_page_id = isset($_GET['page_id']) ? (int) $_GET['page_id'] : 0;
     1670    $req_uri           = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
     1671
     1672    // 1. Direct interception for ?page_id=2 (old sample page default in WordPress)
     1673    if ($requested_page_id === 2 || strpos($req_uri, 'page_id=2') !== false || strpos($req_uri, 'sample-page') !== false) {
     1674        $about_url = nexversal_get_about_page_url();
     1675        wp_safe_redirect($about_url, 301);
     1676        exit;
     1677    }
     1678
     1679    $clean_path = parse_url($req_uri, PHP_URL_PATH);
     1680    $clean_path = $clean_path ? rtrim($clean_path, '/') : '';
     1681
     1682    // Direct alias for /blogs to canonical /blog/
     1683    if ($clean_path === '/blogs') {
     1684        wp_safe_redirect(nexversal_get_blogs_page_url(), 301);
     1685        exit;
     1686    }
     1687
     1688    // 2. Intercept 404s and map to 301 destinations from Persistent Master Record
     1689    if (is_404() || !empty($clean_path)) {
     1690        $blog_url = nexversal_get_blogs_page_url();
     1691        $redirects = array(
     1692            '/aboutAbout'                                              => nexversal_get_about_page_url(),
     1693            '/contactContact'                                          => nexversal_get_contact_page_url(),
     1694            '/Home'                                                    => home_url('/'),
     1695            '/category/comparisonsComparisons'                         => home_url('/category/comparisons/'),
     1696            '/sample-page'                                             => nexversal_get_about_page_url(),
     1697            '/blogs'                                                   => $blog_url,
     1698            '/kepler-vs-github-copilot'                                => home_url('/blog/kepler-ai-coding'),
     1699            '/gitkraken-kepler'                                        => home_url('/blog/setup-gitkraken-kepler'),
     1700            '/seo-in-the-age-of-answer-engines'                        => home_url('/blog/best-ai-seo-tools'),
     1701            '/search-marketing-course'                                 => home_url('/blog/best-ai-seo-tools'),
     1702            '/category/artificial-intelligence'                        => home_url('/blog'),
     1703            '/future-of-artificial-intelligence-2026'                  => home_url('/blog'),
     1704            '/the-self-taught-engineers-curriculum'                     => home_url('/blog/best-free-ai-tools-for-coding-2026'),
     1705            '/the-anatomy-of-a-supply-chain-attack'                    => home_url('/blog'),
     1706            '/the-quiet-revolution-of-agentic-llms'                    => home_url('/blog/chatgpt-vs-claude-vs-gemini-which-should-you-use'),
     1707            '/designing-with-restraint'                                => home_url('/blog'),
     1708            '/best-ai-video-generators-for-creators-in-2026'          => home_url('/blog/ai-tools-for-a-video-generator'),
     1709            '/category/education'                                      => home_url('/blog/best-ai-tools-for-students'),
     1710            '/why-pricing-is-strategy-not-a-number'                    => home_url('/blog/ai-tools-for-small-business'),
     1711            '/how-to-learn-seo-at-home-for-free-complete-2026-roadmap' => home_url('/blog/best-ai-seo-tools'),
     1712            '/key-takeaways-for-mastering-rankings'                    => home_url('/blog/best-ai-seo-tools'),
     1713            '/the-best-chatgpt-alternatives-worth-trying'              => home_url('/blog/chatgpt-alternatives'),
     1714            '/best-ai-tools-for-text-to-video-generators'              => home_url('/blog/ai-tools-for-a-video-generator'),
     1715            '/ai-tools-for-text-to-video-generators'                   => home_url('/blog/ai-tools-for-a-video-generator'),
     1716        );
     1717
     1718        if (isset($redirects[$clean_path])) {
     1719            wp_safe_redirect($redirects[$clean_path], 301);
     1720            exit;
     1721        }
     1722
     1723        // If request query or URL contains page_id=2 or sample-page
     1724        if (strpos($req_uri, 'page_id=2') !== false || strpos($req_uri, 'sample-page') !== false) {
     1725            wp_safe_redirect(nexversal_get_about_page_url(), 301);
     1726            exit;
     1727        }
     1728    }
     1729}
     1730add_action('template_redirect', 'nexversal_redirect_legacy_and_about_urls', 1);
     1731
     1732/**
     1733 * Auto-heal legacy menu items in database that point to ?page_id=2 or deleted sample-page
     1734 */
     1735function nexversal_heal_legacy_menu_and_pages() {
     1736    if (get_option('nexversal_v351_about_healed')) {
     1737        return;
     1738    }
     1739
     1740    $about = get_page_by_path('about') ?: get_page_by_path('about-us');
     1741    $about_id = $about ? $about->ID : 0;
     1742
     1743    $all_menu_items = get_posts(array(
     1744        'post_type'        => 'nav_menu_item',
     1745        'numberposts'      => -1,
     1746        'post_status'      => 'any',
     1747        'suppress_filters' => true,
     1748    ));
     1749
     1750    if (!empty($all_menu_items)) {
     1751        foreach ($all_menu_items as $mi) {
     1752            $url    = (string) get_post_meta($mi->ID, '_menu_item_url', true);
     1753            $obj_id = (int) get_post_meta($mi->ID, '_menu_item_object_id', true);
     1754            $title  = strtolower(trim($mi->post_title));
     1755
     1756            if ($obj_id === 2 || strpos($url, 'page_id=2') !== false || strpos($url, 'sample-page') !== false || $title === 'sample page' || ($about_id && ($title === 'about' || $title === 'about us') && $obj_id !== $about_id && empty($url))) {
     1757                if ($about_id) {
     1758                    update_post_meta($mi->ID, '_menu_item_object_id', $about_id);
     1759                    update_post_meta($mi->ID, '_menu_item_type', 'post_type');
     1760                    update_post_meta($mi->ID, '_menu_item_object', 'page');
     1761                    update_post_meta($mi->ID, '_menu_item_url', '');
     1762                } else {
     1763                    update_post_meta($mi->ID, '_menu_item_url', home_url('/about/'));
     1764                }
     1765            }
     1766        }
     1767    }
     1768
     1769    update_option('nexversal_v351_about_healed', 1);
     1770}
     1771add_action('init', 'nexversal_heal_legacy_menu_and_pages');
     1772
     1773/**
     1774 * ==========================================================================
     1775 * Newsletter Subscribers System (Storage, AJAX, Export & Admin View)
     1776 * ==========================================================================
     1777 */
     1778
     1779/**
     1780 * Handle AJAX newsletter subscription requests securely.
     1781 */
     1782function nexversal_handle_newsletter_subscription() {
     1783    if (!check_ajax_referer('nexversal_newsletter_nonce', 'nonce', false)) {
     1784        wp_send_json_error(array('message' => esc_html__('Security verification failed. Please refresh the page.', 'nexversal')));
     1785    }
     1786
     1787    $email = isset($_POST['email']) ? sanitize_email(wp_unslash($_POST['email'])) : '';
     1788
     1789    if (empty($email)) {
     1790        wp_send_json_error(array('message' => esc_html__('Please enter your email address.', 'nexversal')));
     1791    }
     1792
     1793    if (!is_email($email)) {
     1794        wp_send_json_error(array('message' => esc_html__('Please enter a valid email address format.', 'nexversal')));
     1795    }
     1796
     1797    $subscribers = get_option('nexversal_subscribers', array());
     1798    if (!is_array($subscribers)) {
     1799        $subscribers = array();
     1800    }
     1801
     1802    // Check if already subscribed
     1803    foreach ($subscribers as $sub) {
     1804        if (isset($sub['email']) && strtolower($sub['email']) === strtolower($email)) {
     1805            wp_send_json_success(array('message' => esc_html__('Already Subscribed! Thank you.', 'nexversal')));
     1806        }
     1807    }
     1808
     1809    // Append new subscriber with timestamp
     1810    $subscribers[] = array(
     1811        'email' => strtolower($email),
     1812        'date'  => current_time('mysql'),
     1813        'ip'    => sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'] ?? '')),
     1814    );
     1815
     1816    update_option('nexversal_subscribers', $subscribers);
     1817
     1818    wp_send_json_success(array('message' => esc_html__('Subscribed successfully! Thank you.', 'nexversal')));
     1819}
     1820add_action('wp_ajax_nexversal_subscribe', 'nexversal_handle_newsletter_subscription');
     1821add_action('wp_ajax_nopriv_nexversal_subscribe', 'nexversal_handle_newsletter_subscription');
     1822
     1823/**
     1824 * Filter the_content to guarantee the email input field and form wrapper are present in newsletter cards.
     1825 */
     1826function nexversal_ensure_newsletter_form_input($content) {
     1827    if (strpos($content, 'nx-newsletter-card') !== false) {
     1828        // If button exists but email input is missing, inject the email input field
     1829        if (strpos($content, '<input') === false && strpos($content, 'nx-newsletter-btn') !== false) {
     1830            $input_field = '<input type="email" name="nx_email" placeholder="' . esc_attr__('Enter your work email...', 'nexversal') . '" required class="nx-newsletter-input" autocomplete="email" />';
     1831            $content = preg_replace('/(<button[^>]*class=["\'][^"\']*nx-newsletter-btn[^"\']*["\'][^>]*>)/i', $input_field . "\n" . '$1', $content, 1);
     1832        }
     1833        // If form wrapper is missing, wrap the input group and privacy text in <form class="nx-newsletter-form">
     1834        if (strpos($content, '<form') === false && strpos($content, 'nx-newsletter-btn') !== false) {
     1835            $content = preg_replace('/(<div[^>]*class=["\'][^"\']*nx-newsletter-input-group[^"\']*["\'][^>]*>)/i', '<form class="nx-newsletter-form">$1', $content, 1);
     1836            $content = preg_replace('/(<\/div>\s*<p[^>]*class=["\'][^"\']*nx-newsletter-privacy[^"\']*["\'][^>]*>.*?<\/p>)/is', '$1</form>', $content, 1);
     1837        }
     1838    }
     1839    return $content;
     1840}
     1841add_filter('the_content', 'nexversal_ensure_newsletter_form_input', 12);
     1842
     1843/**
     1844 * Register Appearance > Subscribers page in WP-Admin.
     1845 */
     1846function nexversal_register_subscribers_admin_menu() {
     1847    add_theme_page(
     1848        esc_html__('Newsletter Subscribers', 'nexversal'),
     1849        esc_html__('Subscribers', 'nexversal'),
     1850        'manage_options',
     1851        'nexversal-subscribers',
     1852        'nexversal_render_subscribers_admin_page'
     1853    );
     1854}
     1855add_action('admin_menu', 'nexversal_register_subscribers_admin_menu');
     1856
     1857/**
     1858 * Render the Subscribers page in WP-Admin with stats, list, delete, and CSV export.
     1859 */
     1860function nexversal_render_subscribers_admin_page() {
     1861    if (!current_user_can('manage_options')) {
     1862        return;
     1863    }
     1864
     1865    $subscribers = get_option('nexversal_subscribers', array());
     1866    if (!is_array($subscribers)) {
     1867        $subscribers = array();
     1868    }
     1869
     1870    // Handle CSV Export
     1871    if (isset($_GET['action']) && 'export_csv' === $_GET['action'] && isset($_GET['_wpnonce']) && wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'])), 'nexversal_export_csv')) {
     1872        if (!headers_sent()) {
     1873            header('Content-Type: text/csv; charset=utf-8');
     1874            header('Content-Disposition: attachment; filename=nexversal-subscribers-' . gmdate('Y-m-d') . '.csv');
     1875            echo "Index,Email,Subscription Date,IP Address\r\n";
     1876            $idx = 1;
     1877            foreach ($subscribers as $sub) {
     1878                $email = isset($sub['email']) ? str_replace('"', '""', $sub['email']) : '';
     1879                $date  = isset($sub['date']) ? str_replace('"', '""', $sub['date']) : '';
     1880                $ip    = isset($sub['ip']) ? str_replace('"', '""', $sub['ip']) : '';
     1881                echo '"' . intval($idx++) . '","' . esc_attr($email) . '","' . esc_attr($date) . '","' . esc_attr($ip) . "\"\r\n";
     1882            }
     1883            exit;
     1884        }
     1885    }
     1886
     1887    // Handle Single Delete Action
     1888    $notice = '';
     1889    if (isset($_GET['action']) && 'delete' === $_GET['action'] && isset($_GET['email']) && isset($_GET['_wpnonce'])) {
     1890        $del_email = sanitize_email(wp_unslash($_GET['email']));
     1891        if (wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'])), 'nexversal_delete_' . $del_email)) {
     1892            $updated = array();
     1893            foreach ($subscribers as $s) {
     1894                if (isset($s['email']) && strtolower($s['email']) !== strtolower($del_email)) {
     1895                    $updated[] = $s;
     1896                }
     1897            }
     1898            $subscribers = $updated;
     1899            update_option('nexversal_subscribers', $subscribers);
     1900            $notice = '<div class="notice notice-success is-dismissible"><p>' . esc_html__('Subscriber removed successfully.', 'nexversal') . '</p></div>';
     1901        }
     1902    }
     1903
     1904    $total_count = count($subscribers);
     1905    $export_url  = wp_nonce_url(admin_url('themes.php?page=nexversal-subscribers&action=export_csv'), 'nexversal_export_csv');
     1906    ?>
     1907    <div class="wrap" style="max-width: 1000px; margin-top: 20px;">
     1908        <h1 style="display: flex; align-items: center; gap: 10px; font-weight: 700;">
     1909            <span class="dashicons dashicons-email-alt" style="font-size: 32px; width: 32px; height: 32px; color: #4f46e5;"></span>
     1910            <?php esc_html_e('Newsletter Subscribers', 'nexversal'); ?>
     1911        </h1>
     1912        <p style="color: #64748b; font-size: 14px;">
     1913            <?php esc_html_e('Manage email leads captured from the Nexversal Newsletter Dispatch boxes across your website.', 'nexversal'); ?>
     1914        </p>
     1915
     1916        <?php echo $notice; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
     1917
     1918        <div style="background: #ffffff; border: 1px solid #e2e8f0; border-radius: 8px; padding: 20px 24px; margin-bottom: 24px; display: flex; align-items: center; justify-content: space-between; box-shadow: 0 1px 3px rgba(0,0,0,0.05);">
     1919            <div>
     1920                <span style="font-size: 13px; font-weight: 600; text-transform: uppercase; color: #64748b; letter-spacing: 0.05em;"><?php esc_html_e('Total Subscribers', 'nexversal'); ?></span>
     1921                <div style="font-size: 32px; font-weight: 800; color: #0f172a; margin-top: 2px;">
     1922                    <?php echo esc_html($total_count); ?>
     1923                </div>
     1924            </div>
     1925            <?php if ($total_count > 0) : ?>
     1926                <div>
     1927                    <a href="<?php echo esc_url($export_url); ?>" class="button button-primary" style="background: #4f46e5; border-color: #4f46e5; padding: 6px 16px; font-weight: 600;">
     1928                        <span class="dashicons dashicons-download" style="vertical-align: middle; margin-top: -2px;"></span>
     1929                        <?php esc_html_e('Download CSV List', 'nexversal'); ?>
     1930                    </a>
     1931                </div>
     1932            <?php endif; ?>
     1933        </div>
     1934
     1935        <?php if ($total_count > 0) : ?>
     1936            <table class="wp-list-table widefat fixed striped posts" style="border-radius: 8px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.05);">
     1937                <thead>
     1938                    <tr>
     1939                        <th style="width: 60px;">#</th>
     1940                        <th><?php esc_html_e('Subscriber Email', 'nexversal'); ?></th>
     1941                        <th style="width: 220px;"><?php esc_html_e('Date & Time (UTC/Site)', 'nexversal'); ?></th>
     1942                        <th style="width: 100px; text-align: center;"><?php esc_html_e('Action', 'nexversal'); ?></th>
     1943                    </tr>
     1944                </thead>
     1945                <tbody>
     1946                    <?php
     1947                    $i = 1;
     1948                    $reversed = array_reverse($subscribers);
     1949                    foreach ($reversed as $sub) :
     1950                        $sub_email = $sub['email'] ?? '';
     1951                        $sub_date  = $sub['date'] ?? '';
     1952                        $del_url   = wp_nonce_url(
     1953                            admin_url('themes.php?page=nexversal-subscribers&action=delete&email=' . urlencode($sub_email)),
     1954                            'nexversal_delete_' . $sub_email
     1955                        );
     1956                        ?>
     1957                        <tr>
     1958                            <td><?php echo esc_html($i++); ?></td>
     1959                            <td>
     1960                                <strong><a href="mailto:<?php echo esc_attr($sub_email); ?>" style="color: #4f46e5; text-decoration: none;"><?php echo esc_html($sub_email); ?></a></strong>
     1961                            </td>
     1962                            <td><?php echo esc_html($sub_date); ?></td>
     1963                            <td style="text-align: center;">
     1964                                <a href="<?php echo esc_url($del_url); ?>" onclick="return confirm('<?php echo esc_js(__('Are you sure you want to delete this subscriber?', 'nexversal')); ?>');" style="color: #ef4444; text-decoration: none; font-size: 13px;">
     1965                                    <?php esc_html_e('Delete', 'nexversal'); ?>
     1966                                </a>
     1967                            </td>
     1968                        </tr>
     1969                    <?php endforeach; ?>
     1970                </tbody>
     1971            </table>
     1972        <?php else : ?>
     1973            <div style="background: #ffffff; border: 1px dashed #cbd5e1; border-radius: 8px; padding: 48px 24px; text-align: center; color: #64748b;">
     1974                <span class="dashicons dashicons-email" style="font-size: 48px; width: 48px; height: 48px; color: #94a3b8; margin-bottom: 12px;"></span>
     1975                <h3 style="color: #334155; margin: 0 0 8px 0; font-weight: 700;"><?php esc_html_e('No Subscribers Yet', 'nexversal'); ?></h3>
     1976                <p style="margin: 0; font-size: 14px; max-width: 480px; margin: 0 auto;">
     1977                    <?php esc_html_e('When visitors enter their email into the newsletter dispatch box on your homepage, their emails and subscription dates will appear here.', 'nexversal'); ?>
     1978                </p>
     1979            </div>
     1980        <?php endif; ?>
     1981    </div>
     1982    <?php
     1983}
     1984
     1985/**
     1986 * ==========================================================================
     1987 * Contact Page Settings (Dedicated WP-Admin Screen under Appearance)
     1988 * ==========================================================================
     1989 */
     1990
     1991/**
     1992 * Register Appearance > Contact Settings page in WP-Admin.
     1993 */
     1994function nexversal_register_contact_admin_menu() {
     1995    add_theme_page(
     1996        esc_html__('Contact Page Settings', 'nexversal'),
     1997        esc_html__('Contact Settings', 'nexversal'),
     1998        'manage_options',
     1999        'nexversal-contact',
     2000        'nexversal_render_contact_admin_page'
     2001    );
     2002}
     2003add_action('admin_menu', 'nexversal_register_contact_admin_menu');
     2004
     2005/**
     2006 * Render the Appearance > Contact Settings admin page.
     2007 */
     2008function nexversal_render_contact_admin_page() {
     2009    if (!current_user_can('manage_options')) {
     2010        return;
     2011    }
     2012
     2013    $notice = '';
     2014
     2015    // Handle Form Submission
     2016    if (isset($_POST['nexversal_save_contact']) && check_admin_referer('nexversal_save_contact_action', 'nexversal_contact_nonce')) {
     2017        $show_info   = !empty($_POST['nexversal_show_contact_info']);
     2018        $info_title  = sanitize_text_field(wp_unslash($_POST['nexversal_contact_title'] ?? ''));
     2019        $info_desc   = sanitize_textarea_field(wp_unslash($_POST['nexversal_contact_desc'] ?? ''));
     2020        $info_email  = sanitize_email(wp_unslash($_POST['nexversal_contact_email'] ?? ''));
     2021        $hq_text     = sanitize_text_field(wp_unslash($_POST['nexversal_contact_hq_text'] ?? ''));
     2022        $hq_url      = esc_url_raw(wp_unslash($_POST['nexversal_contact_hq_url'] ?? ''));
     2023        $soc_links   = sanitize_textarea_field(wp_unslash($_POST['nexversal_custom_social_links'] ?? ''));
     2024
     2025        set_theme_mod('nexversal_show_contact_info', $show_info);
     2026        set_theme_mod('nexversal_contact_title', $info_title);
     2027        set_theme_mod('nexversal_contact_desc', $info_desc);
     2028        set_theme_mod('nexversal_contact_email', $info_email);
     2029        set_theme_mod('nexversal_contact_hq_text', $hq_text);
     2030        set_theme_mod('nexversal_contact_hq_url', $hq_url);
     2031        set_theme_mod('nexversal_custom_social_links', $soc_links);
     2032
     2033        $notice = '<div class="notice notice-success is-dismissible"><p><strong>' . esc_html__('Contact page settings saved successfully!', 'nexversal') . '</strong></p></div>';
     2034    }
     2035
     2036    // Retrieve active values
     2037    $show_info   = get_theme_mod('nexversal_show_contact_info', true);
     2038    $info_title  = get_theme_mod('nexversal_contact_title', __('Contact Information', 'nexversal'));
     2039    $info_desc   = get_theme_mod('nexversal_contact_desc', __('We are dedicated to fast response times and transparent communication.', 'nexversal'));
     2040    $info_email  = get_theme_mod('nexversal_contact_email', get_option('admin_email', 'contact@nexversal.com'));
     2041    $hq_text     = get_theme_mod('nexversal_contact_hq_text', 'nexversal.com/contact');
     2042    $hq_url      = get_theme_mod('nexversal_contact_hq_url', home_url('/contact/'));
     2043    $soc_links   = get_theme_mod('nexversal_custom_social_links', "https://facebook.com/nexversal\nhttps://twitter.com/nexversal\nhttps://linkedin.com/company/nexversal\nhttps://github.com/nexversal\nhttps://youtube.com/@nexversal");
     2044    $customizer_url = admin_url('customize.php?autofocus[section]=nexversal_contact');
     2045    $contact_url    = home_url('/contact/');
     2046    ?>
     2047    <div class="wrap" style="max-width: 900px; margin-top: 20px;">
     2048        <div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; margin-bottom: 16px;">
     2049            <h1 style="display: flex; align-items: center; gap: 10px; font-weight: 700; margin: 0;">
     2050                <span class="dashicons dashicons-location-alt" style="font-size: 30px; width: 30px; height: 30px; color: #4f46e5;"></span>
     2051                <?php esc_html_e('Contact Page Settings', 'nexversal'); ?>
     2052            </h1>
     2053            <div style="display: flex; gap: 8px;">
     2054                <a href="<?php echo esc_url($contact_url); ?>" target="_blank" class="button">
     2055                    <span class="dashicons dashicons-external" style="vertical-align: middle; margin-top: -2px;"></span>
     2056                    <?php esc_html_e('View Contact Page', 'nexversal'); ?>
     2057                </a>
     2058                <a href="<?php echo esc_url($customizer_url); ?>" class="button button-secondary">
     2059                    <span class="dashicons dashicons-admin-appearance" style="vertical-align: middle; margin-top: -2px;"></span>
     2060                    <?php esc_html_e('Customize Live', 'nexversal'); ?>
     2061                </a>
     2062            </div>
     2063        </div>
     2064
     2065        <p style="color: #64748b; font-size: 14px; margin-bottom: 24px;">
     2066            <?php esc_html_e('Configure your public contact information card, support email, headquarters link, and response time displayed on the Contact Us page.', 'nexversal'); ?>
     2067        </p>
     2068
     2069        <?php echo $notice; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
     2070
     2071        <form method="post" action="" style="background: #ffffff; border: 1px solid #e2e8f0; border-radius: 8px; padding: 24px 30px; box-shadow: 0 1px 3px rgba(0,0,0,0.05);">
     2072            <?php wp_nonce_field('nexversal_save_contact_action', 'nexversal_contact_nonce'); ?>
     2073
     2074            <table class="form-table" role="presentation">
     2075                <tbody>
     2076                    <tr>
     2077                        <th scope="row">
     2078                            <label for="nexversal_show_contact_info"><?php esc_html_e('Contact Info Card', 'nexversal'); ?></label>
     2079                        </th>
     2080                        <td>
     2081                            <label for="nexversal_show_contact_info" style="font-weight: 600;">
     2082                                <input type="checkbox" name="nexversal_show_contact_info" id="nexversal_show_contact_info" value="1" <?php checked($show_info, true); ?> />
     2083                                <?php esc_html_e('Display Contact Information Card alongside the contact form', 'nexversal'); ?>
     2084                            </label>
     2085                            <p class="description"><?php esc_html_e('If unchecked, only the Send Us a Message form will be displayed centered on the page.', 'nexversal'); ?></p>
     2086                        </td>
     2087                    </tr>
     2088
     2089                    <tr>
     2090                        <th scope="row">
     2091                            <label for="nexversal_contact_title"><?php esc_html_e('Card Heading', 'nexversal'); ?></label>
     2092                        </th>
     2093                        <td>
     2094                            <input type="text" name="nexversal_contact_title" id="nexversal_contact_title" value="<?php echo esc_attr($info_title); ?>" class="regular-text" />
     2095                            <p class="description"><?php esc_html_e('Default: Contact Information', 'nexversal'); ?></p>
     2096                        </td>
     2097                    </tr>
     2098
     2099                    <tr>
     2100                        <th scope="row">
     2101                            <label for="nexversal_contact_desc"><?php esc_html_e('Card Description', 'nexversal'); ?></label>
     2102                        </th>
     2103                        <td>
     2104                            <textarea name="nexversal_contact_desc" id="nexversal_contact_desc" rows="3" class="large-text"><?php echo esc_textarea($info_desc); ?></textarea>
     2105                            <p class="description"><?php esc_html_e('A short intro explaining your support commitment to visitors.', 'nexversal'); ?></p>
     2106                        </td>
     2107                    </tr>
     2108
     2109                    <tr>
     2110                        <th scope="row">
     2111                            <label for="nexversal_contact_email"><?php esc_html_e('Support Email Address', 'nexversal'); ?></label>
     2112                        </th>
     2113                        <td>
     2114                            <input type="email" name="nexversal_contact_email" id="nexversal_contact_email" value="<?php echo esc_attr($info_email); ?>" class="regular-text" />
     2115                            <p class="description"><?php esc_html_e('The public email address visitors can click to email you directly.', 'nexversal'); ?></p>
     2116                        </td>
     2117                    </tr>
     2118
     2119                    <tr>
     2120                        <th scope="row">
     2121                            <label for="nexversal_contact_hq_text"><?php esc_html_e('Headquarters / City Text', 'nexversal'); ?></label>
     2122                        </th>
     2123                        <td>
     2124                            <input type="text" name="nexversal_contact_hq_text" id="nexversal_contact_hq_text" value="<?php echo esc_attr($hq_text); ?>" class="regular-text" />
     2125                            <p class="description"><?php esc_html_e('e.g. San Francisco, CA or nexversal.com/contact', 'nexversal'); ?></p>
     2126                        </td>
     2127                    </tr>
     2128
     2129                    <tr>
     2130                        <th scope="row">
     2131                            <label for="nexversal_contact_hq_url"><?php esc_html_e('Headquarters Link / Maps URL', 'nexversal'); ?></label>
     2132                        </th>
     2133                        <td>
     2134                            <input type="url" name="nexversal_contact_hq_url" id="nexversal_contact_hq_url" value="<?php echo esc_attr($hq_url); ?>" class="large-text" />
     2135                            <p class="description"><?php esc_html_e('Link opens in a new tab when clicked (e.g. your Google Maps location or Contact URL).', 'nexversal'); ?></p>
     2136                        </td>
     2137                    </tr>
     2138
     2139                    <tr>
     2140                        <th scope="row">
     2141                            <label for="nexversal_custom_social_links"><?php esc_html_e('Follow Us Social Links', 'nexversal'); ?></label>
     2142                        </th>
     2143                        <td>
     2144                            <textarea name="nexversal_custom_social_links" id="nexversal_custom_social_links" rows="5" class="large-text" placeholder="https://facebook.com/yourpage&#10;https://x.com/yourhandle&#10;https://linkedin.com/in/yourprofile&#10;https://github.com/yourorg"><?php echo esc_textarea($soc_links); ?></textarea>
     2145                            <p class="description">
     2146                                <?php esc_html_e('Enter one URL per line (e.g. Facebook, X/Twitter, LinkedIn, YouTube, Instagram, GitHub, TikTok, Discord, Telegram, or personal website). Nexversal automatically detects the brand and generates its official logo icon!', 'nexversal'); ?>
     2147                            </p>
     2148                        </td>
     2149                    </tr>
     2150                </tbody>
     2151            </table>
     2152
     2153            <div style="margin-top: 24px; padding-top: 20px; border-top: 1px solid #e2e8f0;">
     2154                <input type="submit" name="nexversal_save_contact" class="button button-primary button-large" value="<?php esc_attr_e('Save Contact Settings', 'nexversal'); ?>" style="background: #4f46e5; border-color: #4f46e5; font-weight: 600; padding: 4px 20px;" />
     2155            </div>
     2156        </form>
     2157    </div>
     2158    <?php
     2159}
     2160
     2161/**
     2162 * ==========================================================================
     2163 * 1-Click Starter Site / Demo Onboarding Engine
     2164 * ==========================================================================
     2165 */
     2166
     2167/**
     2168 * Register Appearance > Starter Site page in WP-Admin
     2169 */
     2170function nexversal_register_starter_site_admin_menu() {
     2171    add_theme_page(
     2172        esc_html__('Nexversal Starter Site', 'nexversal'),
     2173        esc_html__('Starter Site', 'nexversal'),
     2174        'manage_options',
     2175        'nexversal-starter',
     2176        'nexversal_render_starter_site_page'
     2177    );
     2178}
     2179add_action('admin_menu', 'nexversal_register_starter_site_admin_menu');
     2180
     2181/**
     2182 * Execute the 1-Click Starter Site Import safely & idempotently
     2183 */
     2184function nexversal_execute_starter_import() {
     2185    if (!current_user_can('manage_options')) {
     2186        return new WP_Error('forbidden', esc_html__('Permission denied.', 'nexversal'));
     2187    }
     2188
     2189    $summary = array(
     2190        'pages'      => 0,
     2191        'categories' => 0,
     2192        'posts'      => 0,
     2193        'menu'       => false,
     2194    );
     2195
     2196    // 1. Categories
     2197    $categories_data = array(
     2198        'Artificial Intelligence' => 'Cutting-edge AI models, autonomous agents, and machine learning insights.',
     2199        'Cloud Computing'         => 'High-scale cloud architectures, serverless systems, and DevOps engineering.',
     2200        'SEO & Performance'       => 'Search optimization, Core Web Vitals, and page speed engineering.',
     2201        'Tech Reviews'            => 'Unbiased evaluations of development tools, SaaS, and productivity software.',
     2202    );
     2203
     2204    $cat_ids = array();
     2205    foreach ($categories_data as $cat_name => $cat_desc) {
     2206        $term = term_exists($cat_name, 'category');
     2207        if (!$term) {
     2208            $inserted = wp_insert_term($cat_name, 'category', array('description' => $cat_desc));
     2209            if (!is_wp_error($inserted)) {
     2210                $cat_ids[$cat_name] = $inserted['term_id'];
     2211                $summary['categories']++;
     2212            }
     2213        } else {
     2214            $cat_ids[$cat_name] = is_array($term) ? $term['term_id'] : $term;
     2215        }
     2216    }
     2217
     2218    // 2. Core Pages via nexversal_setup_default_content
     2219    nexversal_setup_default_content();
     2220
     2221    $home_page    = get_page_by_path('home');
     2222    $blog_page    = get_page_by_path('blog') ?: get_page_by_path('blogs');
     2223    $about_page   = get_page_by_path('about') ?: get_page_by_path('about-us');
     2224    $contact_page = get_page_by_path('contact') ?: get_page_by_path('contact-us');
     2225
     2226    if ($home_page) $summary['pages']++;
     2227    if ($blog_page) $summary['pages']++;
     2228    if ($about_page) $summary['pages']++;
     2229    if ($contact_page) $summary['pages']++;
     2230
     2231    // 3. Demo Articles
     2232    $demo_articles = array(
     2233        array(
     2234            'title'    => 'Top 10 AI Tools Transforming Modern Software Engineering in 2026',
     2235            'category' => 'Artificial Intelligence',
     2236            'featured' => '1',
     2237            'views'    => 2840,
     2238            'excerpt'  => 'Explore next-generation AI coding assistants, agentic frameworks, and autonomous developer tools reshaping engineering productivity this year.',
     2239            'content'  => '<!-- wp:paragraph {"dropCap":true} -->
     2240<p class="has-drop-cap">Artificial intelligence is evolving beyond simple code autocomplete widgets into autonomous, agentic pair programmers capable of analyzing large codebases, maintaining documentation integrity, and writing exhaustive automated test suites.</p>
     2241<!-- /wp:paragraph -->
     2242
     2243<!-- wp:heading {"level":2} -->
     2244<h2>The Rise of Autonomous Agentic Pair Programmers</h2>
     2245<!-- /wp:heading -->
     2246
     2247<!-- wp:paragraph -->
     2248<p>Modern engineering teams are rapidly adopting multimodal agents that parse git repositories, execute local sandbox commands, and verify complex edge cases before proposing pull requests. This dramatically compresses developer feedback loops and eliminates boilerplate engineering.</p>
     2249<!-- /wp:paragraph -->
     2250
     2251<!-- wp:heading {"level":3} -->
     2252<h3>Key Architecture Benchmarks for 2026</h3>
     2253<!-- /wp:heading -->
     2254
     2255<!-- wp:list -->
     2256<ul>
     2257<li><strong>Sub-second Streaming Throughput:</strong> Instantaneous generation for interactive terminal workflows.</li>
     2258<li><strong>1M+ Token Context Memory:</strong> Complete architectural recall across multi-service repositories.</li>
     2259<li><strong>Strict Compiler Verification:</strong> Zero hallucinations through automated type checking and lint validation.</li>
     2260</ul>
     2261<!-- /wp:list -->',
     2262        ),
     2263        array(
     2264            'title'    => 'Comparing Cloud Databases: SQL vs NoSQL for High-Scale Apps',
     2265            'category' => 'Cloud Computing',
     2266            'featured' => '0',
     2267            'views'    => 1940,
     2268            'excerpt'  => 'An architectural deep-dive into transactional ACID guarantees versus horizontal distributed scalability in modern cloud applications.',
     2269            'content'  => '<p>Choosing the right database architecture is one of the most critical decisions in modern systems engineering. While relational databases like PostgreSQL provide atomic ACID transactions, horizontally scalable document stores excel at high-velocity ingestion.</p><h2>Transactional Guarantees vs Read Latency</h2><p>When engineering for multi-region active-active deployments, distributed consensus protocols require deliberate trade-offs between consistency and partition tolerance.</p>',
     2270        ),
     2271        array(
     2272            'title'    => 'The Ultimate Guide to Core Web Vitals and Page Experience',
     2273            'category' => 'SEO & Performance',
     2274            'featured' => '0',
     2275            'views'    => 1680,
     2276            'excerpt'  => 'Master LCP, INP, and CLS optimization techniques to achieve perfect 100/100 PageSpeed scores and maximize organic Google rankings.',
     2277            'content'  => '<p>Google’s Core Web Vitals are foundational ranking factors that directly dictate search visibility and user retention. Achieving sub-second Largest Contentful Paint (LCP) and minimal Interaction to Next Paint (INP) requires disciplined script management and clean semantic HTML.</p><h2>Optimizing Interaction to Next Paint (INP)</h2><p>Eliminate blocking JavaScript execution on the main thread and leverage modern CSS layout containment to deliver buttery smooth 60fps mobile responsiveness.</p>',
     2278        ),
     2279        array(
     2280            'title'    => 'Next-Gen Web Frameworks: Architecture Comparison and Benchmarks',
     2281            'category' => 'Tech Reviews',
     2282            'featured' => '0',
     2283            'views'    => 1420,
     2284            'excerpt'  => 'Comparing server-side rendering, partial hydration, and edge-native architectures across high-performance web platforms.',
     2285            'content'  => '<p>Modern web development has moved past monolithic client-side JavaScript bundles toward island architectures and edge rendering. By streaming HTML directly from edge nodes, modern platforms achieve instantaneous first paint times.</p>',
     2286        ),
     2287    );
     2288
     2289    foreach ($demo_articles as $art) {
     2290        $existing = get_page_by_title($art['title'], OBJECT, 'post');
     2291        if (!$existing) {
     2292            $cat_id = $cat_ids[$art['category']] ?? 1;
     2293            $new_post_id = wp_insert_post(array(
     2294                'post_title'   => $art['title'],
     2295                'post_content' => $art['content'],
     2296                'post_excerpt' => $art['excerpt'],
     2297                'post_status'  => 'publish',
     2298                'post_type'    => 'post',
     2299                'post_category'=> array($cat_id),
     2300            ));
     2301            if ($new_post_id && !is_wp_error($new_post_id)) {
     2302                if (!empty($art['featured'])) {
     2303                    update_post_meta($new_post_id, '_nexversal_featured_in_hero', '1');
     2304                }
     2305                update_post_meta($new_post_id, '_nexversal_post_views', (int) $art['views']);
     2306                $summary['posts']++;
     2307            }
     2308        } else {
     2309            if (!empty($art['featured'])) {
     2310                update_post_meta($existing->ID, '_nexversal_featured_in_hero', '1');
     2311            }
     2312        }
     2313    }
     2314
     2315    // 4. Ensure Primary Menu is active
     2316    $menu_obj = wp_get_nav_menu_object('Main Menu');
     2317    if ($menu_obj) {
     2318        $locations = get_theme_mod('nav_menu_locations', array());
     2319        $locations['primary'] = $menu_obj->term_id;
     2320        set_theme_mod('nav_menu_locations', $locations);
     2321        $summary['menu'] = true;
     2322    }
     2323
     2324    return $summary;
     2325}
     2326
     2327/**
     2328 * Render Appearance > Starter Site page in WP-Admin
     2329 */
     2330function nexversal_render_starter_site_page() {
     2331    if (!current_user_can('manage_options')) {
     2332        return;
     2333    }
     2334
     2335    $notice = '';
     2336    if (isset($_POST['nexversal_run_starter_import']) && check_admin_referer('nexversal_starter_import_action', 'nexversal_starter_nonce')) {
     2337        $result = nexversal_execute_starter_import();
     2338        if (is_wp_error($result)) {
     2339            $notice = '<div class="notice notice-error is-dismissible"><p>' . esc_html($result->get_error_message()) . '</p></div>';
     2340        } else {
     2341            $msg = sprintf(
     2342                /* translators: 1: categories count, 2: posts count */
     2343                esc_html__('🎉 Starter Site Imported Successfully! Core Pages verified/created, %1$d Categories mapped, %2$d Demo Stories ready, and Primary Navigation Menu linked.', 'nexversal'),
     2344                $result['categories'],
     2345                $result['posts']
     2346            );
     2347            $notice = '<div class="notice notice-success is-dismissible"><p><strong>' . $msg . '</strong></p></div>';
     2348        }
     2349    }
     2350
     2351    $screenshot_url = get_template_directory_uri() . '/screenshot.png';
     2352    $customizer_url = admin_url('customize.php');
     2353    $home_link      = home_url('/');
     2354    $contact_set    = admin_url('themes.php?page=nexversal-contact');
     2355    ?>
     2356    <div class="wrap" style="max-width: 1040px; margin-top: 24px;">
     2357        <div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; margin-bottom: 20px;">
     2358            <div>
     2359                <h1 style="display: flex; align-items: center; gap: 12px; font-weight: 800; font-size: 26px; margin: 0; color: #0f172a;">
     2360                    <span class="dashicons dashicons-admin-site-alt3" style="font-size: 32px; width: 32px; height: 32px; color: #4f46e5;"></span>
     2361                    <?php esc_html_e('Nexversal 1-Click Starter Site', 'nexversal'); ?>
     2362                </h1>
     2363                <p style="color: #64748b; font-size: 14px; margin: 6px 0 0 0;">
     2364                    <?php esc_html_e('Set up a complete, jaw-dropping Tech & Magazine website in 5 seconds. Zero manual configuration required.', 'nexversal'); ?>
     2365                </p>
     2366            </div>
     2367            <div style="display: flex; gap: 10px;">
     2368                <a href="<?php echo esc_url($home_link); ?>" target="_blank" class="button button-secondary">
     2369                    <span class="dashicons dashicons-external" style="vertical-align: middle; margin-top: -2px;"></span>
     2370                    <?php esc_html_e('Visit Live Site', 'nexversal'); ?>
     2371                </a>
     2372                <a href="<?php echo esc_url($customizer_url); ?>" class="button button-secondary">
     2373                    <span class="dashicons dashicons-admin-appearance" style="vertical-align: middle; margin-top: -2px;"></span>
     2374                    <?php esc_html_e('Live Customizer', 'nexversal'); ?>
     2375                </a>
     2376            </div>
     2377        </div>
     2378
     2379        <?php echo $notice; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
     2380
     2381        <div style="display: grid; grid-template-columns: 1.15fr 0.85fr; gap: 28px; margin-top: 20px; align-items: start;">
     2382            <!-- Left Card: Starter Demo Preview & Action -->
     2383            <div style="background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 16px rgba(0,0,0,0.04);">
     2384                <div style="position: relative; overflow: hidden; max-height: 280px; background: #0f172a;">
     2385                    <img src="<?php echo esc_url($screenshot_url); ?>" alt="<?php esc_attr_e('Nexversal Demo Preview', 'nexversal'); ?>" style="width: 100%; height: auto; display: block; object-fit: cover;" />
     2386                    <div style="position: absolute; top: 14px; left: 14px; background: rgba(15,23,42,0.85); color: #38bdf8; padding: 4px 12px; border-radius: 20px; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; backdrop-filter: blur(4px);">
     2387                        ⚡ <?php esc_html_e('Tech & Magazine Edition', 'nexversal'); ?>
     2388                    </div>
     2389                </div>
     2390
     2391                <div style="padding: 28px 30px;">
     2392                    <h3 style="font-size: 18px; font-weight: 800; color: #0f172a; margin: 0 0 10px 0;">
     2393                        <?php esc_html_e('Ready-Made Tech & Magazine Demo', 'nexversal'); ?>
     2394                    </h3>
     2395                    <p style="color: #64748b; font-size: 14px; line-height: 1.6; margin: 0 0 20px 0;">
     2396                        <?php esc_html_e('Clicking the button below instantly configures your entire site with our flagship Tech & Magazine structure. Perfectly pre-linked and optimized for Google Core Web Vitals.', 'nexversal'); ?>
     2397                    </p>
     2398
     2399                    <form method="post" action="">
     2400                        <?php wp_nonce_field('nexversal_starter_import_action', 'nexversal_starter_nonce'); ?>
     2401                       
     2402                        <div style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 14px 16px; margin-bottom: 22px;">
     2403                            <label style="display: flex; align-items: flex-start; gap: 10px; cursor: pointer; font-size: 13px; font-weight: 600; color: #1e293b;">
     2404                                <input type="checkbox" checked="checked" disabled="disabled" style="margin-top: 2px;" />
     2405                                <div>
     2406                                    <span><?php esc_html_e('Safe & Idempotent Onboarding Mode', 'nexversal'); ?></span>
     2407                                    <span style="display: block; font-size: 11px; font-weight: 400; color: #64748b; margin-top: 2px;">
     2408                                        <?php esc_html_e('Existing posts, pages, and media are completely safe and will never be deleted or duplicated.', 'nexversal'); ?>
     2409                                    </span>
     2410                                </div>
     2411                            </label>
     2412                        </div>
     2413
     2414                        <button type="submit" name="nexversal_run_starter_import" class="button button-primary button-hero" style="background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%); border: none; font-weight: 700; font-size: 15px; padding: 12px 28px; height: auto; border-radius: 8px; box-shadow: 0 4px 14px rgba(79, 70, 229, 0.35); cursor: pointer; display: inline-flex; align-items: center; gap: 8px;">
     2415                            <span>🚀 <?php esc_html_e('Import Starter Site (1-Click)', 'nexversal'); ?></span>
     2416                        </button>
     2417                    </form>
     2418                </div>
     2419            </div>
     2420
     2421            <!-- Right Card: What Gets Imported & Features -->
     2422            <div style="display: flex; flex-direction: column; gap: 20px;">
     2423                <div style="background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 26px; box-shadow: 0 4px 16px rgba(0,0,0,0.04);">
     2424                    <h3 style="font-size: 16px; font-weight: 700; color: #0f172a; margin: 0 0 16px 0; display: flex; align-items: center; gap: 8px;">
     2425                        <span class="dashicons dashicons-yes-alt" style="color: #10b981;"></span>
     2426                        <?php esc_html_e('What’s Included in This Starter Site:', 'nexversal'); ?>
     2427                    </h3>
     2428
     2429                    <ul style="margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 14px;">
     2430                        <li style="display: flex; gap: 12px; font-size: 13px; color: #334155; line-height: 1.5;">
     2431                            <span style="color: #4f46e5; font-size: 16px; font-weight: 700;">&#10003;</span>
     2432                            <div>
     2433                                <strong><?php esc_html_e('4 Complete Core Pages:', 'nexversal'); ?></strong><br>
     2434                                <?php esc_html_e('Home (2-Column Hero), Blogs (4-Column Grid), About Us, and Contact Us.', 'nexversal'); ?>
     2435                            </div>
     2436                        </li>
     2437                        <li style="display: flex; gap: 12px; font-size: 13px; color: #334155; line-height: 1.5;">
     2438                            <span style="color: #4f46e5; font-size: 16px; font-weight: 700;">&#10003;</span>
     2439                            <div>
     2440                                <strong><?php esc_html_e('2-Column Hero & Featured Story Card:', 'nexversal'); ?></strong><br>
     2441                                <?php esc_html_e('Main headline on the left, trending featured article card automatically pinned on the right.', 'nexversal'); ?>
     2442                            </div>
     2443                        </li>
     2444                        <li style="display: flex; gap: 12px; font-size: 13px; color: #334155; line-height: 1.5;">
     2445                            <span style="color: #4f46e5; font-size: 16px; font-weight: 700;">&#10003;</span>
     2446                            <div>
     2447                                <strong><?php esc_html_e('Pre-Mapped Navigation Menu:', 'nexversal'); ?></strong><br>
     2448                                <?php esc_html_e('Auto-connected to Primary Menu location with clean header links.', 'nexversal'); ?>
     2449                            </div>
     2450                        </li>
     2451                        <li style="display: flex; gap: 12px; font-size: 13px; color: #334155; line-height: 1.5;">
     2452                            <span style="color: #4f46e5; font-size: 16px; font-weight: 700;">&#10003;</span>
     2453                            <div>
     2454                                <strong><?php esc_html_e('Tech Categories & Sample Articles:', 'nexversal'); ?></strong><br>
     2455                                <?php esc_html_e('AI, Cloud, SEO, and Reviews categories with trending tags.', 'nexversal'); ?>
     2456                            </div>
     2457                        </li>
     2458                    </ul>
     2459                </div>
     2460
     2461                <div style="background: #f1f5f9; border: 1px solid #cbd5e1; border-radius: 12px; padding: 20px 22px;">
     2462                    <h4 style="font-size: 14px; font-weight: 700; color: #1e293b; margin: 0 0 8px 0;">
     2463                        <?php esc_html_e('Need to customize details afterwards?', 'nexversal'); ?>
     2464                    </h4>
     2465                    <p style="font-size: 12px; color: #64748b; line-height: 1.5; margin: 0 0 12px 0;">
     2466                        <?php esc_html_e('You can change contact emails, social links, and brand colors anytime from Appearance > Contact Settings or Appearance > Customize.', 'nexversal'); ?>
     2467                    </p>
     2468                    <a href="<?php echo esc_url($contact_set); ?>" class="button button-small" style="font-weight: 600;">
     2469                        <?php esc_html_e('Open Contact Settings', 'nexversal'); ?>
     2470                    </a>
     2471                </div>
     2472            </div>
     2473        </div>
     2474    </div>
     2475    <?php
     2476}
     2477
     2478
     2479/**
     2480 * ==========================================================================
     2481 * Hero Featured Article & Post Views System
     2482 * ==========================================================================
     2483 */
     2484
     2485/**
     2486 * Register Meta Box in Post Editor for Hero Featured Article
     2487 */
     2488function nexversal_add_featured_post_meta_box() {
     2489    add_meta_box(
     2490        'nexversal_featured_post_box',
     2491        esc_html__('★ Hero Featured Article', 'nexversal'),
     2492        'nexversal_render_featured_post_meta_box',
     2493        'post',
     2494        'side',
     2495        'high'
     2496    );
     2497}
     2498add_action('add_meta_boxes', 'nexversal_add_featured_post_meta_box');
     2499
     2500/**
     2501 * Render the Meta Box in post editor
     2502 */
     2503function nexversal_render_featured_post_meta_box($post) {
     2504    wp_nonce_field('nexversal_featured_post_nonce_action', 'nexversal_featured_post_nonce');
     2505    $is_featured = get_post_meta($post->ID, '_nexversal_featured_in_hero', true);
     2506    $views       = (int) get_post_meta($post->ID, '_nexversal_post_views', true);
     2507    ?>
     2508    <p>
     2509        <label for="nexversal_featured_in_hero" style="font-weight: 600; cursor: pointer; display: flex; align-items: flex-start; gap: 8px;">
     2510            <input type="checkbox" name="nexversal_featured_in_hero" id="nexversal_featured_in_hero" value="1" <?php checked($is_featured, '1'); ?> style="margin-top: 2px;" />
     2511            <span><?php esc_html_e('Feature in Homepage Hero', 'nexversal'); ?></span>
     2512        </label>
     2513    </p>
     2514    <p class="description" style="font-size: 12px; color: #64748b; line-height: 1.4; margin-top: 6px;">
     2515        <?php esc_html_e('Display this article at the top of the homepage next to the main headline. If none selected, the theme automatically displays your trending / most-viewed article.', 'nexversal'); ?>
     2516    </p>
     2517    <div style="margin-top: 12px; padding-top: 8px; border-top: 1px dashed #cbd5e1; font-size: 12px; color: #64748b; display: flex; align-items: center; justify-content: space-between;">
     2518        <span><?php esc_html_e('Article Views:', 'nexversal'); ?></span>
     2519        <strong style="color: #0f172a; font-size: 13px;"><?php echo number_format_i18n($views); ?></strong>
     2520    </div>
     2521    <?php
     2522}
     2523
     2524/**
     2525 * Save the Meta Box value
     2526 */
     2527function nexversal_save_featured_post_meta_box($post_id) {
     2528    if (!isset($_POST['nexversal_featured_post_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nexversal_featured_post_nonce'])), 'nexversal_featured_post_nonce_action')) {
     2529        return;
     2530    }
     2531    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
     2532        return;
     2533    }
     2534    if (!current_user_can('edit_post', $post_id)) {
     2535        return;
     2536    }
     2537
     2538    if (!empty($_POST['nexversal_featured_in_hero'])) {
     2539        update_post_meta($post_id, '_nexversal_featured_in_hero', '1');
     2540    } else {
     2541        delete_post_meta($post_id, '_nexversal_featured_in_hero');
     2542    }
     2543}
     2544add_action('save_post_post', 'nexversal_save_featured_post_meta_box');
     2545
     2546/**
     2547 * Track Post Views on single article visits
     2548 */
     2549function nexversal_track_post_views() {
     2550    if (!is_single() || is_preview()) {
     2551        return;
     2552    }
     2553    global $post;
     2554    if (!$post || !isset($post->ID)) {
     2555        return;
     2556    }
     2557    $views = (int) get_post_meta($post->ID, '_nexversal_post_views', true);
     2558    update_post_meta($post->ID, '_nexversal_post_views', $views + 1);
     2559}
     2560add_action('template_redirect', 'nexversal_track_post_views');
     2561
     2562/**
     2563 * Add Featured and Views columns to WP-Admin posts list
     2564 */
     2565function nexversal_add_post_columns($columns) {
     2566    $columns['nx_featured'] = esc_html__('Hero Card', 'nexversal');
     2567    $columns['nx_views']    = esc_html__('Views', 'nexversal');
     2568    return $columns;
     2569}
     2570add_filter('manage_posts_columns', 'nexversal_add_post_columns');
     2571
     2572function nexversal_custom_post_columns($column, $post_id) {
     2573    if ('nx_featured' === $column) {
     2574        $is_feat = get_post_meta($post_id, '_nexversal_featured_in_hero', true);
     2575        if ('1' === $is_feat) {
     2576            echo '<span style="color: #f59e0b; font-weight: 700;">&#9733; ' . esc_html__('Featured', 'nexversal') . '</span>';
     2577        } else {
     2578            echo '<span style="color: #94a3b8;">&mdash;</span>';
     2579        }
     2580    } elseif ('nx_views' === $column) {
     2581        $views = (int) get_post_meta($post_id, '_nexversal_post_views', true);
     2582        echo '<strong>' . number_format_i18n($views) . '</strong>';
     2583    }
     2584}
     2585add_action('manage_posts_custom_column', 'nexversal_custom_post_columns', 10, 2);
     2586
     2587/**
     2588 * Retrieve the Hero Featured Post:
     2589 * 1. Post manually checked '_nexversal_featured_in_hero'
     2590 * 2. Fallback: Post with highest views
     2591 * 3. Fallback: Sticky post
     2592 * 4. Fallback: Latest post
     2593 */
     2594function nexversal_get_hero_featured_post() {
     2595    // 1. Manually selected
     2596    $args_selected = array(
     2597        'post_type'      => 'post',
     2598        'post_status'    => 'publish',
     2599        'posts_per_page' => 1,
     2600        'meta_key'       => '_nexversal_featured_in_hero',
     2601        'meta_value'     => '1',
     2602        'orderby'        => 'date',
     2603        'order'          => 'DESC',
     2604    );
     2605    $selected_query = new WP_Query($args_selected);
     2606    if ($selected_query->have_posts()) {
     2607        $p = $selected_query->posts[0];
     2608        wp_reset_postdata();
     2609        return $p;
     2610    }
     2611
     2612    // 2. Fallback: Highest views
     2613    $args_views = array(
     2614        'post_type'      => 'post',
     2615        'post_status'    => 'publish',
     2616        'posts_per_page' => 1,
     2617        'meta_key'       => '_nexversal_post_views',
     2618        'orderby'        => 'meta_value_num',
     2619        'order'          => 'DESC',
     2620    );
     2621    $views_query = new WP_Query($args_views);
     2622    if ($views_query->have_posts() && (int) get_post_meta($views_query->posts[0]->ID, '_nexversal_post_views', true) > 0) {
     2623        $p = $views_query->posts[0];
     2624        wp_reset_postdata();
     2625        return $p;
     2626    }
     2627
     2628    // 3. Fallback: Sticky posts
     2629    $sticky = get_option('sticky_posts');
     2630    if (!empty($sticky)) {
     2631        $args_sticky = array(
     2632            'post_type'           => 'post',
     2633            'post_status'         => 'publish',
     2634            'posts_per_page'      => 1,
     2635            'post__in'            => $sticky,
     2636            'ignore_sticky_posts' => 1,
     2637        );
     2638        $sticky_query = new WP_Query($args_sticky);
     2639        if ($sticky_query->have_posts()) {
     2640            $p = $sticky_query->posts[0];
     2641            wp_reset_postdata();
     2642            return $p;
     2643        }
     2644    }
     2645
     2646    // 4. Fallback: Latest published post
     2647    $args_latest = array(
     2648        'post_type'      => 'post',
     2649        'post_status'    => 'publish',
     2650        'posts_per_page' => 1,
     2651        'orderby'        => 'date',
     2652        'order'          => 'DESC',
     2653    );
     2654    $latest_query = new WP_Query($args_latest);
     2655    if ($latest_query->have_posts()) {
     2656        $p = $latest_query->posts[0];
     2657        wp_reset_postdata();
     2658        return $p;
     2659    }
     2660
     2661    return null;
     2662}
     2663
     2664/**
     2665 * Render the Hero Featured Article Card HTML
     2666 */
     2667function nexversal_get_hero_featured_card_html() {
     2668    $featured_post = nexversal_get_hero_featured_post();
     2669    if (!$featured_post) {
     2670        return '';
     2671    }
     2672
     2673    $post_id     = $featured_post->ID;
     2674    $title       = get_the_title($post_id);
     2675    $permalink   = get_permalink($post_id);
     2676    $author_id   = $featured_post->post_author;
     2677    $author      = get_the_author_meta('display_name', $author_id);
     2678    $cats        = get_the_category($post_id);
     2679    $cat_name    = !empty($cats) ? $cats[0]->name : __('Article', 'nexversal');
     2680    $cat_link    = !empty($cats) ? get_category_link($cats[0]->term_id) : '#';
     2681    $is_manual   = ('1' === get_post_meta($post_id, '_nexversal_featured_in_hero', true));
     2682
     2683    // Calculate reading time
     2684    $content      = get_post_field('post_content', $post_id);
     2685    $word_count   = str_word_count(strip_tags($content));
     2686    $reading_time = max(1, ceil($word_count / 200)) . ' ' . esc_html__('min read', 'nexversal');
     2687
     2688    // Get thumbnail or high-tech fallback
     2689    $has_thumb  = has_post_thumbnail($post_id);
     2690    $thumb_html = '';
     2691    if ($has_thumb) {
     2692        $thumb_html = get_the_post_thumbnail($post_id, 'medium_large', array(
     2693            'class'   => 'nx-hero-card-img',
     2694            'loading' => 'eager',
     2695            'alt'     => esc_attr($title),
     2696        ));
     2697    } else {
     2698        $thumb_html = '<div class="nx-hero-card-img-fallback">' .
     2699            '<svg width="54" height="54" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>' .
     2700            '</div>';
     2701    }
     2702
     2703    $raw_excerpt = get_the_excerpt($post_id);
     2704    if (empty($raw_excerpt)) {
     2705        $raw_excerpt = wp_strip_all_tags($content);
     2706    }
     2707    $excerpt = wp_trim_words($raw_excerpt, 16, '...');
     2708
     2709    ob_start();
     2710    ?>
     2711    <article class="nx-hero-featured-card">
     2712        <div class="nx-hero-card-badge-wrap">
     2713            <span class="nx-hero-card-featured-tag">
     2714                <svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>
     2715                <?php echo $is_manual ? esc_html__('Featured Story', 'nexversal') : esc_html__('Trending Story', 'nexversal'); ?>
     2716            </span>
     2717        </div>
     2718        <a href="<?php echo esc_url($permalink); ?>" class="nx-hero-card-thumb-wrap" tabindex="-1" aria-hidden="true">
     2719            <?php echo $thumb_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
     2720        </a>
     2721        <div class="nx-hero-card-body">
     2722            <div class="nx-hero-card-meta-top">
     2723                <a href="<?php echo esc_url($cat_link); ?>" class="nx-hero-card-cat">
     2724                    <?php echo esc_html($cat_name); ?>
     2725                </a>
     2726                <span class="nx-hero-card-time"><?php echo esc_html($reading_time); ?></span>
     2727            </div>
     2728            <h3 class="nx-hero-card-title">
     2729                <a href="<?php echo esc_url($permalink); ?>"><?php echo esc_html($title); ?></a>
     2730            </h3>
     2731            <?php if (!empty($excerpt)) : ?>
     2732                <p class="nx-hero-card-excerpt"><?php echo esc_html($excerpt); ?></p>
     2733            <?php endif; ?>
     2734            <div class="nx-hero-card-footer">
     2735                <div class="nx-hero-card-author">
     2736                    <?php echo get_avatar($author_id, 24, '', '', array('class' => 'nx-hero-card-avatar')); ?>
     2737                    <span><?php echo esc_html($author); ?></span>
     2738                </div>
     2739                <a href="<?php echo esc_url($permalink); ?>" class="nx-hero-card-read-link">
     2740                    <span><?php esc_html_e('Read Story', 'nexversal'); ?></span>
     2741                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>
     2742                </a>
     2743            </div>
     2744        </div>
     2745    </article>
     2746    <?php
     2747    return ob_get_clean();
     2748}
     2749
     2750/**
     2751 * Filter render_block to inject the Featured Card into any nx-hero-section group on Home page
     2752 */
     2753function nexversal_render_hero_block_enhancement($block_content, $block) {
     2754    if ('core/group' === ($block['blockName'] ?? '') && !empty($block['attrs']['className']) && strpos($block['attrs']['className'], 'nx-hero-section') !== false && strpos($block_content, 'nx-hero-grid') === false) {
     2755        $pos_gt    = strpos($block_content, '>');
     2756        $pos_close = strrpos($block_content, '</div>');
     2757        if ($pos_gt !== false && $pos_close !== false && $pos_close > $pos_gt) {
     2758            $open_tag      = substr($block_content, 0, $pos_gt + 1);
     2759            $inner_content = substr($block_content, $pos_gt + 1, $pos_close - ($pos_gt + 1));
     2760            $featured_card = nexversal_get_hero_featured_card_html();
     2761            if (!empty($featured_card)) {
     2762                $featured_col = '<div class="nx-hero-featured-col">' . $featured_card . '</div>';
     2763                return $open_tag . '<div class="nx-hero-grid"><div class="nx-hero-content-col">' . $inner_content . '</div>' . $featured_col . '</div></div>';
     2764            }
     2765        }
     2766    }
     2767    return $block_content;
     2768}
     2769add_filter('render_block', 'nexversal_render_hero_block_enhancement', 10, 2);
     2770
     2771/**
     2772 * ==========================================================================
     2773 * Page Flexibility: Astra-Style Per-Page Layout Settings
     2774 * ==========================================================================
     2775 */
     2776
     2777/**
     2778 * Check if a specific page setting is disabled for the current post/page
     2779 */
     2780function nexversal_is_meta_disabled($feature, $post_id = 0) {
     2781    if (!$post_id) {
     2782        if (is_singular()) {
     2783            $post_id = get_the_ID();
     2784        } elseif (is_front_page() && 'page' === get_option('show_on_front')) {
     2785            $post_id = (int) get_option('page_on_front');
     2786        }
     2787    }
     2788    if (!$post_id) {
     2789        return false;
     2790    }
     2791    $val = get_post_meta($post_id, '_nexversal_' . $feature, true);
     2792    return ('1' === $val);
     2793}
     2794
     2795/**
     2796 * Retrieve the active content layout for the current page
     2797 */
     2798function nexversal_get_page_layout($post_id = 0) {
     2799    if (!$post_id) {
     2800        if (is_singular()) {
     2801            $post_id = get_the_ID();
     2802        } elseif (is_front_page() && 'page' === get_option('show_on_front')) {
     2803            $post_id = (int) get_option('page_on_front');
     2804        }
     2805    }
     2806    if (!$post_id) {
     2807        return 'default';
     2808    }
     2809    $layout = get_post_meta($post_id, '_nexversal_content_layout', true);
     2810    return !empty($layout) ? $layout : 'default';
     2811}
     2812
     2813/**
     2814 * Register the Page Settings Meta Box for Pages & Posts
     2815 */
     2816function nexversal_add_page_settings_meta_box() {
     2817    $screens = array('page', 'post');
     2818    foreach ($screens as $screen) {
     2819        add_meta_box(
     2820            'nexversal_page_settings_box',
     2821            esc_html__('Nexversal Page Settings', 'nexversal'),
     2822            'nexversal_render_page_settings_meta_box',
     2823            $screen,
     2824            'side',
     2825            'default'
     2826        );
     2827    }
     2828}
     2829add_action('add_meta_boxes', 'nexversal_add_page_settings_meta_box');
     2830
     2831/**
     2832 * Render the Page Settings Meta Box in post/page editor
     2833 */
     2834function nexversal_render_page_settings_meta_box($post) {
     2835    wp_nonce_field('nexversal_page_settings_nonce_action', 'nexversal_page_settings_nonce');
     2836
     2837    $disable_header      = get_post_meta($post->ID, '_nexversal_disable_header', true);
     2838    $disable_footer      = get_post_meta($post->ID, '_nexversal_disable_footer', true);
     2839    $disable_title       = get_post_meta($post->ID, '_nexversal_disable_title', true);
     2840    $disable_breadcrumbs = get_post_meta($post->ID, '_nexversal_disable_breadcrumbs', true);
     2841    $disable_sidebar     = get_post_meta($post->ID, '_nexversal_disable_sidebar', true);
     2842    $content_layout      = get_post_meta($post->ID, '_nexversal_content_layout', true);
     2843    if (empty($content_layout)) {
     2844        $content_layout = 'default';
     2845    }
     2846    ?>
     2847    <div class="nx-page-meta-box-wrap" style="font-size: 13px;">
     2848        <p style="font-weight: 700; color: #1e293b; margin: 4px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">
     2849            <?php esc_html_e('Content Layout', 'nexversal'); ?>
     2850        </p>
     2851        <div style="margin-bottom: 14px;">
     2852            <label style="display: block; margin-bottom: 6px; cursor: pointer;">
     2853                <input type="radio" name="nexversal_content_layout" value="default" <?php checked($content_layout, 'default'); ?> />
     2854                <span><?php esc_html_e('Default Theme Layout', 'nexversal'); ?></span>
     2855            </label>
     2856            <label style="display: block; margin-bottom: 6px; cursor: pointer;">
     2857                <input type="radio" name="nexversal_content_layout" value="full-width-contained" <?php checked($content_layout, 'full-width-contained'); ?> />
     2858                <span><?php esc_html_e('Full Width (Contained)', 'nexversal'); ?></span>
     2859            </label>
     2860            <label style="display: block; margin-bottom: 6px; cursor: pointer;">
     2861                <input type="radio" name="nexversal_content_layout" value="full-width-stretched" <?php checked($content_layout, 'full-width-stretched'); ?> />
     2862                <span style="font-weight: 600; color: #4f46e5;"><?php esc_html_e('Full Width Stretched (Canvas)', 'nexversal'); ?></span>
     2863            </label>
     2864            <p class="description" style="font-size: 11px; color: #64748b; margin-top: 4px; line-height: 1.4;">
     2865                <?php esc_html_e('Canvas is ideal for Elementor or full-screen custom landing pages.', 'nexversal'); ?>
     2866            </p>
     2867        </div>
     2868
     2869        <p style="font-weight: 700; color: #1e293b; margin: 12px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">
     2870            <?php esc_html_e('Disable Elements', 'nexversal'); ?>
     2871        </p>
     2872        <div style="display: flex; flex-direction: column; gap: 8px;">
     2873            <label style="cursor: pointer; display: flex; align-items: center; gap: 8px;">
     2874                <input type="checkbox" name="nexversal_disable_header" value="1" <?php checked($disable_header, '1'); ?> />
     2875                <span><?php esc_html_e('Disable Header', 'nexversal'); ?></span>
     2876            </label>
     2877
     2878            <label style="cursor: pointer; display: flex; align-items: center; gap: 8px;">
     2879                <input type="checkbox" name="nexversal_disable_footer" value="1" <?php checked($disable_footer, '1'); ?> />
     2880                <span><?php esc_html_e('Disable Footer', 'nexversal'); ?></span>
     2881            </label>
     2882
     2883            <label style="cursor: pointer; display: flex; align-items: center; gap: 8px;">
     2884                <input type="checkbox" name="nexversal_disable_title" value="1" <?php checked($disable_title, '1'); ?> />
     2885                <span><?php esc_html_e('Disable Page Title', 'nexversal'); ?></span>
     2886            </label>
     2887
     2888            <label style="cursor: pointer; display: flex; align-items: center; gap: 8px;">
     2889                <input type="checkbox" name="nexversal_disable_breadcrumbs" value="1" <?php checked($disable_breadcrumbs, '1'); ?> />
     2890                <span><?php esc_html_e('Disable Breadcrumbs', 'nexversal'); ?></span>
     2891            </label>
     2892
     2893            <label style="cursor: pointer; display: flex; align-items: center; gap: 8px;">
     2894                <input type="checkbox" name="nexversal_disable_sidebar" value="1" <?php checked($disable_sidebar, '1'); ?> />
     2895                <span><?php esc_html_e('Disable Sidebar (Force 100% Width)', 'nexversal'); ?></span>
     2896            </label>
     2897        </div>
     2898    </div>
     2899    <?php
     2900}
     2901
     2902/**
     2903 * Save Page Settings Meta Box
     2904 */
     2905function nexversal_save_page_settings_meta_box($post_id) {
     2906    if (!isset($_POST['nexversal_page_settings_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nexversal_page_settings_nonce'])), 'nexversal_page_settings_nonce_action')) {
     2907        return;
     2908    }
     2909    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
     2910        return;
     2911    }
     2912    if (!current_user_can('edit_post', $post_id)) {
     2913        return;
     2914    }
     2915
     2916    $checkbox_keys = array(
     2917        'disable_header',
     2918        'disable_footer',
     2919        'disable_title',
     2920        'disable_breadcrumbs',
     2921        'disable_sidebar',
     2922    );
     2923
     2924    foreach ($checkbox_keys as $key) {
     2925        if (!empty($_POST['nexversal_' . $key])) {
     2926            update_post_meta($post_id, '_nexversal_' . $key, '1');
     2927        } else {
     2928            delete_post_meta($post_id, '_nexversal_' . $key);
     2929        }
     2930    }
     2931
     2932    if (isset($_POST['nexversal_content_layout'])) {
     2933        $layout = sanitize_key($_POST['nexversal_content_layout']);
     2934        if (in_array($layout, array('default', 'full-width-contained', 'full-width-stretched'), true)) {
     2935            update_post_meta($post_id, '_nexversal_content_layout', $layout);
     2936        }
     2937    }
     2938}
     2939add_action('save_post', 'nexversal_save_page_settings_meta_box');
     2940
     2941/**
     2942 * Filter body_class to inject layout & disabled classes for CSS hooks
     2943 */
     2944function nexversal_page_settings_body_classes($classes) {
     2945    $post_id = 0;
     2946    if (is_singular()) {
     2947        $post_id = get_the_ID();
     2948    } elseif (is_front_page() && 'page' === get_option('show_on_front')) {
     2949        $post_id = (int) get_option('page_on_front');
     2950    } elseif (is_home() && 'page' === get_option('show_on_front')) {
     2951        $post_id = (int) get_option('page_for_posts');
     2952    }
     2953
     2954    if ($post_id) {
     2955        $layout = nexversal_get_page_layout($post_id);
     2956        if ('full-width-stretched' === $layout) {
     2957            $classes[] = 'nx-layout-stretched';
     2958        } elseif ('full-width-contained' === $layout) {
     2959            $classes[] = 'nx-layout-contained';
     2960        }
     2961
     2962        if (nexversal_is_meta_disabled('disable_header', $post_id)) {
     2963            $classes[] = 'nx-no-header';
     2964        }
     2965        if (nexversal_is_meta_disabled('disable_footer', $post_id)) {
     2966            $classes[] = 'nx-no-footer';
     2967        }
     2968        if (nexversal_is_meta_disabled('disable_title', $post_id)) {
     2969            $classes[] = 'nx-no-title';
     2970        }
     2971        if (nexversal_is_meta_disabled('disable_breadcrumbs', $post_id)) {
     2972            $classes[] = 'nx-no-breadcrumbs';
     2973        }
     2974        if (nexversal_is_meta_disabled('disable_sidebar', $post_id)) {
     2975            $classes[] = 'nx-no-sidebar';
     2976        }
     2977    }
     2978
     2979    // Auto-detect templates or conditions without sidebar
     2980    if (is_page_template('template-blog.php') || is_page_template('template-full-width.php') || !is_active_sidebar('sidebar-1')) {
     2981        if (!in_array('nx-no-sidebar', $classes, true)) {
     2982            $classes[] = 'nx-no-sidebar';
     2983        }
     2984    }
     2985
     2986    return array_unique($classes);
     2987}
     2988add_filter('body_class', 'nexversal_page_settings_body_classes');
     2989
     2990
     2991
     2992
     2993
  • nexversal/3.5.9/header.php

    r357433 r357886  
    11<?php
    22/**
    3  * Security: Prevent direct script access
     3 * Header template for Nexversal Theme
     4 *
     5 * @package Nexversal
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
    410 */
     11
    512if (!defined('ABSPATH')) {
    613    exit;
    714}
    8 
    9 /**
    10  * Header template
    11  *
    12  * @package Nexversal
    13  */
    1415?><!DOCTYPE html>
    1516<html <?php language_attributes(); ?>>
    … …  
    2930<?php endif; ?>
    3031
     32<?php if (!function_exists('nexversal_is_meta_disabled') || !nexversal_is_meta_disabled('disable_header')) : ?>
    3133<header id="masthead" class="site-header">
    3234    <div class="container">
    … …  
    5961                    'container'      => false,
    6062                    'fallback_cb'    => function () {
    61                         echo '<ul>';
     63                        echo '<ul id="primary-menu" class="menu">';
    6264                        echo '<li><a href="' . esc_url(home_url('/')) . '">' . esc_html__('Home', 'nexversal') . '</a></li>';
    63                         wp_list_pages(array(
    64                             'title_li' => '',
    65                             'depth'    => 1,
    66                             'number'   => 5,
    67                         ));
     65
     66                        $blog_url    = function_exists('nexversal_get_blogs_page_url') ? nexversal_get_blogs_page_url() : home_url('/blog/');
     67                        $about_url   = function_exists('nexversal_get_about_page_url') ? nexversal_get_about_page_url() : home_url('/about/');
     68                        $contact_url = function_exists('nexversal_get_contact_page_url') ? nexversal_get_contact_page_url() : home_url('/contact/');
     69
     70                        echo '<li><a href="' . esc_url($blog_url) . '">' . esc_html__('Blogs', 'nexversal') . '</a></li>';
     71                        echo '<li><a href="' . esc_url($about_url) . '">' . esc_html__('About Us', 'nexversal') . '</a></li>';
     72                        echo '<li><a href="' . esc_url($contact_url) . '">' . esc_html__('Contact', 'nexversal') . '</a></li>';
    6873                        echo '</ul>';
    6974                    },
    … …  
    126131endif;
    127132?>
     133<?php endif; // End disable_header check ?>
    128134
  • nexversal/3.5.9/inc/ad-manager.php

    r357433 r357886  
    11<?php
    22/**
    3  * Nexversal Built-in Ad & Monetization Engine (PRO Feature - $15/year)
    4  *
    5  * Provides ready-to-use AdSense, Mediavine, and custom banner ad slots
    6  * with automatic in-article paragraph injection and responsive containers.
    7  * Integrates with Lemon Squeezy & cryptographic license verification.
     3 * Nexversal Built-in Ad & Monetization Engine (v3.5.0)
     4 *
     5 * Beginner-Friendly & Powerful Ad Architecture:
     6 * - 1-Click Google Auto-Ads (Just enter Publisher ID)
     7 * - Free Plan: Up to 3 Simultaneous Active Ads (Dropdown Position Selectors)
     8 * - Pro Plan ($15/yr): Unlimited Simultaneous Ads & Ad-Blocker Bypass
     9 * - Automatic Worldwide Geo-Targeting (Visitors in 195+ countries see ads in their local currency)
     10 * - Real-Time Impressions, Clicks & CTR Analytics Dashboard
    811 *
    912 * @package Nexversal
    10  * @version 2.3.0
     13 * @author Nexes Agency & Muhammad Shahid
     14 * @copyright 2026 Nexes Agency & Muhammad Shahid
     15 * @license GNU General Public License v2 or later
     16 * @link https://nexversal.com
     17 * @version 3.5.0
    1118 */
    1219
    … …  
    1421    exit;
    1522}
     23
     24/**
     25 * Load AdSense Cumulative Layout Shift (CLS) Prevention Engine
     26 */
     27require_once get_template_directory() . '/inc/ad-cls-optimizer.php';
    1628
    1729/**
    … …  
    3547        return esc_url($custom_url);
    3648    }
    37     // Direct Lemon Squeezy Store Checkout
    3849    return apply_filters('nexversal_pro_checkout_url', 'https://nexversal.lemonsqueezy.com/checkout/buy/nexversal-pro');
     50}
     51
     52/**
     53 * Detect visitor country code automatically using Cloudflare, Fastly, AWS, or server geo-headers.
     54 * Supports all 195+ countries worldwide (US, GB, CA, AU, DE, AE, SA, PK, IN, etc.).
     55 *
     56 * @return string ISO 2-letter country code or 'XX'
     57 */
     58function nexversal_get_visitor_country() {
     59    $country = '';
     60
     61    // 1. Cloudflare IP-Geolocation header (Cloudflare handles 195+ countries globally)
     62    if (!empty($_SERVER['HTTP_CF_IPCOUNTRY'])) {
     63        $country = sanitize_text_field(wp_unslash($_SERVER['HTTP_CF_IPCOUNTRY']));
     64    }
     65    // 2. AWS CloudFront Geolocation header
     66    elseif (!empty($_SERVER['HTTP_CLOUDFRONT_VIEWER_COUNTRY'])) {
     67        $country = sanitize_text_field(wp_unslash($_SERVER['HTTP_CLOUDFRONT_VIEWER_COUNTRY']));
     68    }
     69    // 3. Fastly / Akamai / Reverse Proxy Country header
     70    elseif (!empty($_SERVER['HTTP_X_COUNTRY_CODE'])) {
     71        $country = sanitize_text_field(wp_unslash($_SERVER['HTTP_X_COUNTRY_CODE']));
     72    }
     73    // 4. Standard GeoIP module (Apache/Nginx mod_geoip or MaxMind)
     74    elseif (!empty($_SERVER['GEOIP_COUNTRY_CODE'])) {
     75        $country = sanitize_text_field(wp_unslash($_SERVER['GEOIP_COUNTRY_CODE']));
     76    } elseif (!empty($_SERVER['HTTP_X_GEOIP_COUNTRY'])) {
     77        $country = sanitize_text_field(wp_unslash($_SERVER['HTTP_X_GEOIP_COUNTRY']));
     78    }
     79
     80    $country = strtoupper(trim($country));
     81    if (!empty($country) && strlen($country) === 2 && ctype_alpha($country)) {
     82        return apply_filters('nexversal_visitor_country', $country);
     83    }
     84
     85    return apply_filters('nexversal_visitor_country', 'XX');
    3986}
    4087
    … …  
    100147        $body = wp_remote_retrieve_body($response);
    101148        $data = json_decode($body, true);
     149
    102150        if (isset($data['activated']) && true === $data['activated']) {
    103151            return array(
    … …  
    117165function nexversal_pro_admin_menu() {
    118166    add_theme_page(
    119         esc_html__('Nexversal PRO ($15/year)', 'nexversal'),
     167        esc_html__('Nexversal PRO & Ad Monetization', 'nexversal'),
    120168        esc_html__('Nexversal PRO ⚡', 'nexversal'),
    121169        'manage_options',
    … …  
    127175
    128176/**
    129  * Handle License Activation / Deactivation Form Submission
     177 * Handle License & Analytics Form Submissions
    130178 */
    131179function nexversal_handle_license_action() {
    … …  
    177225        exit;
    178226    }
     227
     228    // Handle Reset Analytics
     229    if (isset($_POST['nexversal_reset_ad_stats'])) {
     230        delete_option('nexversal_ad_analytics');
     231        wp_safe_redirect(add_query_arg(array('page' => 'nexversal-pro', 'stats_reset' => '1'), admin_url('themes.php')));
     232        exit;
     233    }
    179234}
    180235add_action('admin_init', 'nexversal_handle_license_action');
    181236
    182237/**
    183  * Render the Appearance > Nexversal PRO Admin Page
     238 * ==========================================================================
     239 * Virtual ads.txt Manager (Dynamic URL Interception & IAB Spec Compliance)
     240 * ==========================================================================
     241 */
     242
     243/**
     244 * Sanitize ads.txt content according to IAB Tech Lab Ads.txt Specification
     245 *
     246 * @param string $raw_content
     247 * @return string Cleaned plain-text records
     248 */
     249function nexversal_sanitize_ads_txt($raw_content) {
     250    if (!is_string($raw_content)) {
     251        return '';
     252    }
     253
     254    // 1. Strip all HTML, XML, and PHP tags to eliminate XSS/injection risks
     255    $content = wp_strip_all_tags($raw_content);
     256
     257    // 2. Normalize Windows (\r\n) and legacy Mac (\r) line breaks to standard Unix LF (\n)
     258    $content = str_replace(array("\r\n", "\r"), "\n", $content);
     259    $lines   = explode("\n", $content);
     260    $clean_lines = array();
     261
     262    foreach ($lines as $line) {
     263        $trimmed = trim($line);
     264
     265        // Preserve intentional blank lines for readability/formatting
     266        if ($trimmed === '') {
     267            $clean_lines[] = '';
     268            continue;
     269        }
     270
     271        // Restrict strictly to standard printable ASCII characters (0x20 space through 0x7E tilde)
     272        // Strips any hidden control codes, binary artifacts, null bytes, or invalid UTF-8 sequences
     273        $sanitized_line = preg_replace('/[^\x20-\x7E]/', '', $trimmed);
     274        $clean_lines[]  = $sanitized_line;
     275    }
     276
     277    return implode("\n", $clean_lines);
     278}
     279
     280/**
     281 * Register top-priority rewrite rule for virtual /ads.txt request
     282 */
     283function nexversal_ads_txt_rewrite_rule() {
     284    add_rewrite_rule('^ads\.txt$', 'index.php?nexversal_ads_txt=1', 'top');
     285}
     286add_action('init', 'nexversal_ads_txt_rewrite_rule');
     287
     288/**
     289 * Register query variable for virtual ads.txt handling
     290 *
     291 * @param array $vars
     292 * @return array
     293 */
     294function nexversal_ads_txt_query_vars($vars) {
     295    $vars[] = 'nexversal_ads_txt';
     296    return $vars;
     297}
     298add_filter('query_vars', 'nexversal_ads_txt_query_vars');
     299
     300/**
     301 * Intercept request early to serve virtual ads.txt dynamically without cPanel file writing
     302 *
     303 * @param WP|null $wp
     304 */
     305function nexversal_maybe_serve_virtual_ads_txt($wp = null) {
     306    $is_ads_txt = false;
     307
     308    // 1. Check matched WordPress query var
     309    if (!empty($wp) && isset($wp->query_vars['nexversal_ads_txt']) && $wp->query_vars['nexversal_ads_txt']) {
     310        $is_ads_txt = true;
     311    } elseif (get_query_var('nexversal_ads_txt')) {
     312        $is_ads_txt = true;
     313    }
     314
     315    // 2. Check matched WordPress request path
     316    if (!$is_ads_txt && !empty($wp) && isset($wp->request) && strtolower(trim($wp->request, '/')) === 'ads.txt') {
     317        $is_ads_txt = true;
     318    }
     319
     320    // 3. Check raw REQUEST_URI for instant resolution prior to rewrite flushing
     321    if (!$is_ads_txt && !empty($_SERVER['REQUEST_URI'])) {
     322        $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
     323        if ($path && strtolower(trim($path, '/')) === 'ads.txt') {
     324            $is_ads_txt = true;
     325        }
     326    }
     327
     328    if ($is_ads_txt) {
     329        nexversal_render_virtual_ads_txt_output();
     330    }
     331}
     332add_action('parse_request', 'nexversal_maybe_serve_virtual_ads_txt', 0);
     333add_action('template_redirect', 'nexversal_maybe_serve_virtual_ads_txt', 0);
     334
     335/**
     336 * Output virtual ads.txt content with strict HTTP headers and clear all output buffers
     337 */
     338function nexversal_render_virtual_ads_txt_output() {
     339    $content = get_option('nexversal_ads_txt_content', '');
     340
     341    // Set HTTP 200 OK status
     342    status_header(200);
     343
     344    // Send correct Content-Type: text/plain; charset=utf-8
     345    header('Content-Type: text/plain; charset=utf-8');
     346    header('X-Content-Type-Options: nosniff');
     347    header('X-Robots-Tag: noindex, follow');
     348    header('Cache-Control: public, max-age=3600');
     349
     350    // Discard any active output buffers to ensure zero HTML or whitespace leakage
     351    while (ob_get_level() > 0) {
     352        ob_end_clean();
     353    }
     354
     355    if (!empty(trim($content))) {
     356        echo trim($content) . "\n";
     357    } else {
     358        // Fallback placeholder comment complying with IAB Tech Lab Ads.txt spec
     359        echo "# Nexversal Virtual Ads.txt Manager\n";
     360        echo "# Status: Active (Zero records configured)\n";
     361        echo "# Configure authorized digital sellers in WordPress Admin > Appearance > Nexversal PRO\n";
     362    }
     363    exit;
     364}
     365
     366/**
     367 * Handle virtual ads.txt form submissions with nonce verification and manage_options permission
     368 */
     369function nexversal_handle_ads_txt_action() {
     370    if (!isset($_POST['nexversal_save_ads_txt'])) {
     371        return;
     372    }
     373
     374    if (!isset($_POST['nexversal_ads_txt_nonce']) || !wp_verify_nonce($_POST['nexversal_ads_txt_nonce'], 'nexversal_ads_txt_action')) {
     375        wp_die(esc_html__('Security verification failed. Please refresh and try again.', 'nexversal'));
     376    }
     377
     378    if (!current_user_can('manage_options')) {
     379        wp_die(esc_html__('Sorry, you do not have permission to manage ads.txt.', 'nexversal'));
     380    }
     381
     382    $raw_content   = isset($_POST['nexversal_ads_txt_content']) ? wp_unslash($_POST['nexversal_ads_txt_content']) : '';
     383    $clean_content = nexversal_sanitize_ads_txt($raw_content);
     384
     385    update_option('nexversal_ads_txt_content', $clean_content);
     386
     387    // Soft-flush rewrite rules to ensure /ads.txt routing is active
     388    flush_rewrite_rules(false);
     389
     390    wp_safe_redirect(add_query_arg(array('page' => 'nexversal-pro', 'ads_txt_saved' => '1'), admin_url('themes.php')));
     391    exit;
     392}
     393add_action('admin_init', 'nexversal_handle_ads_txt_action');
     394
     395/**
     396 * Record an ad impression or click in lightweight aggregated stats
     397 *
     398 * @param string $slot
     399 * @param string $type 'impression' or 'click'
     400 * @param string $country
     401 */
     402function nexversal_record_ad_event($slot, $type = 'impression', $country = '') {
     403    if (empty($slot)) return;
     404    if (empty($country)) {
     405        $country = nexversal_get_visitor_country();
     406    }
     407
     408    $stats = get_option('nexversal_ad_analytics', array());
     409    if (!is_array($stats)) {
     410        $stats = array();
     411    }
     412
     413    if (!isset($stats['slots'][$slot])) {
     414        $stats['slots'][$slot] = array('impressions' => 0, 'clicks' => 0);
     415    }
     416
     417    if (!isset($stats['countries'][$country])) {
     418        $stats['countries'][$country] = array('impressions' => 0, 'clicks' => 0);
     419    }
     420
     421    if (!isset($stats['total'])) {
     422        $stats['total'] = array('impressions' => 0, 'clicks' => 0);
     423    }
     424
     425    if ($type === 'click') {
     426        $stats['slots'][$slot]['clicks']++;
     427        $stats['countries'][$country]['clicks']++;
     428        $stats['total']['clicks']++;
     429    } else {
     430        $stats['slots'][$slot]['impressions']++;
     431        $stats['countries'][$country]['impressions']++;
     432        $stats['total']['impressions']++;
     433    }
     434
     435    update_option('nexversal_ad_analytics', $stats, false);
     436}
     437
     438/**
     439 * Handle AJAX click/impression tracking beacons securely
     440 */
     441function nexversal_handle_ad_beacon() {
     442    $slot    = isset($_POST['slot']) ? sanitize_key($_POST['slot']) : '';
     443    $type    = isset($_POST['type']) && $_POST['type'] === 'click' ? 'click' : 'impression';
     444    $country = nexversal_get_visitor_country();
     445
     446    if (!empty($slot)) {
     447        nexversal_record_ad_event($slot, $type, $country);
     448        wp_send_json_success(array('status' => 'recorded'));
     449    }
     450    wp_send_json_error(array('status' => 'invalid_slot'));
     451}
     452add_action('wp_ajax_nexversal_ad_beacon', 'nexversal_handle_ad_beacon');
     453add_action('wp_ajax_nopriv_nexversal_ad_beacon', 'nexversal_handle_ad_beacon');
     454
     455/**
     456 * Retrieve list of active ad slots respecting Free vs Pro plan limits.
     457 * - Free Plan: Up to 3 active slots maximum.
     458 * - Pro Plan: Unlimited active slots.
     459 *
     460 * @return array Array of slot slugs that are permitted to render
     461 */
     462function nexversal_get_allowed_ad_slots() {
     463    $slots = array('header', 'article', 'post_bottom', 'infeed', 'sidebar');
     464    $enabled_slots = array();
     465
     466    foreach ($slots as $slot) {
     467        $slot_on = get_theme_mod("nexversal_ad_{$slot}_enabled", false);
     468        $ad_code = get_theme_mod("nexversal_ad_{$slot}_code", '');
     469        if ($slot_on && !empty(trim($ad_code))) {
     470            $enabled_slots[] = $slot;
     471        }
     472    }
     473
     474    // Pro Plan: Unlimited
     475    if (nexversal_is_pro_active()) {
     476        return $enabled_slots;
     477    }
     478
     479    // Free Plan: Limit to 3 slots
     480    return array_slice($enabled_slots, 0, 3);
     481}
     482
     483/**
     484 * Count how many slots are currently configured and enabled
     485 *
     486 * @return int
     487 */
     488function nexversal_count_active_ad_slots() {
     489    $slots = array('header', 'article', 'post_bottom', 'infeed', 'sidebar');
     490    $count = 0;
     491    foreach ($slots as $slot) {
     492        $slot_on = get_theme_mod("nexversal_ad_{$slot}_enabled", false);
     493        $ad_code = get_theme_mod("nexversal_ad_{$slot}_code", '');
     494        if ($slot_on && !empty(trim($ad_code))) {
     495            $count++;
     496        }
     497    }
     498    return $count;
     499}
     500
     501/**
     502 * Global Page Ad Execution Counter & Free Plan Limit Enforcer
     503 *
     504 * Implements a strict, immutable ceiling of exactly 3 ads per page for the Free version.
     505 * - Free Version: Maximum 3 ads rendered per page across all sources:
     506 *   structural slots, in-article injector, and shortcodes.
     507 * - PRO Version: Unlimited ad impressions per page.
     508 *
     509 * @return int Number of ads rendered on the current request
     510 */
     511function nexversal_get_page_ad_count() {
     512    if (!isset($GLOBALS['nexversal_page_ad_count'])) {
     513        $GLOBALS['nexversal_page_ad_count'] = 0;
     514    }
     515    return (int) $GLOBALS['nexversal_page_ad_count'];
     516}
     517
     518/**
     519 * Determine if another ad is allowed to render on the current page
     520 *
     521 * @return bool True if ad is permitted to render, false if Free limit is reached.
     522 */
     523function nexversal_can_render_ad() {
     524    // PRO plan allows unlimited ads
     525    if (nexversal_is_pro_active()) {
     526        return true;
     527    }
     528    // Free plan strictly allows up to 3 ads per page
     529    return nexversal_get_page_ad_count() < 3;
     530}
     531
     532/**
     533 * Increment the global page ad execution tracker
     534 *
     535 * @return int Updated ad count
     536 */
     537function nexversal_increment_page_ad_count() {
     538    if (!isset($GLOBALS['nexversal_page_ad_count'])) {
     539        $GLOBALS['nexversal_page_ad_count'] = 0;
     540    }
     541    $GLOBALS['nexversal_page_ad_count']++;
     542    return $GLOBALS['nexversal_page_ad_count'];
     543}
     544
     545/**
     546 * Reset the global page ad execution tracker (useful for testing and sub-requests)
     547 */
     548function nexversal_reset_page_ad_count() {
     549    $GLOBALS['nexversal_page_ad_count'] = 0;
     550}
     551
     552/**
     553 * Determine whether the current visitor is an authenticated administrator or editor
     554 * who must be shielded from live Google AdSense ads to prevent invalid clicks and account suspensions.
     555 *
     556 * @return bool True if current visitor is an admin or editor, false otherwise.
     557 */
     558function nexversal_is_ad_shielded_user() {
     559    if (!function_exists('is_user_logged_in') || !is_user_logged_in()) {
     560        return false;
     561    }
     562
     563    // Strict validation checks for Administrator or Editor roles / capabilities
     564    $is_shielded = (
     565        current_user_can('administrator') ||
     566        current_user_can('manage_options') ||
     567        current_user_can('editor') ||
     568        current_user_can('edit_others_posts')
     569    );
     570
     571    /**
     572     * Filter whether the current user should be shielded from live AdSense ads.
     573     *
     574     * @param bool $is_shielded
     575     */
     576    return (bool) apply_filters('nexversal_is_ad_shielded_user', $is_shielded);
     577}
     578
     579/**
     580 * Production-grade WordPress PHP wrapper function to conditionalize Google AdSense code output within theme templates.
     581 *
     582 * Implements strict user validation checks using current_user_can('administrator') and editor checks.
     583 * - Authenticated administrators & editors: Intercepts real AdSense publisher scripts and replaces
     584 *   them entirely with a safe local HTML placeholder block containing developer diagnostics,
     585 *   or maps them to Google's official demo test ad parameters (data-ad-test="on").
     586 * - Standard web visitors: Outputs genuine production ad code completely unmodified.
     587 *
     588 * @param string $raw_ad_code Raw ad snippet or AdSense script/ins tags.
     589 * @param string $slot        Optional slot slug (e.g. 'header', 'article', 'post_bottom', 'infeed', 'sidebar').
     590 * @param string $slot_name   Optional human-readable slot name (e.g. 'Header Leaderboard').
     591 * @param string $mode        Optional mode override: 'placeholder' (default) or 'test_ad'.
     592 * @return string Genuine production ad code for visitors, or safe developer diagnostic block for admin/editor.
     593 */
     594function nexversal_wrap_adsense_code($raw_ad_code, $slot = '', $slot_name = '', $mode = '') {
     595    if (empty(trim($raw_ad_code))) {
     596        return '';
     597    }
     598
     599    // 1. Strict user validation: Standard visitors always get genuine unmodified production ad code
     600    if (!nexversal_is_ad_shielded_user()) {
     601        return $raw_ad_code;
     602    }
     603
     604    // 2. Resolve shielding mode ('placeholder' by default, or 'test_ad')
     605    if (empty($mode)) {
     606        /**
     607         * Filter to toggle between safe local HTML placeholder block or Google official demo test ads.
     608         *
     609         * @param string $mode 'placeholder' (default) or 'test_ad'
     610         * @param string $slot Ad slot slug
     611         */
     612        $mode = (string) apply_filters('nexversal_adsense_shield_mode', 'placeholder', $slot);
     613    }
     614
     615    // 3. Option B: Map to Google's Official Demo Test Ad Slot Parameters (data-ad-test="on")
     616    if ($mode === 'test_ad') {
     617        if (stripos($raw_ad_code, 'adsbygoogle') !== false) {
     618            if (stripos($raw_ad_code, 'data-ad-test') === false) {
     619                $test_code = preg_replace('/<ins\b([^>]*)>/i', '<ins$1 data-ad-test="on">', $raw_ad_code);
     620                if (!empty($test_code)) {
     621                    return "<!-- [AdSense Shield] Google Official Demo Test Ad Active (data-ad-test=\"on\") -->\n" . $test_code;
     622                }
     623            }
     624        }
     625        return $raw_ad_code;
     626    }
     627
     628    // 4. Option A (Default): Safe Local HTML Placeholder Block with Developer Diagnostics
     629    // Extract metadata from the raw ad code for diagnostics
     630    $detected_pub = '';
     631    if (preg_match('/(?:client|data-ad-client)=["\'](ca-pub-[0-9]+|pub-[0-9]+)["\']/i', $raw_ad_code, $m)) {
     632        $detected_pub = $m[1];
     633    } elseif (preg_match('/ca-pub-[0-9]+/i', $raw_ad_code, $m)) {
     634        $detected_pub = $m[0];
     635    }
     636
     637    $detected_slot_id = '';
     638    if (preg_match('/data-ad-slot=["\']([0-9]+)["\']/i', $raw_ad_code, $m)) {
     639        $detected_slot_id = $m[1];
     640    }
     641
     642    // Resolve human-friendly slot label
     643    if (empty($slot_name)) {
     644        if (!empty($slot) && function_exists('nexversal_get_ad_slot_specs')) {
     645            $specs = nexversal_get_ad_slot_specs($slot);
     646            $slot_name = !empty($specs['name']) ? $specs['name'] : ucfirst(str_replace('_', ' ', $slot));
     647        } else {
     648            $slot_name = !empty($slot) ? ucfirst(str_replace('_', ' ', $slot)) : __('Ad Placement', 'nexversal');
     649        }
     650    }
     651
     652    // Identify user role for diagnostic display
     653    $current_user = wp_get_current_user();
     654    $roles_list   = !empty($current_user->roles) ? implode(', ', array_map('ucfirst', $current_user->roles)) : 'Administrator';
     655
     656    ob_start();
     657    ?>
     658    <div class="nx-ad-admin-shield" data-shield-slot="<?php echo esc_attr($slot); ?>" role="region" aria-label="<?php echo esc_attr(sprintf(__('Ad Slot: %s - Hidden for Admin', 'nexversal'), $slot_name)); ?>">
     659        <div class="nx-shield-inner">
     660            <div class="nx-shield-header">
     661                <div class="nx-shield-title">
     662                    <svg class="nx-shield-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
     663                        <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
     664                        <path d="m9 12 2 2 4-4"/>
     665                    </svg>
     666                    <span><strong>Ad Slot Active:</strong> <?php echo esc_html($slot_name); ?></span>
     667                </div>
     668                <span class="nx-shield-badge"><?php esc_html_e('ADMIN SHIELD ACTIVE', 'nexversal'); ?></span>
     669            </div>
     670            <p class="nx-shield-desc">
     671                <?php esc_html_e('Hidden for Admin to Prevent Invalid Clicks & AdSense Policy Violations. Standard visitors receive genuine production ads.', 'nexversal'); ?>
     672            </p>
     673            <div class="nx-shield-meta">
     674                <span class="nx-shield-chip"><strong>Role:</strong> <?php echo esc_html($roles_list); ?></span>
     675                <?php if (!empty($detected_pub)) : ?>
     676                    <span class="nx-shield-chip"><strong>Client:</strong> <?php echo esc_html($detected_pub); ?></span>
     677                <?php endif; ?>
     678                <?php if (!empty($detected_slot_id)) : ?>
     679                    <span class="nx-shield-chip"><strong>Slot ID:</strong> <?php echo esc_html($detected_slot_id); ?></span>
     680                <?php endif; ?>
     681                <span class="nx-shield-chip nx-shield-chip-status">&#10003; 0 External Ad Requests</span>
     682            </div>
     683        </div>
     684    </div>
     685    <?php
     686    return trim(ob_get_clean());
     687}
     688
     689/**
     690 * Output Google AdSense Auto-Ads script in head if Publisher ID is entered
     691 * Intercepted strictly with type="text/plain" until GDPR cookie consent is verified.
     692 * Suppressed completely for authenticated administrators and editors to prevent invalid traffic.
     693 */
     694function nexversal_render_adsense_auto_script() {
     695    $pub_id = get_theme_mod('nexversal_adsense_pub_id', '');
     696    if (!empty($pub_id)) {
     697        // Suppress Auto-Ads if current singular post has disabled ads via Monetization Controls
     698        if (is_singular() && function_exists('nexversal_is_ad_disabled_for_post') && nexversal_is_ad_disabled_for_post()) {
     699            echo "<!-- [AdSense Shield] Auto Ads script suppressed for post #" . esc_attr(get_the_ID()) . " via Monetization Controls -->\n";
     700            return;
     701        }
     702
     703        // Prevent Auto-Ads execution for logged-in Administrator/Editor
     704        if (function_exists('nexversal_is_ad_shielded_user') && nexversal_is_ad_shielded_user()) {
     705            echo "<!-- [AdSense Shield] Auto Ads script suppressed for logged-in Administrator/Editor to prevent invalid clicks and policy violations -->\n";
     706            return;
     707        }
     708
     709        $pub_id = trim($pub_id);
     710        // Guarantee ca-pub- prefix
     711        if (strpos($pub_id, 'ca-pub-') === false && strpos($pub_id, 'pub-') === 0) {
     712            $pub_id = 'ca-' . $pub_id;
     713        } elseif (strpos($pub_id, 'ca-pub-') === false) {
     714            $pub_id = 'ca-pub-' . $pub_id;
     715        }
     716
     717        $script_src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=' . esc_attr($pub_id);
     718
     719        // Strict Free Plan Limit: Instruct Google crawler to cap Auto Ads to max 3 on Free version
     720        $is_pro       = nexversal_is_pro_active();
     721        $max_ads_attr = !$is_pro ? ' data-max-ads-per-page="3"' : '';
     722
     723        if (function_exists('nexversal_has_cookie_consent') && !nexversal_has_cookie_consent()) {
     724            ?>
     725            <!-- Google AdSense 1-Click Auto Ads (GDPR Intercepted: Inert Until Consent Granted<?php echo !$is_pro ? ' | Free Plan Max 3 Ads' : ''; ?>) -->
     726            <script type="text/plain" data-nx-consent="adsense" data-src="<?php echo esc_url($script_src); ?>"<?php echo $max_ads_attr; ?> async crossorigin="anonymous"></script>
     727            <?php
     728        } else {
     729            ?>
     730            <!-- Google AdSense 1-Click Auto Ads (Active<?php echo !$is_pro ? ' | Free Plan Max 3 Ads' : ''; ?>) -->
     731            <script async src="<?php echo esc_url($script_src); ?>"<?php echo $max_ads_attr; ?> crossorigin="anonymous"></script>
     732            <?php
     733        }
     734    }
     735}
     736add_action('wp_head', 'nexversal_render_adsense_auto_script', 5);
     737
     738/**
     739 * Render the Appearance > Nexversal PRO Admin Page (v3.5.0)
    184740 */
    185741function nexversal_pro_admin_page() {
    … …  
    188744    $plan_name    = get_option('nexversal_pro_license_plan', 'Nexversal PRO ($15/year)');
    189745    $activated_at = get_option('nexversal_pro_license_activated_at', '');
     746    $stats        = get_option('nexversal_ad_analytics', array());
     747
     748    $total_imp    = isset($stats['total']['impressions']) ? (int) $stats['total']['impressions'] : 0;
     749    $total_clicks = isset($stats['total']['clicks']) ? (int) $stats['total']['clicks'] : 0;
     750    $total_ctr    = $total_imp > 0 ? round(($total_clicks / $total_imp) * 100, 2) : 0;
     751    $active_slots = nexversal_count_active_ad_slots();
    190752    ?>
    191     <div class="wrap" style="max-width: 900px; margin: 30px auto; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
     753    <div class="wrap" style="max-width: 1050px; margin: 25px auto; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
    192754       
    193755        <?php if (isset($_GET['activated'])) : ?>
    194756            <div class="notice notice-success is-dismissible" style="padding: 14px 18px; border-radius: 6px; border-left-color: #10b981;">
    195                 <p style="font-size: 14px; margin: 0;"><strong>🎉 <?php esc_html_e('Nexversal PRO Activated Successfully! All 5 Ad Slots & Monetization features are now unlocked.', 'nexversal'); ?></strong></p>
     757                <p style="font-size: 14px; margin: 0;"><strong>🎉 <?php esc_html_e('Nexversal PRO Activated Successfully! Unlimited ad slots, Ad-Blocker Bypass, and real-time Analytics are now unlocked.', 'nexversal'); ?></strong></p>
    196758            </div>
    197759        <?php elseif (isset($_GET['error']) && $_GET['error'] === 'invalid_key') : ?>
    198760            <div class="notice notice-error is-dismissible" style="padding: 14px 18px; border-radius: 6px;">
    199                 <p style="font-size: 14px; margin: 0;"><strong>❌ <?php esc_html_e('Invalid License Key. Please enter the valid key received from Lemon Squeezy after purchasing the $15/year plan.', 'nexversal'); ?></strong></p>
     761                <p style="font-size: 14px; margin: 0;"><strong>❌ <?php esc_html_e('Invalid License Key. Please enter the valid key received from Lemon Squeezy ($15/year).', 'nexversal'); ?></strong></p>
    200762            </div>
    201763        <?php elseif (isset($_GET['deactivated'])) : ?>
    202764            <div class="notice notice-info is-dismissible" style="padding: 14px 18px; border-radius: 6px;">
    203                 <p style="font-size: 14px; margin: 0;"><?php esc_html_e('Nexversal PRO License has been deactivated.', 'nexversal'); ?></p>
     765                <p style="font-size: 14px; margin: 0;"><?php esc_html_e('Nexversal PRO License has been deactivated. Free Ad Engine (up to 3 ads) remains active.', 'nexversal'); ?></p>
    204766            </div>
    205767        <?php elseif (isset($_GET['url_saved'])) : ?>
    206768            <div class="notice notice-success is-dismissible" style="padding: 14px 18px; border-radius: 6px; border-left-color: #10b981;">
    207                 <p style="font-size: 14px; margin: 0;"><strong>✓ <?php esc_html_e('Lemon Squeezy Checkout URL updated successfully! All buttons now link to your live checkout.', 'nexversal'); ?></strong></p>
     769                <p style="font-size: 14px; margin: 0;"><strong>✓ <?php esc_html_e('Lemon Squeezy Checkout URL updated successfully!', 'nexversal'); ?></strong></p>
     770            </div>
     771        <?php elseif (isset($_GET['stats_reset'])) : ?>
     772            <div class="notice notice-success is-dismissible" style="padding: 14px 18px; border-radius: 6px; border-left-color: #10b981;">
     773                <p style="font-size: 14px; margin: 0;"><?php esc_html_e('Ad Analytics statistics have been reset.', 'nexversal'); ?></p>
     774            </div>
     775        <?php elseif (isset($_GET['ads_txt_saved'])) : ?>
     776            <div class="notice notice-success is-dismissible" style="padding: 14px 18px; border-radius: 6px; border-left-color: #10b981;">
     777                <p style="font-size: 14px; margin: 0;"><strong>✓ <?php esc_html_e('ads.txt updated successfully! Served dynamically at /ads.txt without cPanel file editing.', 'nexversal'); ?></strong></p>
    208778            </div>
    209779        <?php endif; ?>
    210780
    211781        <!-- Brand Header Card -->
    212         <div style="background: linear-gradient(135deg, #1e1b4b 0%, #0f172a 100%); color: #fff; padding: 36px 40px; border-radius: 12px; box-shadow: 0 10px 25px rgba(0,0,0,0.15); margin-bottom: 28px;">
     782        <div style="background: linear-gradient(135deg, #090d16 0%, #1e1b4b 60%, #312e81 100%); color: #fff; padding: 36px 40px; border-radius: 14px; box-shadow: 0 10px 30px rgba(0,0,0,0.25); margin-bottom: 28px;">
    213783            <div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px;">
    214784                <div>
    215                     <span style="display: inline-block; background: rgba(99, 102, 241, 0.3); border: 1px solid rgba(165, 180, 252, 0.4); color: #c7d2fe; font-size: 11px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; padding: 4px 12px; border-radius: 999px; margin-bottom: 12px;">
    216                         Lemon Squeezy Verified • $15 / Year
     785                    <span style="display: inline-block; background: rgba(99, 102, 241, 0.35); border: 1px solid rgba(165, 180, 252, 0.4); color: #c7d2fe; font-size: 11px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; padding: 4px 12px; border-radius: 999px; margin-bottom: 12px;">
     786                        Version 3.5.0 • Monetization Engine
    217787                    </span>
    218788                    <h1 style="font-size: 28px; font-weight: 900; margin: 0 0 8px 0; color: #fff; letter-spacing: -0.02em;">
    219                         Nexversal PRO — Ad & Monetization Engine
     789                        Nexversal Monetization & Ad Suite
    220790                    </h1>
    221                     <p style="font-size: 15px; color: #cbd5e1; margin: 0; line-height: 1.6; max-width: 580px;">
    222                         Built-in AdSense, In-Article & Sticky Sidebar Ad Engine. Save $50/year on external ad plugins while maximizing organic blog earnings.
     791                    <p style="font-size: 14.5px; color: #cbd5e1; margin: 0; line-height: 1.6; max-width: 620px;">
     792                        Free Plan allows <strong>up to 3 simultaneous ads</strong> with automatic location detection. PRO Plan ($15/yr) unlocks <strong>unlimited simultaneous ads</strong>, Ad-Blocker Bypass, and CTR analytics.
    223793                    </p>
    224794                </div>
    225795                <div style="text-align: right;">
    226796                    <?php if ($is_active) : ?>
    227                         <div style="background: #10b981; color: #fff; font-size: 14px; font-weight: 800; padding: 8px 18px; border-radius: 999px; display: inline-flex; align-items: center; gap: 6px; box-shadow: 0 4px 12px rgba(16,185,129,0.35);">
    228                             <span>✓</span> <?php esc_html_e('PRO Plan Active', 'nexversal'); ?>
     797                        <div style="background: #10b981; color: #fff; font-size: 14px; font-weight: 800; padding: 8px 18px; border-radius: 999px; display: inline-flex; align-items: center; gap: 6px; box-shadow: 0 4px 14px rgba(16,185,129,0.4);">
     798                            <span>✓</span> <?php esc_html_e('PRO Plan Active (Unlimited Ads)', 'nexversal'); ?>
    229799                        </div>
    230800                    <?php else : ?>
    231                         <div style="background: #ef4444; color: #fff; font-size: 13px; font-weight: 800; padding: 6px 14px; border-radius: 999px; display: inline-flex; align-items: center; gap: 6px;">
    232                             <span>🔒</span> <?php esc_html_e('PRO Locked (Free Plan)', 'nexversal'); ?>
     801                        <div style="background: rgba(255, 255, 255, 0.12); color: #cbd5e1; font-size: 13px; font-weight: 700; padding: 6px 14px; border-radius: 999px; display: inline-flex; align-items: center; gap: 6px; border: 1px solid rgba(255,255,255,0.2);">
     802                            <span>⚡</span> <?php printf(esc_html__('Free Plan: %d of 3 Slots Active', 'nexversal'), esc_html($active_slots)); ?>
    233803                        </div>
    234804                    <?php endif; ?>
    … …  
    237807        </div>
    238808
     809        <!-- 3-Column Plan Breakdown -->
     810        <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; margin-bottom: 28px;">
     811            <div style="background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 22px; box-shadow: 0 2px 6px rgba(0,0,0,0.03);">
     812                <span style="font-size: 11px; font-weight: 800; color: #10b981; background: #ecfdf5; padding: 3px 8px; border-radius: 6px; text-transform: uppercase;">Free Plan (Lifetime)</span>
     813                <h3 style="font-size: 17px; font-weight: 800; margin: 10px 0 6px 0; color: #0f172a;">Run 3 Active Ads</h3>
     814                <p style="font-size: 13px; color: #64748b; line-height: 1.5; margin: 0;">Run any 3 ads of your choice (Header, In-Article, Bottom, Sidebar, or Grid). Includes 1-click Google Auto Ads and automatic country detection.</p>
     815            </div>
     816            <div style="background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 22px; box-shadow: 0 2px 6px rgba(0,0,0,0.03);">
     817                <span style="font-size: 11px; font-weight: 800; color: #8b5cf6; background: #f3e8ff; padding: 3px 8px; border-radius: 6px; text-transform: uppercase;">PRO Feature</span>
     818                <h3 style="font-size: 17px; font-weight: 800; margin: 10px 0 6px 0; color: #0f172a;">Ad-Blocker Bypass</h3>
     819                <p style="font-size: 13px; color: #64748b; line-height: 1.5; margin: 0;">Detects active ad blockers and replaces blank space with custom affiliate banners or sponsor notices that ad blockers cannot touch.</p>
     820            </div>
     821            <div style="background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 22px; box-shadow: 0 2px 6px rgba(0,0,0,0.03);">
     822                <span style="font-size: 11px; font-weight: 800; color: #4f46e5; background: #eef2ff; padding: 3px 8px; border-radius: 6px; text-transform: uppercase;">PRO Feature</span>
     823                <h3 style="font-size: 17px; font-weight: 800; margin: 10px 0 6px 0; color: #0f172a;">Unlimited Ads & Analytics</h3>
     824                <p style="font-size: 13px; color: #64748b; line-height: 1.5; margin: 0;">Run 4, 5 or all slots at the same time without limits. Track real-time impressions, clicks, and CTR % to maximize blog revenue.</p>
     825            </div>
     826        </div>
     827
     828        <!-- Real-Time Monetization Analytics Dashboard -->
     829        <div style="background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 28px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05); margin-bottom: 28px;">
     830            <div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px; margin-bottom: 20px;">
     831                <div>
     832                    <h3 style="font-size: 18px; font-weight: 800; margin: 0 0 4px 0; color: #0f172a;">
     833                        📊 <?php esc_html_e('Ad Performance & CTR Analytics', 'nexversal'); ?>
     834                        <?php if (!$is_active) : ?>
     835                            <span style="font-size: 11px; font-weight: 800; color: #6366f1; background: #eef2ff; padding: 2px 8px; border-radius: 4px; vertical-align: middle; margin-left: 6px;">PRO Preview</span>
     836                        <?php endif; ?>
     837                    </h3>
     838                    <p style="font-size: 13px; color: #64748b; margin: 0;">
     839                        <?php esc_html_e('Real-time tracking of impressions, clicks, click-through rates (CTR), and visitor countries.', 'nexversal'); ?>
     840                    </p>
     841                </div>
     842                <div>
     843                    <form method="post" action="" style="display: inline-block;">
     844                        <?php wp_nonce_field('nexversal_license_action', 'nexversal_license_nonce'); ?>
     845                        <input type="submit" name="nexversal_reset_ad_stats" class="button" value="<?php esc_attr_e('Reset Stats', 'nexversal'); ?>" onclick="return confirm('<?php echo esc_js(__('Are you sure you want to reset all ad statistics?', 'nexversal')); ?>');" style="font-size: 12px;">
     846                    </form>
     847                    <a href="<?php echo esc_url(admin_url('customize.php?autofocus[section]=nexversal_monetization')); ?>" class="button button-primary" style="background: #4f46e5; border-color: #4f46e5; font-size: 12px; padding: 0 14px; height: 30px; line-height: 28px; margin-left: 6px;">
     848                        <?php esc_html_e('Configure Ads in Customizer ➔', 'nexversal'); ?>
     849                    </a>
     850                </div>
     851            </div>
     852
     853            <!-- Stats KPI Cards -->
     854            <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin-bottom: 24px;">
     855                <div style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 10px; padding: 18px;">
     856                    <div style="font-size: 12px; font-weight: 700; color: #64748b; text-transform: uppercase;"><?php esc_html_e('Total Impressions', 'nexversal'); ?></div>
     857                    <div style="font-size: 26px; font-weight: 900; color: #0f172a; margin-top: 4px;"><?php echo number_format_i18n($total_imp); ?></div>
     858                </div>
     859                <div style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 10px; padding: 18px;">
     860                    <div style="font-size: 12px; font-weight: 700; color: #64748b; text-transform: uppercase;"><?php esc_html_e('Total Clicks', 'nexversal'); ?></div>
     861                    <div style="font-size: 26px; font-weight: 900; color: #4f46e5; margin-top: 4px;"><?php echo number_format_i18n($total_clicks); ?></div>
     862                </div>
     863                <div style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 10px; padding: 18px;">
     864                    <div style="font-size: 12px; font-weight: 700; color: #64748b; text-transform: uppercase;"><?php esc_html_e('Avg. Click-Through Rate (CTR)', 'nexversal'); ?></div>
     865                    <div style="font-size: 26px; font-weight: 900; color: #10b981; margin-top: 4px;"><?php echo esc_html($total_ctr); ?>%</div>
     866                </div>
     867            </div>
     868
     869            <!-- Slot Breakdown Table -->
     870            <table class="widefat striped" style="border: 1px solid #e2e8f0; border-radius: 8px; overflow: hidden;">
     871                <thead>
     872                    <tr>
     873                        <th style="padding: 10px 14px; font-weight: 700;"><?php esc_html_e('Ad Slot', 'nexversal'); ?></th>
     874                        <th style="padding: 10px 14px; font-weight: 700;"><?php esc_html_e('Impressions', 'nexversal'); ?></th>
     875                        <th style="padding: 10px 14px; font-weight: 700;"><?php esc_html_e('Clicks', 'nexversal'); ?></th>
     876                        <th style="padding: 10px 14px; font-weight: 700;"><?php esc_html_e('CTR %', 'nexversal'); ?></th>
     877                    </tr>
     878                </thead>
     879                <tbody>
     880                    <?php
     881                    $slots = array(
     882                        'header'      => __('Header Banner (728x90)', 'nexversal'),
     883                        'article'     => __('In-Article Mid-Content', 'nexversal'),
     884                        'post_bottom' => __('Below Post Content', 'nexversal'),
     885                        'infeed'      => __('Homepage In-Feed Grid', 'nexversal'),
     886                        'sidebar'     => __('Sticky Sidebar', 'nexversal'),
     887                    );
     888                    foreach ($slots as $s_key => $s_name) :
     889                        $s_imp    = isset($stats['slots'][$s_key]['impressions']) ? (int) $stats['slots'][$s_key]['impressions'] : 0;
     890                        $s_clicks = isset($stats['slots'][$s_key]['clicks']) ? (int) $stats['slots'][$s_key]['clicks'] : 0;
     891                        $s_ctr    = $s_imp > 0 ? round(($s_clicks / $s_imp) * 100, 2) : 0;
     892                        ?>
     893                        <tr>
     894                            <td style="padding: 10px 14px; font-weight: 600; color: #1e293b;"><?php echo esc_html($s_name); ?></td>
     895                            <td style="padding: 10px 14px;"><?php echo number_format_i18n($s_imp); ?></td>
     896                            <td style="padding: 10px 14px;"><?php echo number_format_i18n($s_clicks); ?></td>
     897                            <td style="padding: 10px 14px;"><span style="background: #eef2ff; color: #4f46e5; font-weight: 700; padding: 2px 6px; border-radius: 4px;"><?php echo esc_html($s_ctr); ?>%</span></td>
     898                        </tr>
     899                    <?php endforeach; ?>
     900                </tbody>
     901            </table>
     902        </div>
     903
     904        <!-- License Management & Upsell Box -->
    239905        <div style="display: grid; grid-template-columns: 1.25fr 1fr; gap: 24px; align-items: start;">
    240906           
    … …  
    242908            <div style="background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 30px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05);">
    243909                <h3 style="font-size: 18px; font-weight: 800; margin-top: 0; margin-bottom: 14px; color: #0f172a;">
    244                     <?php esc_html_e('License Key Activation', 'nexversal'); ?>
     910                    <?php esc_html_e('PRO License Activation', 'nexversal'); ?>
    245911                </h3>
    246912
    … …  
    264930                        <input type="submit" name="nexversal_deactivate_license" class="button" value="<?php esc_attr_e('Deactivate License', 'nexversal'); ?>" onclick="return confirm('<?php echo esc_js(__('Are you sure you want to deactivate your PRO license?', 'nexversal')); ?>');" style="color: #b91c1c; border-color: #fca5a5;">
    265931                        <a href="<?php echo esc_url(admin_url('customize.php?autofocus[section]=nexversal_monetization')); ?>" class="button button-primary" style="margin-left: 10px; background: #4f46e5; border-color: #4f46e5; height: auto; padding: 4px 14px;">
    266                             <?php esc_html_e('Manage Ad Slots in Customizer ➔', 'nexversal'); ?>
     932                            <?php esc_html_e('Configure Ads in Customizer ➔', 'nexversal'); ?>
    267933                        </a>
    268934                    </form>
    … …  
    270936                <?php else : ?>
    271937                    <p style="font-size: 14px; color: #64748b; line-height: 1.6; margin-bottom: 20px;">
    272                         <?php esc_html_e('Purchase your license via Lemon Squeezy ($15/year) to automatically receive your instant license key.', 'nexversal'); ?>
     938                        <?php esc_html_e('Upgrade to PRO ($15/year) to unlock unlimited simultaneous ads, Ad-Blocker Bypass, and real-time analytics.', 'nexversal'); ?>
    273939                    </p>
    274940
    … …  
    303969                </h4>
    304970                <ul style="margin: 0 0 20px 0; padding-left: 0; list-style: none; font-size: 13.5px; color: #334155; line-height: 1.85;">
    305                     <li>✓ <strong>Auto In-Article AdSense:</strong> Automatically inserts after paragraph 3</li>
    306                     <li>✓ <strong>Sticky Sidebar Ad (300×600):</strong> Floating ad as user scrolls down</li>
    307                     <li>✓ <strong>In-Feed Post Grid Ad:</strong> Blends natively into your articles grid</li>
    308                     <li>✓ <strong>Header 728×90 Leaderboard:</strong> High-impact top banner visibility</li>
    309                     <li>✓ <strong>Post Bottom Banner:</strong> Captures readers right when finishing reading</li>
     971                    <li>✓ <strong>Unlimited Active Ads:</strong> Run all 5 ad placements at the same time</li>
     972                    <li>✓ <strong>Ad-Blocker Bypass:</strong> Forces fallback banners when AdSense is blocked</li>
     973                    <li>✓ <strong>Automatic Geo-Targeting:</strong> Visitors see ads based on real-time location</li>
     974                    <li>✓ <strong>CTR Analytics:</strong> Live impressions, clicks & conversion tracking</li>
    310975                    <li>✓ <strong>Google Policy Compliant:</strong> Auto "Advertisement" label</li>
    311976                    <li>✓ <strong>Save $50/Year:</strong> Zero external ad plugins required</li>
    … …  
    3351000            </form>
    3361001        </div>
     1002
     1003        <!-- Automated Virtual ads.txt Manager -->
     1004        <div style="margin-top: 28px; background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 26px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05);">
     1005            <div style="display: flex; justify-content: space-between; align-items: flex-start; flex-wrap: wrap; gap: 12px; margin-bottom: 12px;">
     1006                <div>
     1007                    <h3 style="margin: 0 0 6px 0; font-size: 17px; font-weight: 800; color: #0f172a; display: flex; align-items: center; gap: 8px;">
     1008                        <span>📄</span> <?php esc_html_e('Automated Ads.txt Manager', 'nexversal'); ?>
     1009                        <span style="font-size: 11px; font-weight: 700; background: #ecfdf5; color: #059669; border: 1px solid #a7f3d0; padding: 3px 8px; border-radius: 20px;">
     1010                            <?php esc_html_e('Virtual Engine Active', 'nexversal'); ?>
     1011                        </span>
     1012                    </h3>
     1013                    <p style="font-size: 13.5px; color: #64748b; margin: 0; line-height: 1.5;">
     1014                        <?php esc_html_e('Declare your authorized digital ad sellers (Google AdSense, AdX, Magnite, PubMatic). Served dynamically at your domain root with proper text/plain headers — zero cPanel file creation needed!', 'nexversal'); ?>
     1015                    </p>
     1016                </div>
     1017                <div>
     1018                    <a href="<?php echo esc_url(home_url('/ads.txt')); ?>" target="_blank" rel="noopener noreferrer" class="button" style="display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600;">
     1019                        <span>🔗</span> <?php esc_html_e('View Live ads.txt', 'nexversal'); ?> ↗
     1020                    </a>
     1021                </div>
     1022            </div>
     1023
     1024            <?php
     1025            $has_physical_file = file_exists(ABSPATH . 'ads.txt');
     1026            if ($has_physical_file) :
     1027            ?>
     1028                <div style="background: #fffbeb; border: 1px solid #fde68a; border-radius: 8px; padding: 12px 16px; margin-bottom: 18px; font-size: 13px; color: #92400e; display: flex; align-items: center; gap: 10px;">
     1029                    <span style="font-size: 18px;">⚠️</span>
     1030                    <div>
     1031                        <strong><?php esc_html_e('Physical ads.txt file detected on your server root (cPanel/public_html):', 'nexversal'); ?></strong><br>
     1032                        <?php esc_html_e('In Apache/cPanel, a physical file on disk takes priority over virtual dynamic URLs. If you want this dashboard to manage your ads.txt dynamically, please delete or rename the physical ads.txt file in cPanel File Manager.', 'nexversal'); ?>
     1033                    </div>
     1034                </div>
     1035            <?php else : ?>
     1036                <div style="background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 8px; padding: 10px 14px; margin-bottom: 18px; font-size: 12.5px; color: #166534; display: flex; align-items: center; gap: 8px;">
     1037                    <span>✓</span>
     1038                    <span><strong><?php esc_html_e('Zero cPanel File Editing:', 'nexversal'); ?></strong> <?php esc_html_e('No physical file exists on disk. Requests to /ads.txt are intercepted dynamically by the theme and served from your database with optimal caching and 200 OK headers.', 'nexversal'); ?></span>
     1039                </div>
     1040            <?php endif; ?>
     1041
     1042            <form method="post" action="">
     1043                <?php wp_nonce_field('nexversal_ads_txt_action', 'nexversal_ads_txt_nonce'); ?>
     1044               
     1045                <div style="margin-bottom: 14px;">
     1046                    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; flex-wrap: wrap; gap: 8px;">
     1047                        <label for="nexversal_ads_txt_content" style="font-size: 13px; font-weight: 700; color: #334155;">
     1048                            <?php esc_html_e('ads.txt Records (IAB Tech Lab Format):', 'nexversal'); ?>
     1049                        </label>
     1050                        <button type="button" id="nx-insert-adsense-btn" class="button button-small" style="font-size: 11px;">
     1051                            + <?php esc_html_e('Insert Google AdSense Template', 'nexversal'); ?>
     1052                        </button>
     1053                    </div>
     1054
     1055                    <textarea id="nexversal_ads_txt_content" name="nexversal_ads_txt_content" rows="10" spellcheck="false" placeholder="# Example:&#10;google.com, pub-XXXXXXXXXXXXXXXX, DIRECT, f08c47fec0942fa0" style="width: 100%; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.6; background: #0f172a; color: #38bdf8; border: 1px solid #1e293b; border-radius: 8px; padding: 14px; box-sizing: border-box;"><?php echo esc_textarea(get_option('nexversal_ads_txt_content', '')); ?></textarea>
     1056                   
     1057                    <p style="font-size: 12px; color: #64748b; margin: 6px 0 0 0;">
     1058                        <?php esc_html_e('Format: <Domain>, <Publisher ID>, <Relationship (DIRECT|RESELLER)>, <Certification Authority ID (Optional)>. Comments start with #.', 'nexversal'); ?>
     1059                    </p>
     1060                </div>
     1061
     1062                <div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px;">
     1063                    <input type="submit" name="nexversal_save_ads_txt" class="button button-primary" value="<?php esc_attr_e('Save & Deploy ads.txt', 'nexversal'); ?>" style="background: #4f46e5; border-color: #4f46e5; font-weight: 700; padding: 7px 22px; height: auto;">
     1064                    <span style="font-size: 12px; color: #94a3b8;">
     1065                        <?php
     1066                        $saved_ads  = get_option('nexversal_ads_txt_content', '');
     1067                        $line_count = !empty(trim($saved_ads)) ? count(array_filter(explode("\n", trim($saved_ads)))) : 0;
     1068                        printf(esc_html__('Currently deployed: %d active line(s)', 'nexversal'), $line_count);
     1069                        ?>
     1070                    </span>
     1071                </div>
     1072            </form>
     1073
     1074            <script>
     1075            document.addEventListener('DOMContentLoaded', function() {
     1076                var btn = document.getElementById('nx-insert-adsense-btn');
     1077                var txt = document.getElementById('nexversal_ads_txt_content');
     1078                if (btn && txt) {
     1079                    btn.addEventListener('click', function() {
     1080                        var snippet = "google.com, pub-XXXXXXXXXXXXXXXX, DIRECT, f08c47fec0942fa0\n";
     1081                        if (txt.value.indexOf('google.com') === -1) {
     1082                            txt.value = (txt.value.trim() ? txt.value.trim() + "\n" : "") + snippet;
     1083                        } else {
     1084                            alert('<?php echo esc_js(__('Google AdSense entry already present in editor.', 'nexversal')); ?>');
     1085                        }
     1086                    });
     1087                }
     1088            });
     1089            </script>
     1090        </div>
    3371091    </div>
    3381092    <?php
    … …  
    3401094
    3411095/**
    342  * Register Monetization & Ad Manager Section in WordPress Customizer
    343  *
    344  * CRITICAL RULE:
    345  * If the user has NOT activated PRO ($15/year), DO NOT SHOW ANY AD SLOTS OR INPUTS!
    346  * Show only the sleek PRO Lock Card.
     1096 * Register Monetization & Ad Manager Section in WordPress Customizer (v3.5.0)
     1097 *
     1098 * Beginner-Friendly & Clean UX:
     1099 * 1. Quick Setup (1-Click Google Auto-Ads)
     1100 * 2. Active Ads Plan Counter (Free: 3 Ads Limit | PRO: Unlimited)
     1101 * 3. Position Dropdown Selectors (Instead of manual numbers)
     1102 * 4. Automatic Geo-Targeting (Zero manual typing)
    3471103 */
    3481104function nexversal_ads_customize_register($wp_customize) {
    349     $is_pro = nexversal_is_pro_active();
    350 
    351     // Section title
    352     $section_title = $is_pro
    353         ? esc_html__('💰 Monetization & Ad Engine [PRO Active]', 'nexversal')
    354         : esc_html__('💰 Monetization & Ad Engine [PRO Locked]', 'nexversal');
    355 
    356     $section_desc = $is_pro
    357         ? esc_html__('Nexversal PRO is active! Configure your automated Google AdSense, in-article, and banner slots below.', 'nexversal')
    358         : esc_html__('🔒 PRO FEATURE ($15/year): Monetization & Ad Engine is locked. Upgrade to PRO to unlock automated in-article AdSense, sticky sidebar ads, and in-feed units.', 'nexversal');
     1105    $is_pro       = nexversal_is_pro_active();
     1106    $active_count = nexversal_count_active_ad_slots();
    3591107
    3601108    $wp_customize->add_section('nexversal_monetization', array(
    361         'title'       => $section_title,
    362         'description' => $section_desc,
     1109        'title'       => esc_html__('💰 Monetization & Ad Engine', 'nexversal'),
     1110        'description' => esc_html__('Manage your blog advertisements. Free plan allows up to 3 active ads with automatic country detection. PRO unlocks unlimited ads and Ad-Blocker bypass!', 'nexversal'),
    3631111        'priority'    => 28,
    3641112    ));
    3651113
    366     // =========================================================================
    367     // IF NOT PRO: SHOW ONLY PRO LOCK CARD AND STOP! NO AD INPUTS VISIBLE!
    368     // =========================================================================
    369     if (!$is_pro) {
    370         $wp_customize->add_setting('nexversal_pro_lock_info', array(
    371             'default'           => '',
    372             'sanitize_callback' => 'wp_kses_post',
    373         ));
    374 
    375         $lock_html = '
    376         <div style="background: #ffffff; border: 1px solid #e2e8f0; border-radius: 10px; padding: 22px 16px; text-align: center; margin-top: 8px; box-shadow: 0 4px 10px rgba(0,0,0,0.04);">
    377             <div style="font-size: 34px; margin-bottom: 8px;">🔒</div>
    378             <h4 style="margin: 0 0 8px 0; font-size: 16px; font-weight: 800; color: #0f172a;">
    379                 ' . esc_html__('Ad Engine is Locked in Free Plan', 'nexversal') . '
    380             </h4>
    381             <p style="font-size: 12.5px; color: #64748b; line-height: 1.55; margin-bottom: 18px;">
    382                 ' . esc_html__('Unlock 5 automated AdSense slots, in-article paragraph injection, and sticky sidebar monetization for just $15/year via Lemon Squeezy.', 'nexversal') . '
    383             </p>
    384             <a href="' . esc_url(nexversal_get_checkout_url()) . '" target="_blank" rel="noopener noreferrer" class="button button-primary" style="background: #10b981; border-color: #10b981; font-weight: 800; width: 100%; text-align: center; padding: 7px 0; height: auto; margin-bottom: 10px; box-shadow: 0 4px 10px rgba(16,185,129,0.3);">
    385                 ⚡ ' . esc_html__('Buy PRO Plan ($15/year)', 'nexversal') . '
    386             </a>
    387             <a href="' . esc_url(admin_url('themes.php?page=nexversal-pro')) . '" class="button" style="width: 100%; text-align: center; font-weight: 600; padding: 5px 0; height: auto;">
    388                 🔑 ' . esc_html__('Enter License Key', 'nexversal') . '
    389             </a>
    390         </div>';
    391 
    392         $wp_customize->add_control(new WP_Customize_Control($wp_customize, 'nexversal_pro_lock_info', array(
    393             'label'       => esc_html__('PRO Feature Required', 'nexversal'),
    394             'description' => $lock_html,
    395             'section'     => 'nexversal_monetization',
    396             'type'        => 'hidden',
    397         )));
    398 
    399         // Exit immediately so ZERO ad checkboxes or textareas are registered for free users!
    400         return;
    401     }
    402 
    403     // =========================================================================
    404     // ONLY REACHED IF PRO IS ACTIVE ($is_pro === true)
    405     // =========================================================================
    406 
    407     // Master Toggle
     1114    // Plan Status Badge
     1115    $status_badge_html = $is_pro
     1116        ? '<div style="background:#ecfdf5;border:1px solid #a7f3d0;color:#065f46;padding:10px 12px;border-radius:8px;font-size:12px;margin-bottom:12px;"><strong>✓ PRO Plan Active:</strong> Unlimited simultaneous ads unlocked!</div>'
     1117        : '<div style="background:#f8fafc;border:1px solid #cbd5e1;color:#1e293b;padding:10px 12px;border-radius:8px;font-size:12px;margin-bottom:12px;"><strong>⚡ Free Plan:</strong> Up to <strong>3 active ads</strong> allowed (Currently: <strong>' . intval($active_count) . '/3 Active</strong>).</div>';
     1118
     1119    $wp_customize->add_setting('nexversal_plan_status_info', array('default' => '', 'sanitize_callback' => 'wp_kses_post'));
     1120    $wp_customize->add_control(new WP_Customize_Control($wp_customize, 'nexversal_plan_status_info', array(
     1121        'label'       => '',
     1122        'description' => $status_badge_html,
     1123        'section'     => 'nexversal_monetization',
     1124        'type'        => 'hidden',
     1125    )));
     1126
     1127    // Master Switch
    4081128    $wp_customize->add_setting('nexversal_ads_enabled', array(
    4091129        'default'           => true,
    … …  
    4111131    ));
    4121132    $wp_customize->add_control('nexversal_ads_enabled', array(
    413         'label'       => esc_html__('Enable Built-in Ad Engine', 'nexversal'),
    414         'description' => esc_html__('Master switch to display or hide all theme ad placements.', 'nexversal'),
     1133        'label'       => esc_html__('Enable All Ads', 'nexversal'),
     1134        'description' => esc_html__('Turn this ON to display ads on your website.', 'nexversal'),
    4151135        'section'     => 'nexversal_monetization',
    4161136        'type'        => 'checkbox',
    4171137    ));
    4181138
    419     // Sponsored Label Toggle (Google AdSense Policy Compliance)
     1139    // Show Advertisement Label
    4201140    $wp_customize->add_setting('nexversal_ads_show_label', array(
    4211141        'default'           => true,
    … …  
    4241144    $wp_customize->add_control('nexversal_ads_show_label', array(
    4251145        'label'       => esc_html__('Show "Advertisement" Label', 'nexversal'),
    426         'description' => esc_html__('Recommended for Google AdSense & regulatory compliance.', 'nexversal'),
     1146        'description' => esc_html__('Required for Google AdSense compliance.', 'nexversal'),
    4271147        'section'     => 'nexversal_monetization',
    4281148        'type'        => 'checkbox',
    4291149    ));
    4301150
    431     // --- Slot 1: Header Leaderboard (Below Navigation) ---
     1151    // -------------------------------------------------------------------------
     1152    // 1-Click Shortcut: Google AdSense Publisher ID
     1153    // -------------------------------------------------------------------------
     1154    $wp_customize->add_setting('nexversal_adsense_pub_id', array(
     1155        'default'           => '',
     1156        'sanitize_callback' => 'sanitize_text_field',
     1157    ));
     1158    $wp_customize->add_control('nexversal_adsense_pub_id', array(
     1159        'label'       => esc_html__('⚡ 1-Click Google Auto-Ads (Optional Shortcut)', 'nexversal'),
     1160        'description' => esc_html__('Paste your AdSense Publisher ID (e.g. ca-pub-xxxxxxxxxxxxxxxx). Google will automatically run ads and auto-detect visitor country without configuring individual slots!', 'nexversal'),
     1161        'section'     => 'nexversal_monetization',
     1162        'type'        => 'text',
     1163        'input_attrs' => array('placeholder' => 'ca-pub-XXXXXXXXXXXXXXXX'),
     1164    ));
     1165
     1166    // Divider: Manual Slot Settings
     1167    $wp_customize->add_setting('nexversal_slots_heading', array('default' => '', 'sanitize_callback' => 'sanitize_text_field'));
     1168    $wp_customize->add_control(new WP_Customize_Control($wp_customize, 'nexversal_slots_heading', array(
     1169        'label'       => esc_html__('📍 Individual Ad Slots (Pick Your 3 Free Slots)', 'nexversal'),
     1170        'description' => esc_html__('Turn ON up to 3 slots for Free, or unlimited with PRO. Country targeting is automatic!', 'nexversal'),
     1171        'section'     => 'nexversal_monetization',
     1172        'type'        => 'hidden',
     1173    )));
     1174
     1175    // --- Slot 1: Header Banner (728x90) ---
    4321176    $wp_customize->add_setting('nexversal_ad_header_enabled', array(
    4331177        'default'           => false,
    … …  
    4351179    ));
    4361180    $wp_customize->add_control('nexversal_ad_header_enabled', array(
    437         'label'    => esc_html__('[Slot 1] Enable Header Banner Ad (728x90)', 'nexversal'),
     1181        'label'    => esc_html__('1. Top Header Banner (728x90)', 'nexversal'),
    4381182        'section'  => 'nexversal_monetization',
    4391183        'type'     => 'checkbox',
    … …  
    4441188    ));
    4451189    $wp_customize->add_control('nexversal_ad_header_code', array(
    446         'label'       => esc_html__('Header Ad Code / HTML / AdSense', 'nexversal'),
    447         'description' => esc_html__('Appears directly beneath the top header across all pages.', 'nexversal'),
     1190        'label'       => '',
     1191        'description' => esc_html__('Paste Top Header ad code / HTML / AdSense.', 'nexversal'),
    4481192        'section'     => 'nexversal_monetization',
    4491193        'type'        => 'textarea',
    450     ));
    451 
    452     // --- Slot 2: Auto In-Article Mid-Content Ad ---
     1194        'input_attrs' => array('rows' => 3, 'placeholder' => '<!-- Paste header ad code here -->'),
     1195    ));
     1196
     1197    // --- Slot 2: In-Article Mid-Content Ad (With Dropdown Menu) ---
    4531198    $wp_customize->add_setting('nexversal_ad_article_enabled', array(
    4541199        'default'           => false,
    … …  
    4561201    ));
    4571202    $wp_customize->add_control('nexversal_ad_article_enabled', array(
    458         'label'    => esc_html__('[Slot 2] Enable In-Article Mid-Content Ad', 'nexversal'),
     1203        'label'    => esc_html__('2. In-Article Content Ad', 'nexversal'),
    4591204        'section'  => 'nexversal_monetization',
    4601205        'type'     => 'checkbox',
    4611206    ));
    4621207    $wp_customize->add_setting('nexversal_ad_article_pos', array(
    463         'default'           => 3,
    464         'sanitize_callback' => 'absint',
     1208        'default'           => '3',
     1209        'sanitize_callback' => 'sanitize_text_field',
    4651210    ));
    4661211    $wp_customize->add_control('nexversal_ad_article_pos', array(
    467         'label'       => esc_html__('Insert after paragraph #', 'nexversal'),
    468         'description' => esc_html__('Default is after paragraph 3 (optimal viewability).', 'nexversal'),
     1212        'label'       => esc_html__('In-Article Ad Position (Dropdown)', 'nexversal'),
     1213        'description' => esc_html__('Choose where inside the article narrative to display the ad.', 'nexversal'),
    4691214        'section'     => 'nexversal_monetization',
    470         'type'        => 'number',
    471         'input_attrs' => array('min' => 1, 'max' => 20, 'step' => 1),
     1215        'type'        => 'select',
     1216        'choices'     => array(
     1217            '2'  => esc_html__('Early — After 2nd Paragraph', 'nexversal'),
     1218            '3'  => esc_html__('Optimal — After 3rd Paragraph (Recommended)', 'nexversal'),
     1219            '4'  => esc_html__('Midway — After 4th Paragraph', 'nexversal'),
     1220            '5'  => esc_html__('Deep — After 5th Paragraph', 'nexversal'),
     1221            '50' => esc_html__('Center — Exact Middle of Article (Auto)', 'nexversal'),
     1222        ),
    4721223    ));
    4731224    $wp_customize->add_setting('nexversal_ad_article_code', array(
    … …  
    4761227    ));
    4771228    $wp_customize->add_control('nexversal_ad_article_code', array(
    478         'label'       => esc_html__('In-Article Ad Code / AdSense', 'nexversal'),
    479         'description' => esc_html__('Automatically injected inside post body narrative.', 'nexversal'),
     1229        'label'       => '',
     1230        'description' => esc_html__('Paste in-article ad code / HTML.', 'nexversal'),
    4801231        'section'     => 'nexversal_monetization',
    4811232        'type'        => 'textarea',
     1233        'input_attrs' => array('rows' => 3, 'placeholder' => '<!-- Paste in-article ad code here -->'),
    4821234    ));
    4831235
    … …  
    4881240    ));
    4891241    $wp_customize->add_control('nexversal_ad_post_bottom_enabled', array(
    490         'label'    => esc_html__('[Slot 3] Enable Post Bottom Ad', 'nexversal'),
     1242        'label'    => esc_html__('3. Below Post Content Ad', 'nexversal'),
    4911243        'section'  => 'nexversal_monetization',
    4921244        'type'     => 'checkbox',
    … …  
    4971249    ));
    4981250    $wp_customize->add_control('nexversal_ad_post_bottom_code', array(
    499         'label'       => esc_html__('Post Bottom Ad Code', 'nexversal'),
    500         'description' => esc_html__('Appears right after post content before author box.', 'nexversal'),
     1251        'label'       => '',
     1252        'description' => esc_html__('Paste post bottom ad code / HTML.', 'nexversal'),
    5011253        'section'     => 'nexversal_monetization',
    5021254        'type'        => 'textarea',
    503     ));
    504 
    505     // --- Slot 4: Homepage In-Feed Ad (Between Cards) ---
     1255        'input_attrs' => array('rows' => 3, 'placeholder' => '<!-- Paste post bottom ad code here -->'),
     1256    ));
     1257
     1258    // --- Slot 4: Homepage In-Feed Ad (With Dropdown Menu) ---
    5061259    $wp_customize->add_setting('nexversal_ad_infeed_enabled', array(
    5071260        'default'           => false,
    … …  
    5091262    ));
    5101263    $wp_customize->add_control('nexversal_ad_infeed_enabled', array(
    511         'label'    => esc_html__('[Slot 4] Enable In-Feed Ad (Post Grid)', 'nexversal'),
     1264        'label'    => esc_html__('4. Homepage In-Feed Grid Ad', 'nexversal'),
    5121265        'section'  => 'nexversal_monetization',
    5131266        'type'     => 'checkbox',
    5141267    ));
    5151268    $wp_customize->add_setting('nexversal_ad_infeed_pos', array(
    516         'default'           => 3,
    517         'sanitize_callback' => 'absint',
     1269        'default'           => '3',
     1270        'sanitize_callback' => 'sanitize_text_field',
    5181271    ));
    5191272    $wp_customize->add_control('nexversal_ad_infeed_pos', array(
    520         'label'       => esc_html__('Display In-Feed Ad after card #', 'nexversal'),
    521         'description' => esc_html__('E.g., 3 means after the 3rd post card in the grid.', 'nexversal'),
     1273        'label'       => esc_html__('In-Feed Card Position (Dropdown)', 'nexversal'),
     1274        'description' => esc_html__('Choose after which article card to insert this ad.', 'nexversal'),
    5221275        'section'     => 'nexversal_monetization',
    523         'type'        => 'number',
    524         'input_attrs' => array('min' => 1, 'max' => 12, 'step' => 1),
     1276        'type'        => 'select',
     1277        'choices'     => array(
     1278            '2' => esc_html__('After 2nd Article Card', 'nexversal'),
     1279            '3' => esc_html__('After 3rd Article Card (Recommended)', 'nexversal'),
     1280            '4' => esc_html__('After 4th Article Card', 'nexversal'),
     1281            '6' => esc_html__('After 6th Article Card', 'nexversal'),
     1282        ),
    5251283    ));
    5261284    $wp_customize->add_setting('nexversal_ad_infeed_code', array(
    … …  
    5291287    ));
    5301288    $wp_customize->add_control('nexversal_ad_infeed_code', array(
    531         'label'       => esc_html__('In-Feed Ad Code / AdSense In-feed Unit', 'nexversal'),
     1289        'label'       => '',
     1290        'description' => esc_html__('Paste in-feed grid ad code / AdSense unit.', 'nexversal'),
    5321291        'section'     => 'nexversal_monetization',
    5331292        'type'        => 'textarea',
     1293        'input_attrs' => array('rows' => 3, 'placeholder' => '<!-- Paste in-feed ad code here -->'),
    5341294    ));
    5351295
    … …  
    5401300    ));
    5411301    $wp_customize->add_control('nexversal_ad_sidebar_enabled', array(
    542         'label'    => esc_html__('[Slot 5] Enable Sticky Sidebar Ad (300x250 / 300x600)', 'nexversal'),
     1302        'label'    => esc_html__('5. Sticky Sidebar Ad (300x250 / 300x600)', 'nexversal'),
    5431303        'section'  => 'nexversal_monetization',
    5441304        'type'     => 'checkbox',
    … …  
    5491309    ));
    5501310    $wp_customize->add_control('nexversal_ad_sidebar_code', array(
    551         'label'       => esc_html__('Sidebar Ad Code', 'nexversal'),
    552         'description' => esc_html__('Floats as user scrolls down the page in the sidebar.', 'nexversal'),
     1311        'label'       => '',
     1312        'description' => esc_html__('Paste sticky sidebar ad code.', 'nexversal'),
    5531313        'section'     => 'nexversal_monetization',
    5541314        'type'        => 'textarea',
    555     ));
     1315        'input_attrs' => array('rows' => 3, 'placeholder' => '<!-- Paste sidebar ad code here -->'),
     1316    ));
     1317
     1318    // -------------------------------------------------------------------------
     1319    // Global Worldwide Geo-Targeting & PRO Upsell Card
     1320    // -------------------------------------------------------------------------
     1321    $geo_info_html = '
     1322    <div style="background:linear-gradient(135deg, #f0fdf4 0%, #ecfdf5 100%);border:1px solid #a7f3d0;padding:12px 14px;border-radius:8px;font-size:12px;margin:12px 0 8px 0;line-height:1.45;">
     1323        <div style="display:flex;align-items:center;justify-content:space-between;gap:6px;font-weight:700;color:#065f46;margin-bottom:4px;">
     1324            <span style="font-size:12.5px;">🌍 ' . esc_html__('Global Smart Geo-Targeting', 'nexversal') . '</span>
     1325            <span style="font-size:10px;font-weight:700;background:#dcfce7;color:#15803d;border:1px solid #86efac;padding:1px 6px;border-radius:9999px;">AUTOMATIC</span>
     1326        </div>
     1327        <p style="margin:0 0 8px 0;color:#334155;font-size:11.5px;line-height:1.45;">
     1328            ' . esc_html__('Zero setup. Serves hyper-targeted, high-CPM ads to every visitor worldwide (195+ countries) in their local currency. Free plan is strictly capped at 3 ads.', 'nexversal') . '
     1329        </p>
     1330        <a href="' . esc_url(nexversal_get_checkout_url()) . '" target="_blank" rel="noopener noreferrer" style="display:inline-flex;align-items:center;gap:4px;font-weight:700;color:#4f46e5;text-decoration:none;font-size:11.5px;">
     1331            ⚡ ' . esc_html__('Upgrade to PRO for Unlimited Ads (/yr) →', 'nexversal') . '
     1332        </a>
     1333    </div>';
     1334
     1335    $wp_customize->add_setting('nexversal_auto_geo_info', array('default' => '', 'sanitize_callback' => 'wp_kses_post'));
     1336    $wp_customize->add_control(new WP_Customize_Control($wp_customize, 'nexversal_auto_geo_info', array(
     1337        'label'       => '',
     1338        'description' => $geo_info_html,
     1339        'section'     => 'nexversal_monetization',
     1340        'type'        => 'hidden',
     1341    )));
     1342
     1343    // -------------------------------------------------------------------------
     1344    // PRO Feature: Ad-Blocker Bypass
     1345    // -------------------------------------------------------------------------
     1346    $wp_customize->add_setting('nexversal_pro_adblock_heading', array('default' => '', 'sanitize_callback' => 'sanitize_text_field'));
     1347    $wp_customize->add_control(new WP_Customize_Control($wp_customize, 'nexversal_pro_adblock_heading', array(
     1348        'label'       => esc_html__('🛡️ PRO: Ad-Blocker Bypass Engine', 'nexversal'),
     1349        'description' => $is_pro
     1350            ? esc_html__('When an ad blocker (uBlock, AdBlock, Brave) blocks an ad, your fallback banner displays automatically!', 'nexversal')
     1351            : esc_html__('🔒 PRO FEATURE ($15/yr): Force ads and affiliate banners to show even when visitors use AdBlockers. Boosts earnings by 25-35%.', 'nexversal'),
     1352        'section'     => 'nexversal_monetization',
     1353        'type'        => 'hidden',
     1354    )));
     1355
     1356    if ($is_pro) {
     1357        $wp_customize->add_setting('nexversal_adblock_bypass_enabled', array(
     1358            'default'           => false,
     1359            'sanitize_callback' => 'nexversal_sanitize_checkbox',
     1360        ));
     1361        $wp_customize->add_control('nexversal_adblock_bypass_enabled', array(
     1362            'label'       => esc_html__('Enable Ad-Blocker Bypass', 'nexversal'),
     1363            'description' => esc_html__('Automatically render fallback message/banner when ads are blocked.', 'nexversal'),
     1364            'section'     => 'nexversal_monetization',
     1365            'type'        => 'checkbox',
     1366        ));
     1367
     1368        $wp_customize->add_setting('nexversal_adblock_fallback_code', array(
     1369            'default'           => '',
     1370            'sanitize_callback' => 'nexversal_sanitize_ad_code',
     1371        ));
     1372        $wp_customize->add_control('nexversal_adblock_fallback_code', array(
     1373            'label'       => esc_html__('Fallback Affiliate Banner / Custom Message HTML', 'nexversal'),
     1374            'description' => esc_html__('Enter custom HTML or an affiliate banner that AdBlockers cannot detect.', 'nexversal'),
     1375            'section'     => 'nexversal_monetization',
     1376            'type'        => 'textarea',
     1377            'input_attrs' => array('rows' => 3, 'placeholder' => '<!-- Paste fallback banner HTML or affiliate code here -->'),
     1378        ));
     1379    }
     1380
     1381    // Upgrade Callout if Free
     1382    if (!$is_pro) {
     1383        $wp_customize->add_setting('nexversal_pro_upgrade_banner', array('default' => '', 'sanitize_callback' => 'wp_kses_post'));
     1384        $upgrade_html = '
     1385        <div style="background: #f8fafc; border: 1px dashed #cbd5e1; border-radius: 8px; padding: 14px; text-align: center; margin-top: 14px;">
     1386            <div style="font-weight: 800; font-size: 13.5px; color: #0f172a; margin-bottom: 4px;">⚡ ' . esc_html__('Run More than 3 Ads? Get PRO!', 'nexversal') . '</div>
     1387            <p style="font-size: 12px; color: #64748b; line-height: 1.45; margin-bottom: 12px;">' . esc_html__('Free plan is capped at 3 simultaneous ads. Upgrade to PRO ($15/year) to run unlimited ads, unlock Ad-Blocker Bypass, and view live CTR analytics.', 'nexversal') . '</p>
     1388            <a href="' . esc_url(nexversal_get_checkout_url()) . '" target="_blank" rel="noopener noreferrer" class="button button-primary" style="background: #10b981; border-color: #10b981; width: 100%; font-weight: 800; text-align: center;">' . esc_html__('Unlock Unlimited Ads ($15/yr) ➔', 'nexversal') . '</a>
     1389        </div>';
     1390
     1391        $wp_customize->add_control(new WP_Customize_Control($wp_customize, 'nexversal_pro_upgrade_banner', array(
     1392            'label'       => '',
     1393            'description' => $upgrade_html,
     1394            'section'     => 'nexversal_monetization',
     1395            'type'        => 'hidden',
     1396        )));
     1397    }
    5561398}
    5571399add_action('customize_register', 'nexversal_ads_customize_register', 40);
     1400
     1401/* ==========================================================================
     1402   Post-by-Post Ad Exclusion Framework (Gutenberg & Classic Meta Boxes)
     1403   ========================================================================== */
     1404
     1405/**
     1406 * Register post meta key for REST API & Gutenberg Sidebar Component
     1407 */
     1408function nexversal_register_monetization_meta() {
     1409    $post_types = array('post', 'page');
     1410    foreach ($post_types as $pt) {
     1411        register_post_meta($pt, '_nexversal_disable_ads', array(
     1412            'show_in_rest'      => true,
     1413            'single'            => true,
     1414            'type'              => 'boolean',
     1415            'auth_callback'     => function() use ($pt) {
     1416                return current_user_can($pt === 'page' ? 'edit_pages' : 'edit_posts');
     1417            },
     1418            'sanitize_callback' => 'rest_sanitize_boolean',
     1419            'description'       => __('Disable Google AdSense and theme ads for this specific post/page.', 'nexversal'),
     1420        ));
     1421    }
     1422}
     1423add_action('init', 'nexversal_register_monetization_meta');
     1424
     1425/**
     1426 * Register "Monetization Controls" Meta Box in Post and Page editor screens
     1427 */
     1428function nexversal_add_monetization_meta_box() {
     1429    $screens = array('post', 'page');
     1430    foreach ($screens as $screen) {
     1431        add_meta_box(
     1432            'nexversal_monetization_metabox',
     1433            __('Monetization Controls', 'nexversal'),
     1434            'nexversal_render_monetization_meta_box',
     1435            $screen,
     1436            'side',
     1437            'default'
     1438        );
     1439    }
     1440}
     1441add_action('add_meta_boxes', 'nexversal_add_monetization_meta_box');
     1442
     1443/**
     1444 * Render the Monetization Controls Meta Box
     1445 *
     1446 * @param WP_Post $post Current post object
     1447 */
     1448function nexversal_render_monetization_meta_box($post) {
     1449    wp_nonce_field('nexversal_save_monetization_action', 'nexversal_monetization_nonce');
     1450    $is_disabled = (bool) get_post_meta($post->ID, '_nexversal_disable_ads', true);
     1451    ?>
     1452    <div class="nx-meta-box-wrap" style="padding: 6px 0;">
     1453        <label for="nexversal_disable_ads" style="display: flex; align-items: flex-start; gap: 8px; cursor: pointer; font-weight: 600; font-size: 13px; line-height: 1.4; color: #1e293b;">
     1454            <input type="checkbox" name="nexversal_disable_ads" id="nexversal_disable_ads" value="1" <?php checked($is_disabled, true); ?> style="margin-top: 2px;" />
     1455            <span><?php esc_html_e('Disable AdSense for this post', 'nexversal'); ?></span>
     1456        </label>
     1457        <p class="description" style="margin: 8px 0 0 24px; font-size: 12px; line-height: 1.4; color: #64748b;">
     1458            <?php esc_html_e('When checked, all header, in-article, bottom, in-feed, sidebar ads, Auto Ads, and shortcodes are completely suppressed on this article.', 'nexversal'); ?>
     1459        </p>
     1460        <div style="margin-top: 12px; padding: 6px 10px; border-radius: 4px; font-size: 11px; font-weight: 500; <?php echo $is_disabled ? 'background: #fef2f2; color: #991b1b; border: 1px solid #fecaca;' : 'background: #f0fdf4; color: #166534; border: 1px solid #bbf7d0;'; ?>">
     1461            <strong><?php esc_html_e('Status:', 'nexversal'); ?></strong>
     1462            <?php echo $is_disabled ? esc_html__('Ads Suppressed on this Post', 'nexversal') : esc_html__('Ads Active (Inheriting Global Settings)', 'nexversal'); ?>
     1463        </div>
     1464    </div>
     1465    <?php
     1466}
     1467
     1468/**
     1469 * Save Monetization Meta Box Data with strict validation & sanitization
     1470 *
     1471 * @param int     $post_id Post ID
     1472 * @param WP_Post $post    Post object
     1473 */
     1474function nexversal_save_monetization_meta_box($post_id, $post) {
     1475    // 1. Verify nonce security check
     1476    if (!isset($_POST['nexversal_monetization_nonce']) || !wp_verify_nonce($_POST['nexversal_monetization_nonce'], 'nexversal_save_monetization_action')) {
     1477        return;
     1478    }
     1479
     1480    // 2. Prevent autosave from overwriting meta
     1481    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
     1482        return;
     1483    }
     1484
     1485    // 3. Prevent revisions from storing post meta
     1486    if (wp_is_post_revision($post_id)) {
     1487        return;
     1488    }
     1489
     1490    // 4. Verify user permissions
     1491    $post_type = get_post_type($post_id);
     1492    $cap = ($post_type === 'page') ? 'edit_page' : 'edit_post';
     1493    if (!current_user_can($cap, $post_id)) {
     1494        return;
     1495    }
     1496
     1497    // 5. Sanitize and save boolean flag
     1498    if (!empty($_POST['nexversal_disable_ads'])) {
     1499        update_post_meta($post_id, '_nexversal_disable_ads', true);
     1500    } else {
     1501        delete_post_meta($post_id, '_nexversal_disable_ads');
     1502    }
     1503}
     1504add_action('save_post', 'nexversal_save_monetization_meta_box', 10, 2);
     1505
     1506/**
     1507 * Check if ads are disabled on a specific post or current singular template
     1508 *
     1509 * @param int|null $post_id Optional post ID
     1510 * @return bool True if ads should be suppressed on this post, false otherwise.
     1511 */
     1512function nexversal_is_ad_disabled_for_post($post_id = null) {
     1513    if (empty($post_id)) {
     1514        if (is_singular()) {
     1515            $post_id = get_queried_object_id();
     1516        } elseif (in_the_loop()) {
     1517            $post_id = get_the_ID();
     1518        }
     1519    }
     1520
     1521    if (empty($post_id)) {
     1522        return false;
     1523    }
     1524
     1525    $disabled = (bool) get_post_meta($post_id, '_nexversal_disable_ads', true);
     1526
     1527    /**
     1528     * Absolute filter hook for theme's structural ad engine
     1529     *
     1530     * @param bool $disabled Whether ads are suppressed
     1531     * @param int  $post_id  The evaluated post ID
     1532     */
     1533    return (bool) apply_filters('nexversal_is_ad_disabled_for_post', $disabled, $post_id);
     1534}
     1535
     1536/**
     1537 * Master structural filter to suppress any ad unit evaluation dynamically
     1538 */
     1539add_filter('nexversal_should_render_ad', function($should_render, $slot = '') {
     1540    if (nexversal_is_ad_disabled_for_post()) {
     1541        return false;
     1542    }
     1543    return $should_render;
     1544}, 10, 2);
     1545
     1546/**
     1547 * Add Ads Status Column to Posts & Pages List Table
     1548 */
     1549function nexversal_add_ad_column_header($columns) {
     1550    $columns['nx_ad_status'] = __('Ads', 'nexversal');
     1551    return $columns;
     1552}
     1553add_filter('manage_post_posts_columns', 'nexversal_add_ad_column_header');
     1554add_filter('manage_page_posts_columns', 'nexversal_add_ad_column_header');
     1555
     1556function nexversal_render_ad_column_content($column, $post_id) {
     1557    if ($column === 'nx_ad_status') {
     1558        $disabled = (bool) get_post_meta($post_id, '_nexversal_disable_ads', true);
     1559        if ($disabled) {
     1560            echo '<span style="display:inline-block; padding: 2px 7px; border-radius: 9999px; font-size: 11px; font-weight: 700; background: #fee2e2; color: #dc2626;">' . esc_html__('Disabled', 'nexversal') . '</span>';
     1561        } else {
     1562            echo '<span style="display:inline-block; padding: 2px 7px; border-radius: 9999px; font-size: 11px; font-weight: 700; background: #dcfce7; color: #16a34a;">' . esc_html__('Active', 'nexversal') . '</span>';
     1563        }
     1564    }
     1565}
     1566add_action('manage_post_posts_custom_column', 'nexversal_render_ad_column_content', 10, 2);
     1567add_action('manage_page_posts_custom_column', 'nexversal_render_ad_column_content', 10, 2);
    5581568
    5591569/**
    … …  
    5681578
    5691579/**
    570  * Render an ad slot with compliance container and label
     1580 * Render an ad slot with compliance container, label, Free limit check & Ad-Blocker Bypass
    5711581 *
    5721582 * @param string $slot Slot slug (header, in_article, post_bottom, infeed, sidebar)
    … …  
    5751585 */
    5761586function nexversal_render_ad($slot, $echo = true) {
    577     // Paid PRO Check: Only render ads if PRO plan ($15/year) is active!
    578     if (!nexversal_is_pro_active()) {
     1587    // 1. Post-by-Post Ad Exclusion Short-circuit
     1588    if (function_exists('nexversal_is_ad_disabled_for_post') && nexversal_is_ad_disabled_for_post()) {
     1589        return '';
     1590    }
     1591
     1592    // 2. Master structural filter
     1593    if (!apply_filters('nexversal_should_render_ad', true, $slot)) {
     1594        return '';
     1595    }
     1596
     1597    // 3. Strict Free Plan Limit: Exactly 3 ads per page across all sources
     1598    if (function_exists('nexversal_can_render_ad') && !nexversal_can_render_ad()) {
    5791599        return '';
    5801600    }
    … …  
    5851605    }
    5861606
    587     $slot_on   = get_theme_mod("nexversal_ad_{$slot}_enabled", false);
    588     $ad_code   = get_theme_mod("nexversal_ad_{$slot}_code", '');
     1607    $slot_on = get_theme_mod("nexversal_ad_{$slot}_enabled", false);
     1608    $ad_code = get_theme_mod("nexversal_ad_{$slot}_code", '');
    5891609
    5901610    if (!$slot_on || empty(trim($ad_code))) {
    … …  
    5921612    }
    5931613
     1614    // Free vs PRO Active Ad Limit Check (Free: Max 3 active slots)
     1615    $allowed_slots = nexversal_get_allowed_ad_slots();
     1616    if (!in_array($slot, $allowed_slots, true)) {
     1617        return ''; // Exceeded Free Plan 3-ad limit
     1618    }
     1619
     1620    $is_pro     = nexversal_is_pro_active();
    5941621    $show_label = get_theme_mod('nexversal_ads_show_label', true);
    595     $output     = '<div class="nx-ad-slot nx-ad-' . esc_attr($slot) . '">';
    596    
    597     if ($show_label) {
    598         $output .= '<span class="nx-ad-label">' . esc_html__('ADVERTISEMENT', 'nexversal') . '</span>';
    599     }
    600    
    601     $output .= '<div class="nx-ad-content">' . $ad_code . '</div>';
    602     $output .= '</div>';
     1622
     1623    // Admin / Editor Shielding: Intercept live AdSense scripts for administrators & editors to prevent invalid traffic
     1624    if (function_exists('nexversal_wrap_adsense_code')) {
     1625        $ad_code = nexversal_wrap_adsense_code($ad_code, $slot);
     1626    }
     1627
     1628    // GDPR Interception: Filter ad scripts into inert type="text/plain" if user consent is pending
     1629    if (function_exists('nexversal_filter_ad_code_for_consent')) {
     1630        $ad_code = nexversal_filter_ad_code_for_consent($ad_code);
     1631    }
     1632
     1633    $fallback = '';
     1634    if ($is_pro && get_theme_mod('nexversal_adblock_bypass_enabled', false)) {
     1635        $fallback = get_theme_mod('nexversal_adblock_fallback_code', '');
     1636    }
     1637
     1638    // CLS Optimization: Generate semantic HTML skeleton wrapper container with reserved bounding box
     1639    if (function_exists('nexversal_render_ad_skeleton')) {
     1640        $output = nexversal_render_ad_skeleton($slot, $ad_code, $fallback, $show_label);
     1641    } else {
     1642        $output = '<div class="nx-ad-slot nx-ad-' . esc_attr($slot) . '" data-ad-slot="' . esc_attr($slot) . '">';
     1643        if ($show_label) {
     1644            $output .= '<span class="nx-ad-label">' . esc_html__('ADVERTISEMENT', 'nexversal') . '</span>';
     1645        }
     1646        $output .= '<div class="nx-ad-content">' . $ad_code . '</div>';
     1647        if (!empty(trim($fallback))) {
     1648            $output .= '<div class="nx-ad-blocker-bypass" style="display: none;">' . $fallback . '</div>';
     1649        }
     1650        $output .= '</div>';
     1651    }
     1652
     1653    // Increment global page ad execution tracker
     1654    if (function_exists('nexversal_increment_page_ad_count')) {
     1655        nexversal_increment_page_ad_count();
     1656    }
    6031657
    6041658    if ($echo) {
    … …  
    6201674    }
    6211675
    622     // Paid PRO Check
    623     if (!nexversal_is_pro_active()) {
     1676    // Post-by-Post Ad Exclusion Short-circuit
     1677    if (function_exists('nexversal_is_ad_disabled_for_post') && nexversal_is_ad_disabled_for_post()) {
     1678        return $content;
     1679    }
     1680
     1681    // Strict Free Plan Limit: Exactly 3 ads per page across all placements
     1682    if (function_exists('nexversal_can_render_ad') && !nexversal_can_render_ad()) {
    6241683        return $content;
    6251684    }
    … …  
    6331692    }
    6341693
    635     $pos = max(1, (int) get_theme_mod('nexversal_ad_article_pos', 3));
     1694    // Check Free vs PRO allowed slots
     1695    $allowed_slots = nexversal_get_allowed_ad_slots();
     1696    if (!in_array('article', $allowed_slots, true)) {
     1697        return $content;
     1698    }
     1699
    6361700    $ad_html = nexversal_render_ad('article', false);
    637 
    6381701    if (empty($ad_html)) {
    6391702        return $content;
    … …  
    6431706    $paragraphs = explode('</p>', $content);
    6441707    $total_p    = count($paragraphs) - 1;
     1708
     1709    $pos_setting = get_theme_mod('nexversal_ad_article_pos', '3');
     1710    if ($pos_setting === '50') {
     1711        // Automatic middle
     1712        $pos = max(1, (int) round($total_p / 2));
     1713    } else {
     1714        $pos = max(1, (int) $pos_setting);
     1715    }
    6451716
    6461717    if ($total_p >= $pos) {
    … …  
    6591730}
    6601731add_filter('the_content', 'nexversal_inject_in_article_ad', 20);
    661 
    662 
  • nexversal/3.5.9/index.php

    r357433 r357886  
    11<?php
    22/**
    3  * Security: Prevent direct script access
     3 * Main Template File (Homepage / Blog Feed) for Nexversal Theme
     4 *
     5 * @package Nexversal
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
    410 */
     11
    512if (!defined('ABSPATH')) {
    613    exit;
    714}
    8 
    9 /**
    10  * Main Template File (Homepage / Blog Feed)
    11  *
    12  * @package Nexversal
    13  */
    1415
    1516get_header();
    … …  
    3132
    3233            <?php
    33             $hero_btn_text = get_theme_mod('nexversal_hero_btn_text', 'Explore Articles');
    34             $hero_btn_url  = get_theme_mod('nexversal_hero_btn_url', '#primary');
    35             if (!empty($hero_btn_text)) :
    36                 ?>
    37                 <div class="nx-hero-actions" style="margin-bottom: 22px;">
    38                     <a href="<?php echo esc_url($hero_btn_url); ?>" class="nx-btn nx-btn-primary nx-hero-btn">
    39                         <span><?php echo esc_html($hero_btn_text); ?></span>
    40                         <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="margin-left: 6px;"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>
    41                     </a>
    42                 </div>
    43             <?php endif; ?>
     34            if (function_exists('nexversal_render_hero_button')) {
     35                nexversal_render_hero_button();
     36            }
     37            ?>
    4438
    4539            <?php
    … …  
    106100        </div>
    107101
    108         <?php get_sidebar(); ?>
     102        <?php
     103        if (!function_exists('nexversal_is_meta_disabled') || !nexversal_is_meta_disabled('disable_sidebar')) {
     104            get_sidebar();
     105        }
     106        ?>
    109107    </div>
    110108</main>
  • nexversal/3.5.9/page.php

    r357433 r357886  
    11<?php
    22/**
    3  * Security: Prevent direct script access
     3 * Page template for Nexversal Theme
     4 *
     5 * @package Nexversal
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
    410 */
     11
    512if (!defined('ABSPATH')) {
    613    exit;
    714}
    8 
    9 /**
    10  * Page template
    11  *
    12  * @package Nexversal
    13  */
    1415
    1516get_header();
    … …  
    2223            while (have_posts()) :
    2324                the_post();
    24 
    25                 $raw_content    = get_the_content();
    26                 $page_title     = get_the_title();
    27                 $page_slug      = get_post_field('post_name', get_the_ID());
    28                 $is_sample_page = ($page_slug === 'sample-page') ||
    29                                   (stripos($raw_content, 'bike messenger by day') !== false) ||
    30                                   (stripos($page_title, 'Sample Page') !== false);
    3125                ?>
    3226                <article id="post-<?php the_ID(); ?>" <?php post_class('nx-single-article nx-page-card'); ?>>
    33                     <?php nexversal_breadcrumbs(); ?>
     27                    <?php
     28                    if (!function_exists('nexversal_is_meta_disabled') || !nexversal_is_meta_disabled('disable_breadcrumbs')) {
     29                        nexversal_breadcrumbs();
     30                    }
     31                    ?>
    3432
    35                     <h1 class="nx-single-title">
    36                         <?php echo $is_sample_page ? esc_html__('About Us — Nexes Agency', 'nexversal') : esc_html($page_title); ?>
    37                     </h1>
     33                    <?php if (!function_exists('nexversal_is_meta_disabled') || !nexversal_is_meta_disabled('disable_title')) : ?>
     34                        <h1 class="nx-single-title">
     35                            <?php the_title(); ?>
     36                        </h1>
     37                    <?php endif; ?>
    3838
    3939                    <?php if (has_post_thumbnail()) : ?>
    … …  
    4444
    4545                    <div class="nx-single-content">
    46                         <?php if ($is_sample_page) : ?>
    47                             <div class="nx-agency-hero" style="background: linear-gradient(135deg, rgba(79, 70, 229, 0.12) 0%, rgba(6, 182, 212, 0.1) 100%); border: 1px solid var(--nx-border); border-radius: var(--nx-radius); padding: 32px 28px; margin-bottom: 32px;">
    48                                 <span style="display: inline-block; font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--nx-primary); background: var(--nx-primary-light); padding: 4px 12px; border-radius: 999px; margin-bottom: 12px;"><?php esc_html_e('Premier Digital Agency • Pakistan', 'nexversal'); ?></span>
    49                                 <h2 style="font-size: 1.85rem; font-weight: 800; margin-top: 0; margin-bottom: 12px; color: var(--nx-dark); line-height: 1.3;">
    50                                     <?php esc_html_e('Welcome to Nexes — Driving Digital Dominance & Engineering Excellence', 'nexversal'); ?>
    51                                 </h2>
    52                                 <p style="font-size: 1.05rem; line-height: 1.7; color: var(--nx-text); margin-bottom: 0;">
    53                                     <?php esc_html_e('We are a premier, full-scale digital agency proudly originating from Pakistan. Nexes unites elite software engineering with cutting-edge SEO and performance marketing to scale ambitious digital brands across the globe.', 'nexversal'); ?>
    54                                 </p>
    55                             </div>
     46                        <?php
     47                        the_content();
    5648
    57                             <div class="nx-profile-lead" style="display: flex; gap: 24px; align-items: flex-start; background: var(--nx-bg); border: 1px solid var(--nx-border); border-radius: var(--nx-radius); padding: 24px; margin-bottom: 32px; flex-wrap: wrap;">
    58                                 <div style="width: 80px; height: 80px; border-radius: 50%; background: linear-gradient(135deg, #4f46e5 0%, #06b6d4 100%); display: flex; align-items: center; justify-content: center; color: #fff; font-weight: 800; font-size: 1.8rem; flex-shrink: 0; box-shadow: var(--nx-shadow-sm);">
    59                                     MS
    60                                 </div>
    61                                 <div style="flex: 1; min-width: 240px;">
    62                                     <span style="font-size: 0.78rem; font-weight: 700; color: var(--nx-primary); text-transform: uppercase; letter-spacing: 0.05em;"><?php esc_html_e('Founder & Lead Specialist', 'nexversal'); ?></span>
    63                                     <h3 style="font-size: 1.45rem; font-weight: 800; margin: 4px 0 8px 0; color: var(--nx-dark);">Muhammad Shahid</h3>
    64                                     <p style="font-size: 0.98rem; line-height: 1.6; color: var(--nx-text); margin-bottom: 0;">
    65                                         Senior <strong>SEO Specialist</strong> and organic search architect with proven experience driving millions of search impressions and high-intent organic clicks. Muhammad specializes in technical SEO, site architecture, semantic search optimization, and algorithm-resilient growth strategies.
    66                                     </p>
    67                                 </div>
    68                             </div>
    69 
    70                             <h3 style="font-size: 1.35rem; font-weight: 800; margin-top: 32px; margin-bottom: 16px; color: var(--nx-dark);"><?php esc_html_e('Our Cross-Functional Agency Capabilities', 'nexversal'); ?></h3>
    71                             <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 20px; margin-bottom: 36px;">
    72                                 <div style="background: var(--nx-bg); border: 1px solid var(--nx-border); border-radius: var(--nx-radius); padding: 22px;">
    73                                     <div style="width: 42px; height: 42px; border-radius: 8px; background: rgba(79, 70, 229, 0.1); color: var(--nx-primary); display: flex; align-items: center; justify-content: center; margin-bottom: 14px;">
    74                                         <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
    75                                     </div>
    76                                     <h4 style="font-size: 1.1rem; font-weight: 700; margin-top: 0; margin-bottom: 8px; color: var(--nx-dark);"><?php esc_html_e('Advanced Search Engine Optimization (SEO)', 'nexversal'); ?></h4>
    77                                     <p style="font-size: 0.92rem; line-height: 1.6; color: var(--nx-text); margin-bottom: 0;"><?php esc_html_e('Full-funnel technical auditing, Core Web Vitals optimization, programmatic keyword strategy, and search engine answer optimization that systematically rank websites on Page 1.', 'nexversal'); ?></p>
    78                                 </div>
    79 
    80                                 <div style="background: var(--nx-bg); border: 1px solid var(--nx-border); border-radius: var(--nx-radius); padding: 22px;">
    81                                     <div style="width: 42px; height: 42px; border-radius: 8px; background: rgba(6, 182, 212, 0.1); color: var(--nx-accent); display: flex; align-items: center; justify-content: center; margin-bottom: 14px;">
    82                                         <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
    83                                     </div>
    84                                     <h4 style="font-size: 1.1rem; font-weight: 700; margin-top: 0; margin-bottom: 8px; color: var(--nx-dark);"><?php esc_html_e('Elite Software Engineering', 'nexversal'); ?></h4>
    85                                     <p style="font-size: 0.92rem; line-height: 1.6; color: var(--nx-text); margin-bottom: 0;"><?php esc_html_e('Our dedicated team of software engineers builds scalable web applications, custom WordPress themes & plugins, performant API microservices, and robust cloud platforms.', 'nexversal'); ?></p>
    86                                 </div>
    87 
    88                                 <div style="background: var(--nx-bg); border: 1px solid var(--nx-border); border-radius: var(--nx-radius); padding: 22px;">
    89                                     <div style="width: 42px; height: 42px; border-radius: 8px; background: rgba(236, 72, 153, 0.1); color: #ec4899; display: flex; align-items: center; justify-content: center; margin-bottom: 14px;">
    90                                         <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"/></svg>
    91                                     </div>
    92                                     <h4 style="font-size: 1.1rem; font-weight: 700; margin-top: 0; margin-bottom: 8px; color: var(--nx-dark);"><?php esc_html_e('Social Media & Performance Marketing', 'nexversal'); ?></h4>
    93                                     <p style="font-size: 0.92rem; line-height: 1.6; color: var(--nx-text); margin-bottom: 0;"><?php esc_html_e('Data-driven social media marketing campaigns, high-converting audience targeting, creative brand storytelling, and multi-channel acquisition that convert visitors into loyal clients.', 'nexversal'); ?></p>
    94                                 </div>
    95                             </div>
    96 
    97                             <div style="background: var(--nx-bg); border: 1px dashed var(--nx-border); border-radius: var(--nx-radius); padding: 26px; text-align: center;">
    98                                 <h4 style="font-size: 1.15rem; font-weight: 700; margin-top: 0; margin-bottom: 8px; color: var(--nx-dark);"><?php esc_html_e('Ready to scale your digital presence?', 'nexversal'); ?></h4>
    99                                 <p style="font-size: 0.95rem; color: var(--nx-text); max-width: 600px; margin: 0 auto 16px auto;"><?php esc_html_e('Partner with Nexes today and experience search excellence, reliable software development, and transformative marketing campaigns.', 'nexversal'); ?></p>
    100                                 <a href="<?php echo esc_url(home_url('/contact/')); ?>" class="nx-btn nx-btn-primary" style="display: inline-flex; align-items: center; gap: 8px;">
    101                                     <span><?php esc_html_e('Get In Touch With Nexes', 'nexversal'); ?></span>
    102                                     <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
    103                                 </a>
    104                             </div>
    105                         <?php else : ?>
    106                             <?php the_content(); ?>
    107                         <?php endif; ?>
     49                        wp_link_pages(array(
     50                            'before' => '<div class="page-links">' . esc_html__('Pages:', 'nexversal'),
     51                            'after'  => '</div>',
     52                        ));
     53                        ?>
    10854                    </div>
    10955
    … …  
    11763        </div>
    11864
    119         <?php get_sidebar(); ?>
     65        <?php
     66        if (!function_exists('nexversal_is_meta_disabled') || !nexversal_is_meta_disabled('disable_sidebar')) {
     67            get_sidebar();
     68        }
     69        ?>
    12070    </div>
    12171</main>
  • nexversal/3.5.9/readme.txt

    r357433 r357886  
    44Tested up to: 7.0
    55Requires PHP: 7.4
    6 Stable tag: 2.5.2
     6Stable tag: 3.5.9
    77License: GNU General Public License v2 or later
    88License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    4747== Copyright ==
    4848
    49 Nexversal WordPress Theme, Copyright 2026 Nexes Agency & Muhammad Shahid.
     49Nexversal WordPress Theme, Copyright (C) 2026 Nexes Agency & Muhammad Shahid.
    5050Nexversal is distributed under the terms of the GNU General Public License v2 or later.
    5151
    … …  
    5858== Changelog ==
    5959
     60= 3.4.0 =
     61* Page Flexibility System: Astra-style per-page & per-post layout settings meta box with 1-click toggles to Disable Header, Disable Footer, Disable Page Title, Disable Breadcrumbs, and Disable Sidebar.
     62* Content Layout Modes: Added Content Layout selector (Default, Full Width Contained, Full Width Stretched Canvas) for 100% compatibility with Elementor, Beaver Builder, and Gutenberg landing pages.
     63* Dynamic 2-Column Hero Section: Refined, sleek hero headline typography and compact button; added dynamic Featured Article Card on desktop with automated fallback to trending/most-viewed stories.
     64* Hero Featured Post Selector: Added "★ Hero Featured Article" meta box in post editor to pin any article to the homepage hero card.
     65* Dedicated Contact Settings Screen: Added Appearance > Contact Settings in WP-Admin for instant live configuration without Gutenberg blocks.
     66
     67= 3.3.0 =
     68* Fixed Home page layout grid: sidebar is now aligned cleanly on the right side next to the main content.
     69* Blog page 4-column article grid: articles now render 4 per row on desktop, eliminating single full-width stretched cards.
     70* Added dynamic Trending Categories tags between Hero CTA button and "Latest Insights & Articles" on Home and Blog pages.
     71* Built-in AJAX Newsletter Subscription: stores email leads directly in WP-Admin with CSV export and management under Appearance > Subscribers.
     72* Automatic email field protection: ensures input field and client-side/server-side validation are always present in newsletter cards.
     73* Fully editable Contact Information: email, headquarters, and response time can now be edited directly in the WordPress Page Editor without design breakage.
     74* Zero-overwrite architecture: automatically preserves existing posts, categories, pages, and menus for users activating the theme on existing websites.
     75* Complete Block Editor visual parity for Home, Blogs, and About Us pages with enhanced editor-style.css.
     76
     77= 3.2.0 =
     78* Full Block Editor Editing: Homepage Hero section, headline, badge, and CTA button are now fully editable native Gutenberg blocks.
     79* Registered "Homepage Hero Banner" block pattern in the WordPress Block Inserter.
     80* Enhanced editor-style.css to render Hero blocks in the editor matching the frontend view.
     81
     82= 3.1.0 =
     83* Fixed menu item duplication: dynamically deduplicated all navbar links so each page appears exactly once.
     84* Cleaned About Us page: removed hardcoded stat cards (200+, 100%, 100/100) and enabled clean WordPress editor content support.
     85
     86= 3.0.0 =
     87* Major Release: Added 4 dedicated page templates (template-home.php, template-blog.php, template-about.php, template-contact.php).
     88* Automated page provisioning: Automatically creates and publishes Home, Blogs, About Us, and Contact pages in WordPress database.
     89* Configures static front page (Home) and posts page (Blogs) with custom layouts out of the box.
     90* Front-page.php template mapping for high-performance homepage rendering.
     91
     92= 3.5.4 =
     93* Prevented Cumulative Layout Shift (CLS = 0.00) across all dynamic Google AdSense insertions.
     94* Generated semantic HTML skeleton wrapper containers (`<aside>`, `.nx-ad-bounding-box`) with exact bounding boxes for 5 ad slots (728x90, 336x280, 300x250, 1:1 In-Feed, 300x600).
     95* Applied explicit `aspect-ratio`, `min-height`, and `min-width` parameters with subtle responsive CSS shimmer placeholder styling.
     96
     97= 3.5.3 =
     98* Added GDPR and Google AdSense Privacy-Compliant Cookie Consent Banner via `wp_footer`.
     99* Implemented Google Consent Mode v2 default signal integration in `<head>`.
     100* Added strict backend PHP interception of Google AdSense and publisher scripts, converting scripts to inert `type="text/plain"` until verified consent is present.
     101* Zero-dependency pure vanilla JavaScript engine with dynamic DOM activation and Zero Layout Shift (CLS = 0).
     102
     103= 3.5.2 =
     104* Added Automated Virtual ads.txt Manager in Appearance > Nexversal PRO settings panel.
     105* Dynamic URL interception for `/ads.txt` with strict `Content-Type: text/plain` headers and output buffer cleanup (zero cPanel file writing required).
     106* Database-sanitized textarea with manage_options capability checks, nonce security, and physical file detection.
     107
     108= 3.5.1 =
     109* Fixed About Us URL 404 issue: Added resilient URL resolution and automatic 301 redirection for legacy `?page_id=2` and `/sample-page/` queries.
     110* Enhanced navigation menu filter to auto-heal broken or stale menu links in runtime and database.
     111* Added fallback 301 redirect in 404.php for legacy sample-page and About URL variants.
     112
     113= 3.5.9 =
     114* Fixed: Full WordPress.org automated theme check compliance (zero plugin-territory shortcodes, updated publisher placeholder, safe fallback attributes).
     115* Added: Explicit add_theme_support() for custom-header and custom-background.
     116* Improved: Cleaned CSV subscriber stream without low-level fopen/fclose calls.
     117* Improved: Global smart geo-targeting monetization engine with zero frontend CLS and transparent ad reservation.
     118
     119= 3.5.8 =
     120* Added Global Page Ad Execution Counter (nexversal_get_page_ad_count & nexversal_can_render_ad) strictly capping Free plan to 3 ads per page across all structural slots, in-article injector, and shortcodes.
     121* Injected data-max-ads-per-page="3" into Google Auto-Ads script tag for Free version, preserved across GDPR consent transitions and suppressed for Admin Shield.
     122* Re-crafted Customizer Geo-Targeting card with high-converting, punchy copy and direct 1-click PRO upgrade link.
     123
     124= 3.5.7 =
     125* Added complete 301 Redirects mapping table for all 22 dead GSC 404 URLs directly into theme runtime and 404 handler.
     126* Fixed /blogs to /blog/ canonical routing bug preventing 404 errors on blog archive navigation.
     127* Fixed template resolution lookup in nexversal_get_blogs_page_url to accept both template-blog.php and template-blogs.php.
     128
     129= 3.5.6 =
     130* Added Post-by-Post Ad Exclusion Framework (Gutenberg sidebar components & classic meta boxes integration).
     131* Registered "Monetization Controls" meta box on post editor screens with "Disable AdSense for this post" checkbox.
     132* Added absolute filter logic (nexversal_is_ad_disabled_for_post) short-circuiting all structural theme ad slots, auto-ads hooks, and shortcodes.
     133* Added visual Ads status badge in WordPress admin posts and pages list table.
     134
     135= 3.5.5 =
     136* Added production-grade Google AdSense Admin Shield wrapper function (nexversal_wrap_adsense_code).
     137* Implemented strict user validation check (current_user_can('administrator') & editors) to prevent accidental self-clicks and AdSense account strikes.
     138* Replaced live publisher scripts with safe local HTML developer diagnostic cards showing real-time slot details, role chips, and zero external requests.
     139* Added support for Google official demo test ad parameters (data-ad-test="on").
     140* Suppressed Auto-Ads head script injection for authenticated administrative and editorial visitors.
     141
     142= 3.5.0 =
     143* Upgraded Ad & Monetization Engine to Freemium model with Google AdSense Auto Ads support and dropdown selectors.
     144* Added customizable author/founder section and adaptive light/dark newsletter subscription styling.
     145* Removed "Background Image" section and custom-background support from Customizer sidebar.
     146
     147= 2.8.0 =
     148* Removed redundant Header Image and separate sidebar CTA options from Customizer.
     149* Added live click-to-edit and selective refresh for the Hero CTA button in Customizer preview.
     150* Added instant live color customization for all buttons site-wide (Hero, Cards, Newsletter, Forms, and Block Editor buttons).
     151* Added customize-preview.js for zero-latency postMessage live updates.
     152
     153= 2.7.0 =
     154* Fixed footer credit line formatting to render dynamic site title without trailing dot, centered on all devices.
     155* Filtered legacy menu objects to guarantee "Sample Page" is never displayed in navigation.
     156* Added automatic single-run page provisioning (About Us, Blogs, Contact) on theme update.
     157
     158= 2.6.0 =
     159* Removed "Sample Page" fallback from navbar and added default Home, Blogs, About Us, Contact links.
     160* Automatically configured essential pages and menu on theme activation.
     161* Added built-in template-contact.php with secure email handling and anti-spam protection.
     162* Dynamically output site name in centered footer copyright credit line.
     163
     164= 2.5.5 =
     165* Added built-in template-contact.php with secure email handling and anti-spam protection.
     166* Dynamically output site name in centered footer copyright credit line.
     167* Linked About/Hire actions directly to official contact channel.
     168
     169= 2.5.4 =
     170* Standardized formal GPL copyright headers across all main PHP template files.
     171* Verified 100% text-domain consistency ('nexversal') across all translation calls.
     172* Prepared release for official WordPress.org Theme Directory hosting.
     173
     174= 2.5.3 =
     175* Resolved all WordPress.org automated theme check requirements.
     176* Fixed dark/light mode header and body color transition synchronization.
     177* Added readme.txt and official GNU GPL copyright notices.
     178* Replaced hardcoded search form with standard get_search_form().
     179* Removed deprecated add_shortcode from theme files.
     180* Added full WordPress core alignment and caption classes.
     181* Centered footer copyright and powered-by credits.
     182* Added customizable button text settings in Customizer.
     183
    60184= 2.5.2 =
    61 * Added complete WordPress.org Theme Handbook compliance.
    62185* Centered footer credits and copyright text.
    63186* Added custom button text controls in Customizer.
    64 * Fixed dark/light mode header background transition synchronization.
    65 * Added WordPress core alignment, caption, sticky, and bypostauthor styling.
    66 * Added custom-header, custom-background, and wp-block-styles theme support.
    67 * Replaced hardcoded search form with get_search_form().
    68 * Removed deprecated add_shortcode from theme files.
    69 * Added readme.txt with full GPL copyright documentation.
    70187
    71188= 2.5.1 =
    … …  
    73190* Added reading progress bar and copy code snippet buttons.
    74191* Initial release of Nexversal.
     192
  • nexversal/3.5.9/search.php

    r357433 r357886  
    11<?php
    22/**
    3  * Security: Prevent direct script access
     3 * Search results template for Nexversal Theme
     4 *
     5 * @package Nexversal
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
    410 */
     11
    512if (!defined('ABSPATH')) {
    613    exit;
    714}
    8 
    9 /**
    10  * Search results template
    11  *
    12  * @package Nexversal
    13  */
    1415
    1516get_header();
    … …  
    6465        </div>
    6566
    66         <?php get_sidebar(); ?>
     67        <?php
     68        if (!function_exists('nexversal_is_meta_disabled') || !nexversal_is_meta_disabled('disable_sidebar')) {
     69            get_sidebar();
     70        }
     71        ?>
    6772    </div>
    6873</main>
  • nexversal/3.5.9/sidebar.php

    r357433 r357886  
    11<?php
    22/**
    3  * Security: Prevent direct script access
     3 * Sidebar template for Nexversal Theme
     4 *
     5 * @package Nexversal
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
    410 */
     11
    512if (!defined('ABSPATH')) {
    613    exit;
    714}
    8 
    9 /**
    10  * Sidebar template
    11  *
    12  * @package Nexversal
    13  */
    1415?>
    1516<aside id="secondary" class="site-sidebar" aria-label="<?php esc_attr_e('Sidebar', 'nexversal'); ?>">
  • nexversal/3.5.9/single.php

    r357433 r357886  
    11<?php
    22/**
    3  * Security: Prevent direct script access
     3 * Single post template for Nexversal Theme
     4 *
     5 * @package Nexversal
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
    410 */
     11
    512if (!defined('ABSPATH')) {
    613    exit;
    714}
    8 
    9 /**
    10  * Single post template
    11  *
    12  * @package Nexversal
    13  */
    1415
    1516get_header();
    … …  
    2425                ?>
    2526                <article id="post-<?php the_ID(); ?>" <?php post_class('nx-single-article'); ?>>
    26                     <?php nexversal_breadcrumbs(); ?>
     27                    <?php
     28                    if (!function_exists('nexversal_is_meta_disabled') || !nexversal_is_meta_disabled('disable_breadcrumbs')) {
     29                        nexversal_breadcrumbs();
     30                    }
     31                    ?>
    2732
    2833                    <?php
    … …  
    3944                    <?php endif; ?>
    4045
    41                     <h1 class="nx-single-title"><?php the_title(); ?></h1>
     46                    <?php if (!function_exists('nexversal_is_meta_disabled') || !nexversal_is_meta_disabled('disable_title')) : ?>
     47                        <h1 class="nx-single-title"><?php the_title(); ?></h1>
     48                    <?php endif; ?>
    4249
    4350                    <div class="nx-single-meta">
    … …  
    199206        </div>
    200207
    201         <?php get_sidebar(); ?>
     208        <?php
     209        if (!function_exists('nexversal_is_meta_disabled') || !nexversal_is_meta_disabled('disable_sidebar')) {
     210            get_sidebar();
     211        }
     212        ?>
    202213    </div>
    203214</main>
  • nexversal/3.5.9/style.css

    r357433 r357886  
    55Author URI: https://nexversal.com/about
    66Description: A modern, ultra-fast, and elegant Tech & Magazine theme for WordPress engineered by Nexes Agency. Features a sleek hero section, responsive article cards, copy code buttons, reading progress bar, customizable accents, dark mode toggle, and rich SEO Schema markup.
    7 Version: 2.5.2
     7Version: 3.5.9
    88Requires at least: 6.0
    99Tested up to: 7.0
    … …  
    1414Tags: blog, news, entertainment, grid-layout, one-column, two-columns, custom-colors, custom-menu, featured-images, footer-widgets, full-width-template, theme-options, translation-ready
    1515
    16 Nexversal WordPress Theme, (C) 2026 Nexes Agency & Muhammad Shahid
     16Nexversal WordPress Theme, (C) 2026 Nexes Agency & Muhammad Shahid.
    1717Nexversal is distributed under the terms of the GNU General Public License v2 or later.
     18Copyright (C) 2026 Nexes Agency & Muhammad Shahid. All rights reserved.
    1819*/
    1920
    … …  
    163164}
    164165
     166/* Custom Header Logo Auto-Sizing */
     167.custom-logo-link {
     168  display: inline-flex;
     169  align-items: center;
     170  line-height: 1;
     171}
     172
     173.custom-logo-link img,
     174.custom-logo {
     175  max-height: 38px !important;
     176  width: auto !important;
     177  max-width: 200px !important;
     178  object-fit: contain !important;
     179  display: block;
     180  transition: opacity 0.2s ease;
     181}
     182
     183.custom-logo:hover {
     184  opacity: 0.9;
     185}
     186
    165187.site-title {
    166188  font-size: 1.4rem;
    … …  
    537559/* Hero Section (Magazine / Tech Focus) */
    538560.nx-hero-section {
    539   padding: clamp(24px, 5vw, 48px) 0 clamp(20px, 4vw, 36px);
     561  padding: clamp(24px, 4vw, 42px) 0 clamp(20px, 3vw, 32px);
    540562  background: linear-gradient(180deg, #ffffff 0%, var(--nx-bg) 100%);
    541563  border-bottom: 1px solid var(--nx-border);
    542   margin-bottom: clamp(24px, 4vw, 40px);
     564  margin-bottom: clamp(24px, 3vw, 36px);
    543565}
    544566
    545567[data-theme="dark"] .nx-hero-section {
    546568  background: linear-gradient(180deg, #111827 0%, var(--nx-bg) 100%);
     569}
     570
     571/* 2-Column Hero Grid: Left Content + Right Featured Article Card */
     572.nx-hero-grid {
     573  display: grid;
     574  grid-template-columns: 1.15fr 0.85fr;
     575  gap: clamp(24px, 4vw, 44px);
     576  align-items: center;
     577  max-width: var(--nx-max-width, 1200px);
     578  margin: 0 auto;
     579  padding: 0 clamp(16px, 3vw, 28px);
     580}
     581
     582.nx-hero-content-col {
     583  display: flex;
     584  flex-direction: column;
     585  align-items: flex-start;
     586  min-width: 0;
    547587}
    548588
    … …  
    552592  background: var(--nx-primary-light);
    553593  color: var(--nx-primary);
    554   font-size: clamp(0.72rem, 2.5vw, 0.8rem);
     594  font-size: clamp(0.7rem, 2vw, 0.76rem);
    555595  font-weight: 700;
    556596  text-transform: uppercase;
    557597  letter-spacing: 0.05em;
    558598  border-radius: 20px;
    559   margin-bottom: 14px;
     599  margin-bottom: 12px;
    560600  max-width: 100%;
    561601  word-break: break-word;
    … …  
    564604
    565605.nx-hero-title {
    566   font-size: clamp(1.55rem, 5vw + 0.5rem, 2.75rem);
     606  font-size: clamp(1.35rem, 2.3vw, 2.05rem);
    567607  font-weight: 800;
    568   letter-spacing: -0.03em;
    569   line-height: 1.2;
    570   max-width: 850px;
    571   margin-bottom: 14px;
     608  letter-spacing: -0.025em;
     609  line-height: 1.25;
     610  max-width: 680px;
     611  margin-top: 0;
     612  margin-bottom: 12px;
    572613  color: var(--nx-dark);
    573614  word-break: break-word;
    … …  
    575616
    576617.nx-hero-description {
    577   font-size: clamp(0.92rem, 2.5vw, 1.15rem);
     618  font-size: clamp(0.9rem, 1.8vw, 1.02rem);
    578619  color: var(--nx-text-light);
    579   max-width: 680px;
     620  max-width: 600px;
    580621  line-height: 1.6;
    581   margin-bottom: 20px;
    582 }
    583 
    584 .nx-hero-btn {
     622  margin-bottom: 16px;
     623}
     624
     625.nx-hero-actions {
     626  margin: 14px 0 20px;
     627  padding-left: 1px;
     628}
     629
     630.nx-hero-btn,
     631.nx-hero-actions .wp-block-button__link {
     632  display: inline-flex !important;
     633  align-items: center !important;
     634  gap: 7px !important;
     635  padding: 9px 20px !important;
     636  background-color: var(--nx-btn-bg, var(--nx-primary)) !important;
     637  color: var(--nx-btn-text, #ffffff) !important;
     638  border: 1px solid var(--nx-btn-bg, var(--nx-primary)) !important;
     639  font-weight: 600 !important;
     640  font-size: 0.88rem !important;
     641  border-radius: 20px !important;
     642  text-decoration: none !important;
     643  box-shadow: 0 3px 10px rgba(79, 70, 229, 0.28) !important;
     644  transition: all 0.2s ease !important;
     645  cursor: pointer;
     646  line-height: 1.3 !important;
     647}
     648
     649.nx-hero-btn:hover,
     650.nx-hero-actions .wp-block-button__link:hover {
     651  background-color: var(--nx-btn-hover, var(--nx-primary-hover)) !important;
     652  border-color: var(--nx-btn-hover, var(--nx-primary-hover)) !important;
     653  color: var(--nx-btn-text, #ffffff) !important;
     654  transform: translateY(-2px) !important;
     655  box-shadow: 0 5px 16px rgba(79, 70, 229, 0.42) !important;
     656}
     657
     658/* Hero Featured Article Card */
     659.nx-hero-featured-col {
     660  display: flex;
     661  justify-content: center;
     662  width: 100%;
     663  min-width: 0;
     664}
     665
     666.nx-hero-featured-card {
     667  width: 100%;
     668  max-width: 440px;
     669  background: var(--nx-card-bg);
     670  border: 1px solid var(--nx-border);
     671  border-radius: var(--nx-radius, 14px);
     672  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.07);
     673  overflow: hidden;
     674  transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
     675  position: relative;
     676  display: flex;
     677  flex-direction: column;
     678}
     679
     680.nx-hero-featured-card:hover {
     681  transform: translateY(-4px);
     682  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.12);
     683  border-color: var(--nx-primary-light, #c7d2fe);
     684}
     685
     686[data-theme="dark"] .nx-hero-featured-card {
     687  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.4);
     688}
     689
     690[data-theme="dark"] .nx-hero-featured-card:hover {
     691  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.6);
     692}
     693
     694.nx-hero-card-badge-wrap {
     695  position: absolute;
     696  top: 12px;
     697  left: 12px;
     698  z-index: 2;
     699}
     700
     701.nx-hero-card-featured-tag {
    585702  display: inline-flex;
    586703  align-items: center;
    587   gap: 6px;
    588   padding: 10px 22px;
    589   background: var(--nx-primary);
    590   color: #ffffff !important;
     704  gap: 5px;
     705  padding: 4px 10px;
     706  background: rgba(15, 23, 42, 0.88);
     707  color: #fbbf24;
     708  font-size: 0.72rem;
    591709  font-weight: 700;
    592   font-size: 0.92rem;
    593   border-radius: var(--nx-radius-sm);
     710  text-transform: uppercase;
     711  letter-spacing: 0.04em;
     712  border-radius: 16px;
     713  backdrop-filter: blur(6px);
     714  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
     715}
     716
     717.nx-hero-card-thumb-wrap {
     718  position: relative;
     719  display: block;
     720  width: 100%;
     721  height: 200px;
     722  overflow: hidden;
     723  background: var(--nx-card-bg-subtle, #f1f5f9);
     724}
     725
     726.nx-hero-card-img {
     727  width: 100%;
     728  height: 100%;
     729  object-fit: cover;
     730  display: block;
     731  transition: transform 0.4s ease;
     732}
     733
     734.nx-hero-featured-card:hover .nx-hero-card-img {
     735  transform: scale(1.05);
     736}
     737
     738.nx-hero-card-img-fallback {
     739  width: 100%;
     740  height: 100%;
     741  display: flex;
     742  align-items: center;
     743  justify-content: center;
     744  background: linear-gradient(135deg, rgba(79, 70, 229, 0.12) 0%, rgba(6, 182, 212, 0.12) 100%);
     745  color: var(--nx-primary);
     746}
     747
     748.nx-hero-card-body {
     749  padding: 18px 20px 20px;
     750  display: flex;
     751  flex-direction: column;
     752  flex-grow: 1;
     753}
     754
     755.nx-hero-card-meta-top {
     756  display: flex;
     757  align-items: center;
     758  justify-content: space-between;
     759  margin-bottom: 8px;
     760  font-size: 0.76rem;
     761}
     762
     763.nx-hero-card-cat {
     764  font-weight: 700;
     765  color: var(--nx-primary);
     766  text-transform: uppercase;
     767  letter-spacing: 0.04em;
    594768  text-decoration: none;
    595   box-shadow: 0 4px 14px rgba(79, 70, 229, 0.3);
    596   transition: all 0.25s ease;
    597 }
    598 
    599 .nx-hero-btn:hover {
    600   background: var(--nx-primary-hover);
    601   transform: translateY(-2px);
    602   box-shadow: 0 6px 20px rgba(79, 70, 229, 0.45);
     769}
     770
     771.nx-hero-card-cat:hover {
     772  text-decoration: underline;
     773}
     774
     775.nx-hero-card-time {
     776  color: var(--nx-text-light);
     777  font-weight: 500;
     778}
     779
     780.nx-hero-card-title {
     781  font-size: 1.12rem;
     782  font-weight: 800;
     783  line-height: 1.35;
     784  margin: 0 0 8px 0;
     785  color: var(--nx-dark);
     786}
     787
     788.nx-hero-card-title a {
     789  color: inherit;
     790  text-decoration: none;
     791  transition: color 0.2s ease;
     792}
     793
     794.nx-hero-card-title a:hover {
     795  color: var(--nx-primary);
     796}
     797
     798.nx-hero-card-excerpt {
     799  font-size: 0.86rem;
     800  line-height: 1.5;
     801  color: var(--nx-text-light);
     802  margin: 0 0 14px 0;
     803  display: -webkit-box;
     804  -webkit-line-clamp: 2;
     805  line-clamp: 2;
     806  -webkit-box-orient: vertical;
     807  overflow: hidden;
     808}
     809
     810.nx-hero-card-footer {
     811  display: flex;
     812  align-items: center;
     813  justify-content: space-between;
     814  padding-top: 12px;
     815  border-top: 1px solid var(--nx-border);
     816  margin-top: auto;
     817  font-size: 0.8rem;
     818}
     819
     820.nx-hero-card-author {
     821  display: flex;
     822  align-items: center;
     823  gap: 7px;
     824  color: var(--nx-dark);
     825  font-weight: 600;
     826}
     827
     828.nx-hero-card-avatar {
     829  width: 22px;
     830  height: 22px;
     831  border-radius: 50%;
     832}
     833
     834.nx-hero-card-read-link {
     835  display: inline-flex;
     836  align-items: center;
     837  gap: 4px;
     838  color: var(--nx-primary);
     839  font-weight: 700;
     840  text-decoration: none;
     841  font-size: 0.82rem;
     842  transition: transform 0.2s ease;
     843}
     844
     845.nx-hero-card-read-link:hover {
     846  transform: translateX(3px);
     847}
     848
     849@media (max-width: 900px) {
     850  .nx-hero-grid {
     851    grid-template-columns: 1fr;
     852    gap: 28px;
     853  }
     854
     855  .nx-hero-featured-card {
     856    max-width: 100%;
     857  }
     858
     859  .nx-hero-card-thumb-wrap {
     860    height: 180px;
     861  }
    603862}
    604863
    … …  
    648907
    649908/* Layout Grid (Main Content + Sidebar) */
    650 .nx-layout-grid {
     909.nx-layout-grid,
     910.site-container {
    651911  display: grid;
    652912  grid-template-columns: 1fr;
    653913  gap: 36px;
    654914  margin-bottom: 60px;
     915  align-items: start;
     916  width: 100%;
    655917}
    656918
    657919@media (min-width: 992px) {
    658   .nx-layout-grid {
     920  .nx-layout-grid,
     921  .site-container {
    659922    grid-template-columns: 2.2fr 1fr;
    660923  }
    661924}
    662925
    663 /* Post Cards Grid */
    664 .nx-posts-grid {
     926.nx-content-area,
     927.content-area {
     928  min-width: 0;
     929  width: 100%;
     930}
     931
     932/* ==========================================================================
     933   Article Grid System (3 Columns with Sidebar, 4 Columns without Sidebar)
     934   ========================================================================== */
     935
     936/* 1. Default (With Sidebar Active): 1-col on mobile, 2-col on tablet, 3-col on desktop */
     937.nx-posts-grid,
     938.posts-grid {
    665939  display: grid;
    666940  grid-template-columns: 1fr;
    667941  gap: 20px;
    668 }
    669 
    670 @media (min-width: 640px) {
    671   .nx-posts-grid {
     942  width: 100%;
     943}
     944
     945@media (min-width: 600px) {
     946  .nx-posts-grid,
     947  .posts-grid {
    672948    grid-template-columns: repeat(2, 1fr);
    673   }
     949    gap: 20px;
     950  }
     951}
     952
     953/* On Desktop when Sidebar is present: 3 articles in a row */
     954@media (min-width: 992px) {
     955  .nx-posts-grid,
     956  .posts-grid {
     957    grid-template-columns: repeat(3, 1fr);
     958    gap: 20px;
     959  }
     960}
     961
     962/* 2. Without Sidebar (Disabled via Page Settings or no active sidebar): 4 articles in a row on Desktop! */
     963@media (min-width: 1080px) {
     964  .nx-no-sidebar .nx-posts-grid,
     965  .nx-no-sidebar .posts-grid,
     966  .nx-layout-grid:not(:has(.site-sidebar)) .nx-posts-grid,
     967  .nx-layout-grid:not(:has(.site-sidebar)) .posts-grid,
     968  .nx-layout-contained .nx-posts-grid,
     969  .nx-layout-contained .posts-grid,
     970  .nx-layout-stretched .nx-posts-grid,
     971  .nx-layout-stretched .posts-grid {
     972    grid-template-columns: repeat(4, 1fr) !important;
     973    gap: 22px !important;
     974  }
     975}
     976
     977@media (min-width: 768px) and (max-width: 1079px) {
     978  .nx-no-sidebar .nx-posts-grid,
     979  .nx-no-sidebar .posts-grid,
     980  .nx-layout-grid:not(:has(.site-sidebar)) .nx-posts-grid,
     981  .nx-layout-grid:not(:has(.site-sidebar)) .posts-grid,
     982  .nx-layout-contained .nx-posts-grid,
     983  .nx-layout-contained .posts-grid,
     984  .nx-layout-stretched .nx-posts-grid,
     985  .nx-layout-stretched .posts-grid {
     986    grid-template-columns: repeat(3, 1fr) !important;
     987    gap: 20px !important;
     988  }
     989}
     990
     991@media (min-width: 520px) and (max-width: 767px) {
     992  .nx-no-sidebar .nx-posts-grid,
     993  .nx-no-sidebar .posts-grid,
     994  .nx-layout-grid:not(:has(.site-sidebar)) .nx-posts-grid,
     995  .nx-layout-grid:not(:has(.site-sidebar)) .posts-grid,
     996  .nx-layout-contained .nx-posts-grid,
     997  .nx-layout-contained .posts-grid,
     998  .nx-layout-stretched .nx-posts-grid,
     999  .nx-layout-stretched .posts-grid {
     1000    grid-template-columns: repeat(2, 1fr) !important;
     1001    gap: 18px !important;
     1002  }
     1003}
     1004
     1005/* 4-Column Post Cards Grid (for Blog page / full-width archives) */
     1006.nx-posts-grid-4col {
     1007  display: grid;
     1008  grid-template-columns: 1fr;
     1009  gap: 20px;
     1010  width: 100%;
     1011}
     1012
     1013@media (min-width: 520px) {
     1014  .nx-posts-grid-4col {
     1015    grid-template-columns: repeat(2, 1fr);
     1016  }
     1017}
     1018
     1019@media (min-width: 768px) {
     1020  .nx-posts-grid-4col {
     1021    grid-template-columns: repeat(3, 1fr);
     1022  }
     1023}
     1024
     1025@media (min-width: 1080px) {
     1026  .nx-posts-grid-4col {
     1027    grid-template-columns: repeat(4, 1fr);
     1028  }
     1029}
     1030
     1031/* Contact Information Details */
     1032.nx-contact-details {
     1033  display: flex;
     1034  flex-direction: column;
     1035  gap: 20px;
     1036  margin-top: 18px;
     1037}
     1038
     1039.nx-contact-item {
     1040  display: flex;
     1041  flex-direction: column;
     1042  gap: 3px;
     1043}
     1044
     1045.nx-contact-label {
     1046  font-size: 0.8rem !important;
     1047  font-weight: 700 !important;
     1048  color: var(--nx-text-light) !important;
     1049  text-transform: uppercase !important;
     1050  letter-spacing: 0.05em !important;
     1051  margin-bottom: 2px !important;
     1052}
     1053
     1054.nx-contact-val {
     1055  font-weight: 600;
     1056  font-size: 0.95rem;
     1057  color: var(--nx-dark);
     1058  margin-top: 0 !important;
     1059  margin-bottom: 0 !important;
     1060}
     1061
     1062.nx-contact-val a {
     1063  color: var(--nx-primary);
     1064  text-decoration: none;
     1065}
     1066
     1067.nx-contact-val a:hover {
     1068  text-decoration: underline;
    6741069}
    6751070
    … …  
    6941089  overflow: hidden;
    6951090  aspect-ratio: 16 / 9;
    696   max-height: 155px;
     1091  max-height: 120px;
    6971092  background: #e2e8f0;
    6981093}
    … …  
    7081103  width: 100%;
    7091104  height: 100%;
    710   min-height: 135px;
     1105  min-height: 105px;
    7111106  background: linear-gradient(135deg, #4f46e5 0%, #06b6d4 100%);
    7121107  display: flex;
    … …  
    7141109  justify-content: center;
    7151110  color: #ffffff;
    716   font-size: 1.5rem;
     1111  font-size: 1.4rem;
    7171112  font-weight: 800;
    7181113  letter-spacing: -0.05em;
    … …  
    7251120
    7261121.nx-card-body {
    727   padding: 16px 18px;
     1122  padding: 13px 15px;
    7281123  display: flex;
    7291124  flex-direction: column;
    … …  
    7331128.nx-category-badge {
    7341129  display: inline-block;
    735   padding: 2px 8px;
     1130  padding: 2px 7px;
    7361131  background: var(--nx-primary-light);
    7371132  color: var(--nx-primary);
    738   font-size: 0.7rem;
     1133  font-size: 0.68rem;
    7391134  font-weight: 700;
    7401135  text-transform: uppercase;
    7411136  letter-spacing: 0.05em;
    7421137  border-radius: 4px;
    743   margin-bottom: 8px;
     1138  margin-bottom: 6px;
    7441139  align-self: flex-start;
    7451140}
    7461141
    7471142.nx-card-title {
    748   font-size: 1.05rem;
     1143  font-size: 0.96rem;
    7491144  font-weight: 700;
    750   line-height: 1.35;
    751   margin-bottom: 8px;
     1145  line-height: 1.32;
     1146  margin-bottom: 6px;
    7521147}
    7531148
    … …  
    7611156
    7621157.nx-card-excerpt {
    763   font-size: 0.85rem;
     1158  font-size: 0.8rem;
    7641159  color: var(--nx-text-light);
    765   line-height: 1.5;
    766   margin-bottom: 12px;
     1160  line-height: 1.45;
     1161  margin-bottom: 8px;
    7671162  flex-grow: 1;
    7681163  display: -webkit-box;
    7691164  -webkit-line-clamp: 2;
     1165  line-clamp: 2;
    7701166  -webkit-box-orient: vertical;
    7711167  overflow: hidden;
    … …  
    7771173  justify-content: space-between;
    7781174  border-top: 1px solid var(--nx-border);
    779   padding-top: 10px;
    780   font-size: 0.75rem;
     1175  padding-top: 8px;
     1176  margin-top: auto;
     1177  font-size: 0.72rem;
    7811178  color: var(--nx-text-light);
    7821179}
    … …  
    8011198
    8021199.nx-card-action {
    803   margin-top: 10px;
    804   padding-top: 8px;
    805   border-top: 1px dashed var(--nx-border);
    806   display: flex;
    807   align-items: center;
    808   justify-content: flex-end;
     1200  display: none !important;
    8091201}
    8101202
    … …  
    12881680}
    12891681
    1290 .nx-btn {
    1291   display: inline-block;
     1682/* ==========================================================================
     1683   Universal Buttons Styling (Site-wide, Hero, Cards, Blocks, Forms)
     1684   ========================================================================== */
     1685.nx-btn,
     1686.nx-hero-btn,
     1687.nx-btn-primary,
     1688.nx-card-cta,
     1689.nx-newsletter-btn,
     1690.nx-contact-submit,
     1691.wp-block-button__link,
     1692.wp-element-button,
     1693button[type="submit"],
     1694input[type="submit"],
     1695.comment-form .submit,
     1696#commentform #submit,
     1697.search-submit {
     1698  display: inline-flex;
     1699  align-items: center;
     1700  justify-content: center;
    12921701  padding: 12px 28px;
    1293   background: var(--nx-primary);
    1294   color: #ffffff;
     1702  background-color: var(--nx-btn-bg, var(--nx-primary)) !important;
     1703  color: var(--nx-btn-text, #ffffff) !important;
     1704  border: 1px solid var(--nx-btn-bg, var(--nx-primary)) !important;
    12951705  border-radius: 30px;
    12961706  font-weight: 600;
    12971707  font-size: 0.95rem;
    1298   transition: background 0.2s;
    1299 }
    1300 
    1301 .nx-btn:hover {
    1302   background: var(--nx-primary-hover);
    1303   color: #ffffff;
     1708  text-decoration: none;
     1709  cursor: pointer;
     1710  transition: all 0.25s ease;
     1711}
     1712
     1713.nx-btn:hover,
     1714.nx-hero-btn:hover,
     1715.nx-btn-primary:hover,
     1716.nx-card-cta:hover,
     1717.nx-newsletter-btn:hover,
     1718.nx-contact-submit:hover,
     1719.wp-block-button__link:hover,
     1720.wp-element-button:hover,
     1721button[type="submit"]:hover,
     1722input[type="submit"]:hover,
     1723.comment-form .submit:hover,
     1724#commentform #submit:hover,
     1725.search-submit:hover {
     1726  background-color: var(--nx-btn-hover, var(--nx-primary-hover)) !important;
     1727  border-color: var(--nx-btn-hover, var(--nx-primary-hover)) !important;
     1728  color: var(--nx-btn-text, #ffffff) !important;
     1729  transform: translateY(-2px);
    13041730}
    13051731
    … …  
    14421868.footer-bottom {
    14431869  padding-top: 28px;
    1444   display: flex;
    1445   flex-direction: column;
    1446   justify-content: center;
    1447   align-items: center;
    1448   text-align: center;
     1870  display: flex !important;
     1871  flex-direction: column !important;
     1872  justify-content: center !important;
     1873  align-items: center !important;
     1874  text-align: center !important;
    14491875  font-size: 0.88rem;
    14501876  gap: 12px;
    14511877  color: #64748b !important;
     1878  width: 100%;
    14521879}
    14531880
    … …  
    14561883.footer-bottom-content {
    14571884  color: #64748b !important;
    1458   margin: 0;
    1459   text-align: center;
     1885  margin: 0 auto !important;
     1886  text-align: center !important;
     1887  width: 100%;
     1888  display: flex;
     1889  justify-content: center;
     1890  align-items: center;
    14601891}
    14611892
    14621893.nx-footer-credits {
    1463   display: flex;
    1464   align-items: center;
    1465   justify-content: center;
    1466   flex-wrap: wrap;
    1467   gap: 8px;
    1468   line-height: 1.6;
     1894  display: flex !important;
     1895  align-items: center !important;
     1896  justify-content: center !important;
     1897  flex-wrap: wrap !important;
     1898  gap: 8px !important;
     1899  line-height: 1.6 !important;
     1900  text-align: center !important;
     1901  margin: 0 auto !important;
    14691902}
    14701903
    … …  
    21612594  }
    21622595
     2596  .custom-logo-link img,
     2597  .custom-logo {
     2598    max-height: 30px !important;
     2599    max-width: 150px !important;
     2600  }
     2601
    21632602  .header-actions {
    21642603    gap: 6px;
    … …  
    24732912}
    24742913
    2475 .nx-ad-header {
    2476   margin: 12px auto;
     2914/* Bounding Box Base for Zero Cumulative Layout Shift (CLS = 0) */
     2915.nx-ad-slot-cls {
     2916  contain: layout;
     2917}
     2918
     2919.nx-ad-bounding-box {
     2920  position: relative;
     2921  display: flex;
     2922  align-items: center;
     2923  justify-content: center;
     2924  margin: 0 auto;
     2925  overflow: hidden;
     2926  border-radius: 8px;
     2927  background-color: transparent;
     2928  border: none;
     2929  box-sizing: border-box;
     2930}
     2931
     2932[data-theme="dark"] .nx-ad-bounding-box,
     2933body.dark-mode .nx-ad-bounding-box {
     2934  background-color: transparent;
     2935  border-color: transparent;
     2936}
     2937
     2938/* Ad Loaded State */
     2939.nx-ad-bounding-box.nx-ad-loaded {
     2940  background-color: transparent !important;
     2941  border-color: transparent !important;
     2942}
     2943
     2944/* Slot 1: Header Banner (728x90 Leaderboard / 320x100 Mobile) */
     2945.nx-ad-box-header {
     2946  width: 728px;
     2947  max-width: 100%;
     2948  min-height: 90px;
     2949  aspect-ratio: 728 / 90;
     2950}
     2951@media (max-width: 767px) {
     2952  .nx-ad-box-header {
     2953    width: 100%;
     2954    max-width: 320px;
     2955    min-height: 100px;
     2956    aspect-ratio: 320 / 100;
     2957  }
     2958}
     2959
     2960/* Slot 2: In-Article Mid-Content (336x280 / 300x250) */
     2961.nx-ad-box-article {
     2962  width: 336px;
     2963  max-width: 100%;
     2964  min-height: 280px;
     2965  aspect-ratio: 336 / 280;
     2966  margin: 28px auto;
     2967}
     2968@media (max-width: 767px) {
     2969  .nx-ad-box-article {
     2970    width: 300px;
     2971    max-width: 100%;
     2972    min-height: 250px;
     2973    aspect-ratio: 300 / 250;
     2974  }
     2975}
     2976
     2977/* Slot 3: Below Post Content (336x280 / 300x250) */
     2978.nx-ad-box-post_bottom {
     2979  width: 336px;
     2980  max-width: 100%;
     2981  min-height: 280px;
     2982  aspect-ratio: 336 / 280;
     2983  margin: 32px auto 24px auto;
     2984}
     2985@media (max-width: 767px) {
     2986  .nx-ad-box-post_bottom {
     2987    width: 300px;
     2988    max-width: 100%;
     2989    min-height: 250px;
     2990    aspect-ratio: 300 / 250;
     2991  }
     2992}
     2993
     2994/* Slot 4: In-Feed Grid Card (360x360 1:1 Aspect Ratio) */
     2995.nx-ad-box-infeed {
     2996  width: 100%;
     2997  min-height: 340px;
     2998  aspect-ratio: 1 / 1;
     2999}
     3000.nx-infeed-ad-card {
    24773001  padding: 16px;
    2478   background: var(--nx-card-bg);
    2479   border: 1px dashed var(--nx-border);
    2480   border-radius: var(--nx-radius-sm);
    2481 }
    2482 
    2483 .nx-ad-article {
    2484   margin: 32px auto;
    2485   padding: 20px;
    2486   background: var(--nx-bg);
    2487   border: 1px dashed var(--nx-border);
    2488   border-radius: var(--nx-radius-sm);
    2489 }
    2490 
    2491 .nx-ad-post_bottom {
    2492   margin: 32px 0 24px 0;
    2493   padding: 20px;
    2494   background: var(--nx-bg);
    2495   border: 1px dashed var(--nx-border);
    2496   border-radius: var(--nx-radius-sm);
    2497 }
    2498 
    2499 .nx-infeed-ad-card {
    2500   display: flex;
    2501   flex-direction: column;
    2502   align-items: center;
    2503   justify-content: center;
    2504   min-height: 280px;
    2505   padding: 24px;
    2506   background: var(--nx-card-bg);
    2507   border: 1px dashed var(--nx-border);
    2508   border-radius: var(--nx-radius);
    2509   text-align: center;
    2510   box-shadow: var(--nx-shadow-sm);
    2511 }
    2512 
    2513 .nx-infeed-ad-card .nx-ad-slot {
    2514   margin: 0;
    2515   width: 100%;
    2516 }
    2517 
     3002  border: 1px solid var(--nx-border, #e2e8f0);
     3003  background: var(--nx-card-bg, #ffffff);
     3004  border-radius: var(--nx-radius, 12px);
     3005  box-shadow: var(--nx-shadow-sm, 0 1px 3px rgba(0,0,0,0.06));
     3006}
     3007@media (max-width: 767px) {
     3008  .nx-ad-box-infeed {
     3009    min-height: 280px;
     3010  }
     3011}
     3012
     3013/* Slot 5: Sticky Half-Page Sidebar (300x600 / 300x250) */
     3014.nx-ad-box-sidebar {
     3015  width: 300px;
     3016  max-width: 100%;
     3017  min-height: 600px;
     3018  aspect-ratio: 300 / 600;
     3019}
    25183020.nx-sidebar-sticky-ad {
    25193021  position: sticky;
    25203022  top: 90px;
    25213023  z-index: 5;
    2522   margin-top: 24px;
    2523   background: var(--nx-card-bg);
     3024}
     3025@media (max-width: 767px) {
     3026  .nx-ad-box-sidebar {
     3027    width: 300px;
     3028    max-width: 100%;
     3029    min-height: 250px;
     3030    aspect-ratio: 300 / 250;
     3031  }
     3032}
     3033
     3034@keyframes nxAdShimmer {
     3035  0% { background-position: 200% 0; }
     3036  100% { background-position: -200% 0; }
     3037}
     3038
     3039.nx-ad-blocker-bypass {
     3040  width: 100%;
     3041  text-align: center;
     3042  padding: 18px 20px;
     3043  background: var(--nx-bg);
    25243044  border: 1px dashed var(--nx-border);
    25253045  border-radius: var(--nx-radius-sm);
    2526   padding: 16px !important;
    2527   text-align: center;
    2528 }
    2529 
    2530 .nx-sidebar-sticky-ad .nx-ad-slot {
    2531   margin: 0;
    2532 }
    2533 
    2534 [data-theme="dark"] .nx-ad-header,
    2535 [data-theme="dark"] .nx-ad-article,
    2536 [data-theme="dark"] .nx-ad-post_bottom,
    2537 [data-theme="dark"] .nx-infeed-ad-card,
    2538 [data-theme="dark"] .nx-sidebar-sticky-ad {
     3046  animation: nxFadeSlideIn 0.3s ease;
     3047}
     3048
     3049[data-theme="dark"] .nx-ad-blocker-bypass {
    25393050  background: #111827;
    25403051  border-color: #1f2937;
     3052}
     3053
     3054.nx-ad-blocker-bypass img {
     3055  max-width: 100%;
     3056  height: auto;
     3057  border-radius: var(--nx-radius-sm);
    25413058}
    25423059
    … …  
    26423159}
    26433160
    2644 
    2645 
    2646 
    2647 
     3161/* ==========================================================================
     3162   Page Flexibility: Astra-Style Layouts & Element Toggles
     3163   ========================================================================== */
     3164
     3165/* Disable Sidebar (Force 100% Content Width) */
     3166.nx-no-sidebar .nx-layout-grid,
     3167.nx-layout-grid:not(:has(.site-sidebar)) {
     3168  grid-template-columns: 1fr !important;
     3169}
     3170
     3171.nx-no-sidebar .nx-content-area,
     3172.nx-layout-grid:not(:has(.site-sidebar)) .nx-content-area {
     3173  max-width: 100% !important;
     3174  width: 100% !important;
     3175}
     3176
     3177/* Full Width (Contained): Outer wrapper expands, content remains safely contained & padded */
     3178.nx-layout-contained .site-main.container,
     3179.nx-layout-contained .container {
     3180  max-width: 100% !important;
     3181  width: 100% !important;
     3182  padding-left: clamp(16px, 3.5vw, 36px) !important;
     3183  padding-right: clamp(16px, 3.5vw, 36px) !important;
     3184}
     3185
     3186.nx-layout-contained .nx-single-article,
     3187.nx-layout-contained .nx-page-card {
     3188  max-width: min(100%, var(--nx-max-width, 1200px)) !important;
     3189  margin-left: auto !important;
     3190  margin-right: auto !important;
     3191  padding: clamp(24px, 4vw, 44px) !important;
     3192}
     3193
     3194/* Full Width Stretched (Canvas / Elementor & Landing Pages) */
     3195/* Container expands to 100% viewport width with safe horizontal breathing gutters */
     3196.nx-layout-stretched .site-main.container,
     3197.nx-layout-stretched .container {
     3198  max-width: 100% !important;
     3199  width: 100% !important;
     3200  padding-left: clamp(16px, 3.5vw, 40px) !important;
     3201  padding-right: clamp(16px, 3.5vw, 40px) !important;
     3202  margin-left: auto !important;
     3203  margin-right: auto !important;
     3204}
     3205
     3206.nx-layout-stretched .site-main {
     3207  margin-top: 24px !important;
     3208  margin-bottom: 40px !important;
     3209}
     3210
     3211.nx-layout-stretched .nx-layout-grid {
     3212  grid-template-columns: 1fr !important;
     3213  gap: 0 !important;
     3214  width: 100% !important;
     3215}
     3216
     3217.nx-layout-stretched .nx-content-area {
     3218  max-width: 100% !important;
     3219  width: 100% !important;
     3220}
     3221
     3222/* Standard Posts & Pages in Stretched Mode: Keep comfortable reading container so text never smashes screen edges */
     3223.nx-layout-stretched .nx-single-article,
     3224.nx-layout-stretched .nx-page-card {
     3225  background: var(--nx-card-bg);
     3226  border: 1px solid var(--nx-border);
     3227  border-radius: var(--nx-radius);
     3228  padding: clamp(24px, 4vw, 48px) !important;
     3229  max-width: min(100%, var(--nx-max-width, 1200px));
     3230  margin-left: auto !important;
     3231  margin-right: auto !important;
     3232  box-shadow: var(--nx-shadow-sm);
     3233}
     3234
     3235/* Pure Page Builders (Elementor, Beaver Builder, or Gutenberg Full-Bleed Blocks) */
     3236/* When an Elementor section or full-bleed block exists, remove container constraints completely */
     3237.nx-layout-stretched .elementor,
     3238.nx-layout-stretched .entry-content:has(.elementor),
     3239.nx-layout-stretched .nx-single-article:has(.elementor),
     3240.nx-layout-stretched .nx-page-card:has(.elementor) {
     3241  background: transparent !important;
     3242  border: none !important;
     3243  border-radius: 0 !important;
     3244  padding: 0 !important;
     3245  max-width: 100% !important;
     3246  box-shadow: none !important;
     3247}
     3248
     3249.nx-layout-stretched:has(.elementor) .site-main.container,
     3250.nx-layout-stretched:has(.elementor) .container {
     3251  padding-left: 0 !important;
     3252  padding-right: 0 !important;
     3253}
     3254
     3255/* Gutenberg alignfull breakout support */
     3256.nx-layout-stretched .alignfull,
     3257.nx-layout-contained .alignfull {
     3258  width: 100vw !important;
     3259  max-width: 100vw !important;
     3260  margin-left: calc(50% - 50vw) !important;
     3261  margin-right: calc(50% - 50vw) !important;
     3262}
     3263
     3264/* ==========================================================================
     3265   Popular Categories Grid (Image 4 Design)
     3266   ========================================================================== */
     3267.nx-categories-browse-all {
     3268  font-size: 0.92rem;
     3269  font-weight: 700;
     3270  color: var(--nx-text-light);
     3271  text-decoration: none;
     3272  display: inline-flex;
     3273  align-items: center;
     3274  gap: 6px;
     3275  transition: color 0.2s ease, transform 0.2s ease;
     3276}
     3277
     3278.nx-categories-browse-all:hover {
     3279  color: var(--nx-primary);
     3280  transform: translateX(3px);
     3281}
     3282
     3283.nx-popular-categories-grid {
     3284  display: grid;
     3285  grid-template-columns: repeat(4, 1fr);
     3286  gap: 18px;
     3287  width: 100%;
     3288}
     3289
     3290@media (max-width: 1080px) {
     3291  .nx-popular-categories-grid {
     3292    grid-template-columns: repeat(3, 1fr);
     3293  }
     3294}
     3295
     3296@media (max-width: 768px) {
     3297  .nx-popular-categories-grid {
     3298    grid-template-columns: repeat(2, 1fr);
     3299    gap: 14px;
     3300  }
     3301}
     3302
     3303@media (max-width: 480px) {
     3304  .nx-popular-categories-grid {
     3305    grid-template-columns: 1fr;
     3306  }
     3307}
     3308
     3309.nx-pop-cat-card {
     3310  display: flex;
     3311  flex-direction: column;
     3312  background: var(--nx-card-bg);
     3313  border: 1px solid var(--nx-border);
     3314  border-radius: var(--nx-radius);
     3315  padding: 22px 20px;
     3316  text-decoration: none;
     3317  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
     3318}
     3319
     3320[data-theme="dark"] .nx-pop-cat-card {
     3321  background: #111827;
     3322  border-color: rgba(255, 255, 255, 0.08);
     3323}
     3324
     3325.nx-pop-cat-card:hover {
     3326  transform: translateY(-3px);
     3327  border-color: var(--nx-primary);
     3328  box-shadow: var(--nx-shadow-md);
     3329}
     3330
     3331.nx-pop-cat-icon {
     3332  width: 36px;
     3333  height: 36px;
     3334  border-radius: 8px;
     3335  display: flex;
     3336  align-items: center;
     3337  justify-content: center;
     3338  color: #ffffff;
     3339  font-weight: 800;
     3340  font-size: 1.15rem;
     3341  line-height: 1;
     3342  margin-bottom: 14px;
     3343}
     3344
     3345.nx-pop-cat-name {
     3346  font-size: 1.02rem;
     3347  font-weight: 800;
     3348  color: var(--nx-dark);
     3349  margin: 0 0 8px 0;
     3350  line-height: 1.3;
     3351}
     3352
     3353[data-theme="dark"] .nx-pop-cat-name {
     3354  color: #ffffff;
     3355}
     3356
     3357.nx-pop-cat-desc {
     3358  font-size: 0.82rem;
     3359  color: var(--nx-text-light);
     3360  line-height: 1.5;
     3361  margin: 0 0 14px 0;
     3362  flex-grow: 1;
     3363  display: -webkit-box;
     3364  -webkit-line-clamp: 2;
     3365  line-clamp: 2;
     3366  -webkit-box-orient: vertical;
     3367  overflow: hidden;
     3368}
     3369
     3370.nx-pop-cat-count {
     3371  font-size: 0.78rem;
     3372  font-weight: 600;
     3373  color: var(--nx-text-light);
     3374  margin-top: auto;
     3375}
     3376
     3377/* ==========================================================================
     3378   Homepage Author Box (Image 3 Design)
     3379   ========================================================================== */
     3380.nx-home-author-card {
     3381  display: flex;
     3382  align-items: center;
     3383  gap: 22px;
     3384  background: var(--nx-card-bg);
     3385  border: 1px solid var(--nx-border);
     3386  border-radius: var(--nx-radius);
     3387  padding: 24px 28px;
     3388  box-shadow: var(--nx-shadow-sm);
     3389}
     3390
     3391[data-theme="dark"] .nx-home-author-card {
     3392  background: #111827;
     3393  border-color: rgba(255, 255, 255, 0.08);
     3394}
     3395
     3396.nx-author-avatar-wrap {
     3397  flex-shrink: 0;
     3398}
     3399
     3400.nx-author-avatar-link {
     3401  display: block;
     3402  text-decoration: none;
     3403  cursor: pointer;
     3404  transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
     3405}
     3406
     3407.nx-author-avatar-link:hover {
     3408  transform: scale(1.06);
     3409}
     3410
     3411.nx-author-avatar-circle {
     3412  width: 62px;
     3413  height: 62px;
     3414  border-radius: 50%;
     3415  background: linear-gradient(135deg, #6366f1 0%, #a855f7 100%);
     3416  display: flex;
     3417  align-items: center;
     3418  justify-content: center;
     3419  color: #ffffff;
     3420  font-size: 1.7rem;
     3421  font-weight: 800;
     3422  box-shadow: 0 4px 14px rgba(99, 102, 241, 0.35);
     3423  overflow: hidden;
     3424  position: relative;
     3425}
     3426
     3427.nx-author-avatar-img {
     3428  width: 100%;
     3429  height: 100%;
     3430  object-fit: cover;
     3431  border-radius: 50%;
     3432  display: block;
     3433}
     3434
     3435.nx-author-avatar-initial {
     3436  line-height: 1;
     3437  display: flex;
     3438  align-items: center;
     3439  justify-content: center;
     3440  user-select: none;
     3441}
     3442
     3443.nx-author-name {
     3444  font-size: 1.15rem;
     3445  font-weight: 800;
     3446  color: var(--nx-dark);
     3447  margin: 0 0 2px 0;
     3448}
     3449
     3450.nx-author-name-link {
     3451  color: inherit;
     3452  text-decoration: none;
     3453  cursor: pointer;
     3454  display: inline-block;
     3455  transition: color 0.2s ease;
     3456}
     3457
     3458.nx-author-name-link:hover {
     3459  color: var(--nx-primary, #4f46e5);
     3460  text-decoration: none;
     3461}
     3462
     3463[data-theme="dark"] .nx-author-name {
     3464  color: #ffffff;
     3465}
     3466
     3467[data-theme="dark"] .nx-author-name-link:hover {
     3468  color: #818cf8;
     3469}
     3470
     3471.nx-author-role {
     3472  font-size: 0.85rem;
     3473  font-weight: 700;
     3474  color: #8b5cf6;
     3475  margin-bottom: 6px;
     3476}
     3477
     3478.nx-author-role-link {
     3479  color: #8b5cf6;
     3480  text-decoration: none;
     3481  cursor: pointer;
     3482  display: inline-block;
     3483  transition: color 0.2s ease, opacity 0.2s ease;
     3484}
     3485
     3486.nx-author-role-link:hover {
     3487  color: #7c3aed;
     3488  text-decoration: underline;
     3489}
     3490
     3491[data-theme="dark"] .nx-author-role-link {
     3492  color: #a78bfa;
     3493}
     3494
     3495[data-theme="dark"] .nx-author-role-link:hover {
     3496  color: #c084fc;
     3497}
     3498
     3499.nx-author-bio {
     3500  font-size: 0.9rem;
     3501  color: var(--nx-text-light);
     3502  line-height: 1.5;
     3503  margin: 0;
     3504}
     3505
     3506@media (max-width: 600px) {
     3507  .nx-home-author-card {
     3508    flex-direction: column;
     3509    text-align: center;
     3510    padding: 24px 20px;
     3511    gap: 16px;
     3512  }
     3513}
     3514
     3515/* ==========================================================================
     3516   Newsletter Box v2 (Adaptive Theme: Light White on Sun / Sleek Dark on Moon)
     3517   ========================================================================== */
     3518.nx-newsletter-v2 {
     3519  background: var(--nx-card-bg, #ffffff);
     3520  border: 1px solid var(--nx-border, #e2e8f0);
     3521  border-radius: 16px;
     3522  padding: clamp(28px, 4vw, 42px);
     3523  box-shadow: var(--nx-shadow-sm, 0 1px 3px rgba(0, 0, 0, 0.05));
     3524  display: grid;
     3525  grid-template-columns: 1.1fr 0.9fr;
     3526  align-items: center;
     3527  gap: 32px;
     3528  transition: background 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
     3529}
     3530
     3531[data-theme="dark"] .nx-newsletter-v2 {
     3532  background: linear-gradient(135deg, #090d16 0%, #111827 50%, #1e1b4b 100%) !important;
     3533  border-color: rgba(255, 255, 255, 0.09) !important;
     3534  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35) !important;
     3535}
     3536
     3537@media (max-width: 900px) {
     3538  .nx-newsletter-v2 {
     3539    grid-template-columns: 1fr;
     3540    gap: 24px;
     3541  }
     3542}
     3543
     3544.nx-newsletter-badge-v2 {
     3545  display: inline-flex;
     3546  align-items: center;
     3547  gap: 6px;
     3548  padding: 3px 10px;
     3549  background: var(--nx-primary-light, #eef2ff);
     3550  color: var(--nx-primary, #4f46e5);
     3551  border: 1px solid rgba(79, 70, 229, 0.15);
     3552  border-radius: 20px;
     3553  font-size: 0.72rem;
     3554  font-weight: 700;
     3555  text-transform: uppercase;
     3556  letter-spacing: 0.05em;
     3557  margin-bottom: 12px;
     3558  transition: background 0.3s ease, color 0.3s ease, border-color 0.3s ease;
     3559}
     3560
     3561[data-theme="dark"] .nx-newsletter-badge-v2 {
     3562  background: rgba(255, 255, 255, 0.08) !important;
     3563  color: #cbd5e1 !important;
     3564  border-color: rgba(255, 255, 255, 0.12) !important;
     3565}
     3566
     3567.nx-newsletter-title-v2 {
     3568  font-size: clamp(1.45rem, 2.5vw, 2.1rem);
     3569  font-weight: 800;
     3570  color: var(--nx-dark, #0f172a);
     3571  margin: 0 0 10px 0;
     3572  line-height: 1.25;
     3573  letter-spacing: -0.02em;
     3574  transition: color 0.3s ease;
     3575}
     3576
     3577[data-theme="dark"] .nx-newsletter-title-v2 {
     3578  color: #ffffff !important;
     3579}
     3580
     3581.nx-nl-highlight {
     3582  color: var(--nx-primary, #4f46e5);
     3583  transition: color 0.3s ease;
     3584}
     3585
     3586[data-theme="dark"] .nx-nl-highlight {
     3587  color: #c084fc !important;
     3588}
     3589
     3590.nx-newsletter-desc-v2 {
     3591  font-size: 0.92rem;
     3592  color: var(--nx-text-light, #64748b);
     3593  line-height: 1.55;
     3594  margin: 0;
     3595  transition: color 0.3s ease;
     3596}
     3597
     3598[data-theme="dark"] .nx-newsletter-desc-v2 {
     3599  color: #94a3b8 !important;
     3600}
     3601
     3602.nx-newsletter-form-v2 {
     3603  width: 100%;
     3604}
     3605
     3606.nx-nl-input-wrap {
     3607  display: flex;
     3608  align-items: center;
     3609  background: #f8fafc;
     3610  border: 1px solid var(--nx-border, #e2e8f0);
     3611  border-radius: 12px;
     3612  padding: 6px 6px 6px 14px;
     3613  transition: background 0.3s ease, border-color 0.2s ease, box-shadow 0.2s ease;
     3614}
     3615
     3616[data-theme="dark"] .nx-nl-input-wrap {
     3617  background: rgba(15, 23, 42, 0.85) !important;
     3618  border-color: rgba(255, 255, 255, 0.14) !important;
     3619}
     3620
     3621.nx-nl-input-wrap:focus-within {
     3622  border-color: var(--nx-primary, #4f46e5);
     3623  box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.15);
     3624}
     3625
     3626[data-theme="dark"] .nx-nl-input-wrap:focus-within {
     3627  border-color: #818cf8 !important;
     3628  box-shadow: 0 0 0 3px rgba(129, 140, 248, 0.25) !important;
     3629}
     3630
     3631.nx-nl-input-icon {
     3632  color: #94a3b8;
     3633  display: flex;
     3634  align-items: center;
     3635  margin-right: 10px;
     3636  flex-shrink: 0;
     3637  transition: color 0.3s ease;
     3638}
     3639
     3640[data-theme="dark"] .nx-nl-input-icon {
     3641  color: #64748b !important;
     3642}
     3643
     3644.nx-nl-email-input {
     3645  background: transparent !important;
     3646  border: none !important;
     3647  color: var(--nx-dark, #0f172a);
     3648  font-size: 0.95rem;
     3649  width: 100%;
     3650  outline: none !important;
     3651  padding: 8px 4px !important;
     3652  transition: color 0.3s ease;
     3653}
     3654
     3655[data-theme="dark"] .nx-nl-email-input {
     3656  color: #ffffff !important;
     3657}
     3658
     3659.nx-nl-email-input::placeholder {
     3660  color: #94a3b8;
     3661}
     3662
     3663[data-theme="dark"] .nx-nl-email-input::placeholder {
     3664  color: #64748b !important;
     3665}
     3666
     3667.nx-nl-submit-btn {
     3668  background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%) !important;
     3669  color: #ffffff !important;
     3670  border: none !important;
     3671  border-radius: 8px !important;
     3672  padding: 10px 22px !important;
     3673  font-weight: 700 !important;
     3674  font-size: 0.92rem !important;
     3675  cursor: pointer;
     3676  white-space: nowrap;
     3677  transition: transform 0.15s ease, opacity 0.2s ease, box-shadow 0.2s ease;
     3678  box-shadow: 0 2px 8px rgba(79, 70, 229, 0.3);
     3679}
     3680
     3681.nx-nl-submit-btn:hover {
     3682  transform: translateY(-1px);
     3683  opacity: 0.95;
     3684  box-shadow: 0 4px 12px rgba(79, 70, 229, 0.4);
     3685}
     3686
     3687/* Newsletter Success State Card (When Subscribed or Logged In) */
     3688.nx-nl-success-card {
     3689  background: #f0fdf4;
     3690  border: 1px solid rgba(16, 185, 129, 0.35);
     3691  border-radius: 14px;
     3692  padding: 20px 24px;
     3693  transition: background 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
     3694  box-shadow: 0 2px 8px rgba(16, 185, 129, 0.08);
     3695  animation: nxFadeSlideIn 0.35s ease-out;
     3696}
     3697
     3698[data-theme="dark"] .nx-nl-success-card {
     3699  background: linear-gradient(135deg, rgba(6, 78, 59, 0.25) 0%, rgba(15, 23, 42, 0.7) 100%) !important;
     3700  border-color: rgba(52, 211, 153, 0.28) !important;
     3701  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.35) !important;
     3702}
     3703
     3704.nx-nl-success-title {
     3705  font-size: 1.1rem;
     3706  font-weight: 800;
     3707  color: #059669;
     3708  margin: 0 0 6px 0;
     3709  display: flex;
     3710  align-items: center;
     3711  gap: 6px;
     3712  line-height: 1.3;
     3713  letter-spacing: -0.01em;
     3714}
     3715
     3716[data-theme="dark"] .nx-nl-success-title {
     3717  color: #34d399 !important;
     3718}
     3719
     3720.nx-nl-success-desc {
     3721  font-size: 0.92rem;
     3722  color: #475569;
     3723  line-height: 1.5;
     3724  margin: 0;
     3725}
     3726
     3727[data-theme="dark"] .nx-nl-success-desc {
     3728  color: #94a3b8 !important;
     3729}
     3730
     3731@keyframes nxFadeSlideIn {
     3732  from {
     3733    opacity: 0;
     3734    transform: translateY(6px);
     3735  }
     3736  to {
     3737    opacity: 1;
     3738    transform: translateY(0);
     3739  }
     3740}
     3741
     3742/* ==========================================================================
     3743   Smart Social Media Icon Buttons (Follow Us Online)
     3744   ========================================================================== */
     3745.nx-contact-social-icons {
     3746  display: flex;
     3747  flex-wrap: wrap;
     3748  gap: 10px;
     3749  align-items: center;
     3750}
     3751
     3752.nx-social-icon-btn {
     3753  display: inline-flex;
     3754  align-items: center;
     3755  justify-content: center;
     3756  width: 38px;
     3757  height: 38px;
     3758  border-radius: 50%;
     3759  background: var(--nx-light);
     3760  border: 1px solid var(--nx-border);
     3761  color: var(--nx-dark);
     3762  text-decoration: none;
     3763  transition: all 0.25s ease;
     3764}
     3765
     3766[data-theme="dark"] .nx-social-icon-btn {
     3767  background: rgba(255, 255, 255, 0.05);
     3768  border-color: rgba(255, 255, 255, 0.1);
     3769  color: #ffffff;
     3770}
     3771
     3772.nx-social-icon-btn svg {
     3773  width: 17px;
     3774  height: 17px;
     3775  fill: currentColor;
     3776  transition: transform 0.2s ease;
     3777}
     3778
     3779.nx-social-icon-btn:hover {
     3780  transform: translateY(-2px);
     3781  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.14);
     3782}
     3783
     3784.nx-social-icon-btn.nx-social-facebook:hover {
     3785  background: #1877f2 !important;
     3786  border-color: #1877f2 !important;
     3787  color: #ffffff !important;
     3788}
     3789
     3790.nx-social-icon-btn.nx-social-twitter:hover {
     3791  background: #000000 !important;
     3792  border-color: #000000 !important;
     3793  color: #ffffff !important;
     3794}
     3795
     3796.nx-social-icon-btn.nx-social-linkedin:hover {
     3797  background: #0a66c2 !important;
     3798  border-color: #0a66c2 !important;
     3799  color: #ffffff !important;
     3800}
     3801
     3802.nx-social-icon-btn.nx-social-instagram:hover {
     3803  background: radial-gradient(circle at 30% 107%, #fdf497 0%, #fdf497 5%, #fd5949 45%, #d6249f 60%, #285AEB 90%) !important;
     3804  border-color: #d6249f !important;
     3805  color: #ffffff !important;
     3806}
     3807
     3808.nx-social-icon-btn.nx-social-youtube:hover {
     3809  background: #ff0000 !important;
     3810  border-color: #ff0000 !important;
     3811  color: #ffffff !important;
     3812}
     3813
     3814.nx-social-icon-btn.nx-social-github:hover {
     3815  background: #24292e !important;
     3816  border-color: #24292e !important;
     3817  color: #ffffff !important;
     3818}
     3819
     3820.nx-social-icon-btn.nx-social-discord:hover {
     3821  background: #5865f2 !important;
     3822  border-color: #5865f2 !important;
     3823  color: #ffffff !important;
     3824}
     3825
     3826.nx-social-icon-btn.nx-social-telegram:hover {
     3827  background: #229ed9 !important;
     3828  border-color: #229ed9 !important;
     3829  color: #ffffff !important;
     3830}
     3831
     3832.nx-social-icon-btn.nx-social-tiktok:hover {
     3833  background: #010101 !important;
     3834  border-color: #010101 !important;
     3835  color: #ffffff !important;
     3836}
     3837
     3838.nx-social-icon-btn.nx-social-website:hover {
     3839  background: var(--nx-primary) !important;
     3840  border-color: var(--nx-primary) !important;
     3841  color: #ffffff !important;
     3842}
     3843
     3844
     3845
     3846
     3847
     3848
  • nexversal/3.5.9/template-full-width.php

    r357433 r357886  
    11<?php
    2 /**
    3  * Security: Prevent direct script access
    4  */
    5 if (!defined('ABSPATH')) {
    6     exit;
    7 }
    8 
    92/**
    103 * Template Name: Full Width (No Sidebar)
    114 *
    125 * @package Nexversal
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
    1310 */
     11
     12if (!defined('ABSPATH')) {
     13    exit;
     14}
    1415
    1516get_header();
    … …  
    2324            ?>
    2425            <article id="post-<?php the_ID(); ?>" <?php post_class('nx-page-card'); ?>>
    25                 <?php nexversal_breadcrumbs(); ?>
     26                <?php
     27                if (!function_exists('nexversal_is_meta_disabled') || !nexversal_is_meta_disabled('disable_breadcrumbs')) {
     28                    nexversal_breadcrumbs();
     29                }
     30                ?>
    2631               
     32                <?php if (!function_exists('nexversal_is_meta_disabled') || !nexversal_is_meta_disabled('disable_title')) : ?>
    2733                <header class="nx-page-header" style="margin-bottom: 24px;">
    2834                    <h1 class="nx-page-title" style="font-size: 2.2rem; font-weight: 800; letter-spacing: -0.03em;"><?php the_title(); ?></h1>
    2935                </header>
     36                <?php endif; ?>
    3037
    3138                <?php if (has_post_thumbnail()) : ?>
  • nexversal/3.5.9/template-parts/content-card.php

    r357433 r357886  
    11<?php
    22/**
    3  * Security: Prevent direct script access
     3 * Template part for displaying an article card in Nexversal Theme
     4 *
     5 * @package Nexversal
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
    410 */
     11
    512if (!defined('ABSPATH')) {
    613    exit;
    714}
    8 
    9 /**
    10  * Template part for displaying a modern article card in grids
    11  *
    12  * @package Nexversal
    13  */
    1415?>
    1516<article id="post-<?php the_ID(); ?>" <?php post_class('nx-card'); ?>>
    … …  
    4041
    4142        <div class="nx-card-excerpt">
    42             <?php echo esc_html(wp_trim_words(get_the_excerpt(), 14, '...')); ?>
     43            <?php echo esc_html(wp_trim_words(get_the_excerpt(), 11, '...')); ?>
    4344        </div>
    4445
    4546        <div class="nx-card-meta">
    4647            <div class="nx-meta-author">
    47                 <?php echo get_avatar(get_the_author_meta('ID'), 22); ?>
     48                <?php echo get_avatar(get_the_author_meta('ID'), 20); ?>
    4849                <span><?php the_author(); ?></span>
    4950            </div>
    … …  
    5455            </div>
    5556        </div>
    56 
    57         <?php
    58         $card_btn_text = get_theme_mod('nexversal_card_btn_text', 'Read Article');
    59         if (!empty($card_btn_text)) :
    60             ?>
    61             <div class="nx-card-action">
    62                 <a href="<?php the_permalink(); ?>" class="nx-card-btn">
    63                     <span><?php echo esc_html($card_btn_text); ?></span>
    64                     <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>
    65                 </a>
    66             </div>
    67         <?php endif; ?>
    6857    </div>
    6958</article>
  • nexversal/3.5.9/template-parts/newsletter-box.php

    r357433 r357886  
    11<?php
    22/**
    3  * Security: Prevent direct script access
     3 * Newsletter Subscription Component for Nexversal Theme (Image 2 Design)
     4 *
     5 * @package Nexversal
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
    410 */
     11
    512if (!defined('ABSPATH')) {
    613    exit;
    714}
    815
    9 /**
    10  * Newsletter Subscription Component
    11  *
    12  * @package Nexversal
    13  */
     16$nl_title         = get_theme_mod('nexversal_newsletter_title', __('New AI tool reviews,', 'nexversal'));
     17$nl_highlight     = get_theme_mod('nexversal_newsletter_highlight', __('in your inbox.', 'nexversal'));
     18$nl_desc          = get_theme_mod('nexversal_newsletter_desc', __('Get new reviews and comparisons in your inbox. No spam, unsubscribe anytime.', 'nexversal'));
     19$nl_btn           = get_theme_mod('nexversal_newsletter_btn_text', __('Subscribe', 'nexversal'));
     20$nl_success_title = get_theme_mod('nexversal_newsletter_success_title', __("You're in. ✨", 'nexversal'));
     21$nl_success_desc  = get_theme_mod('nexversal_newsletter_success_desc', __("We'll email you new reviews and comparisons as we publish them.", 'nexversal'));
     22
     23$is_logged_in     = is_user_logged_in();
    1424?>
    15 <section class="nx-newsletter-card">
    16     <div class="nx-newsletter-content">
    17         <span class="nx-newsletter-badge">
    18             <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline></svg>
    19             <?php esc_html_e('Nexversal Tech Dispatch', 'nexversal'); ?>
     25<section class="nx-newsletter-v2" data-logged-in="<?php echo $is_logged_in ? 'true' : 'false'; ?>">
     26    <div class="nx-newsletter-left">
     27        <span class="nx-newsletter-badge-v2">
     28            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><circle cx="12" cy="12" r="3"/><line x1="12" y1="2" x2="12" y2="6"/><line x1="12" y1="18" x2="12" y2="22"/><line x1="4.93" y1="4.93" x2="7.76" y2="7.76"/><line x1="16.24" y1="16.24" x2="19.07" y2="19.07"/><line x1="2" y1="12" x2="6" y2="12"/><line x1="18" y1="12" x2="22" y2="12"/><line x1="4.93" y1="19.07" x2="7.76" y2="16.24"/><line x1="16.24" y1="7.76" x2="19.07" y2="4.93"/></svg>
     29            <?php esc_html_e('Newsletter', 'nexversal'); ?>
    2030        </span>
    21         <h3 class="nx-newsletter-title"><?php esc_html_e('Stay Ahead in Tech & Modern Software', 'nexversal'); ?></h3>
    22         <p class="nx-newsletter-desc">
    23             <?php esc_html_e('Join developers, engineers, and digital innovators getting our weekly deep-dives on AI tools, cloud architectures, and development strategies.', 'nexversal'); ?>
     31        <h3 class="nx-newsletter-title-v2">
     32            <?php echo esc_html($nl_title); ?> <span class="nx-nl-highlight"><?php echo esc_html($nl_highlight); ?></span>
     33        </h3>
     34        <p class="nx-newsletter-desc-v2">
     35            <?php echo esc_html($nl_desc); ?>
    2436        </p>
    2537    </div>
    26     <form class="nx-newsletter-form" onsubmit="event.preventDefault(); var btn=this.querySelector('button'); btn.innerText='Subscribed!'; btn.style.background='#10b981'; this.querySelector('input').disabled=true;">
    27         <div class="nx-newsletter-input-group">
    28             <input type="email" placeholder="<?php esc_attr_e('Enter your work email...', 'nexversal'); ?>" required class="nx-newsletter-input" />
    29             <button type="submit" class="nx-newsletter-btn">
    30                 <span><?php echo esc_html(get_theme_mod('nexversal_newsletter_btn_text', __('Subscribe', 'nexversal'))); ?></span>
    31                 <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>
    32             </button>
     38
     39    <div class="nx-newsletter-right">
     40        <!-- Success State Card (Shown when subscribed or user is logged in) -->
     41        <div class="nx-nl-success-card" style="<?php echo $is_logged_in ? 'display: block;' : 'display: none;'; ?>">
     42            <div class="nx-nl-success-title"><?php echo esc_html($nl_success_title); ?></div>
     43            <div class="nx-nl-success-desc"><?php echo esc_html($nl_success_desc); ?></div>
    3344        </div>
    34         <p class="nx-newsletter-privacy">
    35             <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>
    36             <?php esc_html_e('No spam. Unsubscribe anytime with 1-click.', 'nexversal'); ?>
    37         </p>
    38     </form>
     45
     46        <!-- Default Email Form (Hidden when logged in or already subscribed) -->
     47        <form class="nx-newsletter-form-v2" method="post" style="<?php echo $is_logged_in ? 'display: none;' : 'display: block;'; ?>">
     48            <div class="nx-nl-input-wrap">
     49                <span class="nx-nl-input-icon">
     50                    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline></svg>
     51                </span>
     52                <input type="email" name="nx_email" placeholder="<?php esc_attr_e('you@example.com', 'nexversal'); ?>" required class="nx-nl-email-input" autocomplete="email" />
     53                <button type="submit" class="nx-nl-submit-btn">
     54                    <span><?php echo esc_html($nl_btn); ?></span>
     55                </button>
     56            </div>
     57            <div class="nx-newsletter-message" style="display: none; font-size: 13px; margin-top: 8px;"></div>
     58        </form>
     59    </div>
    3960</section>
    4061
  • nexversal/3.5.9/template-parts/social-share.php

    r357433 r357886  
    11<?php
    22/**
    3  * Security: Prevent direct script access
     3 * Social Share Buttons Component for Nexversal Theme
     4 *
     5 * @package Nexversal
     6 * @author Nexes Agency & Muhammad Shahid
     7 * @copyright 2026 Nexes Agency & Muhammad Shahid
     8 * @license GNU General Public License v2 or later
     9 * @link https://nexversal.com
    410 */
     11
    512if (!defined('ABSPATH')) {
    613    exit;
    714}
    8 
    9 /**
    10  * Social Share Buttons Component
    11  *
    12  * @package Nexversal
    13  */
    1415
    1516$post_url   = rawurlencode(get_permalink());
Note: See TracChangeset for help on using the changeset viewer.