Skip to content

Preparing JSON files

Each file is a single JSON object, one canonical document. The safest way to start is to export a pattern record and change its values, so the shape is guaranteed correct.

Set identity deliberately. See Record identity for the full rules.

  • New record. Omit id and _match, and give a new unique slug (and parent for hierarchical types).
  • Update. Keep the existing record’s slug (and parent), or use _match.id.

For hierarchical types such as pages and hierarchical CPTs, always set parent, because identity is the pair (parent, slug).

fields is a map of field name to value, mirroring the pattern file exactly. These are ACF fields, and the theme defines the names.

"fields": {
"hero_section": { "heading": "Hero heading", "description": "Hero copy." },
"intro_section": {
"heading": "Intro heading",
"points": [ { "point": "Point 1" }, { "point": "Point 2" } ]
}
}
  • A group is a nested object, a repeater is a list of row objects, and a simple field is a string, number or boolean.
  • Key names must match the pattern, including sub-keys inside repeaters, groups and flexible content. A renamed key raises octa_unknown_field and is dropped.
  • Don’t add fields that aren’t in the pattern. Omit what you don’t fill in.
  • Repeaters use the same keys as the pattern row, and you can add or remove rows freely.
  • Flexible content may gain more sections, but only using layouts that already exist in the pattern. The acf_fc_layout must match a defined layout. An invented layout raises octa_unknown_layout.

A relation field (post object or relationship) is written as a list of "{post_type}/{slug}" strings.

"fields": { "related_offers": ["offer/service-5", "offer/service-7"] }

It works recursively, inside groups and repeater rows. A missing target is skipped with octa_relation_not_found. A plain-text field that merely contains a /, such as a URL, is left alone, because detection is by field type, not content.

A map of taxonomy slug to a list of term slugs, for posts only.

"taxonomies": { "category": ["news"], "series": ["series-x"] }
  • Only existing terms are assigned, whether in the database or in the same batch as separate term files. An unknown term raises octa_term_not_found. Bulk import does not create terms from this field, so add a term file to the batch instead.
  • Replace per taxonomy. The list is authoritative, [] detaches all, and a taxonomy not in the map is left untouched.
  • Use slugs, not IDs.

The block is plugin-neutral. Octa Editor maps it to Yoast or Rank Math.

"seo": { "title": "SEO title", "description": "SEO description." }
  • Omit for no change. "" or null clears the override and returns to the SEO plugin’s default template.
  • Write template variables in the active plugin’s syntax. Check _meta.providers.seo in the pattern file. Yoast uses %%title%%, and Rank Math uses %title%.
  • Plain text only. HTML in seo.* is stripped.
  • Don’t add a _meta block to new files. It’s read-only export data, ignored on import.
  • Don’t rename field keys or change group and repeater structure against the pattern.
  • Don’t reuse the same slug under the same parent in two files of one batch.
  • Don’t wrap the JSON in code fences or add comments. The file must be exactly one JSON object.
{
"type": "post",
"post_type": "page",
"status": "publish",
"title": "New implementation service",
"slug": "new-implementation-service",
"parent": "services",
"menu_order": 3,
"seo": { "title": "", "description": "Implementations from analysis to hand-off." },
"fields": {
"hero_section": {
"heading": "New implementation service",
"description": "End-to-end implementations, from analysis to hand-off."
},
"related_offers": ["offer/service-5"]
},
"content": ""
}
{
"type": "term",
"taxonomy": "series",
"title": "Implementation series",
"slug": "implementation-series",
"description": "A series about implementations.",
"fields": {}
}