How to Add default values to Contentful fields

by: Philip Howley

Contentful default value fields

Our Iron Cove website is a Gatsby JS using a headless CMS (Contentful). Recently the dev and marketing teams have put in an enormous effort to boost SEO. We modernized our site and added Structured data.

What is Structured data?

"Structured data is a standardized format to mark up the information about the web page. It serves to search engines like Google, Bing, and others to better understand what the web page is about. ... Search engines may use structured data in the so-called rich snippets, to visually improve the user experience." source

SEO tools

  • We use the Screaming Frog SEO Spider Tool to analyze all of our pages and find the weak pages and create strategies to make them stronger. A lot goes into "good SEO" and we are working very hard to get the biggest bang for our buck.
  • A member of our marketing team suggested to boost our website's blog pages we should add a field for the author of the blog and an area to link to that author's choice of Social Media.

Add a Default Value

  • Adding a couple of default fields to Contentful seemed like a trivial task, but it turned out to take some time. This blog showcases how we added these fields in case anyone needs to do something similar for their sites.

We love Contentful at Iron Cove. It is user friendly and relatively straight forward to update. We have a "Space" in Contentful, and that is where we host the content for our site. We create "types" like Blog, Case Study, and Technology to develop different types of content. In each of these types, we create fields that will hold our pieces of content for that specific Type. Examples of this would be a slug or a title. To add a field, you create it in that Type, choose some pre-set settings, and presto! You

Graphql

We then pull that data down using Graphql and tie it to specific locations in the React components housed inside our Gatsby framework.

A road less traveled

We didn't want to make these two fields required because that would slow down the production of our blogs. Our writers dislike having too many required fields as all fields are required. We just wanted to provide default values for both fields so that if the writer didn't fill in the fields, the default values would be used instead.

How do you add default fields in Contentful?

Out of the box, Contentful doesn't have a default field solution. It may seem surprising, but there is a good reason. Contentful created a slightly more sophisticated way to add a field that has default values to enable the developers to develop the fields they need.

Command Line Tools

  • Lots of this flexibility can be harnessed from the command line
  • Extensions are built and managed with a Contentful Space through the Contentful Management APIs extension endpoint. To make this as convenient as possible, the Create Content Extension CLI supports managing extensions.

Custom Extensions

  • Contenful has a handy github repo to see examples of custom extensions
  • We searched this repo and found an example for a default field - default field which is exactly what we needed!

Two required files

  • To build this, you need two required files:

  • extension.html (contains the markup code and logi)

  • extension.json (describes the properties of an extension)

A peek at the code

  • To give you an idea of these two files:

extension.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <link rel="stylesheet" href="https://contentful.github.io/ui-extensions-sdk/cf-extension.css">
  <script src="https://unpkg.com/contentful-ui-extensions-sdk@3"></script>
</head>
<body>
  <div class="cf-form-field">
    <input type="text" class="cf-form-input">
    <div class="cf-form-hint">I am a UI Extension with a default value:
      <span class="default-value"></span>
    </div>
  </div>
  <script>
    'use strict';
    window.contentfulExtension.init(function (extension) {

      extension.window.startAutoResizer();

      var inputEl = document.querySelector('.cf-form-input');
      inputEl.value = extension.field.getValue() || '';

      var detachValueChangeHandler = extension.field.onValueChanged(valueChangeHandler);

      inputEl.addEventListener('input', keyboardInputHandler);
      window.addEventListener('onbeforeunload', unloadHandler);

      var defaultColor = extension.parameters.instance.defaultColor;
      var defaultColorText = document.createTextNode(defaultColor || 'none');
      document.querySelector('.default-value').appendChild(defaultColorText);

      var isNewlyCreated = extension.entry.getSys().version < 2;
      var hasNoValue = typeof extension.field.getValue() === 'undefined';

      if (isNewlyCreated && hasNoValue) {
        extension.field.setValue(defaultColor || '');
      }

      function valueChangeHandler(value) {
        value = value || '';

        if (value !== inputEl.value) {
          inputEl.value = value;
        }

        if (/^#([a-f0-9]{3}){1,2}$/i.test(value)) {
          extension.field.setInvalid(false);
          document.querySelector(".cf-form-field").style.borderLeft = "5px solid " + value;
        } else {
          extension.field.setInvalid(true);
          document.querySelector(".cf-form-field").style.borderLeft = "0";
        }
      }

      function keyboardInputHandler() {
        var value = inputEl.value;

        if (typeof value === 'string' && value.length > 0) {
          extension.field.setValue(value);
        } else {
          extension.field.removeValue();
          inputEl.value = '';
        }
      }

      function unloadHandler() {
        window.removeEventListener('onbeforeunload', unloadHandler);
        inputEl.removeEventListener('input', keyboardInputHandler);
        detachValueChangeHandler();
      }
    });
  </script>
</body>
</html>

extension.json

