b2c-business-manager-extensions について
Salesforce B2C Commerce の開発者向けに、Business Manager の管理画面をカスタマイズする拡張機能の作成方法を説明するスキルです。メニュー、ダイアログ、フォーム拡張に加え、XML スキーマや権限設定も扱います。
主な機能
- 01Business Manager 拡張 Cartridge の作成
- 02メニュー項目とアクションの設定
- 03既存ページへのダイアログアクション追加
- 04検索フォーム項目の拡張
- 05スキーマとコントローラーの規約確認
活用シーン
- 01Business Manager に独自のナビゲーションやページを追加
- 02注文・商品ページに操作ボタンを配置
- 03注文・顧客検索フォームに項目を追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ salesforcecommercecloud/ b2c-developer-tooling --skill b2c-business-manager-extensionsインストール後、Claude Code で/b2c-business-manager-extensionsを入力して読み込まれたか確認します。
同梱ファイルevals/trigger-evals.jsonreferences/EXTENSIONS-XML.md
詳細
Business Manager 拡張機能スキル
このスキルでは、管理インターフェイスをカスタマイズするための Business Manager(BM)拡張カートリッジの作成方法を説明します。
概要
BM 拡張機能は、単一の bm_extensions.xml 記述子と、ISML ページをレンダリングするコントローラーを通じて、Business Manager にカスタム機能を追加します。
| 拡張機能の種類 | 目的 |
|---|---|
| メニュー項目 | ナビゲーションセクション(Admin またはサイトのメニュー内のコンテナー)を追加します |
| メニューアクション | メニュー項目の下に機能的なリンク/ページを追加し、コントローラーノードに接続します |
| ダイアログアクション | 定義済みの拡張ポイントで既存の BM ページにボタンを追加します |
| フォーム拡張機能 | 既存の BM 検索フォーム(注文/顧客検索)にフィールドを追加します |
⚠️ スキーマの要点(最初にお読みください)
よくある間違いを以下に示します。この記述子では、extensibility/* 名前空間ではなく、bmmodules/2007-12-11 スキーマ(bmext.xsd)を使用します。
- 名前空間は
http://www.demandware.com/xml/bmmodules/2007-12-11です。 name、short_description、descriptionは、必須のxml:lang属性を持つ子要素であり、属性でもリソースキーでもありません。要素を言語ごとに繰り返してローカライズします。name="..."属性はありません。<icon>はパスを格納する単純な文字列の要素です(<icon>icons/q.png</icon>)。<icon path="..."/>ではありません。positionは昇順です。数値が小さいほどメニューの上位に表示されます。コア BM 項目は 2000~12000 の範囲なので、カスタム項目には通常、大きな数値(例:99999)を指定して最下部に配置するか、-1を指定して「Home」アクションを最上部に配置します。- ダイアログアクションの拡張ポイント属性は
xp_ref(アンダースコア)です。また、ダイアログアクションは子要素<menuactions><menuaction-ref action-id="..."/></menuactions>を使ってメニューアクションにリンクします。menuaction-ref属性はありません。 - プラットフォームのサンプルに合わせて、ファイルエンコーディングには
ISO-8859-1を使用します。
権威あるスキーマで詳細を確認するには、次のようにします。
b2c docs schema bmext
ファイル構成
/bm_my_extension
/cartridge
bm_extensions.xml # Extension definitions (required)
bm_my_extension.properties # Cartridge properties (required)
/controllers
MyExtension.js # Controller for menu actions
/templates
/default
/extensions
mypage.isml # Custom BM pages
/static
/default
/icons
my-icon.png # Menu icons
bm_my_extension.properties は標準的なカートリッジマーカーファイルです。
## cartridge.properties for cartridge bm_my_extension
demandware.cartridges.bm_my_extension.multipleLanguageStorefront=true
demandware.cartridges.bm_my_extension.id=bm_my_extension
基本的な bm_extensions.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<extensions xmlns="http://www.demandware.com/xml/bmmodules/2007-12-11"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.demandware.com/xml/bmmodules/2007-12-11 bmext.xsd">
<menuitem id="acme_id01" position="99999" site="false">
<name xml:lang="x-default">ACME Tools</name>
<short_description xml:lang="x-default">ACME admin tools</short_description>
<description xml:lang="x-default">Tools and utilities from the ACME team</description>
<icon>icons/acme.png</icon>
</menuitem>
<menuaction id="acme-home" menupath="acme_id01" position="-1" site="false">
<name xml:lang="x-default">Home</name>
<short_description xml:lang="x-default">ACME Home</short_description>
<exec pipeline="ACME" node="Start"/>
<sub-pipelines>
<pipeline name="ACME-Start"/>
</sub-pipelines>
<icon>icons/acme.png</icon>
</menuaction>
</extensions>
pipeline="ACME" はコントローラー ACME.js に解決され、node="Start" はそのエクスポートされた Start 関数に解決されます(この関数には Start.public = true を設定する必要があります)。
メニュー項目
トップレベルのナビゲーションコンテナーです。site="false" を指定すると項目はAdministrationメニューに配置され、site="true"(デフォルト)を指定するとサイトメニューに配置されます。
<menuitem id="acme_id01" position="99999" site="false">
<name xml:lang="x-default">ACME Tools</name>
<name xml:lang="de">ACME Werkzeuge</name>
<short_description xml:lang="x-default">ACME admin tools</short_description>
<icon>icons/acme.png</icon>
</menuitem>
| 属性 | 必須 | デフォルト | 説明 |
|---|---|---|---|
id | はい | - | 一意の識別子です。コア BM の ID との衝突を避けるため、プレフィックスを付けてください。 |
site | いいえ | true | true = サイトメニュー、false = Administration メニュー |
position | いいえ | - | 並び順です。数値が小さいほど上位に表示されます。最下部に配置するには、大きな値を指定してください。 |
type | いいえ | BM | BM または CSC(Customer Service Center) |
子要素:name(必須、ローカライズ対象)、short_description、description(ローカライズ対象)、icon(文字列のパス)、sldsIconName(SLDS ユーティリティアイコン名。新しい BM UI ではこちらが推奨されます)、exec。
メニューアクション
メニュー項目の下にある機能ページです。それぞれを <exec> 経由でコントローラーノードに接続し、使用するすべてのコントローラーノードを <sub-pipelines> に登録します。
<menuaction id="acme-export" menupath="acme_id01" position="20" site="false">
<name xml:lang="x-default">Product Export</name>
<short_description xml:lang="x-default">Export products to CSV</short_description>
<exec pipeline="ACME" node="Export"/>
<sub-pipelines>
<pipeline name="ACME-Export"/>
<pipeline name="ACME-Download"/>
</sub-pipelines>
<parameters>
<parameter name="defaultFormat" value="csv"/>
</parameters>
<icon>icons/export.png</icon>
</menuaction>
| 属性 | 必須 | デフォルト | 説明 |
|---|---|---|---|
id | はい | - | 一意の識別子 |
menupath | いいえ | - | 親メニュー項目の id(または、紐付け先のコア BM メニュー/項目の id) |
site | いいえ | true | 親メニュー項目と一致する必要があります |
position | いいえ | - | 並び順(数値が小さいほど上位。-1 は最上位に表示されます) |
extern | いいえ | false | true の場合、アクションを新しいウィンドウで開きます |
主な子要素:name(必須)、short_description、description、extended_description、exec、sub-pipelines、parameters、icon。
注:
<exec>が受け取るのはpipelineとnodeのみです(どちらも必須)。https属性はありません。スキーマのapis、scapis、required-features要素は、カスタムメニューアクションではサポートされていません。
NoPermissionCheck の慣用パターン
BM は、要求されたコントローラーノードが sub-pipelines に登録されているメニューアクションに対する権限を、ログイン中のユーザーが持っているか確認します。モジュール権限の確認なしで動作する必要があるエンドポイント(キープアライブの ping、サービスワーカー、ページの JavaScript から呼び出されるポーリング/AJAX エンドポイントなど)は、予約済み ID NoPermissionCheck を持つ専用アクションにノードを登録し、<exec> は指定しないでください。
<menuaction id="NoPermissionCheck" site="false">
<name xml:lang="x-default">Dummy</name>
<short_description xml:lang="x-default">Holds pipelines that do not require a permission check</short_description>
<sub-pipelines>
<pipeline name="ACME-Keepalive"/>
<pipeline name="ACME-ServiceWorker"/>
<pipeline name="ACME-Poll"/>
</sub-pipelines>
</menuaction>
これを行わないと、モジュールへのアクセス権が付与されていないユーザーには、これらのノードが 403 を返します。認証済みの BM ユーザー全員に公開しても安全なノードだけをここに登録してください。
ダイアログアクション
名前付きの拡張ポイント(xp_ref)に、既存の BM ページのボタンを追加します。
<dialogaction id="acme-order-sync" xp_ref="OrderPage-OrderDetails" position="100">
<name xml:lang="x-default">Sync Order</name>
<exec pipeline="ACME" node="OrderSync"/>
<parameters>
<parameter name="OrderNo"/>
</parameters>
<menuactions>
<menuaction-ref action-id="acme-home"/>
</menuactions>
</dialogaction>
| 属性 | 必須 | デフォルト | 説明 |
|---|---|---|---|
id | はい | - | 一意の識別子 |
xp_ref | はい | - | 拡張ポイント ID(アンダースコアに注意) |
position | いいえ | - | 並び順 |
class | いいえ | - | 任意の CSS クラス |
extern | いいえ | false | true の場合、新しいウィンドウで開きます |
子要素:name(任意、ローカライズ可能)、exec(必須)、parameters、menuactions(権限確認を行うメニューアクションを参照する <menuaction-ref action-id="..."/> を1つ以上)。ダイアログアクションには icon 子要素を指定できません。
一般的な拡張ポイント:OrderPage-OrderDetails、ProductPage-General、ProductPage-Images、CustomerPage-Profile、ContentPage-General、CatalogPage-CategoryGeneral。
フォーム拡張
既存の BM 検索フォーム(注文検索や顧客検索など)にフィールドを追加します。
<formextension id="order-search">
<valueinput type="string" name="invoiceNumber">
<label xml:lang="x-default">Invoice Number</label>
<label xml:lang="de">Rechnungsnummer</label>
</valueinput>
<valueinput type="string" name="syncStatus" defaultvalue="">
<label xml:lang="x-default">Sync Status</label>
<option>All</option>
<option>Synced</option>
<option>Pending</option>
<option>Failed</option>
</valueinput>
<valueinput type="int" name="minQuantity">
<label xml:lang="x-default">Minimum Quantity</label>
</valueinput>
</formextension>
id は対象のフォーム(例:order-search、customer-search)と一致させます。valueinput には type(string、int、double のいずれか)と name が必要です。defaultvalue は任意です。各 valueinput にはローカライズされた <label> 子要素と、ドロップダウン用の任意の <option> 子要素を指定できます。
コントローラーの例
コントローラーは controllers/ に配置し、.public = true を設定した関数をエクスポートします。ロジックを共有できるよう */cartridge/... 形式の require を使用し、BM セッションがある場合にのみページノードへのアクセスを許可します。
'use strict';
var ISML = require('dw/template/ISML');
var URLUtils = require('dw/web/URLUtils');
var Logger = require('dw/system/Logger');
var log = Logger.getLogger('bm', 'ACME');
/**
* Render the dashboard. Wired to <exec pipeline="ACME" node="Start"/>.
*/
function Start() {
// BM nodes should only be reachable in an authenticated BM session
if (!session.userAuthenticated) {
response.setStatus(403);
return;
}
ISML.renderTemplate('extensions/acme/dashboard', {
stats: getStats()
});
}
Start.public = true;
module.exports.Start = Start;
/**
* Process an action, then redirect back to the dashboard.
*/
function Process() {
var action = request.httpParameterMap.action.stringValue;
try {
performAction(action);
response.redirect(URLUtils.url('ACME-Start', 'message', 'Done'));
} catch (e) {
log.error('Action failed: {0}', e.message);
response.redirect(URLUtils.url('ACME-Start', 'error', e.message));
}
}
Process.public = true;
module.exports.Process = Process;
/**
* Lightweight endpoint called by page JS — registered under NoPermissionCheck.
*/
function Keepalive() {
response.setContentType('application/json');
response.writer.print('{"ok":true}');
}
Keepalive.public = true;
module.exports.Keepalive = Keepalive;
<exec> または <sub-pipelines> から参照されるすべてのノードは、エクスポートされ、.public = true が設定されている必要があります。そうでない場合、BM は 403 を返します。
テンプレートの例
BM テンプレートは templates/default/extensions/ に配置します。URLUtils.url('Controller-Node', ...) を使って node を参照します。
<isdecorate template="application/MenuFrame">
<isinclude template="inc/Modules"/>
<div class="acme-dashboard">
<h1>ACME Dashboard</h1>
<isif condition="${request.httpParameterMap.message.submitted}">
<div class="success">${request.httpParameterMap.message.stringValue}</div>
</isif>
<table class="data">
<thead><tr><th>Metric</th><th>Value</th></tr></thead>
<tbody>
<isloop items="${pdict.stats}" var="stat">
<tr><td>${stat.label}</td><td>${stat.value}</td></tr>
</isloop>
</tbody>
</table>
<a href="${URLUtils.url('ACME-Process', 'action', 'refresh')}" class="button">
Refresh
</a>
</div>
</isdecorate>
application/MenuFrame でデコレートし(inc/Modules を含めると)、ページに標準の BM クロームが適用されます。完全にカスタムのページにしたい場合は、通常の HTML ドキュメントも使用できます(最新の qlabs 方式では、コンテナーテンプレートにシングルページアプリをマウントします)。
既存の BM メニューへの追加
新しいメニュー項目を追加する代わりに、メニューアクションの menupath をコア BM メニューの ID に設定します。コア ID の一覧はリファレンスにあります。特に便利なものを以下に示します。
| メニュー | id | site |
|---|---|---|
| サイト設定 | site-prefs | true |
| マーチャントツール › 商品とカタログ | prod-cat | true |
| マーチャントツール › 注文 | orders | true |
| 管理 › オペレーション | operations | false |
| 管理 › サイト開発 | studio | false |
| 管理 › グローバル設定 | global-prefs | false |
<menuaction id="acme-pref" menupath="site-prefs" position="2000" site="true">
<name xml:lang="x-default">ACME Preferences</name>
<exec pipeline="ACME" node="Preferences"/>
<sub-pipelines>
<pipeline name="ACME-Preferences"/>
</sub-pipelines>
</menuaction>
独自の
menuitem/menuactionに**コア BM のid**を再利用すると、拡張機能が非表示になります。常に一意の接頭辞付き ID を使い、コア ID はmenupathからのみ参照してください。
拡張機能を有効にする
- カートリッジをBusiness Manager サイトのカートリッジパスに追加します。
- Administration › Sites › Manage Sites › Business Manager › Settings
- カートリッジ ID(例:
bm_my_extension)をカートリッジパスに追加します。
- ロールにモジュールを付与します。
- Administration › Organization › Roles › (role) › Business Manager Modules
- カスタムモジュールを有効にします(拡張機能をパスに追加すると表示されます)。
NoPermissionCheckの下に登録されたノードには、この権限を付与しなくてもアクセスできます。
ベストプラクティス
- 迷ったときは、
b2c docs schema bmextを使って XSD に照らして検証します。 - コア BM の ID と衝突したり、意図せずその背後に隠れたりしないよう、すべての ID に接頭辞を付けます。
- ページで使用するすべてのノードを
sub-pipelinesに登録します。登録しないと 403 エラーになります。 NoPermissionCheckを使うのは、認証済みの BM ユーザーなら誰でも安全にアクセスできるエンドポイント(キープアライブ、サービスワーカー、ポーリングなど)に限ります。- BM カートリッジはストアフロントのカートリッジと分けます。
- ページノードへのアクセスを
session.userAuthenticatedで制御します。 - 管理者以外のロールでテストし、権限の境界を確認します。
詳細リファレンス
- 拡張機能 XML リファレンス — スキーマ、すべての要素/属性、
NoPermissionCheckのパターン、コア BM メニュー ID の完全な一覧を掲載しています。