From salesforce-commerce
Writes ISML templates for Salesforce B2C Commerce storefronts using <isprint>, <isif>, <isloop>, <isset>, <isinclude>, <isdecorate>, ${pdict.*} expressions, Resource.msg() localization, content slots, and inheritance.
npx claudepluginhub orcaqubits/agentic-commerce-skills-plugins --plugin salesforce-commerceThis skill is limited to using the following tools:
Build ISML (Internet Store Markup Language) templates for Salesforce B2C Commerce storefronts.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides MCP server integration in Claude Code plugins via .mcp.json or plugin.json configs for stdio, SSE, HTTP types, enabling external services as tools.
Build ISML (Internet Store Markup Language) templates for Salesforce B2C Commerce storefronts.
Fetch live documentation FIRST:
Why: ISML syntax, tag attributes, encoding modes, and localization patterns evolve with each B2C Commerce release. Always verify current specs before generating template code.
| Tag | Purpose | Key Attributes |
|---|---|---|
<isprint> | Output with encoding | value, encoding (required for XSS safety) |
<isif> / <iselseif> / <iselse> | Conditional rendering | condition |
<isloop> | Iteration | items, var, status, begin, end, step |
<isset> | Variable assignment | name, value, scope (page/request/session) |
<isinclude> | Include partial template | template (path) or url (controller action) |
<isdecorate> | Decorator/layout wrapper | template (decorator path) |
<isreplace> | Insertion point in decorator | (no attributes) |
<isslot> | Content slot | id, context (category/folder/global), description |
<iscache> | Template-level caching | type, hour, varyby |
<isscript> | Inline server-side JS | (use sparingly -- prefer controllers) |
<iscontent> | Set content type/charset | type, charset |
<isstatus> | Set HTTP status code | code |
<isredirect> | Server-side redirect | location |
<iscomment> | Server-side comment | (not rendered to client) |
<isprint>| Mode | Context | When to Use |
|---|---|---|
htmlcontent | HTML body text | Default for most output (de facto SFRA standard) |
htmlsinglequote | Single-quoted HTML attributes | <div title='...'> |
htmldoublequote | Double-quoted HTML attributes | <div title="..."> |
htmlunquote | Unquoted HTML attributes | Rarely needed; prefer quoted attributes |
jshtml | JavaScript strings in HTML | <script>var x = '...';</script> |
jsattribute | JS in HTML event attributes | onclick="..." |
jsonvalue | JSON values | JSON data output |
uricomponent | URL query parameters | Query string values |
uristrict | Full URI encoding | Path segments |
xmlcontent | XML body content | XML/RSS feeds |
off | No encoding | Trusted content ONLY -- avoid in production |
Always specify encoding. Choose based on output context. Never use raw ${variable} for user-controlled data without encoding.
Pipeline Dictionary (pdict):
${pdict.variableName} -- access controller-passed data (SFRA: from res.render())pdict contains only what the controller explicitly passedObject Navigation:
${pdict.product.name} -- dot notation for nested properties${pdict.basket.totalGrossPrice.value} -- deep property accessOperators: Arithmetic (+, -, *, /, %), comparison (==, !=, <, >), logical (&&, ||, !), ternary (${cond ? a : b}).
<isloop> Status Object| Property | Type | Description |
|---|---|---|
first | Boolean | True on first iteration |
last | Boolean | True on last iteration |
count | Number | Current iteration (1-based) |
index | Number | Current iteration (0-based) |
Access via the status attribute: <isloop items="${list}" var="item" status="loopstate">, then use ${loopstate.first}, ${loopstate.index}, etc.
<isset> Scope Rules| Scope | Lifetime | Use Case |
|---|---|---|
page | Current template render | Temporary computation within a template |
request | Current HTTP request | Share data across included templates |
session | Current user session | Persist across requests (use sparingly) |
Default scope is session -- always specify scope explicitly to avoid unintended session pollution.
${Resource.msg('key', 'bundleName', 'Default')}
${Resource.msgf('key', 'bundle', 'Default {0}', param)}
Common bundles: forms, common, error, product. Always provide meaningful default values. Resource bundles are .properties files in templates/resources/.
Decorators wrap child content via <isdecorate> and <isreplace>:
<!-- Child template -->
<isdecorate template="common/layout/page">
<h1>Page Content</h1>
<!-- replaces <isreplace /> in decorator -->
</isdecorate>
The decorator template defines shared layout (header, footer, <head>) and uses <isreplace /> to mark where child content is inserted. Nested decorators are supported.
<!-- Pattern: product loop skeleton -->
<!-- Fetch live docs for loopstate properties -->
<isloop items="${pdict.products}" var="product" status="loopstate">
<isprint value="${product.name}" encoding="htmlcontent" />
</isloop>
<!-- Pattern: URL generation -->
<a href="${URLUtils.url('Product-Show', 'pid', product.ID)}">
<isprint value="${product.name}" encoding="htmlcontent" />
</a>
| Method | Purpose |
|---|---|
URLUtils.url() | Generate absolute URL for controller action |
URLUtils.https() | Force HTTPS URL |
URLUtils.staticURL() | URL to static asset in cartridge |
URLUtils.absURL() | Absolute URL with full domain |
URLUtils.home() | Homepage URL |
URLUtils.continueURL() | Current request URL for form returns |
Configured in Business Manager. Slots support HTML, products, categories, or content assets. Use descriptive IDs (home-banner-top, category-promo-sidebar) and set appropriate context (global, category, folder). Slot rendering can be cached separately from template caching.
<isscript> executes on the server and can access the full SFCC API -- keep logic minimal and move heavy processing to controllers or scripts.<isset scope="session"> persists across requests -- avoid session bloat by defaulting to page scope.res.render() is available.<iscache> is separate from CDN caching; both must be configured correctly.encoding="off" unless input is fully trusted.<isscript> blocks -- move logic to controllers or scripts.<isset> to compute expensive values once and reuse.<iscache> for templates that do not change per request.<isinclude>.| Directory | Contents |
|---|---|
common/layout/ | Decorators (page, checkout, account) |
components/ | Shared partials (header, footer, navigation) |
product/ | Product display templates |
search/ | Search results templates |
account/ | Customer account templates |
cart/ | Cart and mini-cart templates |
checkout/ | Checkout flow templates |
Fetch the ISML tag reference, encoding mode documentation, and resource bundle guide for exact tag attributes, encoding behaviors, and localization APIs before implementing.