# Objects type for theme setting

**URL:** https://meta.discourse.org/t/objects-type-for-theme-setting/305009
**Category:** Developer Guides
**Tags:** how-to, theme-guides
**Created:** [April 23, 2024, 6:24am UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009 "2024-04-23T06:24:06Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![Discourse](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/discourse/32/148734_2.png) [@Discourse](https://meta.discourse.org/u/Discourse)
#### Post date: [April 23, 2024, 6:24am UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/1 "2024-04-23T06:24:06Z")

</div>

We are introducing a new `type: objects` to [the supported types for theme settings](https://meta.discourse.org/t/add-settings-to-your-discourse-theme/82557#symbols-supported-types-2) which can be used to replace the existing `json_schema` type which we intend to deprecate soon.

### Defining an objects type theme setting

To create an objects type theme setting, first define a top level key just like any theme setting which will be used as the setting’s name.

```yaml
links: ...

```

Next add the `type`, `default` and `schema` keywords to the setting.

```yaml
links:
  type: objects
  default: []
  schema: ...

```

`type: objects` indicates that this will be an objects type setting while the `default: []` annotation sets the default value of the setting to an empty array. Note that the default value can also be set to an array of objects which we will demonstrate once the `schema` has been defined.

To define the schema, first define the `name` of the schema like so:

```yaml
links:
  type: objects
  default: []
  schema:
    name: link

```

Next, we will add the `properties` keyword to the schema which will allow us to define and validate how each object should look like.

```yaml
links:
  type: objects
  default: []
  schema:
    name: link
    properties:
      name: ...

```

In the example above, we are stating that the `link` object has a `name` property. To define the type of data that is expected, each property needs to define the `type` keyword.

```yaml
links:
  type: objects
  default: []
  schema:
    name: link
    properties:
      name:
        type: string

```

The above schema definition states that the `link` object has a `name` property of type `string` which means that only string values will be accepted for the property. Currently the following types are supported:

- `string`: Value of property is stored as a string.
- `integer`: Value of property is stored as an integer.
- `float`: Value of property is stored as a float.
- `boolean`: Value of property is `true` or `false`.
- `upload`: Value of property is the attachment URL
- `enum`: Value of property must be one of the values defined in the `choices` keyword.

```yaml
links:
  type: objects
  default: []
  schema:
    name: link
    properties:
      name:
        type: enum
        choices:
          - name 1
          - name 2
          - name 3

```

- `categories`: Value of property is an array of valid category ids.
- `groups`: Value of property is an array of valid group ids.
- `tags`: Value of property is an array of valid tag names.
- `icon`: Value of property is the name of a single icon from the Discourse icon set. Selected icons are automatically added to the sprite sheet, so they can be rendered without being registered separately.

With the schema defined, the default value of the setting can now be set by defining a array in yaml like so:

```yaml
links:
  type: objects
  default:
    - name: link 1
      title: link 1 title
    - name: link 2
      title: link 2 title
  schema:
    name: link
    properties:
      name:
        type: string
      title:
        type: string

```

#### Required properties

All properties defined are optional by default. To mark a property as required, simply annotate the property with `required: true. A property can also be marked as optional by annotating the property with `required: false`.

```yaml
links:
  type: objects
  default: []
  schema:
    name: link
    properties:
      name:
        type: string
        required: true
      title:
        type: string
        required: false

```

#### Custom Validations

For certain property types, there are built in support for custom validations which can be declared by annotating the property with the `validations` keyword.

```yaml
links:
  type: objects
  default: []
  schema:
    name: link
    properties:
      name:
        type: string
        required: true
        validations:
          min: 1
          max: 2048
          url: true

```

#### Validations for `string` types

- `min_length`: Minimum length of the property. Value of the keyword has to be an integer.
- `max_length`: Maximum length of the property Value of the keyword has to be an integer.
- `url`: Validates that the property is a valid URL. Value of the keyword can be `true/false`.

#### Validations for `integer` and `float` types

- `min`: Minimum value of the property. Value of the keyword has to be an integer.
- `max`: Maximum value of the property. Value of the keyword has to be an integer.

#### Validations for `tags`, `groups` and `categories` types

- `min`: Minimum number of records for the property. Value of the keyword has to be an integer.
- `max`: Maximum number of records for the property. Value of the keyword has to be an integer.

#### Resolving group membership

Object settings can resolve `type: groups` properties to a boolean for the current user. This is useful when theme code only needs to know whether the current user is in one of the configured groups, because `currentUser.groups` only includes groups that are visible to the user.

Add `resolve_group_membership: true` to the `groups` property:

```yaml
menu_sections:
  type: objects
  default:
    - name: section 1
      groups:
        - 1
        - 3
  schema:
    name: menu section
    properties:
      name:
        type: string
      groups:
        type: groups
        resolve_group_membership: true

```

The admin UI and stored setting value still use the original `groups` array. In the frontend runtime `settings` object, Discourse removes the group IDs from each object and adds a boolean with the same property name prefixed by `user_in_`:

```gjs
for (const section of settings.menu_sections) {
  if (section.user_in_groups) {
    // User is in at least one selected group for this section.
  }
}

```

This option is only valid on object schema properties with `type: groups`. It also works on nested object schemas and with automatic groups such as `logged_in_users` and `anonymous_users`.

#### Nested objects structure

An object can also have a property which contains an array of objects. In order to create a nested objects structure, a property can also be annotated with `type: objects` and the associated `schema` definition.

```yaml
sections:
  type: objects
  default:
    - name: section 1
      links:
        - name: link 1
          url: /some/url
        - name: link 2
          url: /some/other/url
  schema:
    name: section
    properties:
      name:
        type: string
        required: true
      links:
        type: objects
        schema:
          name: link
          properties:
            name:
              type: string
            url:
              type: string

```

### Setting description and localization

To add a description for the setting in the `en` locale, create a file `locales/en.yml` with the following format given the following objects type theme setting.

```yaml
sections:
  type: objects
  default:
    - name: section 1
      links:
        - name: link 1
          url: /some/url
        - name: link 2
          url: /some/other/url
  schema:
    name: section
    properties:
      name:
        type: string
        required: true
      links:
        type: objects
        schema:
          name: link
          properties:
            name:
              type: string
            url:
              type: string

```

```yaml
en:
  theme_metadata:
    settings:
      sections:
        description: This is a description for the sections theme setting
        schema:
          properties:
            name:
              label: Name
              description: The description for the property
            links:
              name:
                label: Name
                description: The description for the property
              url:
                label: URL
                description: The description for the property

```

* * *

This document is version controlled - suggest changes [on github](https://github.com/discourse/discourse/blob/main/docs/developer-guides/docs/05-themes-components/10-objects-for-theme-settings.md).

---

<div class="post-metadata">

### Author: ![merefield](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/merefield/32/176214_2.png) [@merefield](https://meta.discourse.org/u/merefield)
#### Post date: [April 23, 2024, 6:35am UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/2 "2024-04-23T06:35:28Z")

</div>

I remain to be convinced deprecation of the json schema style is a good idea.

Whilst these can get pretty complex and aren’t the most “developer friendly” of formats (so this is a great change in that regard), there are online tools to validate json schemas which is a really useful way to validate both the schema and against any default data.

e.g. [https://www.jsonschemavalidator.net/](https://www.jsonschemavalidator.net/)

How will that work in this new world?

---

<div class="post-metadata">

### Author: ![tgxworld](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/tgxworld/32/106117_2.png) [@tgxworld](https://meta.discourse.org/u/tgxworld)
#### Post date: [April 23, 2024, 7:17am UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/4 "2024-04-23T07:17:11Z")

</div>

> [@merefield](#):
>
> to validate both the schema and against any default data.

When uploading a theme, we will be validating the default data against the defined schema. That being said, we are not validating that the schema definition is valid now but it wouldn’t be hard for us to do so. Even for the json schema setting right now, I don’t think we are validating the default data against the defined schema.

> [@merefield](#):
>
> I remain to be convinced deprecation of the json schema style is a good idea.

Our current implementation of json schema type settings is kind of broken in many ways with the most obvious being the editor in the admin interface. We discussed this internally and decided that it is much easier for us to maintain a limited schema format defined by us instead of allowing all the possibilities that comes along with json schema.

---

<div class="post-metadata">

### Author: ![merefield](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/merefield/32/176214_2.png) [@merefield](https://meta.discourse.org/u/merefield)
#### Post date: [April 23, 2024, 8:11am UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/6 "2024-04-23T08:11:13Z")

</div>

Some cool features here:

- you can get rid of `JSON.parse` and access the setting directly to the get object which is really nice.

- the url validator!

:chefs_kiss: :chefs_kiss:

---

<div class="post-metadata">

### Author: ![merefield](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/merefield/32/176214_2.png) [@merefield](https://meta.discourse.org/u/merefield)
#### Post date: [April 23, 2024, 9:01am UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/7 "2024-04-23T09:01:00Z")

</div>

Is there any way for multiple lines to be respected in the editor?

This _default_ **works** :

```plaintext
- name: markdown
  value: > 
    ## Heading
      * first bullet
      * second bullet

```

But once you edit this, the carriage returns are lost

Moreover, it would be nice to have a “text” type that could store more long-form data and perhaps expose a larger “text-area” editor

---

<div class="post-metadata">

### Author: ![Arkshine](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/arkshine/32/298682_2.png) [@Arkshine](https://meta.discourse.org/u/Arkshine)
#### Post date: [April 25, 2024, 2:13pm UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/8 "2024-04-25T14:13:36Z")

</div>

Here are some feedbacks:

- Refreshing the current page `/schema/<setting_name>` returns a routing error.  

- Make the error readable. I understand it’s a very low priority. For example, something like that:

---

<div class="post-metadata">

### Author: ![tgxworld](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/tgxworld/32/106117_2.png) [@tgxworld](https://meta.discourse.org/u/tgxworld)
#### Post date: [April 25, 2024, 10:57pm UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/9 "2024-04-25T22:57:41Z")

</div>

I noticed this and it has been fixed in

[https://github.com/discourse/discourse/commit/25bcee43c60c7b707a07934984563e565d04d242](https://github.com/discourse/discourse/commit/25bcee43c60c7b707a07934984563e565d04d242)

---

<div class="post-metadata">

### Author: ![manuel](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/manuel/32/468169_2.png) [@manuel](https://meta.discourse.org/u/manuel)
#### Post date: [May 9, 2024, 9:04am UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/10 "2024-05-09T09:04:21Z")

</div>

Will we be able to re-order items on the interface?

E.g. that’s the object settings editor on the easy footer theme component. I can’t re-arrange any items right now:

 ![image](https://global.discourse-cdn.com/meta/original/4X/8/c/6/8c6d67d005fc2fd87140784946e09e9a80a9f0be.png)

---

<div class="post-metadata">

### Author: ![Arkshine](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/arkshine/32/298682_2.png) [@Arkshine](https://meta.discourse.org/u/Arkshine)
#### Post date: [May 10, 2024, 1:28pm UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/11 "2024-05-10T13:28:28Z")

</div>

> [@manuel](#):
>
> Will we be able to re-order items on the interface?

I wanted to request this feature as well! 👍

* * *

On a side note, it would be helpful if the first post contained information about the `identifier` property.

Before looking at Nolo’s image above, I thought replacing the default child label with a property value was impossible. After looking at the code, I found the `identifier` property.

---

<div class="post-metadata">

### Author: ![tgxworld](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/tgxworld/32/106117_2.png) [@tgxworld](https://meta.discourse.org/u/tgxworld)
#### Post date: [May 13, 2024, 12:47am UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/12 "2024-05-13T00:47:37Z")

</div>

> [@manuel](#):
>
> Will we be able to re-order items on the interface?

> [@Arkshine](#):
>
> I wanted to request this feature as well!

Reordering is certainly something that has been brought up internally as well. I’ll try to land that this week.

> [@Arkshine](#):
>
> it would be helpful if the first post contained information about the `identifier` property.

Noted. I’ll update the first post about the `identifier` property.

---

<div class="post-metadata">

### Author: ![merefield](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/merefield/32/176214_2.png) [@merefield](https://meta.discourse.org/u/merefield)
#### Post date: [May 13, 2024, 6:03am UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/13 "2024-05-13T06:03:35Z")

</div>

Yep to replace the (soon to be legacy?) json system it needs to match or exceed the old interface:

 ![image](https://global.discourse-cdn.com/meta/original/4X/5/1/2/512764152c8bf291bbbb7f78aa45f8899bd67e5e.png)

including the ordering.

---

<div class="post-metadata">

### Author: ![gormus](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/gormus/32/428592_2.png) [@gormus](https://meta.discourse.org/u/gormus)
#### Post date: [August 11, 2024, 4:42pm UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/14 "2024-08-11T16:42:44Z")

</div>

> [@Discourse](#):
>
> Currently the following types are supported:
> 
> - `string`: Value of property is stored as a string.
> 
> - `integer`: Value of property is stored as an integer.
> 
> - `float`: Value of property is stored as a float.
> 
> - `boolean`: Value of property is `true` or `false`.
> 
> - `enum`: Value of property must be one of the values defined in the `choices` keyword.
> 
> - `categories`: Value of property is an array of valid category ids.
> 
> - `groups`: Value of property is an array of valid group ids.
> 
> - `tags`: Value of property is an array of valid tag names.

Hi, are there any plans to support other field types soon?

For example;

- a `long_string` with markdown format; perhaps with customizable toolbar,
- a `date` field (with validation rules),
- a `color` field (with validation rules)?

---

<div class="post-metadata">

### Author: ![awesomerobot](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/awesomerobot/32/142900_2.png) [@awesomerobot](https://meta.discourse.org/u/awesomerobot)
#### Post date: [August 20, 2024, 2:14pm UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/15 "2024-08-20T14:14:02Z")

</div>

> [@gormus](#):
>
> Hi, are there any plans to support other field types soon?

There’s no current plan, though I agree that it would be useful. I’d like an `icon` field myself.

---

<div class="post-metadata">

### Author: ![gormus](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/gormus/32/428592_2.png) [@gormus](https://meta.discourse.org/u/gormus)
#### Post date: [August 21, 2024, 6:31pm UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/16 "2024-08-21T18:31:21Z")

</div>

> [@Discourse](#):
>
> With the schema defined, the default value of the setting can now be set by defining a array in yaml like so:
> 
> ```plaintext
> links:
> type: objects
> default:
> - name: link 1
> title: link 1 title
> - name: link 2
> title: link 2 title
> schema:
> name: link
> properties:
> name:
> type: string 
> title: 
> type: string
> 
> ```

In my experience, it seems to be working like saved presets. In this example the first 2 entries could benefit from these presets, but anything after that all new entries will come up blank initially.

This also means we cannot set default values for each field. for example, if I want to have a checkbox, to start at checked state I cannot have it.

```plaintext
links:
  type: objects
  default:
    - name: link 1
      title: link 1 title
    - name: link 2
      title: link 2 title
  schema:
    name: link
    properties:
      is_active:
        type: boolean
        default: true 

```

`default: true` will not work in there as expected.

Could there be a way to set the default values per field, for each entries that are created?

---

<div class="post-metadata">

### Author: ![manuel](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/manuel/32/468169_2.png) [@manuel](https://meta.discourse.org/u/manuel)
#### Post date: [December 5, 2024, 12:47pm UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/18 "2024-12-05T12:47:48Z")

</div>

Is there a way to import object properties to variables in Sass?

---

<div class="post-metadata">

### Author: ![Arkshine](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/arkshine/32/298682_2.png) [@Arkshine](https://meta.discourse.org/u/Arkshine)
#### Post date: [December 5, 2024, 1:22pm UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/19 "2024-12-05T13:22:57Z")

</div>

You can always parse the string, but that doesn’t sound like a great idea to promote this way. 😅

> <https://github.com/Arkshine/discourse-banner-featured-links/blob/main/scss/functions.scss#L78-L110>

> <https://github.com/Arkshine/discourse-banner-featured-links/blob/main/common/common.scss#L9C2-L9C46>

---

<div class="post-metadata">

### Author: ![manuel](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/manuel/32/468169_2.png) [@manuel](https://meta.discourse.org/u/manuel)
#### Post date: [December 6, 2024, 1:54pm UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/20 "2024-12-06T13:54:03Z")

</div>

> [@Arkshine](#):
>
> You can always parse the string, but that doesn’t sound like a great idea to promote this way. 😅

Thank you for sharing the example! Though yeah.. it doesn’t look that tempting 🙃

---

<div class="post-metadata">

### Author: ![merefield](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/merefield/32/176214_2.png) [@merefield](https://meta.discourse.org/u/merefield)
#### Post date: [December 6, 2024, 1:57pm UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/21 "2024-12-06T13:57:19Z")

</div>

> [@merefield](#):
>
> Yep to replace the (soon to be legacy?) json system it needs to match or exceed the old interface:
> 
> ![image](https://global.discourse-cdn.com/meta/original/4X/5/1/2/512764152c8bf291bbbb7f78aa45f8899bd67e5e.png)
> 
> including the ordering.

Out of interest, without spending too much time looking, where are we with this?

---

<div class="post-metadata">

### Author: ![Arkshine](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/arkshine/32/298682_2.png) [@Arkshine](https://meta.discourse.org/u/Arkshine)
#### Post date: [December 6, 2024, 3:17pm UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/22 "2024-12-06T15:17:20Z")

</div>

Yes, it isn’t very good, don’t do it. 😄. It was more of an attempt to see if it was possible, but not a reasonable approach.  
I agree with you; it would be nice to have a direct way! 👍

> [@merefield](#):
>
> Out of interest, without spending too much time looking, where are we with this?

I would like to know, too!  
Also, if I’m right, that would be the only missing feature parity with the json\_schema.

---

<div class="post-metadata">

### Author: ![Arkshine](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/arkshine/32/298682_2.png) [@Arkshine](https://meta.discourse.org/u/Arkshine)
#### Post date: [December 15, 2024, 5:16am UTC](https://meta.discourse.org/t/objects-type-for-theme-setting/305009/23 "2024-12-15T05:16:08Z")

</div>

I was looking for the upload type to be available, but it’s not.  
A quick look at the core shows that the topic, post, and upload types have been implemented server-side but not in the front end. Is there a specific reason for that? 🤔

[Next page](https://meta.discourse.org/t/objects-type-for-theme-setting/305009.md?page=2)
