Sridhar Katakam's Weblog

Lightbox for Screenshots on wp.org plugin pages

Posted on November 14, 2025 | 0 comments

The screenshots for plugins in the official WordPress repo, when clicked, load the full image in the same tab. We have to press browser’s back button (or use a keyboard shortcut) and do this for any other screenshots we want to view in full.

Here’s a userscript that fixes this in your browser. To use this, you need a Chrome extension like Tampermonkey. I use AdGuard Mac app for this.

// ==UserScript==
// @name         WordPress Plugin Screenshots Lightbox (Image Gallery)
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  Lightbox for WordPress plugin image gallery screenshots
// @match        *://wordpress.org/plugins/*
// @match        *://*.wordpress.org/plugins/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // Check if we're on a plugin page
    if (!window.location.pathname.match(/\/plugins\/[^\/]+\/?$/)) {
        return;
    }

    // Add styles
    const style = document.createElement('style');
    style.textContent = `
        #wp-screenshot-lightbox {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.95);
            z-index: 999999;
            align-items: center;
            justify-content: center;
        }
        
        #wp-screenshot-lightbox.active {
            display: flex;
        }
        
        #wp-screenshot-lightbox img {
            max-width: 90vw;
            max-height: 90vh;
            object-fit: contain;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
        }
        
        .wp-lightbox-close {
            position: absolute;
            top: 20px;
            right: 30px;
            font-size: 40px;
            color: white;
            cursor: pointer;
            background: none;
            border: none;
            padding: 0;
            width: 50px;
            height: 50px;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: opacity 0.2s;
        }
        
        .wp-lightbox-close:hover {
            opacity: 0.7;
        }
        
        .wp-lightbox-nav {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            font-size: 60px;
            color: white;
            cursor: pointer;
            background: none;
            border: none;
            padding: 0 20px;
            user-select: none;
            transition: opacity 0.2s;
        }
        
        .wp-lightbox-nav:hover:not(:disabled) {
            opacity: 0.7;
        }
        
        .wp-lightbox-nav:disabled {
            opacity: 0.2;
            cursor: not-allowed;
        }
        
        .wp-lightbox-prev {
            left: 0;
        }
        
        .wp-lightbox-next {
            right: 0;
        }
        
        .wp-lightbox-counter {
            position: absolute;
            bottom: 30px;
            left: 50%;
            transform: translateX(-50%);
            color: white;
            background: rgba(0, 0, 0, 0.7);
            padding: 10px 20px;
            border-radius: 5px;
            font-size: 16px;
        }
    `;
    document.head.appendChild(style);

    // Create lightbox HTML
    const lightbox = document.createElement('div');
    lightbox.id = 'wp-screenshot-lightbox';
    lightbox.innerHTML = `
        <button class="wp-lightbox-close" aria-label="Close">×</button>
        <button class="wp-lightbox-nav wp-lightbox-prev" aria-label="Previous">‹</button>
        <img src="" alt="Screenshot" />
        <button class="wp-lightbox-nav wp-lightbox-next" aria-label="Next">›</button>
        <div class="wp-lightbox-counter"></div>
    `;
    document.body.appendChild(lightbox);

    const img = lightbox.querySelector('img');
    const closeBtn = lightbox.querySelector('.wp-lightbox-close');
    const prevBtn = lightbox.querySelector('.wp-lightbox-prev');
    const nextBtn = lightbox.querySelector('.wp-lightbox-next');
    const counter = lightbox.querySelector('.wp-lightbox-counter');

    let screenshots = [];
    let currentIndex = 0;

    function initLightbox() {
        // Get the main gallery container
        const gallery = document.querySelector('.image-gallery-slides');
        if (!gallery) return;

        // Find all screenshot links using event delegation
        const screenshotLinks = gallery.querySelectorAll('.image-gallery-image a');
        screenshots = Array.from(screenshotLinks).map(link => link.href);

        if (screenshots.length === 0) return;
    }

    // Use event delegation on the gallery container
    document.addEventListener('click', (e) => {
        // Check if click is on an image gallery link or its child
        const link = e.target.closest('.image-gallery-slide .image-gallery-image a');
        if (!link) return;

        e.preventDefault();
        
        // Find which index this link corresponds to
        const allLinks = document.querySelectorAll('.image-gallery-slide .image-gallery-image a');
        screenshots = Array.from(allLinks).map(l => l.href);
        currentIndex = Array.from(allLinks).indexOf(link);
        
        if (currentIndex !== -1) {
            showLightbox();
        }
    });

    function showLightbox() {
        img.src = screenshots[currentIndex];
        lightbox.classList.add('active');
        document.body.style.overflow = 'hidden';
        updateUI();
    }

    function closeLightbox() {
        lightbox.classList.remove('active');
        document.body.style.overflow = '';
    }

    function updateUI() {
        counter.textContent = `${currentIndex + 1} / ${screenshots.length}`;
        prevBtn.disabled = currentIndex === 0;
        nextBtn.disabled = currentIndex === screenshots.length - 1;
        
        // Hide elements if only one image
        if (screenshots.length === 1) {
            counter.style.display = 'none';
            prevBtn.style.display = 'none';
            nextBtn.style.display = 'none';
        } else {
            counter.style.display = 'block';
            prevBtn.style.display = 'flex';
            nextBtn.style.display = 'flex';
        }
    }

    function navigate(direction) {
        const newIndex = currentIndex + direction;
        if (newIndex >= 0 && newIndex < screenshots.length) {
            currentIndex = newIndex;
            img.src = screenshots[currentIndex];
            updateUI();
        }
    }

    // Event listeners
    closeBtn.addEventListener('click', closeLightbox);
    prevBtn.addEventListener('click', () => navigate(-1));
    nextBtn.addEventListener('click', () => navigate(1));

    // Close on overlay click
    lightbox.addEventListener('click', (e) => {
        if (e.target === lightbox) {
            closeLightbox();
        }
    });

    // Keyboard navigation
    document.addEventListener('keydown', (e) => {
        if (!lightbox.classList.contains('active')) return;

        switch(e.key) {
            case 'Escape':
                closeLightbox();
                break;
            case 'ArrowLeft':
                navigate(-1);
                break;
            case 'ArrowRight':
                navigate(1);
                break;
        }
    });

    // Initialize
    initLightbox();
})();

Leave the first comment