MADORIMADORI

Blueprints

Blueprints define the content schema for your entries, globals, taxonomies, and forms. They describe which fields appear in the Control Panel, how those fields are organised into tabs and sections, and what validation and visibility rules apply.

A blueprint is a YAML file that maps directly to the editing experience — every tab, section, and field you configure becomes a real interface element in the Control Panel.


Configuration Reference

File Location

Blueprints live at resources/blueprints/{type}/{handle}.yaml where {type} is one of:

Type Path Used By
collections resources/blueprints/collections/{handle}.yaml Collection entries
globals resources/blueprints/globals/{handle}.yaml Global data sets
taxonomies resources/blueprints/taxonomies/{handle}.yaml Taxonomy terms
forms resources/blueprints/forms/{handle}.yaml Form definitions

Top-Level Structure

A blueprint consists of named tabs, each containing fields and optional sections:

tabs:
  <tab_handle>:
    display: <Tab Label>
    fields:
      - handle: <field_handle>
        field:
          type: <field_type>
          # ...field config
    sections:
      <section_handle>:
        display: <Section Label>
        fields:
          - handle: <field_handle>
            field:
              type: <field_type>

Tabs

Tabs divide the editing interface into logical groups. Each tab renders as a clickable tab in the Control Panel. The tab handle is used internally; the display value is shown to editors.

tabs:
  content:
    display: Content
    fields:
      - handle: title
        field:
          type: text
          display: Title
          required: true

      - handle: body
        field:
          type: tiptap
          display: Body

  metadata:
    display: Metadata
    fields:
      - handle: published_at
        field:
          type: date
          display: Publish Date

      - handle: status
        field:
          type: select
          display: Status
          options:
            options:
              - draft
              - published
              - archived

Tabs render in the order they appear in the YAML. Place the most-used fields in the first tab so editors land on them by default.


Sections

Sections provide visual grouping within a tab. They render as labelled groups with a heading, useful when a single tab contains many fields that benefit from logical separation.

tabs:
  main:
    display: Main
    fields:
      - handle: title
        field:
          type: text
          display: Title
          required: true

      - handle: slug
        field:
          type: slug
          display: URL Slug
          required: true

    sections:
      seo:
        display: SEO Settings
        fields:
          - handle: meta_title
            field:
              type: text
              display: Meta Title
              validate:
                - max:60
              options:
                placeholder: Override the page title for search engines

          - handle: meta_description
            field:
              type: text
              display: Meta Description
              validate:
                - max:160
              options:
                placeholder: Brief description for search results

      social:
        display: Social Sharing
        fields:
          - handle: og_image
            field:
              type: asset
              display: Social Image
              options:
                max_files: 1

          - handle: og_description
            field:
              type: text
              display: Social Description
              validate:
                - max:200

Fields defined directly under the tab appear first, followed by sections in definition order.


Field Configuration

Each field in a blueprint is defined with a handle (the storage key) and a field object containing its configuration.

Field Properties

Property Type Required Description
type string Yes One of the 18 field type identifiers
display string No Label shown in the CP. Auto-generated from handle if omitted
required boolean No Whether the field must have a value. Default: false
default any No Default value pre-populated on create forms
validate string[] No Array of validation rule strings
options object No Type-specific configuration options
visibility object No Conditional display rules

Field Handle

The handle becomes the key in your content files. Use snake_case for handles:

- handle: featured_image    # stored as featured_image in content YAML
  field:
    type: asset
    display: Featured Image  # shown to editors in the CP

Default Values

Set default values to pre-populate fields when creating new entries:

- handle: status
  field:
    type: select
    display: Status
    default: draft
    options:
      options:
        - draft
        - published

- handle: featured
  field:
    type: toggle
    display: Featured
    default: false

- handle: author_name
  field:
    type: text
    display: Author
    default: Editorial Team

Default values appear in create forms only. Edit forms show the persisted entry data.

Help Text

Add instructions below a field using the instructions property within options:

- handle: slug
  field:
    type: slug
    display: URL Slug
    required: true
    options:
      placeholder: e.g. my-page-title

The 18 Field Types

