
【第585回】Personalization:Sitemap Builder で Resolver を設定する
前回の記事では、Salesforce Personalization の Google Chrome 拡張機能である Sitemap Builder の Page Types を使用して TrailNest の各ページを、
Home
Category
Product Detail
Cart
Checkout
Order Confirmation
として認識できるように設定しました。
Page Type によって、「今表示されているのは何のページなのか」を判定できるようになりましたが、Product Detail を認識できただけでは、まだ、
「どの商品を見ているのか」
「商品の名前は何か」
「価格はいくらなのか」
といった、具体的なデータまでは取得していません。
今回は、それを設定していきます。
Personalization 基礎シリーズ
Sitemap Builder シリーズ
Data 360 設定シリーズ
Personalization 設定シリーズ
Resolver とは
Sitemap Builder の Resolver は、Web ページ上から必要な値を取得するための再利用可能な処理です。
ヘルプドキュメントでは、Resolver を、DOM、URL、Storage、JavaScript Context などから値を取得し、複数の Event や Page Type から 再利用できる小さな関数 として説明しています。
例えば Product Detail に、
<main
id="trailnest-app"
data-product-id="TN-BP-003"
data-product-name="Trail Pro 35L"
data-product-price="139000">という HTML があったとします。
Resolver を使用すると、ここから、
Product ID
→ TN-BP-003Product Name
→ Trail Pro 35LProduct Price
→ 139000
のように必要な値だけを取得できます。
取得した値は、後ほど Product View や Add to Cart などの Event から利用します。
つまり、今回の Sitemap の流れを簡単にすると、
Page Type
→ 「Product Detail が表示されている」と判断Resolver
→ 「表示されている商品は TN-BP-003」と取得Event
→ 「TN-BP-003 が閲覧された」と送信
という関係になります。
Sitemap Builder の Resolver は、Salesforce Interactions SDK が持つデータ取得用の Resolver を、画面上から設定できるようにしたものです。
例えば、CSS Selector (text) を選択すると HTML 要素のテキストを取得し、CSS Selector Attribute を選択すると HTML 要素の指定した属性値を取得します。
Salesforce Interactions SDK には、これらに対応する fromSelector() や fromSelectorAttribute() などの Resolver が用意されており、Sitemap Builder を使用すると、この処理を JavaScript で一から記述せずに設定できます。
Resolvers タブを開く
Sitemap Builder の Resolvers タブを開き、+ Add New Resolver をクリックします。

Resolver の作成画面には、主に次の設定があります。
※ ここは説明だけにして、下のセクションで実際に手を動かします。
① Name
作成する Resolver の名前です。
例えば、
Product ID
Product Name
Product Price
のように、取得する値が分かる名前を設定します。
後ほど Event から Resolver を選択するため、用途が分かりやすい名前にしておくと便利です。
② Kind
Resolver の作成方法を指定します。
今回の画面では、
Built-in
Custom JavaScript
を選択できます。
Built-in では、CSS Selector や URL など、Sitemap Builder が用意している方法を使用して値を取得します。
Custom JavaScript は、Built-in だけでは取得しにくい値を JavaScript で独自に取得したい場合に使用します。
今回は HTML 上に必要なデータを用意してあるため、基本的に Built-in を使用します。
③ Method
どこから、どのような方法で値を取得するのかを指定します。
主に次の方法が用意されています。
CSS Selector (text)
CSS Selector に一致する最初の HTML 要素からテキストを取得CSS Selector Attribute
CSS Selector に一致する最初の HTML 要素から指定した属性を取得CSS Selector (multiple)
一致する複数の HTML 要素からテキストを取得CSS Selector Attribute (multiple)
一致する複数の HTML 要素から指定した属性を取得Current URL (href)
現在表示しているページの URL を取得Meta Tag (name or property)
HTML の Meta Tag から値を取得Window Path
window オブジェクト上に存在する値を取得
などから選択できます。
例えば、
CSS Selector (text) は、HTML 要素の表示テキストを取得します。
<h1 class="product-title">Trail Pro 35L</h1>
であれば、product-title から、Trail Pro 35L を取得するといった使い方です。
一方、CSS Selector Attribute は、HTML 要素に設定されている属性の値を取得します。
例えば、
<main
id="trailnest-app"
data-product-id="TN-BP-003">から data-product-id を取得する、といった使い方です。
今回の TrailNest では data-product-id、data-product-name、data-product-price を用意しているため、この CSS Selector Attribute を多く使用します。
④ Output Type
Built-in Resolver では、取得した値をどのデータ型として扱うか指定します。今回の画面では Text、Number、Boolean、Date から選択できます。
※ Custom JavaScript Resolver では Output Type は指定しません。
例えば
Product ID や Product Name は Text、
Product Price は Number
として取得します。
Tips:HTML から取得した値が文字列であっても、Output Type を Number にすることで数値として扱えるようになります。
⑤ Selector
どの HTML 要素から値を取得するのかを CSS Selector で指定します。
手入力することもできますが、Pick を使用すると、現在表示している Web ページから対象となる要素を選択できます。
⑥ Output
設定した Resolver が、現在の Web ページから実際にどの値を取得できたかを確認する場所です。
Resolver を設定するときは、対象となるページをブラウザで開いた状態にしておくと、取得結果を確認しながら設定できます。
Product ID の Resolver を作成
それでは、最初の Resolver として Product ID を作成します。
まず TrailNest で任意の商品を開き、Product Detail を表示しておきます。
例えば、今回の商品ページには、次のような HTML が存在します。
<main
id="trailnest-app"
data-page-type="product_detail"
data-product-id="TN-BP-003"
data-product-name="Trail Pro 35L"
data-product-price="139000">今回取得したいのは、
data-product-id="TN-BP-003"
の TN-BP-003 です。
Add New Resolver をクリックし、次の内容を設定します。
Name:Product ID
Kind:Built-in
Method:CSS Selector Attribute
Output Type:Text
Selector:#trailnest-app
Attribute:data-product-id

