mcpField
B
b2c-isml

b2c-isml

github.com/salesforcecommercecloud开发5794 次安装今天更新
代码仓库

关于 b2c-isml

面向 Salesforce B2C Commerce 开发者的 ISML 模板技能,用于创建生成动态 HTML 的服务端模板。它汇总标签、表达式、模板复用、本地化和缓存等实践,并强调将复杂逻辑移至控制器或辅助脚本。

主要功能

  1. 01使用 ISML 标签编写条件与循环
  2. 02通过表达式输出动态内容
  3. 03复用模板并采用装饰器布局
  4. 04调用本地化与 URL 工具
  5. 05应用缓存和输出编码实践

适用场景

  1. 01创建商品详情和首页模板
  2. 02构建可复用的页面组件
  3. 03为页面添加本地化文本和链接
  4. 04整理模板逻辑并改善页面布局一致性

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/salesforcecommercecloud/b2c-developer-tooling --skill b2c-isml

安装后在 Claude Code 中输入/b2c-isml确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
trigger-evals.json
references/
EXPRESSIONS.md
TAGS.md

详细介绍

ISML 技能

本技能将指导你在 Salesforce B2C Commerce 中创建和使用 ISML(Isomorphic Markup Language)模板。ISML 模板将 HTML 与动态服务器端标签结合起来。

概述

ISML 模板是用于生成 HTML 的服务器端模板。它们使用以 is 为前缀的特殊标签,以及 ${...} 语法的表达式来嵌入动态内容。

文件位置

模板位于 cartridge 的 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 - 布尔值,在第一次迭代时为 true
  • last - 布尔值,在最后一次迭代时为 true
  • odd - 布尔值,在奇数次迭代时为 true
  • even - 布尔值,在偶数次迭代时为 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>。

最佳实践

  1. 对敏感信息使用 <iscomment>,而非 HTML 注释
  2. 在需要使用 <iscontent> 的模板中将其放在最前面
  3. 在 util/modules.isml 中定义模块,以保持一致性
  4. 保持模板简洁——将逻辑移至控制器/辅助程序中
  5. 使用装饰器来统一页面布局
  6. 使用 <iscache> 为可缓存页面启用缓存
  7. 对输出进行编码——默认编码可防止 XSS

详细参考

如需完整的标签文档:

评论

支持 Markdown