Madori supports these built-in field types:

Type Stores Best For
text string Titles, names, short text
slug string URL identifiers
markdown string Long-form plain Markdown
tiptap object (JSON) Rich text with formatting
number number Prices, counts, measurements
toggle boolean On/off flags
select string Single choice from options
multiselect string[] Multiple choices from options
date string (YYYY-MM-DD) Dates
asset string or string[] Files and images
entries string[] Cross-references to entries
taxonomy string[] Term assignments
replicator object[] Flexible page blocks (explicit sets)
blocks object[] Page blocks (auto-discovers is_block fieldsets)
grid object[] Tabular repeatable data
yaml string Arbitrary structured data
code string Code snippets, embeds
hidden any Internal metadata

See Field Types for detailed configuration options per type.


Visibility Conditions

Visibility conditions show or hide fields based on another field's current value. When a field is hidden, its value is excluded from the submission payload.

Configuration

- handle: field_handle
  field:
    type: text
    visibility:
      field: <other_field_handle>
      operator: <operator>
      value: <comparison_value>

Operators

Operator Description Value Required
equals Field value exactly matches the comparison value Yes
not_equals Field value does not match the comparison value Yes
contains Field value (string) contains the comparison value as a substring Yes
empty Field value is undefined, null, or empty string No
not_empty Field value is defined and not empty No

Examples

Show a field when a toggle is enabled:

- handle: show_cta
  field:
    type: toggle
    display: Show Call to Action
    default: false

- handle: cta_text
  field:
    type: text
    display: CTA Button Text
    visibility:
      field: show_cta
      operator: equals
      value: true

- handle: cta_url
  field:
    type: text
    display: CTA Link URL
    validate:
      - url
    visibility:
      field: show_cta
      operator: equals
      value: true

Show a field based on a select value:

- handle: link_type
  field:
    type: select
    display: Link Type
    default: internal
    options:
      options:
        - internal
        - external

- handle: external_url
  field:
    type: text
    display: External URL
    validate:
      - url
    visibility:
      field: link_type
      operator: equals
      value: external

- handle: entry_reference
  field:
    type: entries
    display: Linked Entry
    visibility:
      field: link_type
      operator: equals
      value: internal

Show a field only when another field has content:

- handle: subtitle
  field:
    type: text
    display: Subtitle

- handle: subtitle_style
  field:
    type: select
    display: Subtitle Style
    options:
      options:
        - normal
        - italic
        - highlighted
    visibility:
      field: subtitle
      operator: not_empty

Payload Behaviour

When a visibility condition evaluates to false:

  1. The field is hidden from the editor in the Control Panel
  2. The field's value is excluded from the submission payload
  3. Validation rules on the hidden field are not enforced

When a visibility condition evaluates to true (or when no condition is set):

  1. The field is displayed normally
  2. The field's value is included in the submission payload
  3. All validation rules are enforced

Validation Rules

Validation rules enforce data constraints on field values. Rules are checked on both client-side (as the editor types) and server-side (on form submission). Invalid data returns structured field-level errors adjacent to the offending field.

Configuration

Validation rules are defined as an array of strings in the validate property:

- handle: email
  field:
    type: text
    display: Email Address
    validate:
      - required
      - email
      - max:254

Available Rules

Rule Syntax Description
required required Field must have a non-empty value
min min:<n> Minimum character length (text types) or minimum value (number)
max max:<n> Maximum character length (text types) or maximum value (number)
regex regex:<pattern> Value must match the regular expression pattern
url url Value must be a valid URL
email email Value must be a valid email address
numeric_range numeric_range:<min>,<max> Number must be within the specified range

Rule Compatibility

Not all rules apply to all field types. Incompatible rules are silently ignored with a console warning.

Rule Compatible Field Types
required All types
min, max text, slug, markdown, tiptap, code, number
regex, url, email text, slug, markdown, tiptap, code
numeric_range number

Validation Error Messages

Each rule produces a specific error message:

