Создание галереи с лайтбоксом на WordPress с помощью ACF

Интерактивная галерея превращает набор фотографий в удобный просмотр: миниатюры занимают компактную сетку, а выбранный снимок открывается поверх страницы. Пользователь изучает изображения без перехода на отдельные вложения и сохраняет контекст материала.

С помощью ACF удобно хранить ссылки на изображения, подписи и альтернативные тексты рядом с записью. Расширенные пользовательские поля отделяют данные от темы, поэтому галерею можно вывести в любом шаблоне и менять разметку без ручного редактирования HTML.

В примере используется поле Repeater, нативный элемент dialog и небольшой скрипт на современном JavaScript. Получится адаптивная галерея с полноразмерным просмотром, закрытием по Escape, возвратом фокуса и корректными подписями.

Подготовка WordPress и расширений

Установите расширение Advanced Custom Fields и активируйте лицензию Pro: для поля Repeater требуется расширенная версия. Обновляйте WordPress, PHP и плагины, а перед изменениями сделайте резервную копию сайта и базы данных.

Создайте дочернюю тему, если основная тема обновляется автоматически. В ней подготовьте каталоги assets/css и assets/js, а затем подключите gallery.css через wp_enqueue_style, а gallery.js через wp_enqueue_script. Файлы родительской темы лучше не изменять, иначе правки могут исчезнуть при обновлении.

Для базовой проверки установленной сборки полезны материалы по WordPress: начните с резервной копии, последовательно активируйте плагины и убедитесь, что сайт открывается без ошибок. Так вы исключите конфликт расширений ещё до начала разработки галереи.

Поля ACF для изображений

В панели ACF откройте раздел групп полей и создайте группу «Галерея». Привяжите её к нужному типу публикации или выберите правило отображения для отдельных страниц. Поле Repeater назовите gallery_images, чтобы его имя совпадало с будущим шаблоном.

Внутри Repeater добавьте подполе image типа Image с источником «Медиатека». В качестве возвращаемого значения выберите ID изображения: WordPress сможет определить актуальный адрес файла и сформировать миниатюру нужного размера. Для ручной подписи создайте текстовое подполе caption.

Альтернативный текст удобно задавать непосредственно в карточке вложения. Шаблон возьмёт его из поля _wp_attachment_image_alt, а при отсутствии использует подпись или название файла. Так изображение получит осмысленное имя для программ экранного доступа.

Шаблон вывода галереи

В дочерней теме создайте файл gallery-template.php и вызовите его из нужного шаблона страницы командой get_template_part( 'gallery-template' ). Внутри файла переберите строки Repeater, получите ID изображения, подпись и адрес полноразмерной версии.

<?php
if ( have_rows( 'gallery_images' ) ) :
?>
<div class="acf-gallery" data-acf-gallery>
    <?php
    while ( have_rows( 'gallery_images' ) ) :
        $image_id = (int) get_sub_field( 'image' );
        $caption  = (string) get_sub_field( 'caption' );
        $alt      = get_post_meta( $image_id, '_wp_attachment_image_alt', true );

        if ( ! $alt ) {
            $alt = $caption ? $caption : get_the_title( $image_id );
        }

        $full = wp_get_attachment_image_src( $image_id, 'full' );
        if ( ! $full ) {
            continue;
        }
    ?>
    <button
        type="button"
        class="acf-gallery__item"
        data-lightbox-open
        data-full="<?php echo esc_url( $full[0] ); ?>"
        data-alt="<?php echo esc_attr( $alt ); ?>"
        data-caption="<?php echo esc_attr( $caption ); ?>"
        aria-haspopup="dialog"
    >
        <?php
        echo wp_get_attachment_image(
            $image_id,
            'large',
            false,
            array(
                'alt'      => $alt,
                'loading'  => 'lazy',
                'decoding' => 'async',
            )
        );
        ?>
    </button>
    <?php endwhile; ?>

    <dialog
        class="acf-lightbox"
        data-lightbox-dialog
        aria-label="Просмотр изображения"
    >
        <button type="button" class="acf-lightbox__close" data-lightbox-close>
            Закрыть
        </button>
        <img class="acf-lightbox__image" data-lightbox-image alt="">
        <p class="acf-lightbox__caption" data-lightbox-caption></p>
    </dialog>
</div>
<?php endif; ?>

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

Функция wp_get_attachment_image формирует оптимизированный тег с поддержкой srcset. Для миниатюр можно использовать размер large, а для модального окна — отдельную полноразмерную копию без изменения оригинала.

Скрипт модального окна

Скрипт находит каждую галерею и навешивает обработчик на её кнопки. При нажатии он переносит адрес, подпись и альтернативный текст в нативный dialog, после чего вызывает showModal(). Библиотека jQuery для этого решения не требуется.

