This is part 2 of our tutorial on adding Stackbit to an existing Hugo theme. In this tutorial we will model our Hugo themes data and configuration files. We also cover some more advanced model types including Object models and object field models.

Tutorial: Adding Stackbit to a Hugo Theme (part 2/2)

This is the second part of a 2 part tutorial on adding Stackbit to an existing Hugo theme. Read Tutorial Part 1

Adding Config & Data Files

In Part 1 we modelled all the markdown files in our theme, but what about data and config files?

Data models can be used to model any .JSON, .YAML and .TOML files located under the dataDir. Depending on your theme and ssg the data might be content for your theme, data for components and also the theme configuration file.

features.json

The tutorial theme https://github.com/stackbithq/uniform-hugo-tutorial has a list of "highlights" on the homepage. They are the boxes that appear at the bottom ie "Free Consultation" etc.

These highlights use a Hugo data file located in data/features.json. The data file looks like this.

// data/features.json

{
  "highlights": [
    {
      "title": "Free Consultation",
      "description": "New clients recieve an obligation free consultation.",
      "image": "images/features/noun_branding_1885335.svg"
    },
    {
      "title": "Certified Accountants",
      "description": "All members of our team are certified accountants.",
      "image": "images/features/noun_The Process_1885341.svg"
    },
    {
      "title": "Tax Compliance",
      "description": "We stay up to date on the latest changes to the tax code.",
      "image": "images/features/noun_3d modeling_1885342.svg"
    }
  ]
}

features.json contains a highlights object, which contains an array of objects. We are going to use a list field type with a nested object field type to model this data.

  features:
    type: data
    label: Features
    file: features.json
    fields:
      - type: list
        name: highlights
        items:
          type: object
          label: Highlight
          labelField: title
          fields:
            - type: string
              name: title
              label: Title
            - type: string
              name: description
              label: Description
            - type: image
              name: image
              label: Icon

Data models follow a very similiar format to page models but importantly they use type: data instead of type: page.

Earlier in the tutorial we set the dataDir to dataDir: exampleSite (at the top of our stackbit.yaml). When we match a data model to the file it's going to be relative to this directory. So in this case we use the matching open file: features.json to match the data file.

contact.yaml

.yaml files are also valid data sources. Here is the data model for data/contact.yaml

  contact:
    type: data
    label: Contact Info
    file: contact.yaml
    fields:
      - type: string
        name: email
        label: Email
      - type: string
        name: phone
        label: Phone

Configuration Files

Most ssgs have a configuration file. Stackbit treats config files as normal data models. Here is the data model for the themes config file located at exampleSite/config.yaml.

This code example does not yet include the menus.

  config:
    type: data
    label: Config
    file: config.toml
    fields:
      - type: string
        name: title
        label: Title
        required: true
      - type: string
        name: baseURL
        label: Base URL
        description: Hostname (and path) to the root
        hidden: true
      - type: string
        name: languageCode
        label: Language Code
        hidden: true
      - type: string
        name: themesDir
        label: Themes Directory
        hidden: true
      - type: string
        name: theme
        label: Theme Name
        hidden: true
      - type: object
        name: params
        label: Params
        description: Site parameters
        required: true
        fields:
          - type: string
            name: google_analytics_id
            label: Google Analytics ID
          - type: string
            name: google_tag_manager_id
            label: Google Tag Manager ID
          - type: object
            name: logo
            label: Params Logo
            fields:
              - type: image
                name: standard
                label: Logo Desktop
                description: the path of the desktop logo image
                required: true
              - type: image
                name: mobile
                label: Logo Mobile
                description: the path of the mobile logo image
              - type: string
                name: alt
                label: Logo Alt Text
          - type: object
            name: homepage_meta_tags
            label: Homepage Metatags
            fields: 
              - type: string
                name: meta_description
                label: meta_description
              - type: string
                name: meta_og_title
                label: meta_og_title
              - type: string
                name: meta_og_type
                label: meta_og_type
              - type: string
                name: meta_og_url
                label: meta_og_url
              - type: string
                name: meta_og_image
                label: meta_og_image
              - type: string
                name: meta_og_description
                label: meta_og_description
              - type: string
                name: meta_twitter_card
                label: meta_twitter_card
              - type: string
                name: meta_twitter_site
                label: meta_twitter_site
              - type: string
                name: meta_twitter_creator
                label: meta_twitter_creator

Modelling Hugo Menus

This theme has 2 menus. main and footer which can be viewed in the config.yaml

# exampleSite/config.yaml

...

[menu]
  # Main Menu
  [[menu.main]]
    name = "Services"
    url = "/services/"
      weight = 1

  [[menu.main]]
      name = "Team"
      url = "/team/"
      weight = 2

  # Footer Menu
  [[menu.footer]]
    name = "Home"
    url = "/"
      weight = 1

  [[menu.footer]]
    name = "Contact"
    url = "/contact/"
      weight = 2

Here we are going to use a Object Model. Ie a content model of type: object and we are going to reference it using an Object Model Field.

# stackbit.yaml
...
models:
  ...
  site_menus:
    type: object # object model
    label: Site Menus
    fields:
      - type: list
        name: main
        label: Main menu
        description: List of items for Main menu
        items:
          type: site_menu_item
      - type: list
        name: footer
        label: Footer menu
        description: List of items for Footer menu
        items:
          type: site_menu_item
  site_menu_item:
    type: object
    label: Site Menu Item
    labelField: name
    fields:
      - type: string
        name: identifier
        label: Identifier
      - type: string
        name: name
        label: Title
        description: The title of the menu item
        required: true
      - type: string
        name: url
        label: URL
        description: The URL the menu item links to
        required: true
      - type: number
        name: weight
        label: Weight
        description: Position for sorting
      - type: string
        name: parent
        label: Parent Menu Identifier
        description: The parent of an entry should be the identifier of another entry.

We've created 2 object models. "site_menus" is a list of menu objects. It includes Main Menu and Footer Menu, which include an object model reference to "site_menu_items".

"site_menu_items" is a single object, with the 4 fields that are used in a Hugo menu item.

Now in the CMS you can add new top level Menus ie Sidebar Menu, and you can add, edit and delete individual menu items from existing menus.

Finally we need to add a reference to "site_menus" to the data model for config.yaml

# stackbit.yaml
...
models:
  ...
  config:
    ...
    - type: site_menus # references the object model we created in the previous step
      name: menu
      label: Menus

Wrapping Up

Now we've modelled both the themes pages and data. The Uniform theme conversion is complete.

Visit https://app.stackbit.com/create and import your theme again.

Documentation