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.
The files
Section titled “The files”Put one file per form at:
{theme}/data/octa-forms/{slug}.jsonBoth 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).
Importing
Section titled “Importing”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):
wp octa-forms theme statuswp octa-forms theme import --all # exits non-zero on any failure, good for CIwp octa-forms theme import --slug=contactwp octa-forms theme import --all --force # also overwrite conflictsStatuses
Section titled “Statuses”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.
Local export (closing the loop)
Section titled “Local export (closing the loop)”On a local or development environment, and only if the directory {child theme}/data/octa-forms/ exists, every save in the form editor also writes the file back. That closes the loop: edit on local, get the file in your repo, commit, deploy, import on production.
Export is off on production, because writing into a theme at runtime is an anti-pattern. Control it with the octa_forms_theme_export_enabled filter.
Filters
Section titled “Filters”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 topublish).octa_forms_theme_export_enabled— the gate for local export.
See Hooks and filters.