Using the Umbraco Content Delivery API with Sitecore XM Cloud Components

Sometimes clients run multiple websites on Umbraco and Sitecore because they had different requirements. It would be convenient if these websites could collaborate more efficiently. For instance, by using the same identity provider. It would also be useful if they could share content. Coincidentally, Umbraco recently introduced the Content Delivery API to export content, and with Sitecore XM Cloud Components you can use an external data source. In this blog, I will explain step by step how content can be reused in Umbraco and Sitecore.

Umbraco blog post

For this example, we use a simple Blog post Document Type. It has a Name, Description, and Image property.

This is what the Blog post 1 content item looks like.

Umbraco Content Delivery API

When we use the Content Delivery API, this is the standard output for Blog post 1.

{
    "name": "Blog post 1",
    "createDate": "2023-08-18T14:09:36.08",
    "updateDate": "2023-08-25T13:08:14.697",
    "route": {
        "path": "/blog-post-1/",
        "startItem": {
            "id": "56eea511-05d8-48fc-abda-c7643441530e",
            "path": "blog-overview"
        }
    },
    "id": "2a25d2d6-21d3-4db5-808f-cdd56640995f",
    "contentType": "blogPost",
    "properties": {
        "blogName": "Blog post 1",
        "description": "This is description 1",
        "image": [
            {
                "id": "98ce9dd4-1f0e-4d70-b8ce-9e737406c959",
                "name": "Umbraco",
                "mediaType": "Image",
                "url": "/media/0kon3gao/umbraco.png",
                "extension": "png",
                "width": 1024,
                "height": 576,
                "bytes": 40057,
                "properties": {},
                "focalPoint": null,
                "crops": []
            }
        ]
    },
    "cultures": {}
}

There are 2 issues with this JSON. Only one image can be selected in our Document Type, yet we get an array in return. And the path is also relative. Fortunately, both can be adjusted in Umbraco. First, I replace the MediaPickerWithCropsValueConverter with the CustomMediaPickerWithCropsValueConverter. This is a copy of the original with several internal classes copied as well. The only difference is the following adjustment:

if (isMultiple == false && converted is MediaWithCrops mediaWithCrops)
{
    return new [] { ToApiMedia(mediaWithCrops) };
}

This is replaced by this:

if (isMultiple == false && converted is MediaWithCrops mediaWithCrops)
{
    return ToApiMedia(mediaWithCrops);
}

Because of this, no array is returned anymore. Umbraco intentionally chose to always return an array, even for one item, so the API does not get a breaking change if Pick multiple items at the Data Type were to change. I understand the choice, but for Sitecore XM Cloud Components, it's better not to get an array.

Secondly, I replace the IApiMediaUrlProvider with the CustomApiMediaUrlProvider. This, too, is a copy of the original. The only difference is the following adjustment:

return _publishedUrlProvider.GetMediaUrl(media, UrlMode.Relative);

This is replaced by this:

return _publishedUrlProvider.GetMediaUrl(media, UrlMode.Absolute);

This way, we always get an absolute URL in return.

The resulting JSON looks like this:

{
    "name": "Blog post 1",
    "createDate": "2023-08-18T14:09:36.08Z",
    "updateDate": "2023-08-25T13:08:14.697Z",
    "route": {
        "path": "/blog-post-1/",
        "startItem": {
            "id": "56eea511-05d8-48fc-abda-c7643441530e",
            "path": "blog-overview"
        }
    },
    "id": "2a25d2d6-21d3-4db5-808f-cdd56640995f",
    "contentType": "blogPost",
    "properties": {
        "blogName": "Blog post 1",
        "description": "This is description 1",
        "image": {
            "id": "98ce9dd4-1f0e-4d70-b8ce-9e737406c959",
            "name": "Umbraco",
            "mediaType": "Image",
            "url": "https://content-website.euwest01.umbraco.io/media/0kon3gao/umbraco.png",
            "extension": "png",
            "width": 1024,
            "height": 576,
            "bytes": 40057,
            "properties": {},
            "focalPoint": null,
            "crops": []
        }
    },
    "cultures": {}
}

You can view all the necessary adjustments in this Gist. This project runs on Umbraco Cloud, so with the following URL, the JSON is available everywhere: https://content-website.euwest01.umbraco.io/umbraco/delivery/api/v1/content?filter=contentType%3AblogPost.

Sitecore XM Cloud Components data sources

Now that the Umbraco content is available as JSON, we can link it to a data source in XM Cloud Components. After clicking on Add data source, I chose Blog content for Name. Then, under Sample data, select Fetch from URL, and under Retrieve data, provide the URL where the JSON is located. When we then click on Fetch, the JSON is fetched, and under Data tree root, we can select which array to iterate over. In this case, I selected items. The data source is now ready to be used within the Components builder.

Sitecore XM Cloud Components builder

I created a new component and added a card to it. On the card's right panel, I clicked on Data scope, then Data collection. There I selected Mapped and chose Blog content for Data source. Since there are 3 items in the JSON, the card is immediately shown 3 times.

Next, I added 3 elements to the card: a Heading 1, Paragraph, and Image element. For Image, I selected the Image Source. There I again chose Mapped and Blog content for Data source. The entire Data path then appeared, and I could select anything that wasn't an array since we already iterate over the items via the card. By selecting the url here, the image was displayed. For the Heading 1 and Paragraph I did the same thing.

Conclusion

As you can see from the image above, the content from Umbraco is displayed within a Sitecore XM Cloud Component. This component is now easy to use within XM Cloud but can also be embedded on other websites. This way, the content can be reused in different locations.