Rule Error Message
required "This field is required"
min:<n> (text) "Must be at least {n} characters"
max:<n> (text) "Must be at most {n} characters"
min:<n> (number) "Must be at least {n}"
max:<n> (number) "Must be at most {n}"
regex:<pattern> "Must match pattern {pattern}"
url "Must be a valid URL"
email "Must be a valid email address"
numeric_range:<min>,<max> "Must be at least {min}" / "Must be at most {max}"

Required vs. Validate

The required field property and the required validation rule both enforce non-empty values. You can use either:

# Using the field property
- handle: title
  field:
    type: text
    required: true

# Using the validation rule
- handle: title
  field:
    type: text
    validate:
      - required

Both approaches produce the same result. Using required: true is the simpler convention for most fields.


Usage Examples

Blog Post Blueprint

A typical blog post with content, metadata, and SEO fields organised into tabs:

tabs:
  content:
    display: Content
    fields:
      - handle: title
        field:
          type: text
          display: Title
          required: true
          validate:
            - required
            - min:3
            - max:120

      - handle: slug
        field:
          type: slug
          display: URL Slug
          required: true
          validate:
            - required
            - regex:^[a-z0-9-]+$

      - handle: featured_image
        field:
          type: asset
          display: Featured Image
          options:
            max_files: 1

      - handle: body
        field:
          type: tiptap
          display: Body
          required: true

      - handle: categories
        field:
          type: taxonomy
          display: Categories

  sidebar:
    display: Sidebar
    fields:
      - handle: status
        field:
          type: select
          display: Status
          required: true
          default: draft
          options:
            options:
              - draft
              - published
              - archived

      - handle: published_at
        field:
          type: date
          display: Publish Date

      - handle: featured
        field:
          type: toggle
          display: Featured
          default: false

      - handle: author
        field:
          type: entries
          display: Author

    sections:
      seo:
        display: SEO
        fields:
          - handle: meta_title
            field:
              type: text
              display: Meta Title
              validate:
                - max:60
              options:
                placeholder: Override page title for search engines

          - handle: meta_description
            field:
              type: text
              display: Meta Description
              validate:
                - max:160
              options:
                placeholder: Brief description for search results

Page Builder Blueprint

A flexible page blueprint using Replicator blocks for composing layouts:

tabs:
  main:
    display: Page
    fields:
      - handle: title
        field:
          type: text
          display: Title
          required: true

      - handle: slug
        field:
          type: slug
          display: URL Slug
          required: true

      - handle: blocks
        field:
          type: replicator
          display: Page Blocks
          options:
            sets:
              - hero
              - features_grid
              - rich_text
              - basic_cta
              - testimonials

  settings:
    display: Settings
    fields:
      - handle: template
        field:
          type: select
          display: Page Template
          default: default
          options:
            options:
              - default
              - full-width
              - sidebar

      - handle: show_navigation
        field:
          type: toggle
          display: Show Navigation
          default: true

      - handle: custom_css
        field:
          type: code
          display: Custom CSS
          visibility:
            field: template
            operator: equals
            value: full-width

Product Blueprint with Conditional Fields

A product schema that reveals different fields based on the product type:

tabs:
  details:
    display: Product Details
    fields:
      - handle: name
        field:
          type: text
          display: Product Name
          required: true
          validate:
            - required
            - max:200

      - handle: slug
        field:
          type: slug
          required: true

      - handle: product_type
        field:
          type: select
          display: Product Type
          required: true
          default: physical
          options:
            options:
              - physical
              - digital
              - subscription

      - handle: price
        field:
          type: number
          display: Price
          required: true
          validate:
            - required
            - numeric_range:0,999999
          options:
            min: 0
            step: 0.01

      - handle: weight
        field:
          type: number
          display: Weight (kg)
          visibility:
            field: product_type
            operator: equals
            value: physical
          options:
            min: 0
            step: 0.1

      - handle: download_url
        field:
          type: text
          display: Download URL
          validate:
            - url
          visibility:
            field: product_type
            operator: equals
            value: digital

      - handle: billing_interval
        field:
          type: select
          display: Billing Interval
          default: monthly
          options:
            options:
              - monthly
              - yearly
          visibility:
            field: product_type
            operator: equals
            value: subscription

      - handle: description
        field:
          type: tiptap
          display: Description

      - handle: images
        field:
          type: asset
          display: Product Images
          options:
            max_files: 10

