こんにちは。
ディレクターの田辺です。
ECサイトを構築するとき、下記のようにされたいことはないでしょうか?
“商品詳細ページで、選択されているバリエーションの商品画像だけを表示したい”
例えば、アパレル商品で、白と黒の2つのカラーバリエーションがある場合に、商品詳細ページにて、白を選択しているときには白の商品画像だけを、黒を選択しているときには黒の商品画像だけを表示させたい、というご要望は多いのではないかと思います。
しかし、ShopifyのデフォルトテーマDawnにはこの機能がありません。
アプリ導入や、有料のテーマを購入することで実装できますが、できればお金をかけずに解決したいのが人情です。
そこで今回は、コードカスタマイズだけで「商品詳細ページにて、選択されているバリエーションの商品画像だけを表示する」機能を実装する方法をご紹介します。
各バリエーションに商品画像が1枚ずつしか存在しない場合はこのコードカスタマイズは不要です
Dawn 11.0.0では、各バリエーションに商品画像が1枚ずつしか設定されていない場合はコードカスタマイズを行わなくても、選択中のバリエーションの商品画像のみを表示することが可能です。各バリエーションに商品画像が複数枚つづ存在する場合のみ、本記事で紹介するコードカスタマイズをご活用ください。
はじめに
今回のコードカスタマイズは、Dawn 11.0.0を前提にしています。
Dawnのバージョンが異なる場合、うまく動かない可能性があることご承知おきください。
また、全ての状況において動作するような汎用的なコードカスタマイズでもありません。
実装コンセプトに、本記事で紹介するコードカスタマイズがうまく動作するであろう前提を記載しますので、ご一読ください。
実装コンセプト
前提
- 画像だけが対象です。動画の場合の動作検証はしていません
- アパレルでよくある「色」と「サイズ」の2つのオプションを持つ商品が対象です
- 「色」と「サイズ」のうち「色」にバリエーションごとの商品画像を紐付けます
- 「色」と「サイズ」のうち「色」がOption1であるとします
ストア管理画面 > オンラインストア > テーマ > カスタマイズ
において商品 > デフォルトの商品
のセクション「商品情報」 > バリエーションを選択した後、他のバリエーションのメディアを非表示にする
が有効であるとします(下図参照)
コンセプト
- 商品画像の並び順と、バリエーションことのサムネイル画像によって、どの画像がどのバリエーションのものかを判定します
- 商品画像は、バリエーションの「色」の順番で並べます。例えば、色の並びがBlack, Green, Brownであり、それぞれに前面と背面の2種類の画像がある場合、商品画像の並びは、Black前面、Black背面、Green前面、Green背面、Brown前面、Brown背面 にします。
- この時、バリエーションに設定するサムネイル画像は、例えば、サイズがSMLの3展開の場合は、Black/S、Black/M、Black/Lには、Black前面の画像を設定します。同様に、Green/S、Green/M、Green/Lには、Green前面を設定、Brown/S、Brown/M、Brown/Lには、Brown前面 を設定します。
このコンセプトを、実際の商品管理に反映すると下図のようになります。
コードカスタマイズ
可能な限り、既存のコードを変更せずに、コードを追加するだけで済むようにします。
まず、スニペット(snippets) > product-media-gallery.liquid
を開きます。
そして、下記のコードを45行目付近に追加します。
{%- liquid
assign variant_featured_media_ids = ""
assign variant_featured_media_key_ids = ""
for variant in product.variants
assign variant_featured_media_ids = variant_featured_media_ids | append: variant.featured_media.id | append: ','
endfor
assign variant_featured_media_ids = variant_featured_media_ids | split: ','
assign variant_featured_media_key_ids = variant_featured_media_ids | uniq
assign product_media_ids = ""
for media in product.media
assign product_media_ids = product_media_ids | append: media.id | append: ','
endfor
assign product_media_ids = product_media_ids | split: ','
assign current_variant_featured_media_id = product.selected_or_first_available_variant.featured_media.id
assign next_cariant_featured_media_key_id = variant_featured_media_key_ids | join: ',' | split: current_variant_featured_media_id | last | remove_first: ',' | split: ',' | first
assign current_variant_media_ids = product_media_ids | join: ',' | split: current_variant_featured_media_id | last | remove_first:',' | split: next_cariant_featured_media_key_id | first | remove_last:',' | prepend: ',' | prepend: current_variant_featured_media_id | split: ','
-%}
<script type="application/json" id="variant_featured_media_key_ids">
{{ variant_featured_media_key_ids | json }}
</script>
<script type="application/json" id="product_media_ids"></script>
<script defer>
window.addEventListener('load', function() {
const variantRadios = document.querySelector('variant-radios');
const variantRadiosInputs = variantRadios.querySelector('fieldset').querySelectorAll('input');
const sliderComponetLis = document.querySelector('slider-component').querySelectorAll('li');
const variantFeaturedMediaKeyIds = JSON.parse(document.getElementById('variant_featured_media_key_ids').textContent);
const productMediaIds = JSON.parse(document.getElementById('product_media_ids').textContent);
const variantData = variantRadios.getVariantData();
variantRadiosInputs.forEach(input => {
input.addEventListener('change', switchImages);
})
function switchImages(e) {
const selectedVariant = variantData.find(variant => variant.option1 == e.target.value);
const selectedVariantFeaturedImageId = String(selectedVariant.featured_media.id);
const nextVariantFeaturedImageId = variantFeaturedMediaKeyIds[variantFeaturedMediaKeyIds.indexOf(selectedVariantFeaturedImageId) + 1];
const startIndex = productMediaIds.indexOf(selectedVariantFeaturedImageId)
const endIndex = nextVariantFeaturedImageId != undefined ? productMediaIds.indexOf(nextVariantFeaturedImageId) : productMediaIds.length;
const selectedVariantImageIds = productMediaIds.slice(startIndex, endIndex);
sliderComponetLis.forEach(li => {
const mediaId = li.dataset.mediaId.split('-').pop();
if (selectedVariantImageIds.indexOf(mediaId) > -1) {
li.classList.remove('adjust-to-variant');
} else {
if(!li.classList.contains('adjust-to-variant')) {
li.classList.add('adjust-to-variant');
}
}
});
}
});
</script>
<style>
.adjust-to-variant {
display: none;
}
</style>
そして、スニペット(snippets) > product-media-gallery.liquid
の164行目付近にあるコードを下記のように変更します。(元コードは95行目付近にありますが、上記のコードを追加したことで164行目あたりまで行数がずれます。)
class="product__media-item grid__item slider__slide{% if single_media_visible %} product__media-item--single{% endif %}{% if product.selected_or_first_available_variant.featured_media == null and forloop.index == 1 %} is-active{% endif %}{% if media.media_type != 'image' %} product__media-item--full{% endif %}{% if section.settings.hide_variants and variant_images contains media.src %} product__media-item--variant{% endif %}{% if settings.animations_reveal_on_scroll %} scroll-trigger animate--fade-in{% endif %}"
↓
class="product__media-item grid__item slider__slide{% if single_media_visible %} product__media-item--single{% endif %}{% if product.selected_or_first_available_variant.featured_media == null and forloop.index == 1 %} is-active{% endif %}{% if media.media_type != 'image' %} product__media-item--full{% endif %}{% if section.settings.hide_variants and variant_images contains media.src %} product__media-item--variant{% endif %}{% if settings.animations_reveal_on_scroll %} scroll-trigger animate--fade-in{% endif %}{% assign media_id_string = media.id | append: '' %}{% unless current_variant_media_ids contains media_id_string %} adjust-to-variant{% endunless %}"
結果
下図のように、商品詳細ページにおいて選択されているバリエーションの商品画像だけが表示されます。
例では、各バリエーションごとに商品画像を2枚づつしか設定していませんが、3枚以上であってもうまく動作するはずです。
まとめ
今回、ご紹介したコードカスタマイズは、「限られた状況でのみ動作する」ものです。
また、十分な動作検証ができているとも言えません。
下記のような場合はぜひお問い合わせください。
- 自分の環境だとXXXやYYYという条件があり、この方法だとうまく動作しない。環境に合わせたコードカスタマイズを教えてほしい
- 単純にバグがあり、うまく動かない。動くようにしてほしい
お問い合わせフォームはこちらです。
追加カスタマイズについても、ある程度までであれば無料で相談に乗らせていただきます。
それでは。