Skip to content

Commit 9e89978

Browse files
arraypressclaude
andcommitted
Mark a required heading, and say "Settings saved." once
The kit marks a required field in the label it draws; this class draws the label in the header cell, so the mark never appeared. Under the Settings menu core prints the settings notices itself -- admin.php pulls in options-head.php for every child of options-general.php -- and printing them here as well said "Settings saved." twice. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015Kwx2STJ4EaVaJofEJJ9Zo
1 parent d71696c commit 9e89978

3 files changed

Lines changed: 61 additions & 5 deletions

File tree

‎src/SettingFields.php‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@
2121
use ArrayPress\FieldKit\Field;
2222
use ArrayPress\FieldKit\FieldSet;
2323
use ArrayPress\FieldKit\Support\Badge;
24+
use ArrayPress\FieldKit\Support\Markup;
25+
use ArrayPress\FieldKit\Support\PageHeader;
2426
use ArrayPress\FieldKit\Support\Sections;
2527
use ArrayPress\FieldKit\Support\Tooltip;
26-
use ArrayPress\FieldKit\Support\PageHeader;
2728

2829
/**
2930
* Registers a tabbed settings page backed by a single option.
@@ -661,8 +662,13 @@ public function render_page(): void {
661662
// No argument: core adds its own "Settings saved." under the `general`
662663
// slug, and asking for this page's slug alone would hide it. A field
663664
// the last save refused is printed here as well, and again under the
664-
// field itself.
665-
settings_errors();
665+
// field itself. Not under the Settings menu, though: admin.php pulls
666+
// in options-head.php for every child of options-general.php, and
667+
// that prints them already -- so a page there said "Settings saved."
668+
// twice.
669+
if ( 'options-general.php' !== (string) $this->config['parent_slug'] ) {
670+
settings_errors();
671+
}
666672

667673
printf( '<form method="post" action="%s">', esc_url( admin_url( 'options.php' ) ) );
668674

@@ -846,16 +852,22 @@ private function render_rows( FieldSet $set, array $fields, array $errors ): voi
846852
// Beside the heading, which this class draws rather than the kit.
847853
$tooltip = Tooltip::for_field( $field );
848854

855+
// The kit marks a required field in the label it draws; this class
856+
// draws the label, so it marks it here.
857+
$required = Markup::required_marker( $field->is_required() );
858+
849859
$header = $type->is_self_labelling() || $type->is_grouped()
850860
? sprintf(
851-
'<span class="field-kit__row-label">%s%s</span>',
861+
'<span class="field-kit__row-label">%s%s%s</span>',
852862
esc_html( $field->label() ),
863+
$required, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- the kit escapes as it builds.
853864
$badge . $tooltip // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped as it is built.
854865
)
855866
: sprintf(
856-
'<label for="%s">%s</label>%s',
867+
'<label for="%s">%s%s</label>%s',
857868
esc_attr( $field->input_id() ),
858869
esc_html( $field->label() ),
870+
$required, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- the kit escapes as it builds.
859871
$badge . $tooltip // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped as it is built.
860872
);
861873

‎tests/SettingFieldsTest.php‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,4 +1366,47 @@ public function test_the_type_helpers_delegate(): void {
13661366
$this->assertFalse( is_setting_on( $page->get_id(), 'flag' ) );
13671367
}
13681368

1369+
/**
1370+
* A required field says so in the heading this class draws.
1371+
*/
1372+
public function test_a_required_field_is_marked_in_its_heading(): void {
1373+
$page = $this->page(
1374+
[
1375+
'fields' => [
1376+
'store_name' => [ 'type' => 'text', 'label' => 'Store name', 'required' => true ],
1377+
'tagline' => [ 'type' => 'text', 'label' => 'Tagline' ],
1378+
],
1379+
]
1380+
);
1381+
1382+
ob_start();
1383+
$page->render_page();
1384+
$html = (string) ob_get_clean();
1385+
1386+
$this->assertMatchesRegularExpression( '/<label for="[^"]*store_name[^"]*">Store name<span class="field-kit__required" aria-hidden="true">\*<\/span>/', $html );
1387+
$this->assertDoesNotMatchRegularExpression( '/Tagline<span class="field-kit__required"/', $html );
1388+
}
1389+
1390+
/**
1391+
* Under the Settings menu core prints the notices; printing them here as
1392+
* well said "Settings saved." twice.
1393+
*/
1394+
public function test_notices_are_not_printed_twice_under_the_settings_menu(): void {
1395+
$GLOBALS['sf_settings_errors_calls'] = 0;
1396+
1397+
$page = $this->page( [ 'parent_slug' => 'options-general.php' ] );
1398+
ob_start();
1399+
$page->render_page();
1400+
ob_end_clean();
1401+
1402+
$this->assertSame( 0, $GLOBALS['sf_settings_errors_calls'] );
1403+
1404+
$page = $this->page( [ 'parent_slug' => '' ] );
1405+
ob_start();
1406+
$page->render_page();
1407+
ob_end_clean();
1408+
1409+
$this->assertSame( 1, $GLOBALS['sf_settings_errors_calls'] );
1410+
}
1411+
13691412
}

‎tests/stubs.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ function get_settings_errors( $setting = '', $sanitize = false ) {
147147

148148
if ( ! function_exists( 'settings_errors' ) ) {
149149
function settings_errors( $setting = '', $sanitize = false, $hide_on_update = false ) {
150+
$GLOBALS['sf_settings_errors_calls'] = ( $GLOBALS['sf_settings_errors_calls'] ?? 0 ) + 1;
150151
foreach ( get_settings_errors( $setting ) as $error ) {
151152
printf( '<div class="notice notice-%s"><p>%s</p></div>', esc_attr( $error['type'] ), esc_html( $error['message'] ) );
152153
}

0 commit comments

Comments
 (0)