Добавление разных изображений для вариантов продукта

Разные изображения для вариантов в теме Horizon от Shopify (без приложений и без Plus). Бесплатное решение от VecomLab.

Актуально для версии темы Horizon 3.1.0


circle-info

Если вы хотите избежать настройки кода, попробуйте тему Shrinearrow-up-right.

Более 120 встроенных функций, которые помогают улучшить конверсию и увеличить средний чек без необходимости настраивать дополнительные приложения и платить за подписки. Всё настраивается без кода, что экономит время и ресурсы.

torii-gateShrine − 15% скидка

Ваш промокод: VECOMLAB

Описание проблемы

По умолчанию в админке Shopify и в настройках темы Horizon каждому варианту можно задать только одно изображение, но не несколько.

Эту проблему платформа частично решает для магазинов на тарифе Plus. Также можно использовать сторонние приложения Shopify, однако это чаще всего невыгодно и неэффективно, так как нередко возникают ошибки, которые приходится исправлять через поддержку месяцами.

Задачу можно решить, используя Metafields and Metaobjects для Variants и редактор кода темы.

Идея

  • У варианта есть метаполе custom.variant_gallery (список файлов).

  • Мы считаем «своими» все картинки, чьё имя файла совпадает со стемом из метаполя или начинается со стема + _ или -.

  • На сервере (Liquid) делаем пред-скрытие лишних картинок для первого кадра.

  • На клиенте (JS) читаем карту «вариант → файлы» и фильтруем при переключении варианта.

  • Если ни у одного варианта метаполя нет — ничего не меняется, всё работает как в теме.

Что нового: зум и quick add

  1. Зум-диалог теперь тоже фильтруется по варианту: и миниатюры, и большие кадры.

  2. Mobile quick add (модалка на странице коллекции): на мобильных в модалке показывается только одно изображение — featured текущего варианта (как в стандартной Horizon), даже если у варианта есть целая серия.

Шаг 1. Метаполе варианта (единожды на весь магазин)

Settings → Metafields and metaobjects → Variants → Add definition

  • Name: Variant Gallery

  • Namespace and key: custom.variant_gallery

  • Type: File → List of files

  • Validations: только Images

  • Options: включить Storefront API access

  • Save

Почему так: это нативный способ связать вариант с файлами в Shopify Files. Ключ совпадает с тем, что использует код.

Шаг 2. Договор по именам файлов

В Files даём серии фото общего варианта общий стем:

В метаполе варианта прикрепляем один «якорный» файл из серии (например, ring-gold.jpg). Остальные подхватятся по стему автоматически.

Шаг 3. Вставки в _product-media-gallery.liquid

Ниже перечислено ровно то, что мы добавили/заменили, и зачем.

3.1. JSON-карта вариант → файлы (сервер → фронт)

Вставить перед {%- if has_image_drop -%}:

Зачем: фронт получает готовый JSON без парсинга DOM. Сразу приводим URL к базовому имени.

В атрибутах тега, рядом с data-presentation и style, добавить:

  • data-vg-ready="0" — анти-мигание: пока скрипт не закончит, картинки скрыты (ниже будет CSS).

  • data-initial-variant-idопционально, для отладки/аналитики; сам скрипт берёт id варианта из формы.

circle-info

Если хотите максимально «чисто» — можно удалить data-initial-variant-id. Функциональность не изменится.

3.3. vg_list для первого рендера

Сразу после {{ block.shopify_attributes }}:

Зачем: знать список файлов текущего варианта на сервере, чтобы пред-скрыть лишние картинки ещё до JS (правильный первый кадр).

Перед вычислением class/style/attributes каждого медиа:

И далее добавляем vg-prehide и display:none:

3.5. Единый набор data-атрибутов на слайд

Перед блоком с attributes:

И заменяем блок attributes на варианты с подстановкой {{- common_data_attrs -}} (для model / image / «без zoom»).

Было:

Стало:

Зачем: фронту нужны тип и URL картинки. data-vg-allow/data-vg-prehide помогают CSS до инициализации JS.

3.6. То же — для Grid

Внутри <ul class="media-gallery__grid"> перед каждым <li> повторяем логику prehide

А в самом <li> для Grid заменяем class= "" и style "" на:

И добавляем data-атрибуты:

3.7. Фильтрация внутри зум-диалога (Liquid)

Миниатюры зума (1)

Внутри блока с миниатюрами (кнопки .dialog-thumbnails-list__thumbnail) добавьте пред-скрытие, как мы делали для слайдов/грида:

В <button> замените class="" и style="" :

И добавьте атрибуты:

Большие кадры в зуме (2)

Для <li> внутри .dialog-zoomed-gallery примените ту же проверку prehide и те же data-атрибуты.

