Guideline on using Cart Item Metafield to build app feature

This guide provides third-party developers with a comprehensive approach to develop app feature that customized product


Prerequisite

  • Developer Center & Engineer: Set up the metafields definition, configure webhooks, complete testing, and get approved

If you are not familiar with the set up step in Developer Center, please refer to this link.

  • EC Admin Portal & Merchants: Install and subscribe to the app, activate app script, configure metafields values from App metafields definition

Below are the key steps involved

In this section, we will show step by step guide on how to build an App that target for merchants that want to sell custom product. Key steps include:

User flow

Storefront & Shoppers: Input custom information, add products to the cart, and complete the checkout process

Storefront App

Render the storefront app widget, capture custom data, listen to events, handle data processing, and manage order-related tasks.

  1. Rendering the storefront app widget & capturing custom product information on the Product Detail Page (PDP)
  2. Listening to add to cart events and then mapping and adding this custom info to corresponding cart items
  3. Retrieve cart item metafields via SDK and display the app widget with this dynamic information via storefront app extension
  4. Ensuring the data is carried over when the cart items metafields are converted to order items metafields after customer succesfully checkout


Render app widget & capture custom product information @ Product Detail Page

To allow shoppers to input customized information or select customized options for specific products, App developers can create a storefront widget using a Storefront App Extension.

This widget can also add functionality to capture the custom data user inputted and associate it with the product being viewed and added to the cart.

Create Custom Fields in Product Detail Page

  • Add input fields for customized information (e.g., text input, dropdowns, checkboxes) using the storefront app extension
  • Use JavaScript to capture the values entered by the shopper (one of the approach)
<!-- Product Detail Page (PDP) -->
<div id="product-customization-widget">
  <label for="customMessage">Custom Message:</label>
  <input type="text" id="customMessage" name="customMessage" placeholder="Enter your message">
  
  <label for="customOption">Select Option:</label>
  <select id="customOption" name="customOption">
    <option value="option1">Option 1</option>
    <option value="option2">Option 2</option>
  </select>
  
  <button id="addToCartButton">Add to Cart</button>
</div>

Add to cart @ Product Detail page

App developers can use the Storefront SDK to listen to the add to cart event.

📘

More details can refer to Storefront SDK

Cart Update Function

When the user adds a product to the cart, the captured customized data entered in the storefront widget can be transformed and added to the corresponding cart item metafields via the Open API.

[Bulk create app metafield] or [Bulk update app metafield].

Listen to Add to Cart Event:

  • Use storefront SDK to capture the event when the user clicks the "Add to Cart" button
  • Retrieve custom data from session storage or directly from input fields
// Function to retrieve custom data
function retrieveCustomData() {
  // Retrieve custom data from session storage
  var customMessage = sessionStorage.getItem('customMessage');
  var customOption = sessionStorage.getItem('customOption');

  // If session storage is empty, retrieve custom data directly from input fields
  if (!customMessage) {
    customMessage = document.getElementById('customMessage').value;
  }
  if (!customOption) {
    customOption = document.getElementById('customOption').value;
  }

  // Return an object containing the custom data
  return {
    customMessage: customMessage,
    customOption: customOption
  };
}

// Example usage
var customData = retrieveCustomData();
console.log('Custom Message:', customData.customMessage);
console.log('Custom Option:', customData.customOption);

Retrieve cart item metafields and display the app widget @ Cart page

By utilizing cart items metafields, Storefront SDK, and Storefront App Extension, developers can display customized product information entered by the shopper previously (e.g., on the product detail page).

Demo store cap screenDesc
Each cart item in the checkout page has a specific architecture that includes several elements; which display product information, promotions, unit price, qty, etc

3rd party developer now can use "Cart ID, Product ID & Variation ID" to be the unique identifiers for each cart items here.
Retrieve cart items metafields value in checkout page via supported storefront SDK

App utilizes metafields to dynamically assemble the storefront widget & render it in the storefront

Display Custom Information on Cart Page

Retrieve Metafields

  • Use the Storefront SDK to retrieve cart items along with their metafields.
  • Display the custom information in the cart UI.
<!-- Cart Page -->
<div id="cartItemsContainer">
  <!-- Cart items will be dynamically inserted here -->
</div>

<script>
  // Fetch cart items and their metafields
  fetch('https://api.shoplineapp.com/carts/cart_id/items', {
    headers: {
      'Authorization': 'Bearer your_api_token'
    }
  }).then(response => response.json()).then(data => {
    var cartItemsContainer = document.getElementById('cartItemsContainer');
    data.items.forEach(item => {
      var itemHtml = `
        <div class="cart-item">
          <img src="${item.image}" alt="${item.title}">
          <h4>${item.title}</h4>
          <p>Custom Message: ${item.metafields.custom_message}</p>
          <p>Custom Option: ${item.metafields.custom_option}</p>
          <p>Price: ${item.price}</p>
          <p>Quantity: ${item.quantity}</p>
        </div>
      `;
      cartItemsContainer.innerHTML += itemHtml;
    });
  }).catch(error => {
    console.error('Error fetching cart items:', error);
  });