ここで、
Selector:#trailnest-app
は、id="trailnest-app" の HTML 要素を探す という意味です。
さらに、
Attribute:data-product-id
によって、その要素から data-product-id の値を取得します。
Sitemap Builder では、次のような Resolver が生成されます。
resolvers.fromSelectorAttribute('#trailnest-app', 'data-product-id')
fromSelectorAttribute() は、指定した CSS Selector に一致する要素から特定の属性値を取得する Resolver です。
正常に評価されれば、Output には、
TN-BP-001
などが表示されます。

これで、現在 Product Detail に表示されている商品の Product ID を取得する Resolver が完成しました。
Save をクリックして保存します。
Product Name の Resolver を作成
続いて Product Name を取得します。
Product Detail には、
data-product-name="Trail Pro 35L"
という属性も用意しています。
Product ID とほぼ同じ設定で、取得する Attribute だけを変更します。
Name:Product Name
Kind:Built-in
Method:CSS Selector Attribute
Output Type:Text
Selector:#trailnest-app
Attribute:data-product-name
生成される Resolver は、
resolvers.fromSelectorAttribute(
'#trailnest-app',
'data-product-name'
)となります。
Output に、Alpine Daypack 18L などと表示されることを確認します。

問題がなければ Save をクリックします。
Product Price の Resolver を作成
次に Product Price を取得します。
HTML には、
data-product-price="139000"
という値を設定しています。
設定は次のようにします。
Name:Product Price
Kind:Built-in
Method:CSS Selector Attribute
Output Type:Number
Selector:#trailnest-app
Attribute:data-product-price
ここで Product ID や Product Name と異なるのが、Output Type を Number にすることです。
HTML の Attribute から取得した 139000 は、元々文字列として存在していますが、Product Price は後ほど価格として Event に含めるため、Number として扱います。
生成される Resolver は
resolvers.fromSelectorAttribute(
'#trailnest-app',
'data-product-price'
)となり、Sitemap Builder 側で指定した Output Type に従って数値として扱われます。
Output に、79000 などと表示されることを確認して Save します。

