You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit be2edf7
Browse filesBrowse the repository at this point in the historyBrowse files
They described the library before the port: a branded header that no longer
exists in that shape, an `encryption` config block that was replaced by a
per-field flag, AES-256-CBC where it is now GCM, eight REST endpoints that
were deleted, and an export that promised to decrypt values it now refuses
to include at all.
A doc describing a deleted API is worse than no doc, because it is the one
thing someone trusts before reading the code.
Corrected across home, reset-export-import, badges, the configuration
reference, the common field options and the sidebar. The three that were
already rewritten — registration, header, encryption, rest-api — are
unchanged.
Two things worth having written down that were not before: a badge's
`disabled` reads backwards on purpose, because it answers "does this
install already have the feature"; and a locked field is skipped on save
entirely, because a disabled control sends nothing and a save path that
iterates its field list would read that as cleared — wiping the premium
settings of any install whose licence lapsed.
@@ -56,8 +56,23 @@ Add a `badge` to a section definition. When the badge is visible, all fields in
56
56
],
57
57
```
58
58
59
-
The section title and badge remain fully visible and clickable (for upgrade links) even when the section's fields are
60
-
dimmed and disabled.
59
+
The section title and badge stay visible and clickable — that is the point of an upgrade link — while the fields under them are disabled.
60
+
61
+
## A locked field keeps its value
62
+
63
+
A disabled control sends nothing, and a save path that iterates its field list rather than the submission reads "nothing" as "cleared". So a locked field is **skipped on save entirely**.
64
+
65
+
Without that, an install whose licence lapsed would have its premium settings wiped by the next unrelated save, and get them back as blanks when the licence returned. The same applies to a field carrying `'disabled' => true` directly.
66
+
67
+
## The condition reads backwards on purpose
68
+
69
+
`disabled`**hides** the badge. It answers "does this install already have the feature?" — true means yes, so there is nothing to sell and nothing to lock:
Copy file name to clipboardExpand all lines: docs/home.md
+9-13Lines changed: 9 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,20 +1,16 @@
1
1
# WordPress Register Setting Fields
2
2
3
-
A WordPress library for creating settings pages with tabs, sections, branded headers, and 30+ field types. Handles registration, rendering, sanitization, and the Settings API — you just define your fields.
3
+
A WordPress library for creating tabbed settings pages. Registration, the menu, the Settings API wiring and export/import live here; every field is rendered, sanitized and made accessible by [wp-field-kit](https://github.com/arraypress/wp-field-kit), which the term, post, user and list-table libraries share.
4
4
5
5
## Features
6
6
7
-
-**30+ field types** — text, number, select, AJAX search, toggles, color pickers, image/file/gallery, WYSIWYG, code editors, and more
8
-
-**Relational fields** — post, page, taxonomy, and user selects with Select2 and AJAX search
-**Tabs & sections** — organize fields into tabbed pages with collapsible sections
11
-
-**Branded header** — logo, title, badge, and integrated tab navigation
12
-
-**Conditional fields** — show/hide fields based on other field values with 12 operators
13
-
-**Encryption** — transparent AES-256-CBC encryption for sensitive fields with constant fallback
14
-
-**Email editor** — full email template editor with merge tags, preview, and send test — integrates with `wp-register-emails`
15
-
-**License field** — license key activation/deactivation with REST callbacks and status persistence
16
-
-**Sanitization** — built-in sanitizers for every field type, extensible via callbacks and filters
17
-
-**Hooks** — filters and actions at every stage of the lifecycle
7
+
-**50+ field types** — text, number, select, searchable and creatable selects, AJAX search, toggles, colour pickers, image/file/gallery, WYSIWYG, code editors, repeaters (stacked or as a table), groups, email panels, licence keys, action buttons, sortable lists
8
+
-**Core's own header** — the shape `options-privacy.php` uses, so it matches the admin and follows the user's colour scheme, with an optional logo and badge
9
+
-**Tabs & sections** — saving one tab leaves the others alone, which is the bug a tabbed settings page has if nobody thinks about it
10
+
-**Conditional fields** — show or hide based on other fields; a hidden field is deleted on save rather than keeping a stale value
11
+
-**Encryption** — AES-256-GCM for any field type, keyed from the site's own salts, with a constant fallback
12
+
-**Every write sanitized** — `update_option()` runs the registered callback before it compares, so a value written by a cron job, an importer or another plugin passes through its own field type exactly as a submitted one does
13
+
-**Accessible by construction** — labels, descriptions, required state and grouping are the renderer's job, so no field type can forget them
18
14
-**Helper functions** — `get_setting_field_value()`, `is_setting_on()`, `is_setting_field_license_active()`, and more
Copy file name to clipboardExpand all lines: docs/reset-export-import.md
+20-26Lines changed: 20 additions & 26 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,8 +1,12 @@
1
1
# Reset & Export/Import
2
2
3
-
## Reset Button
3
+
These three live in the **Screen Options** panel, which opens next to Help. They are a screen's occasional controls, not something to read past on every visit — and Screen Options is a panel WordPress already provides rather than a row of buttons across the page title.
4
4
5
-
Adds a "Reset to Defaults" button next to Submit. When tabs are present, only fields on the current tab are reset.
5
+
Each is a form posting to `admin-post.php` with a nonce, not a link. They change state, and a link that changes state can be followed by a prefetch or a crawler.
6
+
7
+
## Reset
8
+
9
+
Restores every setting on the tab being viewed to its default.
When viewing the General tab, clicking reset restores only `site_name` to `'My Site'`. The Advanced tab's `cache_ttl` is untouched.
35
+
When viewing the General tab, resetting restores only `site_name` to `'My Site'`. The Advanced tab's `cache_ttl` is untouched.
32
36
33
-
A confirm dialog is shown before any reset occurs.
37
+
A reset removes the stored keys rather than writing defaults over them: a field with no stored value renders its configured default, so removing the key *is* the reset. A confirmation is shown first.
34
38
35
39
## Export/Import
36
40
@@ -49,30 +53,26 @@ Clicking **Export Settings** downloads a JSON file named `{settings_id}-settings
49
53
50
54
```json
51
55
{
52
-
"settings_id": "my_plugin",
56
+
"id": "my_plugin",
53
57
"version": 1,
54
-
"exported_at": "2025-06-15 10:30:00",
55
-
"data": {
58
+
"values": {
56
59
"site_name": "My Site",
57
-
"cache_ttl": 3600,
58
-
"api_key": "sk-live-abc123"
60
+
"cache_ttl": 3600
59
61
}
60
62
}
61
63
```
62
64
63
-
Encrypted fields are exported **decrypted** so the file works across environments with different encryption keys.
64
-
65
-
Fields skipped during export: layout fields (`message`, `html`, `separator`, `heading`), `hidden`, `action_button`, `clipboard`, and any field whose value comes from a PHP constant.
65
+
**Encrypted fields are left out entirely.** The key is derived from the site's own salts, so an encrypted value cannot be read anywhere else — exporting it would put a credential in a file for no benefit at all. See [Encryption](advanced/encryption.md).
66
66
67
67
### Import
68
68
69
-
Clicking **Import Settings** opens a file picker. After selecting a `.json` file, a confirm dialog is shown. On confirm:
69
+
Core's own import form — a `.wp-upload-form` with a visible label, the upload limit beside it and a plain file input, the same shape `wp_import_upload_form()` produces on `import.php`.
70
70
71
-
1. The `settings_id` in the file is validated against the current settings page
72
-
2. Each value is run through the standard field sanitizer
73
-
3. Encrypted fields are re-encrypted with the current environment's key
74
-
4. Values are merged with existing options (fields not in the file are preserved)
75
-
5. The page reloads
71
+
On upload:
72
+
73
+
1. The `id` in the file is checked against this settings page, and a file from another page is refused by name.
74
+
2. The values are handed to `update_option()`, which means they pass through this page's registered sanitize callback like every other write — each value sanitized by its own field type.
75
+
3. A key that is not a field on this page is dropped there rather than becoming part of the option. An uploaded file is untrusted input, and this is where that is enforced.
| POST |`/setting-fields/v1/reset`| Reset fields to defaults |
92
-
| GET |`/setting-fields/v1/export`| Export settings as JSON |
93
-
| POST |`/setting-fields/v1/import`| Import settings from JSON |
87
+
### Not REST
94
88
95
-
All three require `manage_options` capability (or the filtered equivalent).
89
+
These are forms posting to `admin-post.php`, not REST routes. An earlier version registered `/reset`, `/export` and `/import` endpoints; a state change driven from a page that already has a form and a nonce does not need one.
0 commit comments