Form Blueprint

A contact form with honeypot protection:

tabs:
  fields:
    display: Form Fields
    fields:
      - handle: name
        field:
          type: text
          display: Full Name
          required: true
          validate:
            - required
            - min:2
            - max:100

      - handle: email
        field:
          type: text
          display: Email Address
          required: true
          validate:
            - required
            - email

      - handle: subject
        field:
          type: select
          display: Subject
          required: true
          options:
            options:
              - General Inquiry
              - Support
              - Feedback
              - Partnership

      - handle: message
        field:
          type: markdown
          display: Message
          required: true
          validate:
            - required
            - min:10
            - max:5000

      - handle: website
        field:
          type: hidden

Common Patterns

Tab Organisation Strategy

Organise tabs by editing frequency. Primary content goes in the first tab. Secondary concerns (SEO, settings, advanced options) go in subsequent tabs:

tabs:
  content:     # Main content (title, body, media)
  sidebar:     # Status, dates, taxonomy
  seo:         # Meta titles and descriptions
  advanced:    # Developer-facing options

Reusable SEO Section

Add consistent SEO fields across blueprints by defining a section:

sections:
  seo:
    display: SEO
    fields:
      - handle: meta_title
        field:
          type: text
          display: Meta Title
          validate:
            - max:60
          options:
            placeholder: Override page title for search engines

      - handle: meta_description
        field:
          type: text
          display: Meta Description
          validate:
            - max:160
          options:
            placeholder: Brief description for search results

      - handle: og_image
        field:
          type: asset
          display: Social Share Image
          options:
            max_files: 1

Or use Fieldsets to share field groups across blueprints.

Progressive Disclosure with Visibility

Use toggles to reveal advanced options, keeping the default editing experience clean:

- handle: show_advanced
  field:
    type: toggle
    display: Show Advanced Options
    default: false

- handle: custom_class
  field:
    type: text
    display: CSS Class
    visibility:
      field: show_advanced
      operator: equals
      value: true

- handle: custom_id
  field:
    type: text
    display: HTML ID
    visibility:
      field: show_advanced
      operator: equals
      value: true

Combining Required + Custom Validation

Layer validation rules for thorough input checking:

- handle: website
  field:
    type: text
    display: Website URL
    required: true
    validate:
      - required
      - url
      - max:500

- handle: phone
  field:
    type: text
    display: Phone Number
    validate:
      - regex:^\+?[\d\s\-()]+$
      - min:7
      - max:20

Status and Publishing Workflow

A common pattern for collection entries with a publish workflow:

- handle: status
  field:
    type: select
    display: Status
    required: true
    default: draft
    options:
      options:
        - draft
        - review
        - published
        - archived

- handle: published_at
  field:
    type: date
    display: Publish Date
    visibility:
      field: status
      operator: equals
      value: published

- handle: archived_reason
  field:
    type: text
    display: Archive Reason
    visibility:
      field: status
      operator: equals
      value: archived

Managing Blueprints

Control Panel

Navigate to Blueprints in the CP sidebar to manage blueprints visually:

  • Create new blueprints for any entity type
  • Add, remove, and reorder fields with drag-and-drop
  • Configure field options, validation, and visibility
  • Add and organise tabs

API

GET    /api/blueprints/{type}           # List all blueprints of a type
GET    /api/blueprints/{type}/{handle}  # Get a specific blueprint
PUT    /api/blueprints/{type}/{handle}  # Create or update a blueprint
DELETE /api/blueprints/{type}/{handle}  # Delete a blueprint

File-Based Management

Edit blueprint YAML files directly for version control and collaboration:

resources/blueprints/
├── collections/
│   ├── blog.yaml
│   ├── pages.yaml
│   └── products.yaml
├── globals/
│   └── site-settings.yaml
├── taxonomies/
│   └── categories.yaml
└── forms/
    └── contact.yaml

Changes to blueprint files are reflected immediately in the Control Panel on the next page load.