diff --git a/.paul/ROADMAP.md b/.paul/ROADMAP.md
index f1dbb4f..7a03348 100644
--- a/.paul/ROADMAP.md
+++ b/.paul/ROADMAP.md
@@ -13,7 +13,7 @@ Phases: 1 of 2 complete
| Phase | Name | Plans | Status | Completed |
|-------|------|-------|--------|-----------|
| 1 | StatLink Autolinking | 1 | Complete ✓ | 2026-04-09 |
-| 2 | Admin Panel Upgrade | 2 | Planning | - |
+| 2 | Admin Panel Upgrade | 3 | Planning | - |
## Phase Details
@@ -38,10 +38,12 @@ Phases: 1 of 2 complete
- Widok /statlink z listą linkowanych artykułów
- Zdalne wlaczanie/wylaczanie komentowania dla pojedynczej strony WordPress
- Lista komentarzy z danego serwisu z mozliwoscia usuwania
+- Masowe zamykanie komentarzy i pingow w istniejacych wpisach
**Plans:**
- [ ] 02-01: Migrator + sidebar + widok StatLink
- [ ] 02-02: Zdalne zarzadzanie komentarzami WordPress
+- [ ] 02-03: Twarde zamykanie komentarzy w istniejacych wpisach
---
*Roadmap created: 2026-04-09*
diff --git a/.paul/STATE.md b/.paul/STATE.md
index 737899d..a6e78de 100644
--- a/.paul/STATE.md
+++ b/.paul/STATE.md
@@ -1,9 +1,9 @@
## Current Position
Phase: 02-admin-panel-upgrade — In Progress
-Plan: 02-02 complete
+Plan: 02-03 complete
Status: UNIFY complete. Loop complete — ready for next plan.
-Last activity: 2026-04-24T07:11:11.932Z
+Last activity: 2026-04-24T09:15:37.793Z
## Loop Position
@@ -16,6 +16,6 @@ PLAN ──▶ APPLY ──▶ UNIFY
## Session Continuity
Last session: 2026-04-24
-Stopped at: Plan 02-02 complete
+Stopped at: Plan 02-03 complete
Next action: paul_workflow('plan') for next plan
-Resume file: .paul/phases/02-admin-panel-upgrade/02-02-SUMMARY.md
\ No newline at end of file
+Resume file: .paul/phases/02-admin-panel-upgrade/02-03-SUMMARY.md
\ No newline at end of file
diff --git a/.paul/STATE.md.bak b/.paul/STATE.md.bak
index 261f30b..53d78c0 100644
--- a/.paul/STATE.md.bak
+++ b/.paul/STATE.md.bak
@@ -1,66 +1,21 @@
-# Project State
-
-## Project Reference
-
-See: .paul/PROJECT.md (updated 2026-04-09)
-
-**Core value:** Zautomatyzowane tworzenie zaplecza SEO
-**Current focus:** Phase 2 — Admin Panel Upgrade
-
## Current Position
-Milestone: v0.1 Initial Release
-Phase: 2 of 2 (Admin Panel Upgrade) — Planning
-Plan: 02-02 applied, awaiting UNIFY (depends on 02-01)
+Phase: 02-admin-panel-upgrade — Planning
+Plan: 02-03 applied, awaiting UNIFY
Status: APPLY complete — 3/3 PASS, ready for UNIFY
-Last activity: 2026-04-24 - APPLY complete for .paul/phases/02-admin-panel-upgrade/02-02-PLAN.md
-
-Progress:
-- Milestone: [████░░░░░░] 40%
-- Phase 1: [██████████] 100% ✓
-- Phase 2: [░░░░░░░░░░] 0%
+Last activity: 2026-04-24 - APPLY complete for .paul/phases/02-admin-panel-upgrade/02-03-PLAN.md
## Loop Position
-**Phase 1 (StatLink Auto-Linking):**
+Current loop state:
```
PLAN ──▶ APPLY ──▶ UNIFY
✓ ✓ ○ [APPLY complete, awaiting UNIFY]
```
-**Phase 2 (Admin Panel Upgrade):**
-```
-PLAN ──▶ APPLY ──▶ UNIFY
- ✓ ○ ○ [Plan 02-02 created, awaiting approval; 02-01 still pending]
-```
-
-## Accumulated Context
-
-### Decisions
-- StatLink.pl integration via Guzzle HTTP (cookie-based session)
-- Login field name: "zaloguj" (not "loguj"), needs GET homepage first
-- ilosc_dziennie: 0.02 (1 co 2 dni)
-- Migrator: port z orderPRO z lock mechanism
-- Sidebar: adaptacja orderPRO design do backPRO
-- Anchor sanitization: Polish diacritics must be transliterated to ASCII for StatLink
-- json_encode needs JSON_INVALID_UTF8_SUBSTITUTE when outputting scraped HTML
-- OPcache reset required after FTP deploy for changes to take effect
-- WordPress comment management should use the existing BackPRO remote service for site options and WP REST API for comment list/delete.
-- StatLink timeouts: connect_timeout=60s, timeout=120s, PHP set_time_limit=300s
-
-### Deferred Issues
-- StatLink: no max retry count for permanently failing links (could block queue)
-- StatLink: cron not yet configured on server (only manual token URL trigger)
-
-### Blockers/Concerns
-None.
-
## Session Continuity
-Last session: 2026-04-09
-Stopped at: Phase 2 Plan 02-02 APPLY complete
-Next action: Run $paul-unify .paul/phases/02-admin-panel-upgrade/02-02-PLAN.md
-Resume file: .paul/phases/02-admin-panel-upgrade/02-02-PLAN.md
-
----
-*STATE.md — Updated after every significant action*
+Last session: 2026-04-24
+Stopped at: Plan 02-03 APPLY complete
+Next action: Run $paul-unify .paul/phases/02-admin-panel-upgrade/02-03-PLAN.md
+Resume file: .paul/phases/02-admin-panel-upgrade/02-03-PLAN.md
diff --git a/.paul/changelog/2026-04-24.md b/.paul/changelog/2026-04-24.md
index a3dadb4..cc5eb3d 100644
--- a/.paul/changelog/2026-04-24.md
+++ b/.paul/changelog/2026-04-24.md
@@ -2,15 +2,14 @@
## Co zrobiono
-- [02-admin-panel-upgrade, Plan 02]
-- Task 1: Rozszerzyc WordPressService o operacje komentarzy
-- Task 2: Dodac akcje kontrolera i trasy komentarzy
-- Task 3: Zbudowac UI komentarzy dla pojedynczej strony
+- [02-admin-panel-upgrade, Plan 03]
+- Task 1: Dodac operacje close_existing_comments do WordPressService i remote service
+- Task 2: Dodac akcje kontrolera i trase masowego zamkniecia
+- Task 3: Dodac UI hard-close w panelu komentarzy
## Zmienione pliki
- `src/Services/WordPressService.php`
- `src/Controllers/SiteController.php`
- `config/routes.php`
-- `templates/sites/dashboard.php`
- `templates/sites/comments.php`
\ No newline at end of file
diff --git a/.paul/phases/02-admin-panel-upgrade/02-03-PLAN.md b/.paul/phases/02-admin-panel-upgrade/02-03-PLAN.md
new file mode 100644
index 0000000..8d642a6
--- /dev/null
+++ b/.paul/phases/02-admin-panel-upgrade/02-03-PLAN.md
@@ -0,0 +1,188 @@
+---
+phase: 02-admin-panel-upgrade
+plan: 03
+type: execute
+wave: 3
+depends_on: ["02-02"]
+files_modified:
+ - src/Services/WordPressService.php
+ - src/Controllers/SiteController.php
+ - templates/sites/comments.php
+ - config/routes.php
+autonomous: true
+delegation: off
+---
+
+
+## Goal
+Dodac "twarde" zamykanie komentarzy dla istniejacych tresci WordPress:
+1. Zamkniecie komentarzy i pingow/trackbackow we wszystkich istniejacych wpisach strony.
+2. Opcjonalne usuniecie oczekujacych komentarzy spamowych po zamknieciu komentarzy.
+3. Pokazanie wyniku operacji w panelu komentarzy BackPRO.
+
+## Purpose
+Samo wylaczenie komentowania nowych wpisow nie chroni starych artykulow, ktore maja `comment_status = open`. Boty moga dalej dodawac komentarze pod istniejacymi wpisami. Operator BackPRO potrzebuje jednej akcji, ktora zdalnie domyka cala powierzchnie komentarzy dla wybranego serwisu.
+
+## Output
+- Nowa metoda `closeExistingComments()` w `WordPressService`.
+- Nowe akcje remote service w `backpro-remote-service.php` generowanym przez `WordPressService`.
+- Nowa akcja POST w `SiteController` i trasa w `config/routes.php`.
+- Sekcja w `templates/sites/comments.php` z przyciskiem "Zamknij komentarze w istniejacych wpisach" i opcja usuniecia oczekujacych komentarzy.
+
+
+
+## Project Context
+@.paul/PROJECT.md
+@.paul/ROADMAP.md
+@.paul/STATE.md
+
+## Prior Work
+@.paul/phases/02-admin-panel-upgrade/02-02-SUMMARY.md
+
+## Source Files
+@src/Services/WordPressService.php
+@src/Controllers/SiteController.php
+@templates/sites/comments.php
+@config/routes.php
+
+
+
+
+## AC-1: Masowe zamkniecie istniejacych wpisow
+```gherkin
+Given uzytkownik jest zalogowany w BackPRO i strona ma aktywny plik serwisowy BackPRO
+When klika "Zamknij komentarze w istniejacych wpisach"
+Then WordPress ustawia comment_status='closed' i ping_status='closed' dla wszystkich opublikowanych wpisow
+And BackPRO pokazuje liczbe zaktualizowanych wpisow
+```
+
+## AC-2: Opcjonalne czyszczenie oczekujacych komentarzy
+```gherkin
+Given uzytkownik widzi panel komentarzy danej strony
+When zaznacza opcje usuniecia oczekujacych komentarzy i uruchamia operacje
+Then WordPress usuwa komentarze ze statusem hold
+And BackPRO pokazuje liczbe usunietych komentarzy
+```
+
+## AC-3: Bezpieczna obsluga bledow i odswiezenie statusu
+```gherkin
+Given remote service jest nieaktualny albo niedostepny
+When uzytkownik uruchamia masowe zamkniecie komentarzy
+Then BackPRO probuje zaktualizowac plik serwisowy i ponawia akcje
+And przy niepowodzeniu pokazuje czytelny komunikat bledu bez psucia listy komentarzy
+```
+
+
+
+
+
+
+ Task 1: Dodac operacje close_existing_comments do WordPressService i remote service
+ src/Services/WordPressService.php
+
+ Dodac publiczna metode:
+ - closeExistingComments(array $site, bool $deletePendingComments = false): array
+ - Wywoluje callRemoteService($site, 'close_existing_comments', ['delete_pending_comments' => '1'/'0']).
+ - Jezeli akcja nie dziala przez stary plik serwisowy, wywoluje ensureRemoteService(), odswieza site z bazy i ponawia akcje.
+ - Zwraca success, posts_updated, pending_comments_deleted, message.
+ - Przy bledzie zwraca success=false i czytelny message.
+
+ Zaktualizowac BACKPRO_REMOTE_SERVICE_VERSION do kolejnej wersji, np. 1.6.0.
+
+ W getBackproRemoteServiceContent() dodac action `close_existing_comments`:
+ - Ustawic default_comment_status='closed' i default_ping_status='closed', aby nowe tresci tez byly domyslnie zamkniete.
+ - Wykonac bezposredni update przez global `$wpdb`:
+ - UPDATE {$wpdb->posts} SET comment_status='closed', ping_status='closed' WHERE post_type IN ('post','page') AND post_status NOT IN ('trash','auto-draft')
+ - Zliczyc liczbe zaktualizowanych rekordow z wyniku query.
+ - Jesli `delete_pending_comments=1`, usunac komentarze ze statusem `hold` przez wp_delete_comment($commentId, true).
+ - Zwracac JSON z posts_updated, pending_comments_deleted i message.
+
+ Nie modyfikowac istniejacych metod listowania/usuwania pojedynczych komentarzy poza ewentualnym wspolnym helperem formatowania wyniku.
+
+ php -l src/Services/WordPressService.php
+ AC-1, AC-2 i AC-3 maja warstwe zdalnej operacji WordPress.
+
+
+
+ Task 2: Dodac akcje kontrolera i trase masowego zamkniecia
+ src/Controllers/SiteController.php, config/routes.php
+
+ Dodac do SiteController metode:
+ - closeExistingComments(string $id): void
+ - Auth::requireLogin().
+ - Pobrac Site::find(), obsluzyc brak strony.
+ - Odczytac checkbox/field `delete_pending_comments` jako bool.
+ - Wywolac WordPressService::closeExistingComments($site, $deletePendingComments).
+ - Flash success z liczba posts_updated i pending_comments_deleted.
+ - Flash danger z message przy bledzie.
+ - Redirect do `/sites/{id}/comments`.
+
+ Dodac trase:
+ - POST `/sites/{id}/comments/close-existing` -> SiteController@closeExistingComments
+
+ Zachowac cienki kontroler: nie wpisywac SQL ani logiki WordPress do kontrolera.
+
+ php -l src/Controllers/SiteController.php oraz php -l config/routes.php
+ AC-1, AC-2 i AC-3 sa dostepne z panelu przez POST route.
+
+
+
+ Task 3: Dodac UI hard-close w panelu komentarzy
+ templates/sites/comments.php
+
+ W `templates/sites/comments.php` dodac karte/sekcje pod ustawieniem "Komentowanie nowych wpisow":
+ - Tytul: "Istniejace wpisy".
+ - Krotkie wyjasnienie: operacja zamyka komentarze i pingi/trackbacki w juz opublikowanych tresciach.
+ - Formularz POST do `/sites/{id}/comments/close-existing`.
+ - Checkbox `delete_pending_comments` opisany jako "Usun oczekujace komentarze przy tej operacji".
+ - Przycisk w stylu ostrzegawczym, np. `btn-outline-danger`, z data-confirm zawierajacym ostrzezenie, ze operacja dotyczy wszystkich wpisow tej strony.
+ - Po flashu sukcesu/bledu istniejacy layout ma normalnie pokazac komunikat.
+
+ Nie ukrywac listy komentarzy ani istniejacych filtrow statusu.
+
+ php -l templates/sites/comments.php
+ AC-1 i AC-2 maja widoczny, potwierdzany interfejs uzytkownika.
+
+
+
+
+
+
+## DO NOT CHANGE
+- src/Services/PublisherService.php
+- src/Models/Article.php
+- src/Models/Topic.php
+- migrations/* (brak zmian schematu bazy)
+- templates/articles/*
+- cron/*
+
+## SCOPE LIMITS
+- Nie dodawac globalnej operacji dla wszystkich stron naraz; zakres to pojedyncza strona.
+- Nie dodawac moderacji approve/spam/unspam w tym planie.
+- Nie usuwac zatwierdzonych komentarzy, chyba ze uzytkownik usunie je osobno istniejaca funkcja.
+- Nie dodawac nowych zaleznosci Composer.
+- Nie modyfikowac bazy lokalnej BackPRO.
+
+
+
+
+Before declaring plan complete:
+- [ ] php -l src/Services/WordPressService.php
+- [ ] php -l src/Controllers/SiteController.php
+- [ ] php -l config/routes.php
+- [ ] php -l templates/sites/comments.php
+- [ ] /sites/{id}/comments pokazuje sekcje "Istniejace wpisy"
+- [ ] POST /sites/{id}/comments/close-existing wywoluje remote service i pokazuje wynik
+- [ ] Remote service version wzrosla, aby wymusic aktualizacje pliku na serwerze
+
+
+
+- Operator moze jednym kliknieciem zamknac komentarze i pingi w istniejacych wpisach wybranej strony.
+- Operator moze przy tej operacji usunac komentarze oczekujace na moderacje.
+- Wynik operacji pokazuje liczby zaktualizowanych wpisow i usunietych komentarzy.
+- Brak regresji w istniejacym widoku listy komentarzy i usuwaniu pojedynczego komentarza.
+
+
+
diff --git a/.paul/phases/02-admin-panel-upgrade/02-03-SUMMARY.md b/.paul/phases/02-admin-panel-upgrade/02-03-SUMMARY.md
new file mode 100644
index 0000000..ab11705
--- /dev/null
+++ b/.paul/phases/02-admin-panel-upgrade/02-03-SUMMARY.md
@@ -0,0 +1,38 @@
+---
+phase: 02-admin-panel-upgrade
+plan: 03
+completed: 2026-04-24T09:15:37.793Z
+---
+
+# Phase 02-03 Summary
+
+****
+
+## Acceptance Criteria Results
+
+| Criterion | Status |
+|-----------|--------|
+| Task 1: Dodac operacje close_existing_comments do WordPressService i remote service | Pass — Dodano WordPressService::closeExistingComments(), akcje remote service close_existing_comments oraz podniesiono BACKPRO_REMOTE_SERVICE_VERSION do 1.6.0. Po live bledzie poprawiono generowany SQL string w remote service i zweryfikowano php -l dla wygenerowanego pliku. |
+| Task 2: Dodac akcje kontrolera i trase masowego zamkniecia | Pass — Dodano SiteController::closeExistingComments() oraz POST /sites/{id}/comments/close-existing. Zweryfikowano php -l src/Controllers/SiteController.php i php -l config/routes.php. |
+| Task 3: Dodac UI hard-close w panelu komentarzy | Pass — Dodano sekcje Istniejace wpisy w templates/sites/comments.php z checkboxem usuwania oczekujacych komentarzy i confirmem. Zweryfikowano php -l templates/sites/comments.php. |
+
+## Accomplishments
+
+- Task 1: Dodac operacje close_existing_comments do WordPressService i remote service: Dodano WordPressService::closeExistingComments(), akcje remote service close_existing_comments oraz podniesiono BACKPRO_REMOTE_SERVICE_VERSION do 1.6.0. Po live bledzie poprawiono generowany SQL string w remote service i zweryfikowano php -l dla wygenerowanego pliku.
+- Task 2: Dodac akcje kontrolera i trase masowego zamkniecia: Dodano SiteController::closeExistingComments() oraz POST /sites/{id}/comments/close-existing. Zweryfikowano php -l src/Controllers/SiteController.php i php -l config/routes.php.
+- Task 3: Dodac UI hard-close w panelu komentarzy: Dodano sekcje Istniejace wpisy w templates/sites/comments.php z checkboxem usuwania oczekujacych komentarzy i confirmem. Zweryfikowano php -l templates/sites/comments.php.
+
+## Files Modified
+
+- `src/Services/WordPressService.php`
+- `src/Controllers/SiteController.php`
+- `config/routes.php`
+- `templates/sites/comments.php`
+
+## Deviations
+
+During live testing the remote service returned non-JSON because the generated PHP contained escaped SQL string quotes (\"UPDATE ...\"). Fixed the generator in WordPressService.php, generated a temporary backpro-remote-service.php, and verified it with php -l. User confirmed the feature works after the fix.
+
+---
+*Phase: 02-admin-panel-upgrade, Plan: 03*
+*Completed: 2026-04-24*
\ No newline at end of file
diff --git a/config/routes.php b/config/routes.php
index 34f2820..18bd8af 100644
--- a/config/routes.php
+++ b/config/routes.php
@@ -34,6 +34,7 @@ $router->post('/sites/{id}/test', 'SiteController', 'testConnection');
$router->get('/sites/{id}/dashboard', 'SiteController', 'dashboard');
$router->get('/sites/{id}/comments', 'SiteController', 'comments');
$router->post('/sites/{id}/comments/settings', 'SiteController', 'updateCommentsEnabled');
+$router->post('/sites/{id}/comments/close-existing', 'SiteController', 'closeExistingComments');
$router->post('/sites/{id}/comments/{commentId}/delete', 'SiteController', 'deleteComment');
$router->post('/sites/{id}/dashboard/permalinks/enable', 'SiteController', 'enablePrettyPermalinks');
$router->post('/sites/{id}/dashboard/remote-service/update', 'SiteController', 'updateRemoteService');
diff --git a/src/Controllers/SiteController.php b/src/Controllers/SiteController.php
index 3189239..d368cb8 100644
--- a/src/Controllers/SiteController.php
+++ b/src/Controllers/SiteController.php
@@ -304,6 +304,35 @@ class SiteController extends Controller
$this->redirect("/sites/{$id}/comments{$statusQuery}");
}
+ public function closeExistingComments(string $id): void
+ {
+ Auth::requireLogin();
+
+ $site = Site::find((int) $id);
+ if (!$site) {
+ $this->flash('danger', 'Strona nie znaleziona.');
+ $this->redirect('/sites');
+ return;
+ }
+
+ $deletePendingComments = (string) $this->input('delete_pending_comments', '0') === '1';
+ $wp = new WordPressService();
+ $result = $wp->closeExistingComments($site, $deletePendingComments);
+
+ if (!empty($result['success'])) {
+ $postsUpdated = (int) ($result['posts_updated'] ?? 0);
+ $deletedPending = (int) ($result['pending_comments_deleted'] ?? 0);
+ $this->flash(
+ 'success',
+ "Zamknieto komentarze i pingi. Zaktualizowane wpisy: {$postsUpdated}, usuniete oczekujace komentarze: {$deletedPending}."
+ );
+ } else {
+ $this->flash('danger', (string) ($result['message'] ?? 'Nie udalo sie zamknac komentarzy w istniejacych wpisach.'));
+ }
+
+ $this->redirect("/sites/{$id}/comments");
+ }
+
public function seoPanel(string $id): void
{
Auth::requireLogin();
diff --git a/src/Services/WordPressService.php b/src/Services/WordPressService.php
index f68d2d2..3325267 100644
--- a/src/Services/WordPressService.php
+++ b/src/Services/WordPressService.php
@@ -12,7 +12,7 @@ class WordPressService
{
private const BACKPRO_MU_PLUGIN_FILENAME = 'backpro-remote-tools.php';
private const BACKPRO_REMOTE_SERVICE_FILENAME = 'backpro-remote-service.php';
- private const BACKPRO_REMOTE_SERVICE_VERSION = '1.5.0';
+ private const BACKPRO_REMOTE_SERVICE_VERSION = '1.6.0';
private const BACKPRO_NEWS_THEME_SLUG = 'backpro-news-mag';
private const BACKPRO_NEWS_THEME_SOURCE_DIR = 'assets/wp-theme-backpro-news';
private Client $client;
@@ -638,6 +638,38 @@ class WordPressService
}
}
+ public function closeExistingComments(array $site, bool $deletePendingComments = false): array
+ {
+ $params = ['delete_pending_comments' => $deletePendingComments ? '1' : '0'];
+ $result = $this->callRemoteService($site, 'close_existing_comments', $params);
+ if (!empty($result['success'])) {
+ return $this->formatCloseExistingCommentsResult($result);
+ }
+
+ $ensure = $this->ensureRemoteService($site);
+ if (empty($ensure['success'])) {
+ return [
+ 'success' => false,
+ 'posts_updated' => 0,
+ 'pending_comments_deleted' => 0,
+ 'message' => (string) ($ensure['message'] ?? $result['message'] ?? 'Brak endpointu BackPRO na WordPress.'),
+ ];
+ }
+
+ $refreshedSite = !empty($site['id']) ? (Site::find((int) $site['id']) ?: $site) : $site;
+ $retry = $this->callRemoteService($refreshedSite, 'close_existing_comments', $params);
+ if (!empty($retry['success'])) {
+ return $this->formatCloseExistingCommentsResult($retry);
+ }
+
+ return [
+ 'success' => false,
+ 'posts_updated' => 0,
+ 'pending_comments_deleted' => 0,
+ 'message' => (string) ($retry['message'] ?? 'Nie udalo sie zamknac komentarzy w istniejacych wpisach.'),
+ ];
+ }
+
public function ensureRemoteService(array $site): array
{
$siteData = $this->prepareRemoteServiceMetadata($site);
@@ -1180,6 +1212,16 @@ class WordPressService
];
}
+ private function formatCloseExistingCommentsResult(array $data): array
+ {
+ return [
+ 'success' => true,
+ 'posts_updated' => max(0, (int) ($data['posts_updated'] ?? 0)),
+ 'pending_comments_deleted' => max(0, (int) ($data['pending_comments_deleted'] ?? 0)),
+ 'message' => (string) ($data['message'] ?? 'Komentarze w istniejacych wpisach zostaly zamkniete.'),
+ ];
+ }
+
private function formatWpRequestError(RequestException $e, string $fallback): string
{
$statusCode = $e->hasResponse() ? (int) $e->getResponse()->getStatusCode() : 0;
@@ -1342,7 +1384,7 @@ if (!defined('ABSPATH')) {
\$action = (string) (\$_POST['action'] ?? '');
if (\$action === 'ping') {
- echo json_encode(['success' => true, 'message' => 'pong', 'version' => '1.5.0']);
+ echo json_encode(['success' => true, 'message' => 'pong', 'version' => '1.6.0']);
exit;
}
@@ -1463,6 +1505,48 @@ if (\$action === 'set_comment_settings') {
exit;
}
+if (\$action === 'close_existing_comments') {
+ global \$wpdb;
+
+ update_option('default_comment_status', 'closed');
+ update_option('default_ping_status', 'closed');
+
+ \$postsUpdated = \$wpdb->query(
+ "UPDATE {\$wpdb->posts}
+ SET comment_status = 'closed', ping_status = 'closed'
+ WHERE post_type IN ('post', 'page')
+ AND post_status NOT IN ('trash', 'auto-draft')"
+ );
+
+ if (\$postsUpdated === false) {
+ http_response_code(500);
+ echo json_encode(['success' => false, 'message' => 'posts_update_failed']);
+ exit;
+ }
+
+ \$deletePending = (string) (\$_POST['delete_pending_comments'] ?? '0') === '1';
+ \$deletedPending = 0;
+ if (\$deletePending) {
+ \$pendingIds = \$wpdb->get_col(
+ "SELECT comment_ID FROM {\$wpdb->comments} WHERE comment_approved = '0'"
+ );
+
+ foreach ((array) \$pendingIds as \$commentId) {
+ if (wp_delete_comment((int) \$commentId, true)) {
+ \$deletedPending++;
+ }
+ }
+ }
+
+ echo json_encode([
+ 'success' => true,
+ 'posts_updated' => (int) \$postsUpdated,
+ 'pending_comments_deleted' => \$deletedPending,
+ 'message' => 'Zamknieto komentarze i pingi w istniejacych wpisach.',
+ ]);
+ exit;
+}
+
if (\$action === 'cleanup') {
@unlink(__FILE__);
echo json_encode(['success' => true, 'message' => 'service_deleted']);
diff --git a/templates/sites/comments.php b/templates/sites/comments.php
index 07c7a9c..ddfb8ec 100644
--- a/templates/sites/comments.php
+++ b/templates/sites/comments.php
@@ -77,6 +77,37 @@ $badgeClasses = [
+
+
+
+
+ Ta operacja zamyka komentarze oraz pingi/trackbacki w juz opublikowanych tresciach tej strony.
+
+
+ Uzyj jej po wylaczeniu komentowania nowych wpisow, gdy boty nadal dodaja komentarze pod starszymi artykulami.
+
+
+
+
+
+