Meridian handbook
For agentsRecipes

Add a content type

How an agent adds a custom content type to a Meridian project with dev type add and dev field add, what the generated schema file holds, and how to verify the type is applied and has an id for every field.

A content type is a kind of document (a walk, an event, a news story) with its own fields. Core types (page, article, event, guide, collection, and with engine-dmo listing and area) already exist; add a custom type only when none of them fits, and extend a core type when it nearly does (see Add a field).

Steps

Check the name is free and see what exists:

engine-dmo describe project --json

Add the type. It gets title, slug (generated from the title) and summary:

engine-dmo dev type add walk --label Walk --plural Walks --apply
wrote config/schema/walk.yaml
...
  + type        walk                             custom, 3 fields
  + field       walk.title                       text
  + field       walk.slug                        slug
  + field       walk.summary                     text

Plan: 3 add field, 1 add type.
applied

Without a database, leave out --apply; the file is still written and checked.

Add its fields, one verb each. Look up a type’s parameters with engine-dmo describe fieldtypes --json first:

engine-dmo dev field add walk distanceKm --type number --label "Distance (km)" --param min=0 --apply
engine-dmo dev field add walk difficulty --type select --options easy,moderate,hard --label Difficulty --required --index --apply
engine-dmo dev field add walk photo --type asset --label Photo --apply
engine-dmo dev field add walk body --type portable_text --label "Route description" --apply

--index is what lets a listing page filter or sort on the field. --required makes the field required at publish.

Read the result:

# config/schema/walk.yaml
key: walk
id: typ_bm5h7rk9j6
label: { en: Walk }
plural: { en: Walks }
ordering: { field: title, direction: asc }

fields:
  - { name: title, id: fld_4crq7vfgva, type: text, required: true, index: true }
  - { name: slug, id: fld_hbjpyckec7, type: slug, source: title, required: true }
  - { name: summary, id: fld_96fyjc4qs9, type: text, multiline: true, max: 280 }
  - { name: distanceKm, id: fld_azkam2rfyt, type: number, label: { en: Distance (km) }, min: 0 }
  - { name: difficulty, id: fld_8tvr5aq659, type: select, label: { en: Difficulty }, required: true, index: true, options: [{ value: easy, id: opt_z9ynd1s738 }, { value: moderate, id: opt_9kkqg3nqew }, { value: hard, id: opt_c5mcqxkfct }] }
  - { name: photo, id: fld_crnr761s22, type: asset, label: { en: Photo } }
  - { name: body, id: fld_yms2apxswc, type: portable_text, label: { en: Route description } }

Your ids will differ: they are minted for your project. Never copy these.

Give the type a route and templates: Add a route and its template.

Writing the file by hand

When you need options the verbs do not offer (option labels, editor groups, structured_data, validation rules), write the schema file yourself without ids and let the engine add them:

# config/schema/walk.yaml
key: walk
label: { en: Walk }
plural: { en: Walks }
fields:
  - { name: title, type: text, required: true, index: true }
  - { name: slug, type: slug, source: title, required: true }
  - { name: summary, type: text, multiline: true, max: 280 }
engine-dmo check --fix

check --fix writes typ_ and fld_ ids into the file, keeping your comments. Content types lists every key a type file takes.

Verify

engine-dmo check
engine-dmo schema plan        # exits 0, "No changes", after apply
engine-dmo describe type walk

describe type prints every field with its id and its translate mode (translate locale for text that differs per locale, translate none for values shared by every locale).

Options of dev type add

FlagEffect
--label <name>The type’s name in the source locale
--plural <name>Its plural, used as the index page’s title
--site <key>A type of one site only, in that site’s schema directory
--sites <a,b>Limit a shared type to these sites
--dry-runPrint the diff, write nothing
--applyApply the schema plan when it is not destructive

The type key is lowercase letters, digits and underscores (walk, tour_operator); tourOperator and tour-operator are refused. Field names may be camel case (distanceKm). Field names id, type, uri, url, status, locale, tags, seo, noindex, author, organisation, createdAt, updatedAt, publishedAt, redirectFrom and translations are reserved.