{
  "id": "default-field-value",
  "name": "Default value for a field",
  "srcdoc": "extension.html",
  "fieldTypes": ["Symbol"],
  "parameters": {
    "instance": [
      {
        "id": "defaultColor",
        "name": "Default color",
        "description": "Set which color is the default color",
        "type": "Enum",
        "options": [{"#0000FF": "blue"}, {"#FFFF00": "yellow"}, {"#FF0000": "red"}],
        "labels": {"empty": "Choose a color"},
        "required": true
      }
    ]
  }
}

Hosting this code

  • You can self host this code or if it isn't too large, you can host it on Contenful, we chose the latter option

Extending the Content web app

You need to install the contentful CLI

$ npm install -g contentful-cli

Authenticate yourself

When you are using the Terminal, and you're trying to push files up to Contentful's server, you need to let them know who you are by providing your Space id and Contentful Management Access Token (you can grab both from your Contentful Admin dashboard)

The extension.html file is going to create a form in your Contentful dashboard with your custom default field UI extension. We just converted the color swatch picker for a default author picker. You provide the unique values for this UI custom component via the extension.json file

Using JavaScript and the DOM you make sure you name the form fields properly and associate them with the values in the extension.json file

Log into Contentful CLI via the terminal

Once logged in you can add your 2 files to Contentful with:

$ contentful extension create --space-id $SPACE

And if you make changes and want to push your updates up to Contentful use:

$ contentful extension update --space-id $SPACE --force

Connect to your type

  • Once you deploy these files to Contentful you can then see the new custom UI component under your Contentful's dashboard's Extensions section.
  • note You need to open a type, create a new field. We used a text field and in the options for the field, we selected the default Author field. Once that was added we could select what we wanted for the default value.

extensions

  • Here's the code we changed to make this work

extension.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <link
      rel="stylesheet"
      href="https://contentful.github.io/ui-extensions-sdk/cf-extension.css"
    />
    <script src="https://unpkg.com/contentful-ui-extensions-sdk@3"></script>
  </head>
  <body>
    <div class="cf-form-field">
      <input type="text" class="cf-form-input" />
      <div class="cf-form-hint">
        I am a UI Extension with a default value:
        <span class="default-value"></span>
      </div>
    </div>
    <script>
      'use strict';
      window.contentfulExtension.init(function(extension) {
        extension.window.startAutoResizer();

        var inputEl = document.querySelector('.cf-form-input');
        inputEl.value = extension.field.getValue() || '';

        var detachValueChangeHandler = extension.field.onValueChanged(
          valueChangeHandler
        );

        inputEl.addEventListener('input', keyboardInputHandler);
        window.addEventListener('onbeforeunload', unloadHandler);

        var defaultAuthor = extension.parameters.instance.defaultAuthor;
        var defaultAuthorText = document.createTextNode(
          defaultAuthor || 'none'
        );
        document.querySelector('.default-value').appendChild(defaultAuthorText);

        var isNewlyCreated = extension.entry.getSys().version < 2;
        var hasNoValue = typeof extension.field.getValue() === 'undefined';

        if (isNewlyCreated && hasNoValue) {
          extension.field.setValue(defaultAuthor || '');
        }

        function valueChangeHandler(value) {
          value = value || '';

          if (value !== inputEl.value) {
            inputEl.value = value;
          }

          if (/^#([a-f0-9]{3}){1,2}$/i.test(value)) {
            extension.field.setInvalid(false);
            document.querySelector('.cf-form-field').style.borderLeft =
              '5px solid ' + value;
          } else {
            extension.field.setInvalid(true);
            document.querySelector('.cf-form-field').style.borderLeft = '0';
          }
        }

        function keyboardInputHandler() {
          var value = inputEl.value;

          if (typeof value === 'string' && value.length > 0) {
            extension.field.setValue(value);
          } else {
            extension.field.removeValue();
            inputEl.value = '';
          }
        }

        function unloadHandler() {
          window.removeEventListener('onbeforeunload', unloadHandler);
          inputEl.removeEventListener('input', keyboardInputHandler);
          detachValueChangeHandler();
        }
      });
    </script>
  </body>
</html>

extension.json

{
  "id": "default-field-value",
  "name": "Default value for a field",
  "srcdoc": "extension.html",
  "fieldTypes": ["Symbol"],
  "parameters": {
    "instance": [
      {
        "id": "defaultAuthor",
        "name": "Default Author",
        "description": "Set which author is the default",
        "type": "Enum",
        "options": [
          { "Social": "Social" },
          { "John Doe": "John Doe" },
          { "Jane Doe": "Jane Doe" },
        ],
        "labels": { "empty": "Choose an Author" },
        "required": true
      }
    ]
  }
}

Choose your default value

  • Below you can see how easy it is to set a default value

UI selecting default value

The power of modularity

Contentful made a smart design choice with this feature. They built in elasticity to this Headless CMS. Now any type of field we need we can build and add to our site. It is a powerful feature and fairly easy to replicate.

If you have questions about Gatsby or Contentful, contact Iron Cove Solutions and we'll be happy to assist you.


Phone & Hours

(888) 959-2825
Monday-Friday: 9am to 5pm

Address

8117 W. Manchester Ave
Suite 915
Playa Del Rey, CA 90293