Часто при разработке на 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()">×</span>
<span class="cvl-nav cvl-prev" onclick="window.changeCustomLightbox(-1)">❮</span>
<img id="cvl-image" src="" alt="">
<span class="cvl-nav cvl-next" onclick="window.changeCustomLightbox(1)">❯</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-код.
- Подключается стили Swiper.js напрямую с CDN.
- Прописываются CSS-правила. Слайды получают скругления, адаптивное соотношение сторон (
aspect-ratio: 4/3) и курсор-лупу (cursor: zoom-in), давая пользователю понять, что картинку можно увеличить. - Стилизуется сам лайтбокс: темный полупрозрачный фон, выравнивание по центру полей 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
Скрипт решает сразу три задачи:
- Инициализация Swiper.js: Настраивается бесконечная прокрутка (
loop: true), автовоспроизведение, пагинация, стрелки и, что самое главное, брейкпоинты для адаптивности (на мобильных — 1 слайд, на планшетах — 2, на ПК — 3). - Создание DOM-элемента Лайтбокса: Скрипт проверяет, существует ли уже на странице элемент
#custom-vanilla-lightbox. Если нет, он добавляет его прямо в<body>. Таким образом, даже если на странице 5 галерей, код лайтбокса создастся только один раз, экономя ресурсы. - Логика Лайтбокса: PHP передает массив полных ссылок в JS через
json_encode($image_urls). В JS реализуются глобальные функции:openCustomLightbox()— открывает модальное окно и блокирует прокрутку страницы (body.style.overflow = "hidden").closeCustomLightbox()— закрывает окно и возвращает прокрутку.changeCustomLightbox()— переключает фото вперед/назад.- Бонус: добавлена поддержка управления с клавиатуры! Галерею можно листать стрелками
Влево/Вправои закрывать на клавишуEscape.
Как использовать?
- Скопируй весь этот сниппет в конец файла
functions.phpтвоей дочерней темы или в плагин Code sbippets. - Открой любую запись или страницу в WordPress, где добавлено поле галереи.
- Вставь шорткод
в текстовый блок или блок шорткода.
Итог
Этот подход демонстрирует отличную практику WordPress-разработки: минимум запросов к базе данных, использование нативного JS вместо jQuery, встроенная адаптивность и доступность с клавиатуры.
