Skip to main content

b2c-custom-objects

Store and query custom business data using CustomObjectMgr, OCAPI Data API, and Shopper Custom Objects API. Use this skill whenever the user needs to create, read, update, or search custom object instances, build processing queues with status fields, choose between site-scoped and organization-scoped storage, or query custom objects with bool/term filters. Also use when persisting non-standard data -- even if they just say 'store config per site' or 'query my custom data'.

소스 정보

저장소
SalesforceCommerceCloud/b2c-developer-tooling
최근 소스 활동
2026년 7월 31일 13:36
감지된 SKILL.md 언어
영어
스타
54
포크
21

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
3 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
b2c-custom-objects
description
Store and query custom business data using CustomObjectMgr, OCAPI Data API, and Shopper Custom Objects API. Use this skill whenever the user needs to create, read, update, or search custom object instances, build processing queues with status fields, choose between site-scoped and organization-scoped storage, or query custom objects with bool/term filters. Also use when persisting non-standard data -- even if they just say 'store config per site' or 'query my custom data'.
# B2C Custom Objects Custom objects store business data that doesn't fit into standard system objects. They support both site-scoped and organization-scoped (global) data, with full CRUD operations via Script API and OCAPI. ## When to Use Custom Objects | Use Case | Example | |----------|---------| | Business configuration | Store configuration per site or globally | | Integration data | Cache external system responses | | Custom entities | Loyalty tiers, custom promotions, vendor data | | Temporary processing | Job processing queues, import staging | ## Custom Object Types Custom objects are defined in Business Manager under **Administration > Site Development > Custom Object Types**. Each type has: - **ID**: Unique identifier (e.g., `CustomConfig`) - **Key Attribute**: Primary key field for lookups - **Attributes**: Custom attributes for data storage - **Scope**: Site-scoped or organization-scoped (global) ## Script API (CustomObjectMgr) ### Getting Custom Objects ```javascript var CustomObjectMgr = require('dw/object/CustomObjectMgr'); // Get a single custom object by type and key var config = CustomObjectMgr.getCustomObject('CustomConfig', 'myConfigKey'); if (config) { var value = config.custom.configValue; } ``` ### Creating Custom Objects ```javascript var CustomObjectMgr = require('dw/object/CustomObjectMgr'); var Transaction = require('dw/system/Transaction'); Transaction.wrap(function() { // Create new custom object (type, keyValue) var obj = CustomObjectMgr.createCustomObject('CustomConfig', 'newKey'); obj.custom.configValue = 'myValue'; obj.custom.isActive = true; }); ``` ### Querying Custom Objects ```javascript var CustomObjectMgr = require('dw/object/CustomObjectMgr'); // Query with attribute filter var objects = CustomObjectMgr.queryCustomObjects( 'CustomConfig', // Type 'custom.isActive = {0}', // Query (uses positional params) 'creationDate desc', // Sort order true // Parameter value for {0} ); while (objects.hasNext()) { var obj = objects.next(); // Process object } objects.close(); ``` ### Deleting Custom Objects ```javascript var CustomObjectMgr = require('dw/object/CustomObjectMgr'); var Transaction = require('dw/system/Transaction'); Transaction.wrap(function() { var obj = CustomObjectMgr.getCustomObject('CustomConfig', 'keyToDelete'); if (obj) { CustomObjectMgr.remove(obj); } }); ``` ### Getting All Objects of a Type ```javascript var CustomObjectMgr = require('dw/object/CustomObjectMgr'); // Get all objects of a type var allConfigs = CustomObjectMgr.getAllCustomObjects('CustomConfig'); while (allConfigs.hasNext()) { var config = allConfigs.next(); // Process } allConfigs.close(); ``` ## CustomObjectMgr API Reference | Method | Description | |--------|-------------| | `getCustomObject(type, keyValue)` | Get single object by type and key | | `createCustomObject(type, keyValue)` | Create new object (within transaction) | | `remove(object)` | Delete object (within transaction) | | `queryCustomObjects(type, query, sortString, ...args)` | Query with filters | | `getAllCustomObjects(type)` | Get all objects of a type | | `describe(type)` | Get metadata about the custom object type | ## OCAPI Data API ### Get Custom Object ```http GET /s/-/dw/data/v25_6/custom_objects/{object_type}/{key} Authorization: Bearer {token} ``` **Note:** Use `/s/{site_id}/dw/data/v25_6/custom_objects/...` for site-scoped objects, or `/s/-/dw/data/v25_6/custom_objects/...` for organization-scoped (global) objects. ### Create Custom Object ```http PUT /s/-/dw/data/v25_6/custom_objects/{object_type}/{key} Authorization: Bearer {token} Content-Type: application/json { "key_property": "myKey", "c_configValue": "myValue", "c_isActive": true } ``` ### Update Custom Object ```http PATCH /s/-/dw/data/v25_6/custom_objects/{object_type}/{key} Authorization: Bearer {token} Content-Type: application/json { "c_configValue": "updatedValue" } ``` ### Delete Custom Object ```http DELETE /s/-/dw/data/v25_6/custom_objects/{object_type}/{key} Authorization: Bearer {token} ``` ### Search Custom Objects ```http POST /s/-/dw/data/v25_6/custom_objects_search/{object_type} Authorization: Bearer {token} Content-Type: application/json { "query": { "bool_query": { "must": [ { "term_query": { "fields": ["c_isActive"], "operator": "is", "values": [true] } } ] } }, "select": "(**)", "sorts": [{ "field": "creation_date", "sort_order": "desc" }], "start": 0, "count": 25 } ``` ### Search Query Types | Query Type | Description | Example | |------------|-------------|---------| | `term_query` | Exact match / comparison | `{"fields": ["c_status"], "operator": "is", "values": ["active"]}` | | `text_query` | Full-text search | `{"fields": ["c_name"], "search_phrase": "test"}` | | `filtered_query` | Query plus a filter — use with `range_filter` for ranges | `{"query": {"match_all_query": {}}, "filter": {"range_filter":{"field": "c_count", "from": 1, "to": 10}}}` | | `bool_query` | Combine queries | `{"must": [...], "should": [...], "must_not": [...]}` | | `match_all_query` | Match all records | `{}` | ## Shopper Custom Objects API (SCAPI) For read-only access from storefronts, use the Shopper Custom Objects API. This requires specific OAuth scopes. ### Get Custom Object (Shopper) ```http GET https://{shortCode}.api.commercecloud.salesforce.com/custom-object/shopper-custom-objects/v1/organizations/{organizationId}/custom-objects/{objectType}/{key}?siteId={siteId} Authorization: Bearer {shopper_token} ``` ### Required Scopes For the Shopper Custom Objects API, configure these scopes in your SLAS client: - `sfcc.shopper-custom-objects` - Global read access to all custom object types - `sfcc.shopper-custom-objects.{objectType}` - Type-specific read access **Note:** SLAS clients can have a maximum of 20 custom object scopes. The custom object type must also be enabled for shopper access in Business Manager. ### Searchable System Fields All custom objects have these system fields available for OCAPI search queries: - `creation_date` - When the object was created (Date) - `last_modified` - When the object was last modified (Date) - `key_value_string` - String key value - `key_value_integer` - Integer key value - `site_id` - Site identifier (for site-scoped objects) ## Best Practices ### Do - Use transactions for create/update/delete operations - Close query iterators when done (`objects.close()`) - Use meaningful key values for efficient lookups - Index frequently queried attributes - Use site-scoped objects for site-specific data - Use organization-scoped objects for shared configuration ### Don't - Store sensitive data without encryption - Create excessive custom object types - Use custom objects for high-volume transactional data - Forget to handle null returns from `getCustomObject()` - Leave query iterators open (causes resource leaks) ## Common Patterns ### Configuration Store ```javascript var CustomObjectMgr = require('dw/object/CustomObjectMgr'); var Site = require('dw/system/Site'); function getConfig(key, defaultValue) { var configKey = Site.current.ID + '_' + key; var obj = CustomObjectMgr.getCustomObject('SiteConfig', configKey); if (obj && obj.custom.value !== null) { return JSON.parse(obj.custom.value); } return defaultValue; } function setConfig(key, value) { var Transaction = require('dw/system/Transaction'); var configKey = Site.current.ID + '_' + key; Transaction.wrap(function() { var obj = CustomObjectMgr.getCustomObject('SiteConfig', configKey); if (!obj) { obj = CustomObjectMgr.createCustomObject('SiteConfig', configKey); } obj.custom.value = JSON.stringify(value); }); } ``` ### Processing Queue ```javascript var CustomObjectMgr = require('dw/object/CustomObjectMgr'); var Transaction = require('dw/system/Transaction'); // Add to queue function enqueue(data) { var key = 'job_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); Transaction.wrap(function() { var obj = CustomObjectMgr.createCustomObject('JobQueue', key); obj.custom.data = JSON.stringify(data); obj.custom.status = 'pending'; }); } // Process queue function processQueue() { var pending = CustomObjectMgr.queryCustomObjects( 'JobQueue', 'custom.status = {0}', 'creationDate asc', 'pending' ); while (pending.hasNext()) { var job = pending.next(); Transaction.wrap(function() { job.custom.status = 'processing'; }); try { var data = JSON.parse(job.custom.data); processJob(data); Transaction.wrap(function() { CustomObjectMgr.remove(job); }); } catch (e) { Transaction.wrap(function() { job.custom.status = 'failed'; job.custom.error = e.message; }); } } pending.close(); } ``` ## Detailed References - [OCAPI Search Queries](references/OCAPI-SEARCH.md) - Full search query syntax and examples
GitHub에서 보기