Как создать слайдер галереи для ACF/SCF поля галереи WordPress

Как создать слайдер для ACF/SCF поля галереи WordPress

от Михаил | Мар 16, 2026 | Уроки

Часто при разработке на WordPress нужно вывести красивые галереи изображений. Использовать громоздкие плагины — не всегда лучшая идея, если важна скорость работы сайта. Сегодня разберем мощный PHP-сниппет, который создает шорткод .

Он берет изображения из поля Advanced Custom Fields (ACF/SCF), превращает их в современный слайдер с помощью Swiper.js и добавляет легкий самописный лайтбокс на Vanilla JS.

Что нужно для работы кода?

  • Установленный плагин ACF (обычно PRO-версия для поля типа "Галерея") или SCF базовая версия.
  • Созданное поле типа «Галерея» (Gallery) с именем (Name) gallery. Поле должно возвращать массив данных изображения (Image Array).
  • Файл functions.php вашей активной темы, куда нужно вставить этот код или плагин Code snippets.

Весь код полностью

add_shortcode('custom_acf_gallery', 'display_acf_gallery_slider_lightbox');
function display_acf_gallery_slider_lightbox($atts) {
    $images = get_field('gallery'); 
    
    if( $images ):
        $slider_id = 'swiper-' . uniqid();
        
        // Массив для хранения ссылок на оригиналы картинок для лайтбокса
        $image_urls = [];
        
        // 1. СТИЛИ (Swiper + Lightbox)
        $output = '
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css" />
        <style>
            /* --- Стили Слайдера --- */
            #' . $slider_id . ' { width: 100%; padding-bottom: 40px; }
            #' . $slider_id . ' .swiper-slide { border-radius: 8px; overflow: hidden; cursor: zoom-in; }
            #' . $slider_id . ' .swiper-slide img { width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block; }
            
            #' . $slider_id . ' .swiper-button-next,
            #' . $slider_id . ' .swiper-button-prev { color: #ffffff; text-shadow: 0 2px 6px rgba(0,0,0,0.4); transition: transform 0.3s ease, opacity 0.3s; }
            #' . $slider_id . ' .swiper-button-next:hover { transform: translateX(3px); }
            #' . $slider_id . ' .swiper-button-prev:hover { transform: translateX(-3px); }
            #' . $slider_id . ' .swiper-button-next:after,
            #' . $slider_id . ' .swiper-button-prev:after { font-size: 24px !important; font-weight: 300; }

            #' . $slider_id . ' .swiper-pagination-bullet { width: 8px; height: 8px; background-color: #bbbbbb; opacity: 0.6; transition: all 0.3s ease; }
            #' . $slider_id . ' .swiper-pagination-bullet:hover { opacity: 1; }
            #' . $slider_id . ' .swiper-pagination-bullet-active { width: 24px; border-radius: 4px; background-color: #333333; opacity: 1; }
            
            /* --- Стили Лайтбокса --- */
            #custom-vanilla-lightbox { display: none; position: fixed; z-index: 999999; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.9); align-items: center; justify-content: center; opacity: 0; transition: opacity 0.3s ease; }
            #custom-vanilla-lightbox.active { display: flex; opacity: 1; }
            #custom-vanilla-lightbox img { max-width: 90%; max-height: 90%; border-radius: 4px; box-shadow: 0 4px 15px rgba(0,0,0,0.5); object-fit: contain; }
            .cvl-close { position: absolute; top: 20px; right: 30px; color: #fff; font-size: 40px; font-weight: bold; cursor: pointer; user-select: none; transition: color 0.2s; z-index: 10; }
            .cvl-close:hover { color: #bbb; }
            .cvl-nav { position: absolute; top: 50%; transform: translateY(-50%); color: #fff; font-size: 50px; font-weight: bold; cursor: pointer; user-select: none; padding: 20px; transition: color 0.2s; z-index: 10; }
            .cvl-nav:hover { color: #bbb; }
            .cvl-prev { left: 20px; }
            .cvl-next { right: 20px; }
        </style>';
        
        // 2. HTML СЛАЙДЕРА
        $output .= '<div id="' . $slider_id . '" class="swiper">';
        $output .= '<div class="swiper-wrapper">';
        
        foreach( $images as $index => $image ):
            $image_urls[] = esc_url($image['url']); // Сохраняем ссылку на большое фото
            
            // Добавили событие onclick для открытия лайтбокса
            $output .= '<div class="swiper-slide" onclick="window.openCustomLightbox(' . $index . ', \'' . $slider_id . '\')">';
            $output .= '<img src="' . esc_url($image['sizes']['large']) . '" alt="' . esc_attr($image['alt']) . '" />';
            $output .= '</div>';
        endforeach;
        
        $output .= '</div>'; // swiper-wrapper
        
        $output .= '<div class="swiper-pagination"></div>';
        $output .= '<div class="swiper-button-prev"></div>';
        $output .= '<div class="swiper-button-next"></div>';
        $output .= '</div>'; // swiper
        
        $json_urls = json_encode($image_urls);
        
        // 3. СКРИПТЫ (Swiper + Логика Лайтбокса)
        $output .= '
        <script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
        <script>
            document.addEventListener("DOMContentLoaded", function() {
                // --- Инициализация Swiper ---
                const swiper = new Swiper("#' . $slider_id . '", {
                    loop: true,
                    speed: 600,
                    grabCursor: true,
                    autoplay: { delay: 3000, disableOnInteraction: false, pauseOnMouseEnter: true },
                    pagination: { el: ".swiper-pagination", clickable: true },
                    navigation: { nextEl: ".swiper-button-next", prevEl: ".swiper-button-prev" },
                    breakpoints: {
                        320: { slidesPerView: 1, spaceBetween: 15 },
                        768: { slidesPerView: 2, spaceBetween: 20 },
                        1024: { slidesPerView: 3, spaceBetween: 30 }
                    }
                });

                // --- Инициализация данных для Лайтбокса ---
                if (!document.getElementById("custom-vanilla-lightbox")) {
                    const lbHtml = `
                        <div id="custom-vanilla-lightbox">
                            <span class="cvl-close" onclick="window.closeCustomLightbox()">&times;</span>
                            <span class="cvl-nav cvl-prev" onclick="window.changeCustomLightbox(-1)">&#10094;</span>
                            <img id="cvl-image" src="" alt="">
                            <span class="cvl-nav cvl-next" onclick="window.changeCustomLightbox(1)">&#10095;</span>
                        </div>
                    `;
                    document.body.insertAdjacentHTML("beforeend", lbHtml);
                }

                if (typeof window.acfGalleries === "undefined") {
                    window.acfGalleries = {};
                }
                window.acfGalleries["' . $slider_id . '"] = ' . $json_urls . ';
                
                // Создаем функции лайтбокса только один раз, чтобы не было конфликтов
                if (typeof window.openCustomLightbox !== "function") {
                    window.currentLightboxIndex = 0;
                    window.currentLightboxGallery = "";

                    window.openCustomLightbox = function(index, galId) {
                        window.currentLightboxIndex = index;
                        window.currentLightboxGallery = galId;
                        window.updateLightboxImage();
                        const lb = document.getElementById("custom-vanilla-lightbox");
                        lb.style.display = "flex";
                        setTimeout(() => { lb.classList.add("active"); }, 10);
                        document.body.style.overflow = "hidden";
                    };

                    window.closeCustomLightbox = function() {
                        const lb = document.getElementById("custom-vanilla-lightbox");
                        lb.classList.remove("active");
                        setTimeout(() => { lb.style.display = "none"; }, 300);
                        document.body.style.overflow = "";
                    };

                    window.changeCustomLightbox = function(step) {
                        const images = window.acfGalleries[window.currentLightboxGallery];
                        window.currentLightboxIndex += step;
                        if (window.currentLightboxIndex >= images.length) window.currentLightboxIndex = 0;
                        else if (window.currentLightboxIndex < 0) window.currentLightboxIndex = images.length - 1;
                        window.updateLightboxImage();
                    };

                    window.updateLightboxImage = function() {
                        const images = window.acfGalleries[window.currentLightboxGallery];
                        document.getElementById("cvl-image").src = images[window.currentLightboxIndex];
                    };

                    // Закрытие по фону и клавиатуре
                    const lbElem = document.getElementById("custom-vanilla-lightbox");
                    lbElem.addEventListener("click", function(e) {
                        if (e.target === this) window.closeCustomLightbox();
                    });

                    document.addEventListener("keydown", function(e) {
                        const lbIsActive = document.getElementById("custom-vanilla-lightbox").classList.contains("active");
                        if (!lbIsActive) return;
                        if (e.key === "Escape") window.closeCustomLightbox();
                        else if (e.key === "ArrowRight") window.changeCustomLightbox(1);
                        else if (e.key === "ArrowLeft") window.changeCustomLightbox(-1);
                    });
                }
            });
        </script>';
        
        return $output;
    endif;
    
    return '';
}

Разбор кода шаг за шагом

Весь код обернут в функцию display_acf_gallery_slider_lightbox, которая привязана к шорткоду с помощью add_shortcode(). Давайте посмотрим, что происходит внутри.

Шаг 1: Получение данных и уникальные ID

$images = get_field('gallery'); 
if( $images ):
    $slider_id = 'swiper-' . uniqid();
    $image_urls = [];
// ...

Сначала мы проверяем, есть ли вообще картинки в поле gallery. Если да, мы генерируем уникальный ID для слайдера с помощью uniqid(). Это критически важный шаг — он позволяет использовать несколько таких шорткодов на одной странице, и слайдеры не будут конфликтовать друг с другом.

Шаг 2: Стилизация (Swiper + Lightbox)

В переменную $output мы начинаем собирать итоговый HTML-код.

  1. Подключается стили Swiper.js напрямую с CDN.
  2. Прописываются CSS-правила. Слайды получают скругления, адаптивное соотношение сторон (aspect-ratio: 4/3) и курсор-лупу (cursor: zoom-in), давая пользователю понять, что картинку можно увеличить.
  3. Стилизуется сам лайтбокс: темный полупрозрачный фон, выравнивание по центру полей Flexbox и плавная анимация появления.

Шаг 3: HTML-структура слайдера

foreach( $images as $index => $image ):
    $image_urls[] = esc_url($image['url']); // Сохраняем оригинал для лайтбокса
    $output .= '<div class="swiper-slide" onclick="window.openCustomLightbox(' . $index . ', \'' . $slider_id . '\')">';
    $output .= '<img src="' . esc_url($image['sizes']['large']) . '" alt="' . esc_attr($image['alt']) . '" />';
    $output .= '</div>';
endforeach;

Здесь мы циклом проходим по всем картинкам.

  • В сам слайдер выводится оптимизированное изображение (размер large), а не тяжелый оригинал.
  • Ссылка на полноразмерный оригинал ($image['url']) бережно сохраняется в массив $image_urls.
  • На каждый слайд вешается обработчик onclick, который передает в скрипт индекс картинки и ID текущей галереи.

Шаг 4: Магия JavaScript

Скрипт решает сразу три задачи:

  1. Инициализация Swiper.js: Настраивается бесконечная прокрутка (loop: true), автовоспроизведение, пагинация, стрелки и, что самое главное, брейкпоинты для адаптивности (на мобильных — 1 слайд, на планшетах — 2, на ПК — 3).
  2. Создание DOM-элемента Лайтбокса: Скрипт проверяет, существует ли уже на странице элемент #custom-vanilla-lightbox. Если нет, он добавляет его прямо в <body>. Таким образом, даже если на странице 5 галерей, код лайтбокса создастся только один раз, экономя ресурсы.
  3. Логика Лайтбокса: PHP передает массив полных ссылок в JS через json_encode($image_urls). В JS реализуются глобальные функции:
    • openCustomLightbox() — открывает модальное окно и блокирует прокрутку страницы (body.style.overflow = "hidden").
    • closeCustomLightbox() — закрывает окно и возвращает прокрутку.
    • changeCustomLightbox() — переключает фото вперед/назад.
    • Бонус: добавлена поддержка управления с клавиатуры! Галерею можно листать стрелками Влево/Вправо и закрывать на клавишу Escape.

Как использовать?

  1. Скопируй весь этот сниппет в конец файла functions.php твоей дочерней темы или в плагин Code sbippets.
  2. Открой любую запись или страницу в WordPress, где добавлено поле галереи.
  3. Вставь шорткод в текстовый блок или блок шорткода.

Итог

Этот подход демонстрирует отличную практику WordPress-разработки: минимум запросов к базе данных, использование нативного JS вместо jQuery, встроенная адаптивность и доступность с клавиатуры.

Было полезно?

Пожалуйста, расскажите об этом друзьям!

VK
Pinterest
OK
Telegram
Linkedin
WhatsApp
Viber
Reddit

Готовы получать больше клиентов?

Ваш сайт может быть не просто визиткой, а полноценным инструментом продаж — работать 24/7, привлекать заявки и усиливать доверие к вашему бизнесу. Оставьте заявку — и мы подскажем, какое решение подойдёт именно вам.

Вам может быть интересно

Telegram Почта Телефон