Skip to content

Commit 524b8ca

Browse files
arraypressclaude
andcommitted
Keep the README to a page
Four sections for four features read as documentation, which the README standard sends to the docs site. One example shows them together. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015Kwx2STJ4EaVaJofEJJ9Zo
1 parent 45ca55d commit 524b8ca

1 file changed

Lines changed: 34 additions & 105 deletions

File tree

‎README.md‎

Lines changed: 34 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -61,56 +61,16 @@ echo $set->render();
6161
$set->save( $_POST['my_plugin'] ?? [] );
6262
```
6363

64-
## Validation
65-
66-
Sanitising coerces; it does not refuse. A field that must hold something, or
67-
something of a particular shape, says so. A value that fails is left where it
68-
was — the stored one stays, every other field is saved — and the reason is
69-
kept for the next render:
70-
71-
```php
72-
$set = new FieldSet(
73-
[
74-
'contact' => [ 'type' => 'email', 'label' => __( 'Contact', 'my-plugin' ), 'required' => true ],
75-
'handle' => [ 'type' => 'text', 'label' => __( 'Handle', 'my-plugin' ), 'validate' => 'slug' ],
76-
'api_key' => [
77-
'type' => 'text',
78-
'label' => __( 'API key', 'my-plugin' ),
79-
'validate' => static fn( $value, $field ) => str_starts_with( $value, 'sk_' ) ? true : __( 'An API key starts with sk_.', 'my-plugin' ),
80-
],
81-
'notify' => [ 'type' => 'tags', 'label' => __( 'Notify', 'my-plugin' ), 'validate' => 'email' ],
82-
],
83-
new OptionContext( 'my_plugin' ),
84-
'my_plugin'
85-
);
86-
87-
$set->save( $_POST['my_plugin'] ?? [] );
88-
89-
// Rendered after a save in the same request, each failing field is marked
90-
// and shows its message. errors() has the messages for a notice of your own.
91-
echo $set->render();
92-
```
93-
94-
The rules are `email`, `url`, `numeric`, `integer`, `slug` and `alphanumeric`.
95-
A callable is given the sanitised value and the field, and returns `true`, a
96-
message, or a `WP_Error`. On `tags` and `list` the rule is applied to each
97-
item. To check a submission without storing any of it, `validate()` takes the
98-
same input as `save()` and returns the messages keyed by field.
99-
100-
`required` and `validate` are checked on the set's own fields. A field inside
101-
a group or a repeater row is marked required in the markup, which the browser
102-
enforces, but is not checked on the server.
103-
10464
## Field types
10565

10666
Text and numeric
107-
: `text` `email` `url` `tel` `password` `hidden` `number` `range` `textarea` `code` `wysiwyg` `code_generator`
67+
: `text` `email` `url` `tel` `password` `hidden` `number` `percentage` `range` `textarea` `code` `wysiwyg` `code_generator`
10868

10969
Date, time and colour
11070
: `date` `time` `datetime` `color` `gradient` `date_range` `time_range`
11171

11272
Choice
113-
: `select` `enhanced_select` `select_multiple` `checkbox` `toggle` `radio` `checkbox_group` `button_group` `card_choice` `country` `currency`
73+
: `select` `enhanced_select` `select_multiple` `checkbox` `toggle` `radio` `checkbox_group` `button_group` `card_choice` `country` `region` `currency`
11474

11575
Relational — one search endpoint behind all of them
11676
: `post` `page` `user` `taxonomy` `ajax` `tags`
@@ -127,86 +87,55 @@ Layout and display
12787
Purpose-built
12888
: `license` `email_editor` `action_button`
12989

130-
## Options from a preset
131-
132-
The lists every settings screen ends up needing — the site's roles, its
133-
timezones, its page templates — are presets, and a select asks for one by
134-
name rather than building it again:
135-
136-
```php
137-
use ArrayPress\FieldKit\FieldSet;
138-
use ArrayPress\FieldKit\Context\OptionContext;
139-
140-
$set = new FieldSet(
141-
[
142-
'notify_role' => [ 'type' => 'select', 'label' => __( 'Notify', 'my-plugin' ), 'options' => 'roles' ],
143-
'timezone' => [ 'type' => 'select', 'label' => __( 'Timezone', 'my-plugin' ), 'options' => 'timezones' ],
144-
'country' => [ 'type' => 'country', 'label' => __( 'Country', 'my-plugin' ), 'continents' => true ],
145-
'currency' => [ 'type' => 'currency', 'label' => __( 'Currency', 'my-plugin' ) ],
146-
],
147-
new OptionContext( 'my_plugin' ),
148-
'my_plugin'
149-
);
150-
```
15190

152-
The built-ins are `roles`, `post_types`, `taxonomies`, `pages`, `timezones`,
153-
`image_sizes`, `page_templates`, `cron_schedules`, `countries` and
154-
`currencies`. The last two draw on `arraypress/wp-countries` and
155-
`arraypress/wp-money`; the `country` and `currency` types use them by default.
91+
## Beyond the quick start
15692

157-
A preset is resolved when the field renders, not when it is declared, and its
158-
options pass through the `field_kit_preset_options` filter. Register your own
159-
with `Presets::register( 'products', fn() => $options )` and any field can say
160-
`'options' => 'products'`.
161-
162-
## A unit in the box, a reveal, a count
163-
164-
Any single-line input takes a `prefix` or a `suffix`, drawn inside the box
165-
and announced with the value. A `percentage` is a number from 0 to 100 with
166-
the sign already in it. A password shows what is typed on request, and
167-
anything with a `maxlength` counts as you go.
93+
Sanitising coerces; it does not refuse. `required` and `validate` do the
94+
refusing on the server: a value that fails is left where it was, every other
95+
field is saved, and the message is kept for the next render. Options can name
96+
a preset instead of listing choices. Any single-line input takes a `prefix`
97+
or a `suffix`, a password can be revealed, and a `maxlength` shows a count. A
98+
`region` follows the country beside it.
16899

169100
```php
170101
$set = new FieldSet(
171102
[
103+
'contact' => [ 'type' => 'email', 'label' => __( 'Contact', 'my-plugin' ), 'required' => true ],
104+
'notify' => [ 'type' => 'tags', 'label' => __( 'Notify', 'my-plugin' ), 'validate' => 'email' ],
105+
'api_key' => [
106+
'type' => 'password',
107+
'label' => __( 'API key', 'my-plugin' ),
108+
'reveal' => true,
109+
'validate' => static fn( $value ) => str_starts_with( $value, 'sk_' ) ? true : __( 'An API key starts with sk_.', 'my-plugin' ),
110+
],
111+
'role' => [ 'type' => 'select', 'label' => __( 'Notify role', 'my-plugin' ), 'options' => 'roles' ],
172112
'price' => [ 'type' => 'number', 'label' => __( 'Price', 'my-plugin' ), 'prefix' => '$', 'step' => 0.01 ],
173113
'discount' => [ 'type' => 'percentage', 'label' => __( 'Discount', 'my-plugin' ) ],
174-
'expires' => [ 'type' => 'number', 'label' => __( 'Expires after', 'my-plugin' ), 'suffix' => 'days' ],
175-
'api_key' => [ 'type' => 'password', 'label' => __( 'API key', 'my-plugin' ), 'reveal' => true ],
176114
'tagline' => [ 'type' => 'text', 'label' => __( 'Tagline', 'my-plugin' ), 'maxlength' => 80 ],
115+
'country' => [ 'type' => 'country', 'label' => __( 'Country', 'my-plugin' ), 'continents' => true ],
116+
'region' => [ 'type' => 'region', 'label' => __( 'State or province', 'my-plugin' ), 'country_key' => 'country' ],
117+
'currency' => [ 'type' => 'currency', 'label' => __( 'Currency', 'my-plugin' ) ],
177118
],
178119
new OptionContext( 'my_plugin' ),
179120
'my_plugin'
180121
);
181-
```
182-
183-
## A country and its regions
184122

185-
A `region` is a state, a province or a county. Given a fixed `country` it is
186-
a select over that country's subdivisions, storing the code the way `country`
187-
stores its own. Given `country_key` — the key of the country field beside it
188-
— it follows whatever is chosen there: a select where the country has
189-
subdivisions on file, a text input where it does not, swapped by the script
190-
on load and on every change.
191-
192-
```php
193-
use ArrayPress\FieldKit\FieldSet;
194-
use ArrayPress\FieldKit\Context\OptionContext;
123+
$set->save( $_POST['my_plugin'] ?? [] );
195124

