{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://guten-fields.com/schema/gutenfields-blocks.schema.json",
  "title": "GutenFields block definitions",
  "description": "An importable definition of one or more GutenFields blocks and options pages. Import with `wp gutenfields import <file>` or the gutenfields/v1/import REST route. Each block becomes a real Gutenberg block; write its render template at theme/gutenfields/{name}.php (or run `wp gutenfields scaffold <name>`). Each options page becomes a wp-admin screen whose values are read with gf_option().",
  "type": "object",
  "anyOf": [
    { "required": ["blocks"] },
    { "required": ["optionsPages"] }
  ],
  "properties": {
    "gutenfields": {
      "description": "Format version of this file. Use \"1.0\".",
      "type": "string"
    },
    "$schema": { "type": "string" },
    "blocks": {
      "type": "array",
      "items": { "$ref": "#/definitions/block" }
    },
    "optionsPages": {
      "description": "Site-wide field groups, edited on their own admin screen rather than on a block.",
      "type": "array",
      "items": { "$ref": "#/definitions/optionsPage" }
    }
  },
  "additionalProperties": false,
  "definitions": {
    "optionsPage": {
      "type": "object",
      "required": ["slug", "title", "fields"],
      "properties": {
        "slug": {
          "description": "Page key, lowercase letters/numbers/hyphens. Values are read with gf_option('{slug}', 'field_name').",
          "type": "string",
          "pattern": "^[a-z0-9][a-z0-9-]*$"
        },
        "title": {
          "description": "Heading shown on the page.",
          "type": "string"
        },
        "menuTitle": {
          "description": "Label in the admin menu. Defaults to the title.",
          "type": "string"
        },
        "description": {
          "description": "Sentence shown above the fields.",
          "type": "string"
        },
        "parent": {
          "description": "Admin menu the page hangs off — e.g. \"gutenfields\" (the default), \"options-general.php\", \"themes.php\". An empty string gives the page its own top-level menu.",
          "type": "string",
          "default": "gutenfields"
        },
        "icon": {
          "description": "Dashicons class for a top-level menu, e.g. \"dashicons-admin-site\". Ignored for submenus.",
          "type": "string"
        },
        "position": {
          "description": "Menu position. Higher sinks further down.",
          "type": "number"
        },
        "capability": {
          "description": "Capability required to see and save the page. Defaults to manage_options; a capability no role has falls back to that default.",
          "type": "string",
          "default": "manage_options"
        },
        "fields": {
          "type": "array",
          "items": { "$ref": "#/definitions/field" }
        }
      },
      "additionalProperties": false
    },
    "block": {
      "type": "object",
      "required": ["name", "title", "fields"],
      "properties": {
        "name": {
          "description": "Block slug, lowercase letters/numbers/hyphens. Registered as gutenfields/{name}; the template is theme/gutenfields/{name}.php.",
          "type": "string",
          "pattern": "^[a-z0-9][a-z0-9-]*$"
        },
        "title": {
          "description": "Human label shown in the block inserter.",
          "type": "string"
        },
        "description": {
          "description": "Short sentence shown in the inserter.",
          "type": "string"
        },
        "category": {
          "description": "Inserter category. Defaults to \"widgets\".",
          "type": "string",
          "default": "widgets"
        },
        "icon": {
          "description": "Dashicon slug. Optional — auto-derived from the first field's type if omitted.",
          "type": "string"
        },
        "supports": {
          "description": "Block supports. Only align and anchor are honoured on import.",
          "type": "object",
          "properties": {
            "align": {
              "oneOf": [
                { "type": "boolean" },
                {
                  "type": "array",
                  "items": { "enum": ["left", "center", "right", "wide", "full"] }
                }
              ]
            },
            "anchor": { "type": "boolean" }
          },
          "additionalProperties": false
        },
        "fields": {
          "type": "array",
          "items": { "$ref": "#/definitions/field" }
        }
      },
      "additionalProperties": false
    },
    "field": {
      "type": "object",
      "required": ["name", "type"],
      "properties": {
        "name": {
          "description": "Field key, lowercase snake_case. Read in the template with gf_field('name').",
          "type": "string",
          "pattern": "^[a-z0-9_]+$"
        },
        "label": {
          "description": "Label shown in the editor sidebar.",
          "type": "string"
        },
        "type": {
          "description": "Field type. Determines the editor control, the stored value shape and the template helper used to read it.",
          "enum": [
            "text", "textarea", "rich", "number", "range", "email", "url",
            "date", "color", "toggle", "select", "radio", "checkbox",
            "image", "gallery", "file", "link", "repeater", "post", "taxonomy",
            "user", "flexible"
          ]
        },
        "default": {
          "description": "Default value. String for text-like fields, boolean for toggle, number for number/range."
        },
        "min": { "type": "number", "description": "range: minimum. repeater/flexible: minimum rows. gallery: minimum images." },
        "max": { "type": "number", "description": "range: maximum. repeater/flexible: maximum rows. gallery: maximum images." },
        "step": { "type": "number", "description": "range: step increment." },
        "options": {
          "description": "select / radio / checkbox choices.",
          "type": "array",
          "items": {
            "type": "object",
            "required": ["value"],
            "properties": {
              "value": { "type": "string" },
              "label": { "type": "string" }
            },
            "additionalProperties": false
          }
        },
        "rowLabel": { "type": "string", "description": "repeater: singular noun for the 'Add …' button." },
        "layout": { "enum": ["block", "row"], "description": "repeater: editor layout of each row." },
        "subfields": {
          "description": "repeater: the fields repeated in every row. Subfields may themselves be repeaters or flexible fields, nesting up to 5 levels deep; a container past that depth is imported as a plain text field.",
          "type": "array",
          "items": { "$ref": "#/definitions/field" }
        },
        "layouts": {
          "description": "flexible: named layouts a row can choose from.",
          "type": "array",
          "items": {
            "type": "object",
            "required": ["name", "subfields"],
            "properties": {
              "name": { "type": "string", "pattern": "^[a-z0-9_]+$" },
              "label": { "type": "string" },
              "subfields": {
                "type": "array",
                "items": { "$ref": "#/definitions/field" }
              }
            },
            "additionalProperties": false
          }
        },
        "postTypes": {
          "description": "post: post types the relation can point at. Defaults to [\"post\"].",
          "type": "array",
          "items": { "type": "string" }
        },
        "taxonomy": { "type": "string", "description": "taxonomy: the taxonomy to pick terms from. Defaults to \"category\"." },
        "multiple": { "type": "boolean", "description": "post/taxonomy/user: allow selecting more than one entity." },
        "conditions": {
          "description": "Show/hide rules, combined by conditionsLogic. Each entry is either a rule pointing at a SIBLING field by name, or a group with its own list and its own all/any — which is how [A AND B] OR [C] is expressed. Groups nest up to 5 levels.",
          "type": "array",
          "items": { "$ref": "#/definitions/condition" }
        },
        "conditionsLogic": { "enum": ["all", "any"], "default": "all" }
      },
      "additionalProperties": false
    },
    "condition": {
      "description": "One entry in a condition list: a rule, or a nested group of entries.",
      "oneOf": [
        { "$ref": "#/definitions/conditionRule" },
        { "$ref": "#/definitions/conditionGroup" }
      ]
    },
    "conditionRule": {
      "type": "object",
      "required": ["field", "operator"],
      "properties": {
        "field": {
          "description": "Name of a sibling field — another field in the same block, or another subfield in the same repeater row.",
          "type": "string"
        },
        "operator": { "enum": ["==", "!=", "contains", ">", "<", "empty", "notEmpty"] },
        "value": { "type": "string" }
      },
      "additionalProperties": false
    },
    "conditionGroup": {
      "type": "object",
      "required": ["conditions"],
      "properties": {
        "logic": {
          "description": "How this group's own entries combine, independently of the level above it.",
          "enum": ["all", "any"],
          "default": "all"
        },
        "conditions": {
          "type": "array",
          "minItems": 1,
          "items": { "$ref": "#/definitions/condition" }
        }
      },
      "additionalProperties": false
    }
  }
}
