From dbdfc9afa9e4cf0e9deb5374754605e119d28f92 Mon Sep 17 00:00:00 2001 From: Vladimir Bryzgalov Date: Sat, 18 Apr 2026 00:12:45 +0500 Subject: [PATCH] feat(admin): always-on dashboard widget + default retro days = 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Dashboard widget is now registered unconditionally. Header + content adapt: shows '⚠️ ошибки доставки' only when failed > 0, otherwise plain title with queue state (pending / sent-24h / failed). Pilot feedback: the conditional widget felt like the plugin was missing — users expect a persistent status readout. - Retro default window changed from 7 days to 0 (no limit). Most pilot uses were 'dump everything since install', so 0 is the more useful default. User can still narrow to N days in the form. - Spec §10 + §14 updated. Co-Authored-By: Claude Opus 4.7 (1M context) --- admin/class-dashboard-widget.php | 18 ++++-- admin/class-settings-page.php | 2 +- admin/views/dashboard-widget.php | 40 +++++++++--- admin/views/settings.php | 2 +- .../plans/2026-04-17-cf7-spam-to-telegram.md | 62 +++++++++++++------ .../2026-04-17-cf7-spam-to-telegram-design.md | 22 ++++--- 6 files changed, 103 insertions(+), 43 deletions(-) diff --git a/admin/class-dashboard-widget.php b/admin/class-dashboard-widget.php index 5b94ab8..04ffa09 100644 --- a/admin/class-dashboard-widget.php +++ b/admin/class-dashboard-widget.php @@ -7,15 +7,18 @@ final class Dashboard_Widget { public function register(): void { - add_action('wp_dashboard_setup', [$this, 'maybe_register_widget']); + add_action('wp_dashboard_setup', [$this, 'register_widget']); } - public function maybe_register_widget(): void + public function register_widget(): void { - if (Queue::count_failed() === 0) return; + $failed_count = Queue::count_failed(); + $title = $failed_count > 0 + ? '⚠️ CF7 Spam → Telegram: ошибки доставки' + : 'CF7 Spam → Telegram'; wp_add_dashboard_widget( - 'cf7stg_dashboard_errors', - '⚠️ CF7 Spam → Telegram: ошибки доставки', + 'cf7stg_dashboard_status', + $title, [$this, 'render'] ); } @@ -23,7 +26,10 @@ final class Dashboard_Widget public function render(): void { $failed = Queue::list_failed(10); - $count = Queue::count_failed(); + $failed_count = Queue::count_failed(); + $pending = Queue::count_by_status(Queue::STATUS_PENDING); + $sent_24h = Queue::count_sent_last_24h(); + $configured = Settings::is_configured(); $settings_url = admin_url('options-general.php?page=cf7stg-settings'); include CF7STG_PLUGIN_DIR . 'admin/views/dashboard-widget.php'; } diff --git a/admin/class-settings-page.php b/admin/class-settings-page.php index 40923ab..aded85d 100644 --- a/admin/class-settings-page.php +++ b/admin/class-settings-page.php @@ -72,7 +72,7 @@ final class Settings_Page { $this->guard('cf7stg_retro'); $count = max(1, min(RetroImporter::MAX_COUNT, (int)($_POST['retro_count'] ?? 10))); - $days = max(0, (int)($_POST['retro_days'] ?? 7)); + $days = max(0, (int)($_POST['retro_days'] ?? 0)); $repeat = !empty($_POST['retro_repeat']); $result = RetroImporter::import($count, $days, $repeat); $this->redirect_back(['retro_added' => (int)$result['added'], 'retro_skipped' => (int)$result['skipped']]); diff --git a/admin/views/dashboard-widget.php b/admin/views/dashboard-widget.php index 21b53e3..2bc3993 100644 --- a/admin/views/dashboard-widget.php +++ b/admin/views/dashboard-widget.php @@ -1,15 +1,35 @@ $failed */ -/** @var int $count */ +/** @var int $failed_count */ +/** @var int $pending */ +/** @var int $sent_24h */ +/** @var bool $configured */ /** @var string $settings_url */ ?> -

Есть неотправленных сообщений (TG-API отвечает ошибкой):

- + +

⚙️ Плагин не настроен — укажите Bot Token и Chat ID в настройках.

+ + +

+ ⏳ В очереди: +  ·  + ✅ За сутки: +  ·  + + 0 ? '⚠️' : '✖'; ?> Ошибки: + +

+ + 0): ?> +

Последние ошибки доставки (TG-API):

+ + +

Открыть настройки →

diff --git a/admin/views/settings.php b/admin/views/settings.php index 108d83d..409e857 100644 --- a/admin/views/settings.php +++ b/admin/views/settings.php @@ -83,7 +83,7 @@ if (isset($_GET['purged'])) $notice = '
Только за последние - дней (0 = без ограничения) + дней (0 = без ограничения)   diff --git a/docs/superpowers/plans/2026-04-17-cf7-spam-to-telegram.md b/docs/superpowers/plans/2026-04-17-cf7-spam-to-telegram.md index 5b25e51..d733ee9 100644 --- a/docs/superpowers/plans/2026-04-17-cf7-spam-to-telegram.md +++ b/docs/superpowers/plans/2026-04-17-cf7-spam-to-telegram.md @@ -2482,7 +2482,7 @@ final class Settings_Page { $this->guard('cf7stg_retro'); $count = max(1, min(RetroImporter::MAX_COUNT, (int)($_POST['retro_count'] ?? 10))); - $days = max(0, (int)($_POST['retro_days'] ?? 7)); + $days = max(0, (int)($_POST['retro_days'] ?? 0)); $repeat = !empty($_POST['retro_repeat']); $result = RetroImporter::import($count, $days, $repeat); $this->redirect_back(['retro_added' => (int)$result['added'], 'retro_skipped' => (int)$result['skipped']]); @@ -2605,7 +2605,7 @@ if (isset($_GET['purged'])) $notice = '
Только за последние - дней (0 = без ограничения) + дней (0 = без ограничения)   @@ -2660,15 +2660,18 @@ final class Dashboard_Widget { public function register(): void { - add_action('wp_dashboard_setup', [$this, 'maybe_register_widget']); + add_action('wp_dashboard_setup', [$this, 'register_widget']); } - public function maybe_register_widget(): void + public function register_widget(): void { - if (Queue::count_failed() === 0) return; + $failed_count = Queue::count_failed(); + $title = $failed_count > 0 + ? '⚠️ CF7 Spam → Telegram: ошибки доставки' + : 'CF7 Spam → Telegram'; wp_add_dashboard_widget( - 'cf7stg_dashboard_errors', - '⚠️ CF7 Spam → Telegram: ошибки доставки', + 'cf7stg_dashboard_status', + $title, [$this, 'render'] ); } @@ -2676,7 +2679,10 @@ final class Dashboard_Widget public function render(): void { $failed = Queue::list_failed(10); - $count = Queue::count_failed(); + $failed_count = Queue::count_failed(); + $pending = Queue::count_by_status(Queue::STATUS_PENDING); + $sent_24h = Queue::count_sent_last_24h(); + $configured = Settings::is_configured(); $settings_url = admin_url('options-general.php?page=cf7stg-settings'); include CF7STG_PLUGIN_DIR . 'admin/views/dashboard-widget.php'; } @@ -2688,18 +2694,38 @@ final class Dashboard_Widget ```php $failed */ -/** @var int $count */ +/** @var int $failed_count */ +/** @var int $pending */ +/** @var int $sent_24h */ +/** @var bool $configured */ /** @var string $settings_url */ ?> -

Есть неотправленных сообщений (TG-API отвечает ошибкой):

-
    - -
  • - created_at); ?> — - last_error); ?> -
  • - -
+ +

⚙️ Плагин не настроен — укажите Bot Token и Chat ID в настройках.

+ + +

+ ⏳ В очереди: +  ·  + ✅ За сутки: +  ·  + + 0 ? '⚠️' : '✖'; ?> Ошибки: + +

+ + 0): ?> +

Последние ошибки доставки (TG-API):

+
    + +
  • + created_at); ?> — + last_error); ?> +
  • + +
+ +

Открыть настройки →

``` diff --git a/docs/superpowers/specs/2026-04-17-cf7-spam-to-telegram-design.md b/docs/superpowers/specs/2026-04-17-cf7-spam-to-telegram-design.md index 83e02f9..1d0f814 100644 --- a/docs/superpowers/specs/2026-04-17-cf7-spam-to-telegram-design.md +++ b/docs/superpowers/specs/2026-04-17-cf7-spam-to-telegram-design.md @@ -257,7 +257,7 @@ apply_filters('cf7stg_classifier_thresholds', ['client' => 3, 'spam' => -2]); **UI:** на странице настроек — блок «Ретроспективная выгрузка из Flamingo»: - `count` (int, default 10, max 50) -- `days` (int, default 7; 0 = без ограничения) +- `days` (int, default 0; 0 = без ограничения) - `allow_repeat` (checkbox) - кнопка «Добавить в очередь» @@ -324,22 +324,30 @@ $schedules['cf7stg_every_minute'] = ['interval' => 60, 'display' => 'Раз в **Ограничения shared-хостинга:** WP-Cron срабатывает при HTTP-запросах к сайту. При малом трафике события могут опаздывать. В UI настроек — короткая подсказка: «Для точности можно настроить внешний cron на `wp-cron.php`». -## 14. Dashboard-виджет (условный) +## 14. Dashboard-виджет -`add_action('wp_dashboard_setup', ...)` → при `Queue::count_failed() > 0` регистрируется виджет `cf7stg_dashboard_errors`: +`add_action('wp_dashboard_setup', ...)` регистрирует виджет `cf7stg_dashboard_status` **всегда** (после пилота: пользователь ожидает увидеть быстрый статус, а не ориентироваться только на появление «тревожной» лампы). + +Заголовок зависит от состояния: +- `failed > 0` → `⚠️ CF7 Spam → Telegram: ошибки доставки` +- иначе → `CF7 Spam → Telegram` + +Содержимое: ``` -⚠️ CF7 Spam → Telegram: ошибки доставки -Есть N неотправленных сообщений (TG-API отвечает ошибкой): +[если !is_configured: ⚙️ Плагин не настроен — укажите Bot Token и Chat ID в настройках.] +⏳ В очереди: N · ✅ За сутки: M · [✖|⚠️] Ошибки: K + +[если K > 0: +Последние ошибки доставки (TG-API): • {created_at} — {last_error} • ... +] [Открыть настройки →] ``` -При `count_failed() == 0` — виджет не регистрируется, дашборд чистый. - ## 15. Обработка ошибок Telegram API `TelegramClient::send_message()` бросает `TelegramException`, у которого метод `is_permanent(): bool`.