Кастомный лайтбокс для WordPress

Делал посты и захотел, чтобы фотографии из поста можно было открывать в лайтбоксе и листать все подряд, без ограничения привязки к галерее. Оказалось, стандартный лайтбокс так не умеет и побороть его крайне тяжело. По-этому Gemini сделал мне кастомный. Добавляю его, где мне нужно, как отдельный блок HTML в конце поста, при этом старые посты не ломаются. Код подкатом, разжевать можно в любой модельке.

<style>
/* Стили адаптивного лайтбокса */
.my-lightbox {
    display: none; position: fixed; z-index: 9999999; left: 0; top: 0; width: 100vw; height: 100vh;
    background-color: rgba(15, 15, 15, 0.95); align-items: center; justify-content: center;
    touch-action: none; user-select: none; -webkit-user-select: none;
}
.my-lightbox img { 
    max-width: 90%; max-height: 85vh; object-fit: contain; 
    transition: transform 0.2s ease;
    pointer-events: auto; cursor: pointer; 
}
.ml-btn {
    position: absolute; top: 50%; transform: translateY(-50%); background: rgba(255,255,255,0.1);
    color: #fff; border: none; font-size: 28px; width: 50px; height: 50px; cursor: pointer; 
    border-radius: 50%; display: flex; align-items: center; justify-content: center; transition: 0.2s; z-index: 10000001;
}
.ml-btn:hover { background: rgba(255,255,255,0.3); }
.ml-prev { left: 20px; } .ml-next { right: 20px; }
.ml-close { position: absolute; top: 20px; right: 25px; color: #fff; font-size: 38px; cursor: pointer; width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; z-index: 10000002; }

@media (max-width: 768px) {
    .ml-btn { display: none; }
    .my-lightbox img { max-width: 95%; }
}
</style>

<div id="myLightboxRoot" class="my-lightbox">
    <div class="ml-close" id="mlCloseBtn">&times;</div>
    <button class="ml-btn ml-prev" id="mlPrevBtn">&#10094;</button>
    <img id="mlMainImg" src="" alt="">
    <button class="ml-btn ml-next" id="mlNextBtn">&#10095;</button>
</div>

<script>
document.addEventListener('DOMContentLoaded', function() {
    var root = document.getElementById('myLightboxRoot');
    
    if (root) {
        document.body.appendChild(root);
    }

    function initIsolatedGallery() {
        var selectors = '.wp-block-image a[href*=".jpg"], .wp-block-image a[href*=".jpeg"], .wp-block-image a[href*=".png"], .wp-block-image a[href*=".webp"], .wp-block-gallery a[href*=".jpg"], .wp-block-gallery a[href*=".jpeg"], .wp-block-gallery a[href*=".png"], .wp-block-gallery a[href*=".webp"]';
        var links = document.querySelectorAll(selectors);
        
        if (links.length === 0) return;

        var images = [];
        var currentIndex = 0;
        var mainImg = document.getElementById('mlMainImg');

        links.forEach(function(link, index) {
            if (images.indexOf(link.href) === -1) {
                images.push(link.href);
            }
            
            link.removeAttribute('data-wp-on--click');
            
            link.addEventListener('click', function(e) {
                e.preventDefault();
                e.stopPropagation();
                currentIndex = images.indexOf(link.href);
                updateLightbox();
                root.style.display = 'flex';
            }, true);
        });

        function updateLightbox() {
            if (mainImg) {
                mainImg.src = images[currentIndex];
            }
        }

        function nextSlide() {
            currentIndex = (currentIndex + 1) % images.length;
            updateLightbox();
        }

        function prevSlide() {
            currentIndex = (currentIndex - 1 + images.length) % images.length;
            updateLightbox();
        }

        var nextBtn = document.getElementById('mlNextBtn');
        var prevBtn = document.getElementById('mlPrevBtn');
        var closeBtn = document.getElementById('mlCloseBtn');

        if (nextBtn) nextBtn.onclick = function(e) { e.stopPropagation(); nextSlide(); };
        if (prevBtn) prevBtn.onclick = function(e) { e.stopPropagation(); prevSlide(); };
        if (closeBtn) closeBtn.onclick = function() { root.style.display = 'none'; };
        
        root.onclick = function() { root.style.display = 'none'; };

        // Клик по самой картинке (разделение 50/50 без опасных амперсандов)
        if (mainImg) {
            mainImg.onclick = function(e) {
                e.stopPropagation(); 
                var rect = mainImg.getBoundingClientRect();
                var clientX = null;

                // Безопасное определение координат мыши или тача
                if (e.clientX) {
                    clientX = e.clientX;
                } else if (e.changedTouches) {
                    if (e.changedTouches[0]) {
                        clientX = e.changedTouches[0].clientX;
                    }
                }
                
                if (!clientX) return;

                var clickX = clientX - rect.left; 
                
                if (clickX > rect.width / 2) {
                    nextSlide();
                } else {
                    prevSlide();
                }
            };
        }

        // Клавиатура
        document.onkeydown = function(e) {
            if (root.style.display === 'flex') {
                if (e.key === 'ArrowRight') nextSlide();
                if (e.key === 'ArrowLeft') prevSlide();
                if (e.key === 'Escape') root.style.display = 'none';
            }
        };

        // Свайпы на мобилках
        var touchStartX = 0;
        var touchEndX = 0;

        root.ontouchstart = function(e) {
            touchStartX = e.changedTouches[0].screenX;
        };

        root.ontouchend = function(e) {
            touchEndX = e.changedTouches[0].screenX;
            var swipeDistance = touchEndX - touchStartX;
            if (swipeDistance < -50) nextSlide();
            if (swipeDistance > 50) prevSlide();
        };
    }

    initIsolatedGallery();
    setTimeout(initIsolatedGallery, 500);
});
</script>

Пришлось переделать без &&, а то WordPress ломает скрипт, при прямой вставке через HTML блок.