Skip to content

Commit 9debca7

Browse files
arraypressclaude
andcommitted
Rewrite the README to the standard
Leads with the problem rather than the API, features are things you can do, and there is one example instead of an inline reference. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tk8y5eZa3CHVVSM6nVxsJw
1 parent fba5097 commit 9debca7

1 file changed

Lines changed: 37 additions & 174 deletions

File tree

‎README.md‎

Lines changed: 37 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
1-
# WordPress Register Setting Fields
1+
# Register Setting Fields
22

3-
Settings pages for the WordPress admin, from a field configuration.
3+
A settings page from a list of fields — the menu, the tabs, the saving and
4+
the sanitising included.
45

5-
Registration, rendering, sanitization and the Settings API are handled; you describe the fields. Every type comes from
6-
[wp-field-kit](https://github.com/arraypress/wp-field-kit), so the same configuration renders the same control here, in
7-
a metabox, on a term screen or in a flyout.
6+
## What it does
87

9-
## Features
8+
A settings screen in WordPress is `add_menu_page`, `register_setting`,
9+
`add_settings_section`, `add_settings_field` and a sanitise callback per
10+
field, repeated until it works. Most of it is the same every time, and the
11+
part that varies is just the list of fields.
1012

11-
- Every field type the kit has — sixty-odd, from text to a repeater to an email editor
12-
- Tabs and sections, with the tab remembered in the URL
13-
- A branded header with a logo, badge and whatever you want beside it
14-
- Conditional fields, encrypted values, and constants that override an option
15-
- Reset, export and import, when you want them
16-
- Values readable through helpers that know what a field meant, not just what it stored
13+
This takes the list. The menu, the tabs, the form, the nonce, the saving and
14+
the per-type sanitising follow from it.
1715

18-
## Requirements
16+
## Features
1917

20-
- PHP 7.4+
21-
- WordPress 5.8+
18+
* Get a settings page from a list of fields, with no `add_settings_field` calls
19+
* Group fields into tabs and sections, saving one tab without touching others
20+
* Read and write a value by name, without knowing how the option is shaped
21+
* Sanitise per field type, rather than writing a callback for each
22+
* Encrypt a field, so an API key is not stored in the clear
23+
* Export, import and reset from Screen Options
24+
* Show a field only when another is set
2225

2326
## Installation
2427

@@ -30,175 +33,35 @@ composer require arraypress/wp-register-setting-fields
3033

3134
```php
3235
register_setting_fields( 'my_plugin', [
33-
'page_title' => __( 'My Plugin Settings', 'my-plugin' ),
34-
'menu_title' => __( 'My Plugin', 'my-plugin' ),
35-
'parent_slug' => 'options-general.php',
36-
'fields' => [
37-
'site_name' => [ 'type' => 'text', 'label' => __( 'Site name', 'my-plugin' ) ],
38-
'enable_feature' => [ 'type' => 'toggle', 'label' => __( 'Enable feature', 'my-plugin' ) ],
39-
'items_per_page' => [
40-
'type' => 'number',
41-
'label' => __( 'Items per page', 'my-plugin' ),
42-
'min' => 1,
43-
'max' => 100,
44-
],
45-
],
36+
'page_title' => __( 'My Plugin Settings', 'my-plugin' ),
37+
'menu_title' => __( 'My Plugin', 'my-plugin' ),
38+
'parent_slug' => 'options-general.php',
39+
'fields' => [
40+
'site_name' => [ 'type' => 'text', 'label' => __( 'Site name', 'my-plugin' ) ],
41+
'enable_feature' => [ 'type' => 'toggle', 'label' => __( 'Enable feature', 'my-plugin' ) ],
42+
'items_per_page' => [
43+
'type' => 'number',
44+
'label' => __( 'Items per page', 'my-plugin' ),
45+
'min' => 1,
46+
'max' => 100,
47+
],
48+
],
4649
] );
4750
```
4851

49-
Reading them back:
52+
Then reading one, anywhere:
5053

5154
```php
5255
$name = get_setting_field_value( 'my_plugin', 'site_name' );
53-
54-
if ( is_setting_on( 'my_plugin', 'enable_feature' ) ) {
55-
// ...
56-
}
57-
```
58-
59-
## Registration
60-
61-
```php
62-
register_setting_fields( 'my_plugin', [
63-
'page_title' => __( 'My Plugin Settings', 'my-plugin' ),
64-
'menu_title' => __( 'My Plugin', 'my-plugin' ),
65-
'menu_slug' => 'my-plugin',
66-
'parent_slug' => 'options-general.php',
67-
'capability' => 'manage_options',
68-
'option_name' => 'my_plugin',
69-
'icon' => 'dashicons-admin-generic',
70-
'position' => null,
71-
'submit_button' => true,
72-
'reset_button' => false,
73-
'export_import' => false,
74-
'tabs' => [ /* ... */ ],
75-
'sections' => [ /* ... */ ],
76-
'fields' => [ /* ... */ ],
77-
] );
78-
```
79-
80-
| Key | What it does |
81-
| --- | --- |
82-
| `page_title` / `menu_title` | The page's heading and its menu entry. |
83-
| `menu_slug` | The page slug. Defaults to the id. |
84-
| `parent_slug` | Where it sits. A top-level menu when empty. |
85-
| `capability` | Who may see it. Defaults to `manage_options`. |
86-
| `option_name` | The option every value is stored in. Defaults to the id. |
87-
| `option_group` | The Settings API group. Defaults to `{id}_group`. |
88-
| `constant_prefix` | Constants that override stored values. Defaults to `{option_name}_`. |
89-
| `header_title`, `logo`, `badge` | A branded header instead of the plain one. |
90-
| `icon`, `position` | Menu icon and position, for a top-level page. |
91-
| `submit_button` | Whether to draw one. |
92-
| `reset_button` | A "restore defaults" button. |
93-
| `export_import` | Buttons to download and upload the settings as JSON. |
94-
| `help_tabs`, `help_sidebar` | Contextual help, in core's own panel. |
95-
96-
## Tabs and sections
97-
98-
A field says which tab and which section it belongs to. Both are optional and can be mixed.
99-
100-
```php
101-
register_setting_fields( 'my_plugin', [
102-
'tabs' => [
103-
'general' => __( 'General', 'my-plugin' ),
104-
'advanced' => __( 'Advanced', 'my-plugin' ),
105-
],
106-
'sections' => [
107-
'branding' => [
108-
'title' => __( 'Branding', 'my-plugin' ),
109-
'description' => __( 'How it looks.', 'my-plugin' ),
110-
],
111-
],
112-
'fields' => [
113-
'site_name' => [
114-
'type' => 'text',
115-
'label' => __( 'Site name', 'my-plugin' ),
116-
'tab' => 'general',
117-
'section' => 'branding',
118-
],
119-
'debug' => [
120-
'type' => 'toggle',
121-
'label' => __( 'Debug mode', 'my-plugin' ),
122-
'tab' => 'advanced',
123-
],
124-
],
125-
] );
126-
```
127-
128-
## Conditional fields
129-
130-
```php
131-
'fields' => [
132-
'mode' => [
133-
'type' => 'select',
134-
'label' => __( 'Mode', 'my-plugin' ),
135-
'options' => [ 'auto' => __( 'Automatic', 'my-plugin' ), 'manual' => __( 'Manual', 'my-plugin' ) ],
136-
],
137-
'api_key' => [
138-
'type' => 'password',
139-
'label' => __( 'API key', 'my-plugin' ),
140-
'depends' => [ 'mode' => 'manual' ],
141-
],
142-
],
14356
```
14457

145-
The field is removed from the tab order when hidden, not merely made invisible.
58+
Field types come from `arraypress/wp-field-kit`, so anything it renders can go
59+
in a settings page.
14660

147-
## Encrypted values
148-
149-
```php
150-
'api_secret' => [
151-
'type' => 'password',
152-
'label' => __( 'API secret', 'my-plugin' ),
153-
'encrypted' => true,
154-
],
155-
```
156-
157-
Stored encrypted, refused REST exposure, and decrypted on the way back out through `get_setting_field_value()`.
158-
159-
## Constants
160-
161-
Any value can be overridden by a constant, which is how a secret stays out of the database on a production install.
162-
163-
```php
164-
// In wp-config.php:
165-
define( 'MY_PLUGIN_API_KEY', 'sk-live-...' );
166-
```
167-
168-
`get_setting_field_value( 'my_plugin', 'api_key' )` returns the constant, and the field renders read-only with a note
169-
saying where the value came from.
170-
171-
## Reading values
172-
173-
| Function | Returns |
174-
| --- | --- |
175-
| `get_setting_field_value( $id, $key, $fallback = null )` | One value, with its default and any constant applied. |
176-
| `get_all_setting_values( $id )` | Everything, keyed by field. |
177-
| `is_setting_on( $id, $key )` | Whether a toggle or checkbox is on. |
178-
| `is_setting_enabled( $id, $key, $option )` | Whether an option is among a multiple field's values. |
179-
| `get_setting_field_list( $id, $key )` | A list field's values as an array. |
180-
| `get_setting_field_ids( $id, $key )` | A relational field's ids, as integers. |
181-
| `get_setting_field_page_url( $id, $key )` | The permalink of a page a field points at. |
182-
| `is_setting_field_page( $id, $key )` | Whether the current request is that page. |
183-
| `update_setting_field_value( $id, $key, $value )` | Write one, sanitized by its own type. |
184-
| `delete_setting_field_value( $id, $key )` | Remove one, so it falls back to its default. |
185-
186-
Email and licence fields have their own: `get_setting_fields_email()`, `is_setting_fields_email_enabled()`,
187-
`get_setting_field_license_status()`, `is_setting_field_license_active()`.
188-
189-
## Custom sanitization
190-
191-
A field's type sanitizes it. Supply a callback to replace that entirely:
192-
193-
```php
194-
'slug' => [
195-
'type' => 'text',
196-
'label' => __( 'Slug', 'my-plugin' ),
197-
'sanitize_callback' => fn( $value ) => sanitize_title( $value ),
198-
],
199-
```
61+
## Requirements
20062

201-
The callback receives the raw value, not one the type has already cleaned.
63+
* PHP 8.3 or later
64+
* WordPress 7.1 or later
20265

20366
## License
20467

0 commit comments

Comments
 (0)