b2c-isml について
Salesforce B2C Commerceの開発者向けISMLテンプレートスキルです。動的HTMLを生成するサーバーサイドテンプレートについて、タグ、式、再利用、ローカライズ、キャッシュを解説し、複雑な処理はコントローラーやヘルパースクリプトに置く方針を示します。
主な機能
- 01ISMLタグによる条件分岐とループ
- 02式による動的コンテンツの出力
- 03テンプレート再利用とデコレーターレイアウト
- 04ローカライズとURLユーティリティの利用
- 05キャッシュと出力エンコードの実践
活用シーン
- 01商品詳細ページやホームページのテンプレート作成
- 02再利用可能なページコンポーネントの構築
- 03ページへのローカライズ済みテキストとリンクの追加
- 04テンプレート処理の整理とレイアウトの統一
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ salesforcecommercecloud/ b2c-developer-tooling --skill b2c-ismlインストール後、Claude Code で/b2c-ismlを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/trigger-evals.jsonreferences/EXPRESSIONS.mdTAGS.md詳細
ISML スキル
このスキルでは、Salesforce B2C Commerce で ISML(Isomorphic Markup Language)テンプレートを作成し、使用する方法を説明します。ISML テンプレートは、HTML と動的なサーバーサイドタグを組み合わせます。
概要
ISML テンプレートは、HTML を生成するサーバーサイドテンプレートです。is で始まる特殊なタグと、動的コンテンツを埋め込む ${...} 構文の式を使用します。
ファイルの場所
テンプレートは、カートリッジの templates ディレクトリに配置します。
/my-cartridge
/cartridge
/templates
/default # Default locale
/product
detail.isml
tile.isml
/home
homepage.isml
/util
modules.isml # Custom tag definitions
/fr_FR # French-specific templates
/product
detail.isml
基本的なタグ
条件分岐
<isif condition="${product.available}">
<span class="in-stock">In Stock</span>
<iselseif condition="${product.preorderable}">
<span class="preorder">Pre-order</span>
<iselse>
<span class="out-of-stock">Out of Stock</span>
</isif>
ループ
<isloop items="${products}" var="product" status="loopstate">
<div class="product ${loopstate.odd ? 'odd' : 'even'}">
<span>${loopstate.count}. ${product.name}</span>
<isif condition="${loopstate.first}">
<span class="badge">Featured</span>
</isif>
</div>
</isloop>
ループのステータスプロパティ:
count- 反復回数(1 から開始)index- 現在のインデックス(0 から開始)first- ブール値。最初の反復では truelast- ブール値。最後の反復では trueodd- ブール値。奇数回目の反復では trueeven- ブール値。偶数回目の反復では true
変数
<isset name="productName" value="${product.name}" scope="page"/>
<span>${productName}</span>
<isremove name="productName" scope="page"/>
スコープ(必須): page、request、session、pdict
出力
<isprint value="${product.name}"/>
<isprint value="${htmlContent}" encoding="off"/>
<isprint value="${price}" style="CURRENCY"/>
<isprint value="${order.creationDate}" style="DATE_SHORT"/>
テンプレートのインクルード
<isinclude template="product/components/price"/>
<isinclude url="${URLUtils.url('Product-GetPrice', 'pid', product.ID)}"/>
デコレーターパターン
ベースデコレーター(layouts/pagelayout.isml):
<!DOCTYPE html>
<html>
<head>
<title>${pdict.pageTitle}</title>
</head>
<body>
<header>
<isinclude template="components/header"/>
</header>
<main>
<isreplace/>
</main>
<footer>
<isinclude template="components/footer"/>
</footer>
</body>
</html>
デコレーターを使用するページ:
<isdecorate template="layouts/pagelayout">
<isslot id="home-banner" context="global"/>
<div class="homepage-content">
<h1>${pdict.welcomeMessage}</h1>
</div>
</isdecorate>
式
式は ${...} 構文を使用して、動的な値を埋め込みます。
${product.name}
${product.price.sales.value}
${product.getAvailabilityModel().isInStock()}
${pdict.myVariable}
${session.customer.firstName}
${request.httpParameterMap.pid.stringValue}
${price > 100 ? 'expensive' : 'affordable'}
${firstName + ' ' + lastName}
${quantity * unitPrice}
組み込みユーティリティ
URLUtils
<a href="${URLUtils.url('Product-Show', 'pid', product.ID)}">View</a>
<a href="${URLUtils.https('Account-Show')}">My Account</a>
<img src="${URLUtils.staticURL('/images/logo.png')}" alt="Logo"/>
<a href="${URLUtils.abs('Home-Show')}">Home</a>
Resource(ローカライズ)
${Resource.msg('button.addtocart', 'product', null)}
${Resource.msgf('cart.items', 'cart', null, cartCount)}
StringUtils
${StringUtils.truncate(description, 100, '...')}
${StringUtils.formatNumber(quantity, '###,###')}
カスタムモジュール
再利用可能なカスタムタグを util/modules.isml で定義します。
<ismodule template="components/productcard"
name="productcard"
attribute="product"
attribute="showPrice"
attribute="showRating"/>
<isinclude template="util/modules"/>
<isproductcard product="${product}" showPrice="${true}" showRating="${true}"/>
コンポーネントテンプレート(components/productcard.isml):
<div class="product-card">
<img src="${product.image.url}" alt="${product.name}"/>
<h3>${product.name}</h3>
<isif condition="${pdict.showPrice}">
<span class="price">${product.price.sales.formatted}</span>
</isif>
<isif condition="${pdict.showRating && product.rating}">
<span class="rating">${product.rating} stars</span>
</isif>
</div>
キャッシュ
<iscache type="relative" hour="24"/>
<iscache type="daily" hour="0" minute="0"/>
<iscache type="relative" hour="1" varyby="price_promotion"/>
テンプレートの先頭に <iscache> を配置してください。
コンテンツタイプ
<iscontent type="text/html" charset="UTF-8"/>
<iscontent type="application/json" charset="UTF-8"/>
<iscontent type="application/xml" charset="UTF-8"/>
埋め込みスクリプト
<isscript>
var ProductMgr = require('dw/catalog/ProductMgr');
var product = ProductMgr.getProduct(pdict.pid);
var price = product.priceModel.price;
</isscript>
<span>${price.toFormattedString()}</span>
ベストプラクティス: <isscript> ブロックは最小限にとどめてください。複雑なロジックはコントローラーまたはヘルパースクリプトに移してください。
コメント
<iscomment>
ISML comment - stripped from output.
Use for documentation and hiding sensitive info.
</iscomment>
タグの配置に関する制約
すべての ISML タグをどこでも使用できるわけではありません。重要な制約は次のとおりです。
| タグ | 使用できる場所 |
|---|---|
<iscontent> | DOCTYPE 宣言より前に配置する必要があります |
<isredirect> | DOCTYPE 宣言より前に配置する必要があります |
<isprint> | <body> 内のみ |
<isbreak> | <body> 内の <isloop> 内のみ |
<iscontinue> | <body> 内の <isloop> 内のみ |
<isnext> | <isloop> 内 |
<isreplace> | <isdecorate> タグ内に配置する必要があります |
<isactivedatahead> | <head> 内のみ |
どこでも使用できるタグ:<isif>、<isloop>、<isinclude>、<isset>、<isremove>、<iscache>、<iscomment>、<ismodule>、<iscookie>、<isstatus>。
ベストプラクティス
- 機密情報には HTML コメントではなく
<iscomment>を使用する <iscontent>が必要なテンプレートでは、最初に配置する- 一貫性を保つため、
util/modules.ismlでモジュールを定義する - テンプレートはシンプルに保ち、ロジックはコントローラーやヘルパーに移す
- 一貫したページレイアウトにはデコレーターを使用する
- キャッシュ可能なページでは
<iscache>を使用してキャッシュを有効にする - 出力をエンコードする。デフォルトのエンコーディングによって XSS を防止できます
詳細なリファレンス
タグの詳細なドキュメントについては、以下を参照してください。