なぜ data-* 属性から取得するのか
今回、Product ID はページ上に表示されていないものの、Product Name や Product Price は、実際のページに表示されています。
例えば Product Name なら、画面上の、
<h1>Trail Pro 35L</h1>
のような要素を CSS Selector (text) で取得することも可能です。
それでも今回は、
data-product-name="Trail Pro 35L"
data-product-price="139000"
という Attribute から取得しています。
理由は、Web ページの見た目とデータ取得をなるべく分離するためです。
例えばデザイン変更によって、
h1.product-title
が、
div.product-header > h2
に変更されると、表示部分を直接参照していた Resolver は修正が必要 になる可能性があります。
一方、Sitemap 用に意図して用意した、
#trailnest-app
data-product-id
data-product-name
data-product-price
さえ維持されていれば、画面のレイアウトが変わっても Resolver への影響を抑えられます。
Selector はできるだけシンプルにし、長い子要素の連鎖や nth-child などに依存せず、ID や一意な Class など安定した情報を利用することが推奨されています。
Custom JavaScript を使用する
ここまでの商品情報は、HTML の data-* 属性から値を取得できるため Built-in Resolver を使用しました。
一方、今回の TrailNest では、
固定値を返したい
Form に入力された値を取得したい
Local Storage に保存された Order 情報を取得したい
といったケースもあります。
このような場合は Custom JavaScript Resolver を使用します。
Custom JavaScript Resolver では、最終的に値を返す 関数 を設定します。
例えば、以下のような形です。
() => 1
※ この Resolver が評価されたら、常に 1 を返すの意味です。
Salesforce Interactions SDK の Resolver 自体も、値そのもの(例:1)ではダメで、あとから評価できる Function を返す仕組み になっています。
Product Quantity の Resolver を作成
Add to Cart では、商品 ID や価格だけでなく Quantity も必要になります。
今回の TrailNest では Add to Cart を 1 回クリックしたときに追加する数量を常に 1 とするため、固定値を返す Resolver を作成します。
設定は次の通りです。
Name:Product Quantity
Kind:Custom JavaScript
Custom JavaScript には次を入力します。
() => 1
Output に、「1」 と表示されることを確認して保存します。

非常に単純ですが、このように固定値も Resolver として定義しておくことで、後ほど Add to Cart Event から再利用できます。
Checkout Email の Resolver を作成
続いて、Checkout ページへ移動します。
今回の TrailNest では、Checkout で Email Address を入力します。
HTML には、
<input
id="email"
name="email"
type="email"
required>が存在します。
入力された Email Address を取得する Resolver を作成します。
Name:Checkout Email
Kind:Custom JavaScript
Custom JavaScript には次を設定します。
() => (document.querySelector('#email')?.value || '').trim()
これで Resolver を評価すると、入力した Email Address が Output に表示されます。

この Resolver は、後ほど Contact Point Email を作成するときに使用します。
Checkout Customer ID の Resolver を作成
今回の TrailNest では、より実際の EC サイトに近づけるために Customer ID も入力するようにしています。
※ 本来はログインの手順を踏みますが、今回は入力させるだけです。
HTML には、
<input
id="customerId"
name="customerId"
type="text"
required>があります。
Customer ID は特定の書式には固定していない ため、空欄でなければ任意の ID を入力できます。
例えば、
CUST-000001
TEST-001
123456
などです。
Resolver は次の内容で作成します。
Name:Checkout Customer ID
Kind:Custom JavaScript
() => (document.querySelector('#customerId')?.value || '').trim()
入力した Customer ID が Output に表示されることを確認します。

この値は後ほど Party Identification に使用し、匿名ユーザーの deviceId と既知顧客の Customer ID を関連付けるために利用します。
Order ID の Resolver を作成
次に Purchase Event で使用する Order 情報も Resolver として用意します。
TrailNest では、Place Order を実行すると Order 情報を Local Storage の、
trailnest_last_order
に保存します。
その中には、
{
orderId: "TN-...",
customer: {...},
items: [...],
total: ...
}といった情報が含まれています。
Order ID を取得する Resolver を作成します。
Name:Order ID
Kind:Custom JavaScript
() => {
try {
const order =
JSON.parse(
localStorage.getItem('trailnest_last_order')
);
return order?.orderId || '';
} catch (e) {
return '';
}
}Order Confirmation ページで評価すると「TN-xxxxxxxxxxxxx」のような Order ID が取得できます。