Вставьте проверку перед <li>

Замените class="" и style="" в <li>

И добавьте атрибуты:

Идея та же: обеспечиваем «чистый» первый кадр в зуме ещё до выполнения JS.

Скрипт:

  • читает #variant-galleries-json;

  • если у товара нет ни одного варианта с метаполем → ставит data-vg-ready="1" и выходит (ничего не меняем);

  • иначе фильтрует image-слайды по текущему варианту; при смене варианта — повторяет;

  • в конце ставит data-vg-ready="1" (анти-мигание выключается).

CSS:

Зачем: полностью убирает «дрожание/моргание» и промежуточные состояние до готовности. Мы не трогаем миниатюры/стрелки — в «чистом» варианте данной версии скрипта их и не скрываем.

Почему это нужно:

  • пока стоит data-vg-ready="0", модалка не «мигает» набором картинок;

  • JS дополнительно гарантирует, что даже после переключений варианта в модалке будет ровно одно изображение.

Что сознательно не трогаем (остается «как в теме»)

Сделаем это в следующих версиях скрипта:

  • Счётчик / стрелки / миниатюры карусели — не настраиваем и не прячем отдельными правилами.

Небольшой аудит «лишнего»

  • data-initial-variant-idопция, можно удалить (скрипт не сломает).

  • MutationObserver сейчас повешен на document.body для «неубиваемости» при динамических перерисовках. Можно ужать до наблюдения только за <media-gallery>, но текущий вариант надёжнее ко всем темам/скриптам.

  • Дублирование логики «пред-скрыт на сервере» + «фильтр на клиенте» — осознанно: даёт идеальный первый кадр (без мусора) и корректную работу при дальнейших переключениях. Это не лишнее, а анти-FOUC-слой.

Итог

Если у варианта заполнено метаполе Variant Gallery, на странице показываются только его фотографии (по имени файла). Если метаполя нет — всё работает как раньше. Первый кадр чистый без миганий (пред-скрытие на сервере), при переключении варианта галерея обновляется скриптом. Никаких приложений, конфликтов и замедлений.

Настройка темы

Режимы Product media (Grid + Hint) и Grid + Dots поддерживаются. Поведение «одно изображение в Mobile quick add» включается только внутри модалки на экранах ≤ 749 px; на странице товара и на десктопе остаётся полноценная галерея по варианту.

Вы можете задать вопросы в телеграм-чатarrow-up-right.

FAQ

chevron-rightЧто мне вообще нужно настроить в админке?hashtag

Только одно: создать метаполе варианта custom.variant_gallery типа File → List of files (только Images) и включить Storefront API access. Всё остальное — вставки в один шаблон _product-media-gallery.liquid.

chevron-rightСколько файлов прикреплять к метаполю варианта?hashtag

Достаточно одного «якорного» файла из серии. Остальные подхватятся автоматически по имени (по «стему»), если названы stem.jpg, stem_2.jpg, stem-3.jpg и т. п.

chevron-rightКак именно должен называться файл?hashtag

У серии фото одной модификации должен быть общий стем (база имени файла): ring-gold.jpg, ring-gold_2.jpg, ring-gold-3.jpg. Совпадение идёт по точному стему или стему с суффиксом _ / -. Регистр и размеры Shopify (_800x) не влияют — скрипт их «чистит».

chevron-rightА если у варианта метаполе пустое?hashtag

Тогда для него показываются все изображения товара (как в исходной теме). Логика включается только если для варианта нашлось хотя бы одно прикреплённое изображение.

chevron-rightЧто будет, если ни у одного варианта метаполя нет?hashtag

Скрипт это видит, ничего не делает и сразу ставит data-vg-ready="1". Галерея работает ровно как в теме, без дополнительных действий и влияния на производительность.

chevron-rightБудут ли «мигания» картинок при загрузке или при переключении варианта?hashtag

Нет. Мы использовали двойную защиту:

  • на стороне Liquid — «пред-скрытие» лишних изображений для первого кадра;

  • на стороне JS — фильтрация при переключениях + флаг data-vg-ready вкупе с мини-CSS, чтобы не было промежуточных состояний на экране.

chevron-rightВ зум-диалоге сейчас показываются все фото. Так задумано?hashtag

Нет, теперь зум тоже фильтруется. И миниатюры, и большие кадры в диалоге показывают только изображения текущего варианта (по тому же правилу стемов). Первый кадр чистый за счёт пред-скрытия в Liquid; дальше — за счёт скрипта.

chevron-rightСчётчик, стрелки, миниатюры карусели — почему вы их не трогали?hashtag