</script>


How to Transform Cart Item Metafield into Order Item Metafield?

As soon as the shopping cart items are checked out, they are immediately converted into order items.

It's important that the Metafields from the cart items are also transferred to the order item Metafields. The following guidelines will cover the best practices for ensuring a smooth transition.

Order Complete

  1. Register and listen to order/create webhook in Developer Portal
    1. For more information of registering webhook, please refer to here
  2. Call Open API Get Order endpoint to get order details when receiving order/createwebhook
  3. Call Open API Get Cart Item App Metafield endpoint to get the Metafield you set for the cart items
  4. Form the cart item resource_id from the Get Order response so as to get the Metafield for each cart item and map each of them to each order item
    1. The resource_id of cart item is formed by cart_id, product_id, and variation_id.
    2. Field Mapping from the Get Order response:
      1. cart_id from cart_attributes.cart_id
      2. product_id from subtotal_items.*.item_id where item_type = "Product"
      3. variation_id from subtotal_items.*.item_variation_key where item_type = "Product"
  5. Get field_value from cart item Metafield to create order item Metafield by calling Bulk Create Order Item Metafield endpoint

Example Response

Following shows the example Get Order and Get Cart Item App Metafield responses

{
    "id": "66501859644e870092a06a81",
    "order_number": "20240524043225577",
    "system_order_number": "20240524043225577",
    "merchant_order_number": null,
    "status": "pending",
    "order_remarks": "",
    ...
    "cart_attributes": {
        "cart_id": "1310719",
        "affiliate_data": {},
        "shop_session_id": ""
    },
    ...
    "subtotal_items": [
        {
            "id": "6650185b644e870092a06a83",
            "item_type": "Product",
            "item_data": {
                "cart_item_id": "2022314",
                "promotion_id": null,
                "parent_item_ids": [],
                "triggering_item_id": "",
                "order_promotion_items": {},
                "custom_discounted_amount": {
                    "cents": 0,
                    "currency_symbol": "HK$",
                    "currency_iso": "HKD",
                    "label": "",
                    "dollars": 0.0
                },
                "custom_discounted_amount_items": []
            },
            "item_id": "64f695ad931347370a5a96a4",
            "item_variation_id": "",
            "item_variation_key": "",
            "item_price": {
                "cents": 20000,
                "currency_symbol": "HK$",
                "currency_iso": "HKD",
                "label": "HK$200.00",
                "dollars": 200.0
            },
            "price": {
                "cents": 20000,
                "currency_symbol": "HK$",
                "currency_iso": "HKD",
                "label": "HK$200.00",
                "dollars": 200.0
            },
            "price_sale": {
                "cents": 0,
                "currency_symbol": "HK$",
                "currency_iso": "HKD",
                "label": "HK$0.00",
                "dollars": 0.0
            },
            "cost": {
                "cents": 0,
                "currency_symbol": "HK$",
                "currency_iso": "HKD",
                "label": "HK$0.00",
                "dollars": 0.0
            },
            "ref_data": null,
            "media": {},
            "product_subscription_id": null,
            "title_translations": {
                "en": "Awesome Proudct"
            },
            "fields_translations": {},
            "sku": "",
            "is_preorder": false,
            "preorder_note_translations": {},
            "quantity": 1,
            "total": {
                "cents": 20000,
                "currency_symbol": "HK$",
                "currency_iso": "HKD",
                "label": "HK$200.00",
                "dollars": 200.0
            },
            "order_discounted_price": null,
            "discounted_price": null,
            "created_by": "admin",
            "object_data": {
                "gender": "unisex",
                "age_group": "all_ages",
                "adult": "no",
                "condition": "new",
                "status": "active",
                "weight": 0.0,
                "barcode_type": "Code 128",
                "max_order_quantity": -1,
                "gtin": "25637906"
            }
        }
    ],
    "updated_at": "2024-05-24T04:35:58.155+00:00",
    "created_at": "2024-05-24T04:32:25.957+00:00",
    ...
}
{
    "items": [
        {
            "id": "665023ef50167f100303b75b",
            "namespace": "65d2d6c049015fec833f7067",
            "key": "imdb_number",
            "field_type": "single_line_text_field",
            "field_value": "abcdefg",
            "metafield_type": "app",
            "resource_id": "1310719-64f695ad931347370a5a96a4",
            "resource_type": "cart_item",
            "merchant_id": "6270db2f9ece2a1f1089d7ac",
            "application_id": "65d2d6c049015fec833f7067",
            "created_at": "2024-05-24T05:21:51.532+00:00",
            "updated_at": "2024-05-24T05:21:51.532+00:00",
        }
    ]
}