Skip to content

Forms in your theme (sync)

You can keep form definitions in your theme’s repository as JSON files and import them into a site. This is similar to ACF’s Local JSON, with one firm rule: it is sync-first. At runtime the database is always the source of truth. The files are a versioned developer artifact, and the runtime never reads them.

That distinction matters. All validation, including the safety check on webhook URLs, runs when a config is saved to the database. It does not run on a file sitting in your repo. Import is the only path in.

Put one file per form at:

{theme}/data/octa-forms/{slug}.json

Both the child and parent theme are scanned, and the child wins for a given slug. The file name is the form’s slug, and it must equal sanitize_title(name).

Each file is an envelope with a title and the config:

{
"title": "Contact",
"config": {
"fields": [ /* … */ ],
"email": { /* … */ },
"settings": { /* … */ }
}
}

The config is exactly the shape stored in the database, without title (that comes from the envelope).

In the admin, go to OctaForms → Developer and use the theme sync section. It shows a status table with Import and Import all buttons.

On a deploy, use WP-CLI (see WP-CLI):

Terminal window
wp octa-forms theme status
wp octa-forms theme import --all # exits non-zero on any failure, good for CI
wp octa-forms theme import --slug=contact
wp octa-forms theme import --all --force # also overwrite conflicts

Status is detected by comparing a hash of the config, not by file dates:

Status Meaning
New No form for this slug yet. Import will create it.
In sync File and database match.
File newer The file changed. A safe import.
Database changed Edited in the admin since the last import.
Conflict Both sides changed. Import overwrites the database, with a one-step undo saved.
Not linked A form with this slug exists but was created independently of the file.
Database only No file. Nothing to import.

Import never deletes anything. Deleting a file leaves the form in the database untouched.

Sync runs one way, from the file into the database. The plugin never writes into your theme.

To move a change you made in the admin back into your repo, open the form editor, copy the raw JSON from the config textarea, and paste it into the config key of the theme file. The next status check will report the two sides as in sync again.

An export file works too. Each entry of its forms list has the same title and config as a theme file, so you can copy an entry into data/octa-forms/{slug}.json and drop its slug key. The export leaves out webhook secrets, so add them back if the form’s webhooks are on.

  • octa_forms_theme_form_dirs — the directories scanned for files.
  • octa_forms_theme_import_status — the status given to forms created by an import (defaults to publish).

See Hooks and filters.