document.querySelectorAll('[data-acf-gallery]').forEach((gallery) => {
  const dialog = gallery.querySelector('[data-lightbox-dialog]');
  const image = gallery.querySelector('[data-lightbox-image]');
  const caption = gallery.querySelector('[data-lightbox-caption]');
  const closeButton = gallery.querySelector('[data-lightbox-close]');
  let activeTrigger = null;

  gallery.querySelectorAll('[data-lightbox-open]').forEach((button) => {
    button.addEventListener('click', () => {
      activeTrigger = button;
      image.src = button.dataset.full;
      image.alt = button.dataset.alt || '';
      caption.textContent = button.dataset.caption || '';

      document.body.classList.add('acf-lightbox-open');
      dialog.showModal();
      closeButton.focus();
    });
  });

  closeButton.addEventListener('click', () => {
    dialog.close();
  });

  dialog.addEventListener('click', (event) => {
    if (event.target === dialog) {
      dialog.close();
    }
  });

  dialog.addEventListener('close', () => {
    document.body.classList.remove('acf-lightbox-open');
    image.removeAttribute('src');
    caption.textContent = '';

    if (activeTrigger) {
      activeTrigger.focus();
    }
  });
});

Нативный dialog размещается в верхнем слое браузера, поэтому ему не требуется ручная настройка z-index. Клавиша Escape закрывает окно, а событие close возвращает фокус исходной кнопке. Щелчок по затемнённому фону также завершает просмотр.

Оформление и адаптивность

Сетку можно задать через CSS Grid: она автоматически перестроится при изменении ширины экрана. Для миниатюр полезно сохранять одинаковое соотношение сторон, а полноразмерное изображение показывать через object-fit: contain, чтобы оно не обрезалось.

.acf-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1rem;
}

.acf-gallery__item {
  display: block;
  width: 100%;
  padding: 0;
  overflow: hidden;
  border: 1px solid rgba(0, 0, 0, 0.15);
  border-radius: 8px;
  background: transparent;
  cursor: zoom-in;
}

.acf-gallery__item img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.acf-gallery__item:focus-visible {
  outline: 3px solid #2563eb;
  outline-offset: 3px;
}

.acf-lightbox {
  width: min(92vw, 1200px);
  max-width: none;
  max-height: 92vh;
  padding: 1rem;
  border: 0;
  background: #111;
  color: #fff;
}

.acf-lightbox[open] {
  display: grid;
  gap: 0.75rem;
}

.acf-lightbox__image {
  display: block;
  max-width: 100%;
  max-height: 76vh;
  margin: auto;
  object-fit: contain;
}

.acf-lightbox__close {
  justify-self: end;
  padding: 0.5rem 0.8rem;
  cursor: pointer;
}

.acf-lightbox__caption {
  margin: 0;
  text-align: center;
}

.acf-lightbox__caption:empty {
  display: none;
}

.acf-lightbox::backdrop {
  background: rgba(0, 0, 0, 0.82);
}

.acf-lightbox-open {
  overflow: hidden;
}

@media (max-width: 600px) {
  .acf-gallery {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem;
  }

  .acf-lightbox {
    width: 96vw;
  }
}

Перед загрузкой подготовьте облегчённую версию для сетки и сохраните отдельный оригинал для модального окна. WordPress может создавать WebP или AVIF, если соответствующие форматы поддерживаются сервером. Для фотографий, полученных со сканера, параметры обработки можно уточнить в программе Nikon Coolscan.

Проверка, доступность и публикация

Проверьте страницу на тестовом сервере с разным количеством изображений, разными пропорциями и разрешениями. Посмотрите галерею на узком экране, обычном мониторе и Retina-дисплее. Убедитесь, что страница сохраняет работоспособность при отключённом JavaScript: миниатюры должны оставаться доступными.

Проверьте навигацию с клавиатуры. Кнопки должны получать заметное состояние фокуса, Enter открывать снимок, Escape закрывать окно, а фокус после закрытия возвращаться к выбранному изображению. Убедитесь, что альтернативные тексты не пусты, подписи читаются, а контраст кнопки закрытия соответствует фону.

Перед публикацией откройте страницу в отдельном профиле браузера и оцените защиту Edge от трекеров: внешние счётчики, шрифты и рекламные скрипты могут менять поведение страницы и увеличивать объём передаваемых данных. Проверьте защищённое соединение, актуальность плагинов, журнал ошибок и работу с минифицированными файлами.

Готовый модуль хранит данные в ACF, а оформление и поведение остаются в дочерней теме. Такое разделение упрощает перенос решения, позволяет менять сетку независимо от записей и сохранять галерею при обновлении WordPress.

Создайте черновик страницы, привяжите к нему группу полей, загрузите снимки и проверьте результат в мобильном и настольном режимах. После успешной проверки перенесите готовые файлы в дочернюю тему, сохраните настройки группы ACF и опубликуйте страницу — галерея будет готова к использованию на сайте.

Иконка пользователя в серых тонах

Настройка Windows

Доступ к скрытым параметрам конфигурации, отключение телеметрии, работа с диспетчером задач и тонкая настройка меню «Пуск» в стиле Windows XP для Windows 7.

Иконка браузера в серо-синих тонах

Веб-браузеры

Скрытые страницы конфигурации в Firefox, Chrome и Opera, быстрый текстовый редактор прямо в браузере, эффект Lightbox JS для изображений и настройка внешнего вида Firefox.

Иконка папки в нейтральных серых тонах

WordPress и блоги

Выполнение PHP-кода в текстовых виджетах, диагностика времени загрузки разделов страницы, правильная очистка блога и условная загрузка виджетов социальных сетей.

Изометрический 3D-рендер: светлый веб-сайт с серо-голубым заголовком, парящий над чистой белой поверхностью Изометрический 3D-рендер: тёмно-серая иконка социального букмаркинга на светлом фоне

Обратная связь

Есть вопрос или предложение по темам блога? Напишите — автор на связи.