今回 Local Storage を使用するのは、TrailNest が簡易的なデモサイトであり、Checkout で作成した注文情報を Order Confirmation ページへ引き継ぐためです。Salesforce Personalization の実装で Local Storage の利用が必須という意味ではありません。
Order Total の Resolver を作成
同じ Order 情報から注文金額も取得します。
Name:Order Total
Kind:Custom JavaScript
() => {
try {
const order =
JSON.parse(
localStorage.getItem('trailnest_last_order')
);
return Number(order?.total || 0);
} catch (e) {
return 0;
}
}例えば、「188000」のような注文合計金額が取得できます。

この値は Purchase Event の Total Value に使用します。
Order Item 用の Resolver を作成
最後に、Purchase Event で購入商品の明細を取得するための Resolver も作成します。
今回の TrailNest では、Order Confirmation に表示される各商品を、次のような HTML 要素として出力しています。
<div
class="checkout-summary-item"
data-product-id="TN-BP-003"
data-quantity="1"
data-price="79000">画面上の見た目はこれまでと同じですが、Sitemap Builder から商品明細を取得できるよう、
data-product-id
data-quantity
data-price
を持たせています。
後ほど Purchase Event の Line Items Selector に、
.checkout-summary-item
を指定します。
すると Sitemap Builder は、一致したそれぞれの商品要素を $item として Resolver に渡します。
例えば、商品が 3 件ある場合は、
1 件目の .checkout-summary-item
→ $item
2 件目の .checkout-summary-item
→ $item
3 件目の .checkout-summary-item
→ $item
という形で、Resolver が商品ごとに評価されます。
そこで、この $item から Product ID、Quantity、Price を取得する 3 つの Resolver を作成します。
① Order Item Product ID
まず、購入商品の Product ID を取得します。
Name:Order Item Product ID
Kind:Custom JavaScript
Custom JavaScript には、次を設定します。
($item) => $item.attr('data-product-id') || ''
「$item.dataset.productId」は、
data-product-id="TN-BP-003"
の値を取得します。
② Order Item Quantity
続いて、購入数量を取得します。
Name:Order Item Quantity
Kind:Custom JavaScript
($item) => Number($item.attr('data-quantity') || 0)
data-quantity の値を Number として取得します。
③ Order Item Price
最後に、商品の単価を取得します。
Name:Order Item Price
Kind:Custom JavaScript
($item) => Number($item.attr('data-price') || 0)
data-price の値を Number として取得します。
※ ちなみに、$item は Purchase Event の Line Items Mapping から渡されるため、Resolver 単体では実際の値を Preview できません。

これで Purchase Event では、
Line Items Selector
→ .checkout-summary-item
Catalog Object ID
→ Order Item Product ID
Quantity
→ Order Item Quantity
Price
→ Order Item Price
という形で、購入した商品を 1 件ずつ Line Item として取得できるようになります。
なお、今回の TrailNest は検証用サイトのため、Sitemap Builder から取得しやすいように Order Confirmation の HTML に data-* 属性を追加していますが、実際の Web サイトでは、Salesforce Personalization のためだけに HTML を変更できない場合もあります。
その場合は、既存の DOM、dataLayer、JavaScript の state、Local Storage、Commerce 側の注文情報など、サイト上ですでに利用できるデータから Line Items を構成する方法を検討します。
今回作成した Resolver
ここまでで、今回の TrailNest で必要となる基本的な Resolver を用意できました。
商品情報
Product ID
Product Name
Product Price
Product Quantity
Profile 情報
Checkout Email
Checkout Customer ID
Order 情報
Order ID
Order Total
Order Item 情報
Order Item Product ID
Order Item Quantity
Order Item Price
商品ページの data-* 属性から取得できる値には Built-in Resolver を使用し、Form や Local Storage などから取得する値には Custom JavaScript Resolver を使用 しました。
つまり、
DOM の Attribute
→ Built-in Resolver
Form の入力値
→ Custom JavaScript Resolver
Local Storage の Order
→ Custom JavaScript Resolver
という使い分けです。
いかがでしたでしょうか。
次回は Profile Attributes を使用します。
今回取得した、
Checkout Email
Checkout Customer ID
を利用して、
Email Address
→ Contact Point Email
Customer ID
→ Party Identification
として Profile Event に含める方法を確認します。
これによって、匿名状態で取得してきた Web 行動を、後ほど既知顧客へ関連付けるための準備を進めます。
今回は以上です。