App Widget in Storefront

Once the merchant has inserted the app widget into their page, the app widget will be rendered in the following way:

  • Each inserted app widget will have a section div in storefront:

  • The section div will contain the following elements:

  1. Script element with the merchant's app widget settings in JSON format
  2. HTML element

Example:

<!-- custom tag name  -->
<section-component>Awesome HTML</section-component>

Output example:

<div id="shopline-section-{section_id}" class="shopline-section">
  
  <!--  Merchant settings JSON -->
	<script type="text/json" data-app-widget-type="app-widget_{appId}_{widget_identifier}">
    {"id": "xxx", "settings": {}, "blocks": []}
  </script>

  <!-- Optional App Widget HTML -->
  <section-component>Awesome HTML</section-component>

</div>

Merchant Settings JSON

The merchant settings configured in SHOP Builder will be rendered in the storefront as JSON object in a script tag.

The script tag will contain the attribute data-app-widget-type with the value constructed in this format:

app-widget_{app_identifier}_{widget_identifier}

  • app_identifier is {app_ID} for Release version, and {app_ID}_TESTING for Development version
  • {widget_identifier} will be the App Widget name set in the Developer Portal (See here for more details).

The JSON data contains the following attributes:

  • id (string): The section id, where you can use it to get the section div
  • settings(object): The settings merchant set in SHOP Builder
  • blocks(array of objects): The block settings merchant set in SHOP Builder

You can use the following example JS code to get the corresponding section div & settings data for every section of your app widget:

class SectionComponent extends HTMLElement {
  constructor() {
    super();
    // To get section container dom
    this.$sectionContainer = this.closest('[id^="shopline-section-"]');
    // To get section data script
    // Please replace {widgetType}
    var $script = this.$sectionContainer.querySelector('script[data-app-widget-type*="{widgetType}"]');
    var scriptContent = $script.innerHTML;
    // To get section data
    this.sectionData = JSON.parse(scriptContent);

    // do something ...
  }
};
// Binding web component
// Please replace the first parameter with your custom tag name
customElements.define('section-component', SectionComponent);

The example is just for reference. You can also get data through JS script according to the rules.


Settings Format

Every setting will have the setting ID as the key, and the corresponding setting as the value.

The setting ID is the ID you defined for your setting in the schema. For example, if your schema is the following:

{
  ...,
  "settings": [
    {
      "id": "setting-id",
      "type": "text"
    }
  ]
}

The setting ID will be the setting-id.

The value format varies on the setting type used. For example, if the setting type is range, the setting value will be an integer. If the setting type is product_picker, the setting value will be an object containing the product attributes.

The full list of setting types format can be found here, in the Return section of each setting type.


__original Field

For specific setting types, besides the setting field, there will be also an {setting_id}__original field.

For example, for product_picker setting type, the setting JSON is like this:

{
  "settings": [
    {
      "product-picker-setting-id": {
        "id": "67279e000000000000000000",
        ...
      },
      "product-picker-setting-id__original": "67279e000000000000000000"
    }
  ]
}

The __original field allows you to distinguish between the case where merchant haven't selected any resources, and the case where the resource is already unpublished / deleted.

For example, for product_picker type, you can use the following logic to distinguish and handle different cases:

// Pseudo code only

if product == null &&  product___original != null {
  // Product is unpublished / deleted
  // Maybe display placeholder
  ...
} else if product == null {
  // No product has been chosen
  // Maybe hide the widget
  ...
} else  {
  // display widget as usual
  ...
}

Below is the behavior of every special setting type under different scenarios:

