---
title: Creating Extensions and Widgets in Oracle Commerce Cloud
description: OCC makes everything easy, and enhancing functionality through customizable extensions and widgets is no exception.
image: https://blog.avenuecode.com/hubfs/jannik-selz-45375-unsplash.jpg
---

[AvenueCode.com](https://avenuecode.com) [News](https://avenuecode.com/news) [Contact](https://avenuecode.com/contact)

[![Avenue Code Snippets Logo](https://blog.avenuecode.com/hubfs/Avenue%20Code%20New%20Logos%20-%202023/AC-Snippets---Black.png)](https://blog.avenuecode.com/?hsLang=en-us) *menu*

- Technology
  
  [Cloud](https://blog.avenuecode.com/blog/topic/cloud?hsLang=en-us) [Delivery Infrastructure](https://blog.avenuecode.com/blog/topic/delivery-infrastructure?hsLang=en-us) [Web Experience](https://blog.avenuecode.com/blog/topic/web-experience?hsLang=en-us) [Agile Mindset](https://blog.avenuecode.com/blog/topic/agile-mindset?hsLang=en-us) [Quality First](https://blog.avenuecode.com/blog/topic/quality-first?hsLang=en-us)
  
  [Design](https://blog.avenuecode.com/blog/topic/design?hsLang=en-us) [Solution Architecture](https://blog.avenuecode.com/blog/topic/solution-architecture?hsLang=en-us) [Data & ML](https://blog.avenuecode.com/blog/topic/data-and-machine-learning?hsLang=en-us) [Mobile Experience](https://blog.avenuecode.com/blog/topic/mobile-experience?hsLang=en-us)
- [Whitepapers](https://blog.avenuecode.com/blog/topic/whitepapers?hsLang=en-us)
- [Spotlight](https://blog.avenuecode.com/blog/topic/spotlight?hsLang=en-us)
- [Extraordinary Women in Tech](https://blog.avenuecode.com/blog/topic/extraordinary-women-in-tech?hsLang=en-us)
- [Avenue Code Culture](https://blog.avenuecode.com/blog/topic/avenue-code-culture?hsLang=en-us)

- [Cloud](https://blog.avenuecode.com/blog/topic/cloud?hsLang=en-us)
- [Design](https://blog.avenuecode.com/blog/topic/design?hsLang=en-us)
- [Delivery Infrastructure](https://blog.avenuecode.com/blog/topic/delivery-infrastructure?hsLang=en-us)
- [Solution Architecture](https://blog.avenuecode.com/blog/topic/solution-architecture?hsLang=en-us)
- [Web Experience](https://blog.avenuecode.com/blog/topic/web-experience?hsLang=en-us)
- [Data & ML](https://blog.avenuecode.com/blog/topic/data-and-machine-learning?hsLang=en-us)
- [Agile Mindset](https://blog.avenuecode.com/blog/topic/agile-mindset?hsLang=en-us)
- [Mobile Experience](https://blog.avenuecode.com/blog/topic/mobile-experience?hsLang=en-us)
- [Quality First](https://blog.avenuecode.com/blog/topic/quality-first?hsLang=en-us)
- [Whitepapers](https://blog.avenuecode.com/blog/topic/whitepapers?hsLang=en-us)
- [Spotlight](https://blog.avenuecode.com/blog/topic/spotlight?hsLang=en-us)
- [Extraordinary Women in Tech](https://blog.avenuecode.com/blog/topic/extraordinary-women-in-tech?hsLang=en-us)
- [Avenue Code Culture](https://blog.avenuecode.com/blog/topic/avenue-code-culture?hsLang=en-us)

# [Creating Extensions and Widgets in Oracle Commerce Cloud](https://blog.avenuecode.com/creating-extensions-and-widgets-in-oracle-commerce-cloud)

- [Tweet](https://twitter.com/share)

*perm\_identity* [Henrique Elias](https://blog.avenuecode.com/creating-extensions-and-widgets-in-oracle-commerce-cloud/author/henrique-elias?hsLang=en-us)

*schedule* 4/25/18 5:00 PM

Oracle Commerce Cloud has gained popularity as an optimal platform solution because it provides all the features needed to build a world-class e-commerce website while also allowing for a high level of customization. Today, we’ll discuss how to customize and enhance functionality in your OCC implementation through extensions.Before we begin our tutorial, let’s review the subcomponents of extensions. Extensions are composed of:

**Widgets**

A widget provides a unit of UI functionality that can be deployed on one or more pages of your web store. Widgets are able to display content to visitors or execute specific functions. They provide custom HTML and/or JavaScript code, as well as, optionally, several other types of auxiliary data for styling, localization, and component re-use.

- **Elements**

- **Stacks**

- **Payment Gateways**

- **Site Settings**

 **JavaScript Modules**

Before we discuss how to create and customize widgets in OCC, we’ll first explain how to create and integrate extensions.

Creating an Extension ID

In order to upload an extension into Commerce Cloud, you must generate an ID for the extension and then use that ID when you define the extension’s metadata. To generate the extension ID:

 Go to “Settings”

- Click on the “Extension” tab
- Click on the “Developer” tab
- Click on the “Generate ID” button, which will allow you to define a name for your widget, as shown below:

![Screen Shot 2018-04-24 at 2.06.39 PM](https://blog.avenuecode.com/hs-fs/hubfs/Screen%20Shot%202018-04-24%20at%202.06.39%20PM.png?width=600&name=Screen%20Shot%202018-04-24%20at%202.06.39%20PM.png)

## Extension Structure

Once you’ve created a unique ID for your extension, you can start to develop it by creating the folder structure. Make sure your extension uses a name that is unique within your Commerce Cloud environment. In other words, do not give your extension the same name as a default widget. Each extension provides metadata describing the author/developer of the extension, as well as other information related to its creation, and this metadata is contained in a manifest file called ext.json, as seen below:

 <extension-name> : The root folder of your extension, must be unique

 ext.json  
 <additional directories to define widgets, elements, payment gateways, site settings>/

 Without the manifest file, the extension cannot be loaded. (See more details at  [ext.json file rules](https://docs.oracle.com/cd/E91846_01/Cloud.12-17/WidgetDev/html/s0204defineextensionmetadatainextjson01.html).)

An example of ext.json is below:

`{  "extensionID": "79f39268-e814-4a2a-9e04-16fd6dc390c2",  "developerID": "987654",  "createdBy": "Henrique Elias",  "version": 1,  "timeCreated": "2018-03-17",  "translations" : [    {      "language" : "en_US",      "name":"WIDGET POC - English",      "description":"Extension description in English"    },    {      "language" : "fr_CA",       "name":"WIDGET POC - French",      "description":" Extension description in French"    }  ] }`

## Uploading Your Extension to Oracle Commerce Cloud

When you have finished developing or changing your extension contents, zip up all the files within your <extension-name> directory. This then becomes the file you upload to Commerce Cloud to make the extension available for use:

Click the “Menu” icon, then click “Settings”

Click “Extensions”

- Click the “Upload Extension” button and select the extension zip file from your local file system

 This tells the system to begin the upload and validation process. Any problems identified during the validation checks are displayed in a warning message. Once uploaded, the file will appear as below. (You may use [this file](https://drive.google.com/file/d/1eex4mHOfCdoI6BXsbUMipK4lca1wCWyp/view), which already includes a widget definition, but remember to update the extension ID in the ext.json file based on the ID generated for you.)

![Screen Shot 2018-04-24 at 2.15.06 PM](https://blog.avenuecode.com/hs-fs/hubfs/Screen%20Shot%202018-04-24%20at%202.15.06%20PM.png?width=600&name=Screen%20Shot%202018-04-24%20at%202.15.06%20PM.png)

## Widget Components

Now that we’ve shown how easy it is to create and upload extensions into OCC, let’s discuss extension subcomponents: widgets. Widgets may be composed of a set of source files and resources, such as:

Templates: display templates for showing content using [knockout.js](http://knockoutjs.com/) data bindings.

- JavaScript: view model per widget (optional).
- CSS: styles for the widget, which can be pure CSS or [Less](http://www.lesscss.org).
- Locale resources: translation resources per locale for the widget.
- Images: images used for the widget, which are referenced via the widget asset mappings.
- Metadata: the metadata that describes the widget.
- Elements: small pieces or fragments of functionality for a widget, including a display template snippet and a view model.
- Configurable widget settings: a mechanism for providing configurable widget settings that the page layout designer can use to customize the widget’s behavior on the Design page; for example, a designer might limit the number of products displayed on a “Related Products” widget.
- Configuration: a default configuration may be delivered with the widget.

## Widget Structure

Widgets are added to an extension’s structure in a /widget directory that is at the same level as the extension’s ext.json file. Each widget should have its own child directory in the /widget directory. The following example shows the directories and files that may be included for a widget:

 

<extension-name> : the root folder of your extension  
    ext.json  
    widget/  
        <widget-name>/  
            widget.json  
            templates/  
                display.template  
            js/  
                <widget-name>.js  
            less  
                widget.less  
            locales/  
                <locale code, for example, en or en\_US>/  
                    ns.<widget-name>.json  
                <other locale codes>/  
                    ns.<widget-name>.json  
            images/

The basic  structure required for a widget to pass validation in an upload is:

<extension-name>  
    ext.json  
    widget/  
        <widget-name>/  
            widget.json

With the exception of global widgets, which we describe in more detail below, all widgets require a template file, titled “display.template,” in the /widget/<widget-type>/templates directory. The template is rendered within the context of the widget and should be written as straight HTML with no surrounding script tag. All knockout bindings and behavior are available in the HTML template code:

**<extension-name> : the root folder of your extension**

    ext.json  
    widget/  
        <widget-name>/  
            widget.json  
            templates/  
                display.template

## Widget.json Metadata File

Much like the ext.json file defines metadata for an extension, a widget.json file defines metadata for a widget. (More details on this are available at [widget.json file rules](https://docs.oracle.com/cd/E91846_01/Cloud.12-17/WidgetDev/html/s0305definewidgetmetadatainwidgetjson01.html).) An example of a widget.json file is provided below:

{  
  "version": 1,  
  "global": false,  
  "javascript": "*widget-name-js*",

  "i18nresources": "*widget-name*",  
  "availableToAllPages": true,  
  "jsEditable": true,  
  "config": {  
  },  
  "translations" : \[  
    {  
      "language": "en",  
      "name": "*Name in English*"  
    },  
    {  
      "language": "de",  
      "name": "*Name in German*"  
    }  
  \]  
}

## Global Widgets and Local Widgets

You may create both global and local widgets. Global widgets are loaded within each page and only need a JS file rather than a template file, whereas local properties apply only to specific instances of widgets. To define a widget as global, set “‘global’ : true” in the widget.json file.

## Widget Page Types

Widgets may be placed in all page types or just specific page types. To make a widget available in all pages, set “‘availableToAllPages’: true” in the widget.json file; otherwise, omit this property and set the “pageTypes” property in the widget file. The available page types are:

- product
- category
- home
- cart
- checkout
- confirmation
- article
- error
- searchResults
- noSearchResults

Note that if the widget is global, you must define the page type and omit the “availableToAllPages” property.

## Global Widgets to Multiple Sites - REST API

By default, global widgets apply to all sites in your Commerce Cloud instance. You may override this default and assign a global widget to be used on only specified sites. To do this, you must issue a POST request using the ‘updateSiteAssociations’ custom action of the widgetDescriptors resource and provide a list of sites in a sites property.

For example, the following request updates myGlobalWidget to execute on siteA and siteB only:

POST /ccadmin/v1/widgetDescriptors/<widget-name>/updateSiteAssociations

{  
  "sites": \["siteA", "siteB"\] // to remove site associations, define as \[\]  
}

## Javascript Code in Widgets

To add JavaScript  code to a widget, you must create a JavaScript file under the <extension-name>/widget/<widget-type>/js directory. The name of the JavaScript file must match the value of the javascript property in the widget.json file, minus the .js extension. The convention is to use the “widget-type” as the JavaScript file name without the .js suffix.

The Javascript file will perform some logic and return an object with extensions to the widget’s view model. The JavaScript file should be in the following format using [RequireJS](http://requirejs.org/docs/api.HTML#defdep.). The module must be defined anonymously. In other words, as shown below, it must not  have a package name defined in the module:

define(  
  // Dependencies  
  \['jquery', 'knockout'\],  
  // Module Implementation  
  function($,ko) {  
     'use strict';  
     var SOME\_CONSTANT = 1024;  
     var privateMethod = function () {  
       // ...  
     };  
     return {  
      // Widget JS available   
      // Some member variables...  
      textInput: ko.observable(),  
      // Some public methods...  
      doSomethingWithInput: function () {  
        //...  
      }  
    }  
});

## Widgets Versioning

Oracle Commerce Cloud allows for multiple versions of a widget. The first version should have the following structure:

**<extension-name>**

**ext.json**

    widget/  
        <widget-name>/  
            widget.json

Subsequent versions should have the following structure:

**<extension-name>**

**ext.json**

 **   widget/  
        v2  
            widget.json**

## Conclusion

In today’s article, we provided a brief introduction to the structures of extensions and widgets and showed how to create and customize them in Oracle Commerce Cloud. OCC makes it easy for e-commerce companies to quickly design a highly stable, functional, and customizable platform for enhanced business operation. At Avenue Code, we’ve built several specialized platforms from scratch, but we’re also adept at helping you quickly adopt [the stable infrastructure and preexisting capabilities of Oracle Commerce Cloud](https://www.avenuecode.com/partners/oracle-implementation-services)while customizing your implementation to accurately represent your brand.

 

Appendix A: Site Settings

An extension can contain [site settings](https://drive.google.com/open?id=1zIt-QgLgq1n339Gfi11cdNDlc3Lv-_tZ), which are configurable parameters that are globally accessible to the storefront code. Site settings are added to the site view model and are available for use by all widgets. Site settings allow you to create a single setting that controls a feature across multiple widgets.  [Site Settings files](https://drive.google.com/open?id=1zIt-QgLgq1n339Gfi11cdNDlc3Lv-_tZ)

A site settings extension creates a custom settings panel in the administration interface after it has been uploaded. This panel allows merchandisers to configure the settings. (To see a site settings panel, go to the “Settings” page and click the name of the site settings extension under “Extension Settings.”)

 Site settings are defined using a JSON-based schema. To add site settings to your storefront, add the following files to your directory structure:

** <extension-name> : extension root directory**

    ext.json  
    config/  
        <settingsID>/ : site settings root directory  
            config.json  
            locales/  
                en\_US.json  
                fr\_FR.json

The resource bundles for site settings are stored in locale files under the /config/locales directory and look similar to the following:

{  
  "resources" : {  
    "enabledHelpText": "Enable the cart message.",  
    "enabledLabel": "Cart Message",  
    "couponHelpText": "Define the coupon name.",  
    "couponLabel": "Coupon",  
    "minSpendHelpText": "Define the minimum spend amount for the coupon.",  
    "minSpendLabel": "Minimum Spend",  
    "sizeHelpText": "The size of the banner.",  
    "sizeLabel": "Banner Size",  
    "sizeSmallLabel": "Small",  
    "sizeMediumLabel": "Medium",  
    "sizeLargeLabel": "Large",  
    "passwordHelpText": "Set the value for API key.",  
    "passwordLabel": "API Key",  
    "title": "Sample Site Settings",  
    "description":"Examples of site settings."  
  }  
}

 The structure of a config.json file looks similar to the following:

{  
  "widgetDescriptorName": "multisiteconfigdemo",  
  "titleResourceId": "title",  
  "descriptionResourceId": "description",  
  "properties": \[  
    {  
      "id": "enabled",  
      "type": "booleanType",  
      "name": "enabled",  
      "helpTextResourceId": "enabledHelpText",  
      "labelResourceId": "enabledLabel",  
      "defaultValue": true  
    },  
    {  
      "id": "coupon",  
      "type": "stringType",  
      "name": "coupon",  
      "helpTextResourceId": "couponHelpText",  
      "labelResourceId": "couponLabel",  
      "defaultValue": "SHIP100",  
      "minLength": 6,  
      "maxLength": 10,  
      "required": true  
    },  
    {  
      "id": "minSpend",  
      "type": "stringType",  
      "name": "minSpend",  
      "helpTextResourceId": "minSpendHelpText",  
      "labelResourceId": "minSpendLabel",  
      "defaultValue": "100",  
      "required": true  
    },  
    {  
      "id": "password",  
      "type": "passwordType",  
      "name": "password",  
      "helpTextResourceId": "passwordHelpText",  
      "labelResourceId": "passwordLabel",  
      "required": true  
    },  
    {  
      "id": "bannerSize",  
      "type": "optionType",  
      "name": "bannerSize",  
      "required": true,  
      "helpTextResourceId": "sizeHelpText",  
      "labelResourceId": "sizeLabel",  
      "defaultValue": "s",  
      "options": \[  
         {  
           "id": "sizeSmall",  
           "value": "s",  
           "labelResourceId": "sizeSmallLabel"  
         },  
         {  
           "id": "sizeMedium",  
           "value": "m",  
           "labelResourceId": "sizeMediumLabel"  
         },  
         {  
           "id": "sizeLarge",  
           "value": "l",  
           "labelResourceId": "sizeLargeLabel"  
         }  
       \]  
    }  
  \]  
}

Once you add a site setting, you will have access to a new section in “Settings,” as shown below:

![Screen Shot 2018-04-24 at 3.09.04 PM](https://blog.avenuecode.com/hs-fs/hubfs/Screen%20Shot%202018-04-24%20at%203.09.04%20PM.png?width=600&name=Screen%20Shot%202018-04-24%20at%203.09.04%20PM.png)

The titleResourceId property specifies a key in the resource bundles that is used to retrieve the title for the panel in the administration interface, e.g. “Sample Site Settings” in the illustration above. The descriptionResourceId property specifies a key for the descriptive text that appears below the title. In the illustration above, this appears as “Examples of site settings.”

 The remainder of the config.json file consists of a properties array that defines individual site settings and their key/value pairs. Site settings use the same standard keys as configurable widget settings: **id, name, type, helpTextResourceId, labelResourceId, defaultValue, and required**. Site settings can also use the same data types that are available to configurable widget settings, e.g. stringType, multiSelectOptionType, and so on.

Site settings can be configured on a site-by-site basis. If your Commerce Cloud instance is running multiple sites, the values a merchandiser specifies in a settings panel apply only to the currently selected site. The merchandiser can then select another site and supply it with different values.

 In some cases, a site settings panel may have settings that make sense for certain sites but not for others. In this situation, you can give merchandisers the option of disabling a site settings panel completely for individual sites. To do this, include the following in the config.json file of the extension that creates the panel:

"enableSiteSpecific": true

## Appendix B: Reducing the Size of Page Responses

The first time a page loads in Commerce Cloud, the server returns all of the data associated with the specified page layout, including the widget template source, element source, and so on. On subsequent page loads, it is possible to limit the returned data to only those widgets that have not been previously rendered. This feature is not enabled out of the box because you should understand the trade-offs involved before using it.

 When this feature is disabled, all of the data for the page is returned and cached for every page call, giving you the performance improvements associated with caching. When the feature is enabled, the system tracks the URLs that have been visited to determine which widgets have not been previously rendered and then limits the returned data to those widgets. Caching all of these URLs is not feasible, however, so caching is turned off when this feature is enabled. Instead, the performance improvements that are gained are driven by the drastically reduced amount of data that is returned from the server. This approach is especially beneficial on mobile devices.

 To enable this feature, you must create an extension that uploads an application-level JavaScript module that depends on the cc-store-configuration-1.0.js library and sets the enableLayoutsRenderedForLayout flag to “true.”

 In addition to enabling the feature, you may also choose to override the storeLayoutIdsRendered() and getLayoutIdsRendered() methods:

 The storeLayoutIdsRendered() method stores IDs for the layouts visited by the shopper until the page is refreshed or the browser is closed. The stored layout IDs let the server know which pages have been cached so it can limit the returned data to new widgets. The number of IDs that the storeLayoutIdsRendered() method stores is determined by the size of the layoutsRenderedArraySize object and is set to 15 out of the box.

You can also choose to override the storeLayoutIdsRendered() method for other purposes, e.g. so that layout IDs are only stored when the store is accessed on a mobile device.

- The getLayoutIdsRendered() method returns the stored layout IDs to the server. You can modify this method so that it ignores certain layouts, effectively disabling the feature for those pages:

** define(**

//-------------------------------------------------------------------  
  // DEPENDENCIES  //-------------------------------------------------------------------  
  \['ccStoreConfiguration'\],  
//-------------------------------------------------------------------  
  // Module definition  
//-------------------------------------------------------------------  
  function(CCStoreConfiguration) {  
    "use strict";  
    return {  
      storeConfiguration: CCStoreConfiguration.getInstance(),  
      enableLayoutsRenderedFeature: function() {  
        storeConfiguration.prototype.enableLayoutsRenderedForLayout = true;  
      }  
    };  
}); 

---

[![LinkedIn Icon](https://blog.avenuecode.com/hubfs/Images/Blog/linkedin.png)](https://www.linkedin.com/in/hcbelias/)

### Author

# Henrique Elias

 Henrique Elias is a Senior Fullstack Developer at Avenue Code.

### Leave a Comment!

### Avenue Code Social

[![Facebook Icon](https://blog.avenuecode.com/hubfs/Images/Blog/facebook.png?t=1486470796564)](https://www.facebook.com/avenuecode)

[![Twitter Icon](https://blog.avenuecode.com/hubfs/Images/Blog/twitter.png?t=1486470796842)](https://twitter.com/AvenueCode)

[![LinkedIn Icon](https://blog.avenuecode.com/hubfs/Images/Blog/linkedin.png?t=1486470796556)](https://www.linkedin.com/company/avenue-code)

### Newsletter

Want to stay on top of all tips and news from Avenue Code?

### Popular Snippets

![Primary Logo AvenueCode Inverted.png](https://blog.avenuecode.com/hs-fs/hubfs/Images/Logos/Primary%20Logo%20AvenueCode%20Inverted.png?width=1104&name=Primary%20Logo%20AvenueCode%20Inverted.png "Primary Logo AvenueCode Inverted.png")

### About Us

- [Who We Are](https://www.avenuecode.com/who-we-are)
- [What We Do](https://www.avenuecode.com/what-we-do)
- [Portfolio](https://www.avenuecode.com/portfolio)
- [Partners](https://www.avenuecode.com/partners)
- [News](https://www.avenuecode.com/news)
- [Events](https://www.avenuecode.com/events)
- [Blog](https://blog.avenuecode.com/)
- [Contact](https://www.avenuecode.com/contact)

### Our Offices

San Francisco

[+1 415 766 4178](tel:+553125161448) [ac.inquiries@avenuecode.com](mailto:brazil.info@avenuecode.com)

Belo Horizonte

[+55 31 2516 1448](tel:+553125161448) [brazil.info@avenuecode.com](mailto:brazil.info@avenuecode.com)

São Paulo

[+55 11 3205 3232](tel:+553125161448) [brazil.info@avenuecode.com](mailto:brazil.info@avenuecode.com)

### We're Hiring!

- [Belo Horizonte](https://www.avenuecode.com/who-we-are)
- [New York](https://www.avenuecode.com/what-we-do)
- [San Francisco](https://www.avenuecode.com/portfolio)
- [São Paulo](https://www.avenuecode.com/partners)

---

©2015 - 2017 Avenue Code

[![Facebook Icon](https://blog.avenuecode.com/hubfs/Images/Icons/facebook-2.png)](https://www.facebook.com/avenuecode) [![Twitter Icon](https://blog.avenuecode.com/hubfs/Images/Icons/twitter-2.png)](https://twitter.com/AvenueCode) [![LinkedIn Icon](https://blog.avenuecode.com/hubfs/Images/Icons/linkedin-2.png)](https://www.linkedin.com/company/avenue-code) [![Glassdoor Icon](https://blog.avenuecode.com/hubfs/Images/Icons/glassdoor-icon-1.png)](https://www.glassdoor.com/Overview/Working-at-Avenue-Code-EI_IE456173.11,22.htm) [![YouTube Icon](https://blog.avenuecode.com/hubfs/Images/Icons/youtube-2.png)](https://www.youtube.com/user/AvenueCodePlay)

Please enable JavaScript to view the [comments powered by Disqus.](http://disqus.com/?ref_noscript)

© 2026 Avenue Code

```json
{
  "@context" : "https://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "Henrique Elias",
    "url" : "https://blog.avenuecode.com/author/henrique-elias"
  },
  "datePublished" : "2018-04-25T20:00:00.000Z",
  "headline" : "Creating Extensions and Widgets in Oracle Commerce Cloud",
  "image" : [ "https://blog.avenuecode.com/hubfs/jannik-selz-45375-unsplash.jpg" ],
  "mainEntityOfPage" : {
    "@id" : "https://blog.avenuecode.com/creating-extensions-and-widgets-in-oracle-commerce-cloud",
    "@type" : "WebPage"
  },
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "url" : "https://blog.avenuecode.com/hubfs/Avenue%20Code%20New%20Logos%20-%202023/Avenue%20Code-primary%20versions_LOGO%20HORIZONTAL%20group%201-7.png"
    },
    "name" : "Avenue Code"
  }
}
```