196-
$set = new FieldSet(
197-
[
198-
'country' => [ 'type' => 'country', 'label' => __( 'Country', 'my-plugin' ) ],
199-
'region' => [ 'type' => 'region', 'label' => __( 'State or province', 'my-plugin' ), 'country_key' => 'country' ],
200-
],
201-
new OptionContext( 'my_plugin' ),
202-
'my_plugin'
203-
);
125+
// Rendered after a save in the same request, each failing field is marked
126+
// and shows its message; errors() has them for a notice of your own.
127+
echo $set->render();
204128
```
205129

206-
Without the script the text input is what submits, so a typed code still
207-
saves. Inside a repeater the lookup is scoped to the row, so each row's
208-
region follows that row's country. The subdivisions are WooCommerce's, by
209-
way of `arraypress/wp-countries`.
130+
Rules are `email`, `url`, `numeric`, `integer`, `slug` and `alphanumeric`; a
131+
callable returns `true`, a message or a `WP_Error`; on `tags` and `list` the
132+
rule applies to each item; `validate()` checks without storing. Presets are
133+
`roles`, `post_types`, `taxonomies`, `pages`, `timezones`, `image_sizes`,
134+
`page_templates`, `cron_schedules`, `countries` and `currencies`, resolved on
135+
render and filterable, with `Presets::register()` for your own. Countries and
136+
regions come from `arraypress/wp-countries`, currencies from
137+
`arraypress/wp-money`; a region is a select where the country has
138+
subdivisions on file and a text input where it does not.
210139

211140
## Requirements
212141

0 commit comments

Comments
 (0)