Setting TypeNormal CaseResource Not
Selected by Merchant
Resource Unpublished /
Deleted
product_pickerproduct: Object of product attributes
product__original: String (product ID)
product: null
product__original: null
product: null
product__original: String (product ID)
products_pickerproducts: Product[]
products__original: String[] (product IDs)
products: []
products__original: []
products: []
products__original: String[] (product IDs)
collection_pickercategory: Object of category attributes
category__original: String (category ID)
category: null
category__original: null
category: null
category__original: String (category ID)
image_picker
(with is_multi_lang: true)
image: Object of image URLs
image__original: Object of image URLs in different locales
(key: locale, value: Object of image URLs)
image: null
image__original: {[locale_key]: {}}
(e.g. {en: {}, ...})
/
image_picker
(with is_multi_lang: false)
image: Object of image URLs
image__original: Object of image URLs
image: null
image__original: {}
/

Image URLs

We have provided two image URLs, one for 800x, and one for 1200x in advance for images type resources (i.e. image from image_picker type, and the product image in product).

{
  "settings": {
    "image": {
      "url": {
        "800x": "https://shoplineimg.com/629446751ffcc7000750101f/5d1c83fe9fc3a000263a58e9/800x.webp?source_format=jpg",
        "1200x": "https://shoplineimg.com/629446751ffcc7000750101f/5d1c83fe9fc3a000263a58e9/1200x.webp?source_format=jpg"
      }
    }
  }
}

In case you need a different resolution of the image, you can replace the 800x part with the resolution you want.

i.e. If the URL for 800x is https://shoplineimg.com/629446751ffcc7000750101f/5d1c83fe9fc3a000263a58e9/800x.webp?source_format=jpg, the URL for 1500x will be https://shoplineimg.com/629446751ffcc7000750101f/5d1c83fe9fc3a000263a58e9/1500x.webp?source_format=jpg.

Please note that we do not recommend using very high resolution of images, as it may impact storefront performance.


Product

For product_picker / products_picker type, the info of the selected product(s) will be included in the JSON data in SHOP. For every product, they will have the following attribute:

AttributeTypeDescription
idStringProduct ID
skuStringProduct SKU
titleStringProduct Title
imageImageThe first product image
(See above for Image format)
urlStringThe relative URL of the product
priceStringPrice of the product (with currency)
availableBooleanReturns true if a product is available for purchase.
Returns false if all of the products variants' inventory quantity values are zero or less, and they are not set to "unlimited quantity"

Example code:

{
  "id": "62946cf094ba250001d4dc37",
  "sku": "",
  "title": "Example Product",
  "image": {
    "url": {
      "800x": "https://shoplineimg.com/629446751ffcc7000750101f/5d1c83fe9fc3a000263a58e9/800x.webp?source_format=jpg",
      "1200x": "https://shoplineimg.com/629446751ffcc7000750101f/5d1c83fe9fc3a000263a58e9/1200x.webp?source_format=jpg"
    }
  },
  "url": "https://example-handle.shoplineapp.com/products/example-product",
  "price": "HK$60.00",
  "available": false
}

Category

For collection_picker type, the info of the selected category will be included in the JSON data in SHOP. Every category will have the following attribute:

AttributeTypeDescription
idStringCategory ID
titleStringCategory Title
urlStringURL of the category
productsArray of ProductList of products in this category
(See above for the Product format)

Example code:

{
  "id": "6294467829a34600181c3696",
  "title": "Featured Products",
  "url": "https://bookstore846.shoplineapp.com/categories/6294467829a34600181c3696?draft=true&amp;amp;debug=true&amp;draft=true&amp;debug=true",
  "products": [
    {
      "id": "62946cf094ba250001d4dc37",
      "sku": "",
      "title": "Example Product",
      "image": {
        "url": {
          "800x": "https://shoplineimg.com/629446751ffcc7000750101f/5d1c83fe9fc3a000263a58e9/800x.webp?source_format=jpg",
          "1200x": "https://shoplineimg.com/629446751ffcc7000750101f/5d1c83fe9fc3a000263a58e9/1200x.webp?source_format=jpg"
        }
      },
      "url": "https://example-handle.shoplineapp.com/products/example-product",
      "price": "HK$60.00",
      "available": false
    }
  ]
}