---
title: "プロダクトバンドルレンダリングのカスタマイズ"
slug: "customizing-the-product-bundle-rendering"
abstract: "コードを修正することでカスタマイズ可能なProduct BundleレンダリングバリアントのScribanテンプレートの概要。"
---
# プロダクトバンドルレンダリングのカスタマイズ

デフォルトの製品バンドルレンダリングには [、Scriban](https://doc.sitecore.com/xp/ja/developers/100/sitecore-experience-commerce/working-with-scriban-templates.html "Working with Scriban templates")テンプレートという形のレンダリングバリアントが含まれています。デフォルトのProduct Bundleレンダリングは、静的バンドルと動的 [バンドル](https://doc.sitecore.com/xp/en/users/100/sitecore-experience-commerce/bundling.html)の両方を扱います。元のレンダリングバリアントに含まれていたすべてのネストされたアイテムは、単一のScribanテンプレートに統合されます。Scribanテンプレートを修正することもできますが、ソフトウェアのアップグレード時にカスタマイズが上書きされないように、新しいカスタムレンダリングバリアントを作成するのが最善です。例えば [カスタムラベルを追加する](https://doc.sitecore.com/xp/ja/developers/100/sitecore-experience-commerce/customize-the-commerce-search-results-rendering-to-identify-product-bundles.html "Customize the Commerce Search Results rendering to identify product bundles")などテンプレートを簡単に変更できるため、Scribanテンプレートは非常にカスタマイズ性と拡張性が高いです。レンダリング時の [ラベルも変更](https://doc.sitecore.com/xp/ja/developers/100/sitecore-experience-commerce/modify-a-label-for-a-rendering-that-uses-a-scriban-template.html "Modify a label for a rendering that uses a Scriban template") 可能です。

> !注Product Bundleの廃止レンダリングは既存サイトでのみ利用可能で、レンダリングバリアントのScribanテンプレートではなくMVCビューに基づいています。

Product Bundleレンダリングバリアントは独自のデフォルトレンダリングバリアントルート [とデフォルトレンダリングバリアント](https://doc.sitecore.com/xp/en/users/93/sitecore-experience-commerce/en/using-rendering-variants-to-display-product-information.html) (*/sitecore/Content///Presentation/Rendering Variants/Product Bundle*)を持っています。マークアップ生成にはScribanテンプレート、[AJAXリクエスト](https://doc.sitecore.com/xp/ja/developers/100/sitecore-experience-commerce/understanding-asynchronous-calls-and-caching.html "Understanding asynchronous calls and caching")として株価情報の取得にはScribanテンプレート、JavaScriptはAJAXリクエストとして取得し、ラベル翻訳にはSXA辞書を使用します。

以下のコードは、デフォルトのレンダリングバリアント内で定義されたProduct BundleレンダリングScribanテンプレートを示しています。カタログ名とバンドルIDはMVCコントローラーに渡され、対応するバンドルリポジトリを使ってモデルを埋める責任があります。モデルはビューに渡され、レンダリングバリアントや埋め込みアイテムo\_model(the-embedded-commerce-items-and-objects-for-scriban-templates.md "The embedded Commerce items and objects for Scriban templates")を用いるScribanテンプレートで利用可能です。モデルは、オプションのバンドルアイテムやアップグレード可能なアイテムを含む、製品バンドルをレンダリングするために必要なすべてのオブジェクトと値を公開します。

{{ # The <div> element contains the bundle data attributes with the values populated from the data model and data source. }}
<div class="bundle-header" data-catalog-name="{{ o\_model.catalog\_name | html.escape }}" data-bundle-id="{{ o\_model.bundle\_id }}"
 data-bundle-list-price="{{ o\_model.list\_price }}" data-bundle-adjusted-price="{{ o\_model.adjusted\_price }}"
 data-bundle-is-on-sale="{{ o\_model.is\_on\_sale }}" data-bundle-is-dynamic="{{ o\_model.is\_dynamic\_bundle }}"
 data-bundle-savings-percentage="{{ i\_datasource.SavingsLeadText | html.escape }} {{ o\_model.savings\_percentage | html.escape }}"
 data-bundle-invalid-variant-error-message="{{ i\_datasource.InvalidVariantMessage | html.escape }}"
 data-bundle-invalid-range-error-message="{{ i\_datasource.InvalidRangeMessage | html.escape }}">
 {{ # The <h3> element displays the bundle title text retrieved from the data source. }}
 <h3 class="bundle-title">{{ i\_datasource.TitleText }}</h3>
</div>
{{ # The <div> element contains all the bundle line items. }}
<div class="bundle-groups-container">
 {{ # Iterate through each bundle line item. }}
 {{ for bundleLineItem in o\_model.line\_items }}
 {{ ## The <form> element contains the bundle data attributes with the values populated from the bundle line item.
 The 'noPanel' CSS class will be applied if the 'hasPanel' computed property in the view model returns false. ## }}
 <form autocomplete="off" class="bundle-group" data-bundle-line-item-id="{{ bundleLineItem.bundle\_line\_item\_id }}"
 data-bundle-line-item-name="{{ bundleLineItem.display\_name | html.escape }}"
 data-bundle-line-item-optional="{{ bundleLineItem.is\_optional }}"
 data-bundle-line-item-upgradable="{{ bundleLineItem.is\_upgradable }}"
 data-bundle-line-item-min-quantity="{{ bundleLineItem.quantity }}"
 data-bundle-line-item-max-quantity="{{ bundleLineItem.maximum\_quantity }}"
 data-bundle-line-item-link="{{ bundleLineItem.product\_link }}"
 data-bind="css: { noPanel: !hasPanel() }">
 {{ # The <div> element contains all the header elements. }}
 <div class="bundle-group-header-container">
 {{ # The <div> element has a binding with the click event to show or hide its content. }}
 <div class="bundle-group-header" data-bind="click: toggleBundleGroupBody">
 {{ ## The <span> element displays the bundle line item summary in this format:
 <Product Display Name> <Separator> <Quantity> <Unit of Measurement>
 Example: Habitat Dwell Digital Wifi Scale (Black) - 2 pcs ## }}
 <span class="bundle-group-product-name">
 {{ ## The <span> element displays the display name of the bundle line item.
 It has a text binding with the bundleLineItemName observable to ensure the value is updated in the
 case when an upgrade item is selected. ## }}
 <span class="product-name-label" data-bind="text: bundleLineItemName">{{ bundleLineItem.display\_name }}</span>
 {{ # The <span> element displays the separator. }}
 <span class="bundle-group-header-separator">-</span>
 {{ ## The <span> element displays the quantity of the bundle line item.
 It has a text binding with the bundleLineItemQuantity observable to ensure the value is updated in the
 case when an upgrade item is selected. ## }}
 <span data-bind="text: bundleLineItemQuantity">{{ bundleLineItem.quantity }}</span>
 {{ # The <span> element displays the unit of measurement retrieved from the data source. }}
 <span class="bundle-group-header-uom">{{ i\_datasource.UnitOfMeasurement }}</span>
 </span>
 {{ # The setArrowClass computed property in the view model determines whether to display the accordion toggle button. }}
 <span data-bind="css: setArrowClass()"></span>
 {{ ## The <a> element is a link to the product page of the bundle line item. Link text is retrieved from the data source.
 It has a href attribute binding with the bundleLineItemLink observable to ensure the value is updated in the
 case when an upgrade item is selected. ## }}
 <a class="product-link" data-bind="attr: { href: bundleLineItemLink }">{{ i\_datasource.ViewProductText }}</a>
 </div>
 {{ ## The <div> element has a visible binding with the bundle line item 'is\_optional' flag.
 Hence, it will only be displayed if the flag is true. ## }}
 <div class="bundle-group-optional" data-bind="visible: {{ bundleLineItem.is\_optional }}">
 {{ ## The <input> element is a checkbox with a checked binding to indicate whether the bundle line item is included in the bundle or not.
 The element is disabled if the computed property 'isCheckboxDisabled' returns true. ## }}
 <input type="checkbox" class="checkbox-inline" data-bind="checked: isIncluded, disable: isCheckboxDisabled()">
 {{ # The <label> element is the checkbox label text that is retrieved from the data source. }}
 <label class="bundle-group-optional-label">{{ i\_datasource.IncludeItemText }}</label>
 </div>
 {{ ## The <div> element contain all elements to display and modify the bundle line item quantity.
 It has a visible binding with the 'is\_dynamic\_bundle' flag in the model.
 Hence, it will only be displayed if the flag is true. ## }}
 <div class="bundle-group-quantity" data-bind="visible: {{ o\_model.is\_dynamic\_bundle }}">
 {{ # The <label> element is the quantity label text that is retrieved from the data source. }}
 <label class="bundle-group-quantity-label">{{ i\_datasource.QuantityLabel }}</label>
 {{ ## The <div> element contains the input field and buttons to set the quantity. }}
 <div class="bundle-group-quantity-input">
 {{ ## The <button> element is used to decrease the bundle line item quantity by one (1) unit.
 Whenever the button is clicked, the click binding will invoke the 'decreaseBundleItemQuantity' function.
 The button is enabled if the computed property 'isQuantityEnabled' returns true. ## }}
 <button class="decrease" data-bind="event: { click: decreaseBundleItemQuantity }, enable: isQuantityEnabled()"></button>
 {{ ## The <input> element is a field to enter the desired quantity for the bundle line item.
 Whenever the input value is changed, the event binding will invoke the 'updateBundleItemQuantity' function.
 The input is enabled if the computed property 'isQuantityEnabled' returns true. ## }}
 <input name="bundleLineItemQuantity" class="quantity" type="number" data-val="true"
 data-bind="event: { change: updateBundleItemQuantity }, value: bundleLineItemQuantity, valueUpdate: 'input', enable: isQuantityEnabled()">
 {{ ## The <button> element is used to increase the bundle line item quantity by one (1) unit.
 Whenever the button is clicked, the click binding will invoke the 'increaseBundleItemQuantity' function.
 The button is enabled if the computed property 'isQuantityEnabled' returns true. ## }}
 <button class="increase" data-bind="event: { click: increaseBundleItemQuantity }, enable: isQuantityEnabled()"></button>
 </div>
 {{ ## The <span> element contains the validation message which is displayed when the bundleLineItemQuantity is invalid. }}
 <span class="validationMessage" data-bind="validationMessage: bundleLineItemQuantity"></span>
 </div>
 {{ ## The <div> element displays information on the selected variants for the bundle line item.
 It has a foreach binding to iterate through the selected variants and is only visible if the bundle
 line item has selected variants. ## }}
 <div class="selected-variant-preview" data-bind="visible: hasSelectedVariants, foreach: selectedVariants">
 {{ ## The <div> element groups together the variant's key and value. }}
 <div class="selected-variant-group">
 {{ # The <span> elements displays the variant's key and value from the view model in this format: <key>: <value> }}
 <span data-bind="text: displayName"></span><span></span>
 <span class="selected-value" data-bind="text: value"></span>
 </div>
 </div>
 </div>
 {{ # The <div> element contains all the body elements. }}
 <div class="bundle-group-body-container">
 {{ # The <div> element contains the available upgrade items of the bundle line item. }}
 <div class="group-upgrade-section">
 {{ ## The <div> element contains the selection elements for the upgrade items.
 The element is visible if the bundle item is upgradable and disabled otherwise. ## }}
 <div class="group-upgrade-selection" data-item-id="{{ bundleLineItem.bundle\_line\_item\_id }}" data-bind="visible: {{ bundleLineItem.is\_upgradable }}">
 {{ # The <label> element is the upgrade options label text that is retrieved from the data source. }}
 <label class="group-upgrade-label">{{ i\_datasource.UpgradeOptionsLabel }}</label>
 {{ ## The <select> element contains all the viable upgrade items.
 Whenever the option is changed, the event binding will invoke the 'onUpgradeItemChanged' function. ## }}
 <select class="group-upgrade-variant-select" data-bind="event: { change: onUpgradeItemChanged }">
 {{ ## Default <option> element when no upgrade item is selected, which is the bundle line item itself.
 The element contains data attributes that is required to update the view model.
 The placeholder text is retrieved from the data source. ## }}
 <option data-upgrade-item-id="{{ bundleLineItem.bundle\_line\_item\_id }}"
 data-upgrade-item-name="{{ bundleLineItem.display\_name | html.escape }}"
 data-upgrade-item-min-quantity="{{ bundleLineItem.quantity }}"
 data-upgrade-item-max-quantity="{{ bundleLineItem.maximum\_quantity }}"
 data-upgrade-item-link="{{ bundleLineItem.product\_link }}" selected>{{ sc\_raw i\_datasource "UpgradeOptionsPlaceholder" }}</option>
 {{ # Iterate through the upgradable items of the bundle item. }}
 {{ for upgradeItem in bundleLineItem.upgradable\_sellable\_item\_list }}
 {{ # Populate the display name of the upgrade item into the <option> element. }}
 <option data-upgrade-item-id="{{ upgradeItem.bundle\_line\_item\_id }}"
 data-upgrade-item-name="{{ upgradeItem.display\_name | html.escape }}"
 data-upgrade-item-min-quantity="{{ upgradeItem.quantity }}"
 data-upgrade-item-max-quantity="{{ upgradeItem.maximum\_quantity }}"
 data-upgrade-item-link="{{ upgradeItem.product\_link }}">{{ upgradeItem.display\_name | html.escape }}</option>
 {{ end }}
 </select>
 </div>
 </div>
 {{ # The <div> element contains the available variant selections of the bundle line item. }}
 <div class="group-variant-section">
 {{ # Iterate through each variant selection. }}
 {{ for variantselection in bundleLineItem.variant\_selections }}
 <div class="group-variant-selection" data-product-id="{{ bundleLineItem.bundle\_line\_item\_id }}">
 {{ # The <label> element contains the display name of the variant. }}
 <label class="group-variant-label">{{ variantselection.display\_name }}</label>
 {{ ## The <select> element contains all the viable options for the variant selection.
 Whenever the option is changed, the event binding will invoke the 'onBundleItemChanged' function.
 The element is disabled if there is only one option and enabled otherwise. ## }}
 <select class="group-variant-select" data-bind="event: { change: onBundleItemChanged }, disable: {{ variantselection.options.size == 1 }}"
 data-variant-key="{{ variantselection.property\_name }}"
 data-variant-display-name="{{ variantselection.display\_name }}">
 {{ # Iterate through the options of each variant selection. }}
 {{ for option in variantselection.options }}
 {{ # Populate the option value into the <option> element. }}
 <option>{{ option.value }}</option>
 {{ end }}
 </select>
 </div>
 {{ end }}
 </div>
 {{ # Iterate through each upgrade item of the bundle line item. }}
 {{ for upgradeItem in bundleLineItem.upgradable\_sellable\_item\_list }}
 <div class="group-upgrade-variant-section">
 {{ # Iterate through each upgrade item variant selection. }}
 {{ for variantselection in upgradeItem.variant\_selections }}
 <div class="group-variant-selection" data-product-id="{{ upgradeItem.bundle\_line\_item\_id }}" >
 {{ # The <label> element contains the display name of the variant. }}
 <label class="group-variant-label">{{ variantselection.display\_name }}</label>
 {{ # The <select> element contains all the viable options for the variant selection. }}
 <select class="group-variant-select" data-variant-key="{{ variantselection.property\_name }}">
 {{ # Iterate through the options of each variant selection. }}
 {{ for option in variantselection.options }}
 {{ # Populate the option value into the <option> element. }}
 <option class="group-variant-select-option">{{ option.value }}</option>
 {{ end }}
 </select>
 </div>
 {{ end }}
 </div>
 {{ end }}
 <div class="product-link-container">
 {{ ## The <a> element is a link to the product page of the bundle line item. Link text is retrieved from the data source.
 It has a href attribute binding with the bundleLineItemLink observable to ensure the value is updated in the
 case when an upgrade item is selected. ## }}
 <a class="product-link" data-bind="attr: { href: bundleLineItemLink }">{{ i\_datasource.ViewProductText }}</a>
 </div>
 </div>
 {{ # The <div> element contains the combination of variants that are valid. }}
 <div class="bundle-variant-combination-list">
 {{ # Iterate through the valid product variants. }}
 {{ for validProductVariant in bundleLineItem.valid\_product\_variants }}
 {{ # The <ul> element has data attributes to store the product ID and variant ID. }}
 <ul class="bundle-variant-combination" data-product-id="{{ bundleLineItem.bundle\_line\_item\_id }}" data-variant-id="{{ validProductVariant.variant\_id }}">
 {{ # Iterate through the variants of the valid product variants. }}
 {{ for variant in validProductVariant.variant\_properties }}
 {{ # The <li> element has data attributes to store the variant key and value. }}
 <li class="bundle-variant-combination-value" data-variant-key="{{ variant.property\_name }}"
 data-variant-value="{{ variant.value }}"></li>
 {{ end }}
 </ul>
 {{ end }}
 </div>
 {{ # Iterate through each upgrade item of the bundle line item. }}
 {{ for upgradeItem in bundleLineItem.upgradable\_sellable\_item\_list }}
 <div class="bundle-upgrade-variant-combination-list">
 {{ # Iterate through the valid product variants. }}
 {{ for validProductVariant in upgradeItem.valid\_product\_variants }}
 {{ # The <ul> element has data attributes to store the product ID and variant ID. }}
 <ul class="bundle-variant-combination" data-product-id="{{ upgradeItem.bundle\_line\_item\_id }}" data-variant-id="{{ validProductVariant.variant\_id }}">
 {{ # Iterate through the variants of the valid product variants. }}
 {{ for variant in validProductVariant.variant\_properties }}
 {{ # The <li> element has data attributes to store the variant key and value. }}
 <li class="bundle-variant-combination-value" data-variant-key="{{ variant.property\_name }}"
 data-variant-value="{{ variant.value }}"></li>
 {{ end }}
 </ul>
 {{ end }}
 </div>
 {{ end }}
 </form>
 {{ end }}
</div>

## プロダクトバンドルレンダリングモデル

Product Bundle Scribanテンプレートでは、以下の図に示すように埋め込まれたアイテムo\_modelを通じて、ProductBundleRenderingModelモデルに含まれるプロパティやオブジェクトにアクセスできます。

![Diagram of the Product Bundle rendering model](https://doc.sitecore.com/api/markdown-image/xp/ja/developers/100/sitecore-experience-commerce/images/ProductBundleModel.png)