feat: settings page with connection tab, admin notices and site health test
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:
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Admin;
|
||||
|
||||
/**
|
||||
* Settings page "Einstellungen → LIT MCP" with tabs (spec §8.4). Settings API, no JS framework.
|
||||
*/
|
||||
final class SettingsPage
|
||||
{
|
||||
public const SLUG = 'lit-mcp';
|
||||
|
||||
/** @var array<string, AdminTab> */
|
||||
private array $tabs = [];
|
||||
|
||||
/** @param list<AdminTab> $tabs The first tab is the default. */
|
||||
public function __construct(array $tabs)
|
||||
{
|
||||
foreach ($tabs as $tab) {
|
||||
$this->tabs[$tab->slug()] = $tab;
|
||||
}
|
||||
}
|
||||
|
||||
public function register(): void
|
||||
{
|
||||
add_action('admin_menu', [$this, 'addMenu']);
|
||||
add_action('admin_init', [$this, 'registerSettings']);
|
||||
foreach ($this->tabs as $tab) {
|
||||
$tab->registerActions();
|
||||
}
|
||||
}
|
||||
|
||||
public function addMenu(): void
|
||||
{
|
||||
add_options_page(
|
||||
__('LIT MCP', 'wp-lit-mcp'),
|
||||
__('LIT MCP', 'wp-lit-mcp'),
|
||||
'manage_options',
|
||||
self::SLUG,
|
||||
[$this, 'render']
|
||||
);
|
||||
}
|
||||
|
||||
public function registerSettings(): void
|
||||
{
|
||||
foreach ($this->tabs as $tab) {
|
||||
$tab->registerSettings();
|
||||
}
|
||||
}
|
||||
|
||||
/** @return list<string> */
|
||||
public function tabSlugs(): array
|
||||
{
|
||||
return array_keys($this->tabs);
|
||||
}
|
||||
|
||||
public function currentTab(): string
|
||||
{
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only tab switch.
|
||||
$requested = isset($_GET['tab']) ? sanitize_key(wp_unslash((string) $_GET['tab'])) : '';
|
||||
|
||||
return isset($this->tabs[$requested]) ? $requested : (string) array_key_first($this->tabs);
|
||||
}
|
||||
|
||||
/** @param array<string, string> $args */
|
||||
public static function url(string $tab = '', array $args = []): string
|
||||
{
|
||||
$query = array_merge(['page' => self::SLUG], $tab !== '' ? ['tab' => $tab] : [], $args);
|
||||
|
||||
return add_query_arg($query, admin_url('options-general.php'));
|
||||
}
|
||||
|
||||
public function render(): void
|
||||
{
|
||||
if (! current_user_can('manage_options')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$current = $this->currentTab();
|
||||
echo '<div class="wrap"><h1>' . esc_html__('LIT MCP', 'wp-lit-mcp') . '</h1>';
|
||||
$this->renderNotice();
|
||||
echo '<nav class="nav-tab-wrapper">';
|
||||
foreach ($this->tabs as $slug => $tab) {
|
||||
printf(
|
||||
'<a href="%s" class="nav-tab%s">%s</a>',
|
||||
esc_url(self::url($slug)),
|
||||
$slug === $current ? ' nav-tab-active' : '',
|
||||
esc_html($tab->label())
|
||||
);
|
||||
}
|
||||
echo '</nav>';
|
||||
$this->tabs[$current]->render();
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
private function renderNotice(): void
|
||||
{
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- display only.
|
||||
$key = isset($_GET['lit_mcp_notice']) ? sanitize_key(wp_unslash((string) $_GET['lit_mcp_notice'])) : '';
|
||||
$notice = match ($key) {
|
||||
'revoked' => ['success', __('Verbindung widerrufen.', 'wp-lit-mcp')],
|
||||
'revoke_failed' => ['error', __('Die Verbindung konnte nicht widerrufen werden.', 'wp-lit-mcp')],
|
||||
'cleared' => ['success', __('Protokoll geleert.', 'wp-lit-mcp')],
|
||||
default => null,
|
||||
};
|
||||
|
||||
if ($notice !== null) {
|
||||
printf(
|
||||
'<div class="notice notice-%s is-dismissible"><p>%s</p></div>',
|
||||
esc_attr($notice[0]),
|
||||
esc_html($notice[1])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user