Чтобы решение было максимально совместимым и минимально «инвазивным». Мы не вмешивались в навигационные элементы, кроме Dots, — их можно будет настроить отдельно, когда появится такая задача.

chevron-rightВ каких случаях скрипт может «не видеть» id варианта?hashtag

Если тема/приложение нестандартно рендерит форму варианта. Скрипт ищет name="id" в форме add to cart. Если поле переименовано или его нет на странице, обновите селектор в функции getVariantId() или бросайте кастомное событие selectVariant/variant:change с detail.variant.id.

chevron-rightУ меня «быстрое просмотр»/модальное окно товара — решение сработает?hashtag

Как правило — да, т.к. скрипт наблюдает MutationObserver за document.body и повторно применяет фильтр. Если модалка подгружает контент динамически, убедитесь, что блок JSON #variant-galleries-json попадает внутрь её DOM.

chevron-rightЧто насчёт производительности?hashtag
  • Блок JSON строится один раз на сервере;

  • JS обходит только видимые элементы галереи и работает по простым строковым проверкам;

  • Если метаполей нет — скрипт фактически «выключается».

  • Оверхеда для страниц без метаполей нет.

chevron-rightSEO/Alt-тексты/Structured data не пострадают?hashtag

Мы не удаляем элементы, только добавляем display:none в стартовое состояние и переключаем видимость. Alt-тексты и schema.org, которые рендерит тема, остаются. Набор изображений в DOM остаётся тем же, просто часть скрыта, пока вариант иной.

chevron-rightНужно ли менять порядок медиа в самом товаре?hashtag

Не обязательно. Но для UX лучше, чтобы «якорное» фото каждого варианта (тот самый stem) находилось рядом с его серией — так пред-скрытие и первый кадр будут визуально логичнее.

chevron-rightЧто если разные варианты случайно получили одинаковый стем?hashtag

Тогда обе серии будут считаться «подходящими» для обоих вариантов. Держите нейминг строгим (разные стемы на разные варианты), чтобы не было пересечений.

chevron-rightМожно ли использовать пробелы/Юникод в именах файлов?hashtag

Можно, но лучше избегать. Shopify даёт URL, а скрипт работает по базовому имени из URL. Рекомендация: латиница, дефисы или подчёркивания.

chevron-rightА видео и 3D-модели?hashtag

Фильтр применяется только к media_type="image". Видео/модели остаются как в теме. Если хотите, чтобы и они «прикреплялись» к вариантам — можно расширить сопоставление по data-media-type и базовым именам постеров/URL.

chevron-rightЧто будет, если я позже переименую файл в Files?hashtag

Сопоставление строится по имени файла. Если переименуете «якорь» или серию, обновите либо имя «якоря» в метаполе, либо верните прежнее имя; иначе серию может «оторвать» от варианта.

chevron-rightКак откатиться назад?hashtag

Удалите добавленный блок JSON, серверные вставки vg_list/prehide, единый блок common_data_attrs, скрипт и мини-CSS. После этого тема вернётся к исходному поведению.

chevron-rightЭто работает на всех языках/локалях?hashtag

Да. Логика не завязана на тексты; важны только атрибуты и имена файлов.

chevron-rightМожет ли это конфликтовать с приложениями-галереями?hashtag

Если приложение полностью заменяет разметку галереи, оно, вероятно, игнорирует наши data-атрибуты. Тогда или отключайте приложение на страницах с этой логикой, или переносите фильтрацию в шаблоны приложения.

chevron-rightБезопасно ли обновлять тему?hashtag

Майорные апдейты темы могут перезаписать _product-media-gallery.liquid. Держите git/Theme Download и diff: если Shopify поменяет структуру этого шаблона, перенесите наши вставки в новую версию файла.

chevron-rightМожно ли вместо «якорного» файла прикреплять все файлы серии?hashtag

Можно, но не нужно. Логика специально построена на стемах, чтобы не «тыкать» каждый файл руками.

chevron-rightМожно ли убрать атрибут data-initial-variant-id?hashtag

Да. Он опционален и никак не влияет на работу фильтра.

chevron-rightЧто делать, если на странице несколько товаров (панель «рекомендованные», кастомные секции и т. п.)?hashtag

В текущем виде скрипт ищет ближайший <media-gallery> рядом с собой. Размещайте его внутри нужного блока товара. Если у вас несколько галерей на одной странице, добавьте уникальные контейнеры/инициализации, чтобы скрипт для каждого товара стоял сразу после его <media-gallery>.

chevron-rightВ модалке quick add почему одно фото?hashtag

Так задумано: на мобильных в быстром добавлении важно не перегружать экран — показываем featured текущего варианта. На PDP остаётся вся серия.

Последнее обновление