fix: neutral hint form for remaining client-facing tool mentions, Limits bounds accessor
Fix round 1 (task 10 review): - FieldValidator's "unknown field" validation error (reaches the client via validation_failed's fields) and PostPresenter's DIVI_HINT (surfaced in the result's hints array) still named lit-content-types/lit-content-update as plain lit-<name>; converted both to the neutral "lit/<name> (direkt: lit-<name>)" form like the other hints from task 10. Re-grepped src/ for any other client-facing error/field/hints text naming a direct-by-default tool as lit-<name> (descriptions/schemas excluded per Q11c) - none left. - Added Limits::bounds() (field => [min, max]) and made LimitsTab use it for the number inputs' min/max instead of a second, hardcoded copy of the same bounds. - LimitsTab now shows a description note when the configured upload_mb exceeds wp_max_upload_size() (PHP's upload_max_filesize/post_max_size), since WordPress would refuse a larger upload before this limit ever applies. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
+29
-5
@@ -40,16 +40,18 @@ final class LimitsTab implements AdminTab
|
||||
public function render(): void
|
||||
{
|
||||
$values = (new Limits())->all();
|
||||
$fields = [
|
||||
'upload_mb' => [__('Maximale Upload-/Download-Größe (MB)', 'wp-lit-mcp'), 1, 100],
|
||||
'log_retention_days' => [__('Protokoll aufbewahren (Tage)', 'wp-lit-mcp'), 1, 3650],
|
||||
'snapshot_count' => [__('Anzahl Designsystem-Snapshots (ab Etappe 4)', 'wp-lit-mcp'), 1, 100],
|
||||
$bounds = Limits::bounds();
|
||||
$labels = [
|
||||
'upload_mb' => __('Maximale Upload-/Download-Größe (MB)', 'wp-lit-mcp'),
|
||||
'log_retention_days' => __('Protokoll aufbewahren (Tage)', 'wp-lit-mcp'),
|
||||
'snapshot_count' => __('Anzahl Designsystem-Snapshots (ab Etappe 4)', 'wp-lit-mcp'),
|
||||
];
|
||||
|
||||
echo '<form method="post" action="options.php">';
|
||||
settings_fields(self::GROUP);
|
||||
echo '<table class="form-table"><tbody>';
|
||||
foreach ($fields as $key => [$label, $min, $max]) {
|
||||
foreach ($labels as $key => $label) {
|
||||
[$min, $max] = $bounds[$key];
|
||||
printf(
|
||||
'<tr><th scope="row"><label for="lit-mcp-%1$s">%2$s</label></th><td>'
|
||||
. '<input id="lit-mcp-%1$s" type="number" min="%3$d" max="%4$d" name="%5$s[%1$s]" value="%6$d">'
|
||||
@@ -63,7 +65,29 @@ final class LimitsTab implements AdminTab
|
||||
);
|
||||
}
|
||||
echo '</tbody></table>';
|
||||
$this->maybeRenderUploadSizeNotice($values['upload_mb']);
|
||||
submit_button();
|
||||
echo '</form>';
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP's own upload_max_filesize/post_max_size (via wp_max_upload_size()) can be lower than
|
||||
* what is configured here – WordPress itself would then refuse a large upload/download before
|
||||
* this limit ever applies. A warning only, since the two are independent knobs.
|
||||
*/
|
||||
private function maybeRenderUploadSizeNotice(int $uploadMb): void
|
||||
{
|
||||
$serverMaxMb = (int) floor(wp_max_upload_size() / (1024 * 1024));
|
||||
if ($serverMaxMb <= 0 || $uploadMb <= $serverMaxMb) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message = sprintf(
|
||||
/* translators: 1: configured limit in MB, 2: server limit in MB */
|
||||
__('%1$d MB übersteigt das Server-Limit von %2$d MB (upload_max_filesize/post_max_size).', 'wp-lit-mcp'),
|
||||
$uploadMb,
|
||||
$serverMaxMb
|
||||
);
|
||||
printf('<p class="description">%s</p>', esc_html($message));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class PostPresenter
|
||||
public const DIVI_HINT = 'Dieser Inhalt ist mit Divi gebaut. Die Divi-Struktur wird über lit-divi-outline '
|
||||
. 'gelesen und mit den lit-divi-*-Tools bearbeitet; fehlen diese Tools, kann der Divi-Inhalt hier nicht '
|
||||
. 'bearbeitet werden. content wird deshalb nicht ausgegeben; Titel, Auszug, Felder und Begriffe sind '
|
||||
. 'über lit-content-update änderbar.';
|
||||
. 'über lit/content-update (direkt: lit-content-update) änderbar.';
|
||||
|
||||
public function __construct(private ContentSchema $schema)
|
||||
{
|
||||
|
||||
@@ -28,7 +28,8 @@ final class FieldValidator
|
||||
$key = (string) $key;
|
||||
$field = $definitions[$key] ?? null;
|
||||
if ($field === null) {
|
||||
$errors[$key] = 'Unbekanntes Feld; verfügbare Felder über lit-content-types abrufen.';
|
||||
$errors[$key] = 'Unbekanntes Feld; verfügbare Felder über lit/content-types (direkt: '
|
||||
. 'lit-content-types) abrufen.';
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,17 @@ final class Limits
|
||||
return self::sanitize(get_option(self::OPTION, []));
|
||||
}
|
||||
|
||||
/**
|
||||
* The [min, max] each field is clamped to by sanitize() – for admin UI form attributes,
|
||||
* so they can't drift from the actual bounds.
|
||||
*
|
||||
* @return array<string, array{int, int}>
|
||||
*/
|
||||
public static function bounds(): array
|
||||
{
|
||||
return self::BOUNDS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Settings API sanitize callback: always returns all keys, clamped to their bounds.
|
||||
*
|
||||
|
||||
@@ -31,6 +31,7 @@ final class LimitsTabTest extends TestCase
|
||||
Functions\when('settings_fields')->justReturn(null);
|
||||
Functions\when('submit_button')->justReturn(null);
|
||||
Functions\when('get_option')->justReturn(['upload_mb' => 8]);
|
||||
Functions\when('wp_max_upload_size')->justReturn(64 * 1024 * 1024);
|
||||
|
||||
ob_start();
|
||||
(new LimitsTab())->render();
|
||||
@@ -39,5 +40,40 @@ final class LimitsTabTest extends TestCase
|
||||
self::assertSame(3, substr_count($html, 'type="number"'));
|
||||
self::assertStringContainsString('name="lit_mcp_limits[upload_mb]" value="8"', $html);
|
||||
self::assertStringContainsString('name="lit_mcp_limits[log_retention_days]" value="90"', $html);
|
||||
self::assertStringContainsString('min="1" max="100"', $html);
|
||||
self::assertStringContainsString('min="1" max="3650"', $html);
|
||||
}
|
||||
|
||||
public function testWarnsWhenUploadMbExceedsTheServersOwnUploadLimit(): void
|
||||
{
|
||||
Functions\stubEscapeFunctions();
|
||||
Functions\stubTranslationFunctions();
|
||||
Functions\when('settings_fields')->justReturn(null);
|
||||
Functions\when('submit_button')->justReturn(null);
|
||||
Functions\when('get_option')->justReturn(['upload_mb' => 50]);
|
||||
Functions\when('wp_max_upload_size')->justReturn(2 * 1024 * 1024);
|
||||
|
||||
ob_start();
|
||||
(new LimitsTab())->render();
|
||||
$html = (string) ob_get_clean();
|
||||
|
||||
self::assertStringContainsString('class="description"', $html);
|
||||
self::assertMatchesRegularExpression('/50 MB.*2 MB/s', $html);
|
||||
}
|
||||
|
||||
public function testNoWarningWhenUploadMbIsWithinTheServersOwnUploadLimit(): void
|
||||
{
|
||||
Functions\stubEscapeFunctions();
|
||||
Functions\stubTranslationFunctions();
|
||||
Functions\when('settings_fields')->justReturn(null);
|
||||
Functions\when('submit_button')->justReturn(null);
|
||||
Functions\when('get_option')->justReturn(['upload_mb' => 5]);
|
||||
Functions\when('wp_max_upload_size')->justReturn(64 * 1024 * 1024);
|
||||
|
||||
ob_start();
|
||||
(new LimitsTab())->render();
|
||||
$html = (string) ob_get_clean();
|
||||
|
||||
self::assertStringNotContainsString('class="description"', $html);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,4 +42,23 @@ final class LimitsTest extends TestCase
|
||||
);
|
||||
self::assertSame(Limits::DEFAULTS, Limits::sanitize(null));
|
||||
}
|
||||
|
||||
public function testBoundsMatchesWhatSanitizeClampsTo(): void
|
||||
{
|
||||
self::assertSame([1, 100], Limits::bounds()['upload_mb']);
|
||||
self::assertSame([1, 3650], Limits::bounds()['log_retention_days']);
|
||||
self::assertSame([1, 100], Limits::bounds()['snapshot_count']);
|
||||
|
||||
// Cross-check against sanitize()'s actual clamping, so the two can't drift apart.
|
||||
$tooLow = array_map(static fn (array $bound): int => $bound[0] - 1, Limits::bounds());
|
||||
$tooHigh = array_map(static fn (array $bound): int => $bound[1] + 1, Limits::bounds());
|
||||
self::assertSame(
|
||||
array_map(static fn (array $bound): int => $bound[0], Limits::bounds()),
|
||||
Limits::sanitize($tooLow)
|
||||
);
|
||||
self::assertSame(
|
||||
array_map(static fn (array $bound): int => $bound[1], Limits::bounds()),
|
||||
Limits::sanitize($tooHigh)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user