How to Bulk Update Content Types in Kontent by Kentico

Jun 17, 2022
Kontent by Kentico

Mature projects in any CMS will have a large number of content types. Maintaining those with scripts makes changes to that model more repeatable, but it can be overwhelming if you need to update a lot of types. You can leverage the management API in Kontent by Kentico to update multiple content types in a single script to lessen your workload.

In a recent project, I've used Cloudinary for all media assets and the Cloudinary custom element from the custom element gallery. This has been working for me just fine, but at one point I needed to change the settings for the custom element across the whole project. In this project, we'd added the settings for custom elements each time they were created, so updating my content model with 70 content types was going to take some effort to update.

As we'd been using the Kontent CLI to manage content model changes, each change to the content model results in a new script getting created. When faced with a large update like this, we didn't want to manually script each content type change, so we wrote a script using the Kontent Management API to automate the task.

To script this, we needed to do three things:

  • Identify the content types and elements that need to be changed
  • Prepare the change that we want to be applied
  • Loop through the content type list, updating as we go 

In our project, the change in question affected sixteen content types. Our method of documenting the content model using Mind Map diagrams in Miro meant that we could easily identify the types in question and their elements and codenames. So all we needed was a simple array of content type codenames. 

We captured this data in a simple array with the codenames of the content type and elements respectively as shown below.

const contentTypes = [
  ['comp_homepage_hero', 'image'],
  ['comp_hero_quote', 'image'],
  ['menu_item', 'tile_image'],
  ['comp_image', 'image'],
  ['comp_hero_slim', 'image'],
  ['location_facility', 'icon'],
  ['comp_hero_tile', 'image'],
  ['restaurant', 'tile_image']];

We could have written an additional script to identify the content types that need changing if needed which would mean that the script could be re-run as the content model grows. 

For our update, we were changing the details for our Cloudinary connection. This means that for each content type, we need the following:

const updateData = (codename) => {
  return [
    {
      op: 'replace',
      path: `/elements/codename:${codename}/json_parameters`,
      value: "{\"cloudName\":\"NEW_CLOUD_NAME\",\"apiKey\":\"123451234512345\"}"
    }
  ]
}

The ${codename} will be a parameter that we can pass in to determine the name of the element to update.

Then, we just need to bring it all together by looping through the contentTypes array as follows.

await Promise.all(contentTypes.map(async (type) => {
  await apiClient
    .modifyContentType()
    .byTypeCodename(type[0])
    .withData(updateData(type[1]))
    .toPromise()
  }));

The first time we had this, we did not use await Promise.all(...), which confused me for a while. This is important to ensure that all changes are applied before the script ends. 

Once run, this takes all of the content types in our codename array and modifies them. The basic idea of looping here is simple but often overlooked. To make this more reusable, we added this to a utility file in our project so that we could easily re-run it with other changes, such as adding new content types to the allowed list in linked items.