100%ご希望に沿う回答ではないことご承知おきください。
質問者様がおっしゃる通り、
座席商品とコース商品に分けて管理する方法しか私も思いつきませんでした。
そこで、
「購入ボタン」で、コース商品をカート投入すると、自動的に座席商品もカートインされる、
という実装を考えてみました。
前提
- 「購入ボタン」は「コレクション購入ボタン」を使用します。
- コース商品は、バリエーションで、Aコース、Bコース、Cコースを、持つとします。
- 座席商品は、0円のアイテムで在庫管理のためだけに使用します。
- コース商品と、それに対応する座席商品を1つずつ含むコレクションを作成し、そのコレクションで「コレクション購入ボタン」を作成します。
- このとき、座席商品がコレクションで2番目に表示されるようにしていただけますと、サンプルコードがそのまま使用できます。
- このままだと、「購入ボタン」を表示した際に、コース商品も座席商品も両方とも表示されてしまうので、「購入ボタン」のコードをカスタマイズし、「座席商品」を隠します。
- コース商品をカート投入した際に、隠された「座席商品」もカート投入されるよう、「購入ボタン」のコードをカスタマイズします。
- 「座席商品」がSold Outの時に、コース商品がカート投入できなくするように、「購入ボタン」のコードをカスタマイズします。
元々の購入ボタンのコードの一部分 (カスタマイズ状況によりコード内容は異なります)
ShopifyBuy.UI.onReady(client).then(function (ui) {
ui.createComponent('collection', {
id: '295396376736',
node: document.getElementById('collection-component-1657357282732'),
moneyFormat: '%C2%A5%7B%7Bamount_no_decimals%7D%7D',
options: {
"product": {
"styles": {
"product": {
"@media (min-width: 601px)": {
"max-width": "calc(25% - 20px)",
"margin-left": "20px",
"margin-bottom": "50px",
"width": "calc(25% - 20px)"
},
"img": {
"height": "calc(100% - 15px)",
"position": "absolute",
"left": "0",
"right": "0",
"top": "0"
},
"imgWrapper": {
"padding-top": "calc(75% + 15px)",
"position": "relative",
"height": "0"
}
}
},
"text": {
"button": "Add to cart"
},
},
上記のコードの最後に、eventsを追加し、下記のようにします。
ShopifyBuy.UI.onReady(client).then(function (ui) {
ui.createComponent('collection', {
id: '295396376736',
node: document.getElementById('collection-component-1657357282732'),
moneyFormat: '%C2%A5%7B%7Bamount_no_decimals%7D%7D',
options: {
"product": {
"styles": {
"product": {
"@media (min-width: 601px)": {
"max-width": "calc(25% - 20px)",
"margin-left": "20px",
"margin-bottom": "50px",
"width": "calc(25% - 20px)"
},
"img": {
"height": "calc(100% - 15px)",
"position": "absolute",
"left": "0",
"right": "0",
"top": "0"
},
"imgWrapper": {
"padding-top": "calc(75% + 15px)",
"position": "relative",
"height": "0"
}
}
},
"text": {
"button": "Add to cart"
},
"events": {
"afterRender": function(component) {
const productElements = component.node.childNodes;
// 座席商品を隠します
if (productElements[1]) {
productElements[1].style.display = 'none'; // コレクション内で、座席を表す商品が何番目かによって配列のインデックスを変更してください。productElements[1]は座席商品が2番目に表示されることを表しています。もし1番目に表示されるならproductElements[0]となります。
}
// 座席商品がSold Outのとき、コース商品の購入ボタンを隠し、Sold Outと表示します。
const isAvailable = Object.values(ShopifyBuy.UI.domains)[0].components.collection[0].products[1].model.availableForSale; // コレクション内での、座席商品の順番によって、products[x]を変更します。
if (!isAvailable && productElements[0]) {
const addToCartButtonElement = productElements[0].querySelector('[data-element="product.buttonWrapper"]'); // コレクション内での、コース商品の順番によって、productElements[x]を変更します。
addToCartButtonElement.innerHTML = '
Sold Out
'
}
},
"addVariantToCart": function (product) { // コース商品をAddToCartする際に、座席商品もAddToCartします
const variantId = Object.values(ShopifyBuy.UI.domains)[0].components.collection[0].products[1].model.variants[0]; // コレクション内での、座席商品の順番によって、products[x]を変更します。
setTimeout(() => {
product.cart.addVariantToCart(variantId, 1, false);
}, 300); // 座席商品をすぐにカート投入しようとするとその前に実行されているAddToCartを阻害する場合があるので、setTimeoutで回避します。
},
},
},
これで、「前提」にあるような挙動をする「購入ボタン」になります。
注意点
- 動けばいいレベルで組んだコードなので、端的に言って雑です。もっと洗練できると思います。
- コース商品の数量を変更できるようにしている場合、コース商品の数量に応じて座席商品のカート投入処理をカスタマイズする必要があります。
- コース商品をカート投入した際に、カートが開きますが、そちらに「座席商品」も表示されます。これを隠すこともできそうですが、最終的にどうやっても、チェックアウト時には表示されてしまいますので、であれば、ここで座席商品を隠す必要はないであろう、という判断です。
- カートでの数量変更を有効にしている場合、コース商品の数量だけをいじられてしまうと、破綻してしまいますので、無効にした方が良いかと思います。無効にする方法は、https://shopify.github.io/buy-button-js/customization/ 内で「LineItem contents defaults」を検索いただくと、なんとなくやり方が分かると思いますが、もし分かりにくい場合は、このスレッドに返信ください。即答は難しいかもしれませんが、回答いたします。
- 正直に申しますと、このカスタマイズが「安定して動作するか」は自信がないです。
もし、ご質問がございましたら、こちらのスレッドに返信ください。
それでは、参考になれば幸いです。
(キュー田辺)