Skip to content

Dry-run, strict & warnings

Every write can be checked before it happens. Two control keys and a structured warnings list make that possible.

"_dry_run": true resolves and validates the whole document but writes nothing to the database. The response tells you exactly what would happen, including create vs update, the resolved record ID, and every warning.

  • On the REST API, add _dry_run to preview.
  • In the bulk importer, a dry-run always runs first, and nothing is written until you confirm.
  • In the editor panel, a dry-run preview is shown before each save.

Use it as the default first step for any automated write.

"_strict": true turns any warning into a hard failure. If validation raises any warning, the whole document is rejected and nothing is written. This is recommended for automation, where a silent octa_unknown_field (for example, a typo’d field name) should stop the write rather than quietly drop a value.

Without _strict, warnings are informational and the write proceeds.

An update that would not change anything is skipped. If every key in the document already matches the stored record, nothing is written: no save hooks run and the record’s modification date stays as it was. Your sitemap lastmod values keep pointing at pages that really changed, and re-importing the same package is safe.

Every response carries "unchanged", which is true only for such a skipped update. Updates also list the keys they would change in "changes", for example ["title", "seo.title", "fields.hero_section"]. A dry-run shows the same information before anything is written, so you can spot an import that would undo someone’s edit on the site.

{ "success": true, "action": "updated", "id": 123, "unchanged": true, "changes": [] }

When a record does change, only the custom fields that differ are written; the others are left alone.

Order counts where WordPress stores it: reordered repeater rows or relation lists are a change, and so are reordered terms in a taxonomy that keeps their order. A draft whose date was never set keeps it floating unless the document sets a different date. WordPress moves a floating date to the moment of each save, so any update that writes such a draft lists date in changes too.

The action stays updated, so existing integrations keep working. The comparison runs against the database at the moment of the write, never against an earlier preview. When the plugin cannot compare a value with certainty, it treats it as a change and writes.

To write anyway, add "_force": true. Use it when you deliberately want the save hooks to run again, for example to rebuild an SEO plugin’s index.

Every dry-run and every write returns a list of structured warnings.

{ "code": "octa_unknown_field", "path": "fields.hero.headng", "message": "…" }

Each warning has a machine-readable code, a path into the document, and a human message. A clean document produces an empty list.

Code Meaning
octa_unknown_key A top-level key without _ that isn’t recognised, often a typo. Its value is not saved.
octa_unknown_control_key An unrecognised _* control key.
octa_unknown_field A fields key not present in the field definition. Value dropped.
octa_unknown_layout A flexible-content layout that isn’t defined. That section is not saved.
octa_term_not_found A taxonomy term slug that doesn’t exist. Assignment skipped.
octa_relation_not_found A relation target that doesn’t exist. Skipped.
octa_parent_not_found The referenced parent doesn’t exist. No fallback to root.
octa_slug_adjusted The slug collided and was auto-suffixed.
octa_status_adjusted The requested status was downgraded, for example with no publish capability.
octa_author_skipped The author couldn’t be set, for lack of capability.

An ideal document produces zero warnings in the preview.

For identity errors like octa_not_found and octa_slug_ambiguous, see Record identity.