update
This commit is contained in:
@@ -13,7 +13,7 @@ Phases: 1 of 2 complete
|
|||||||
| Phase | Name | Plans | Status | Completed |
|
| Phase | Name | Plans | Status | Completed |
|
||||||
|-------|------|-------|--------|-----------|
|
|-------|------|-------|--------|-----------|
|
||||||
| 1 | StatLink Autolinking | 1 | Complete ✓ | 2026-04-09 |
|
| 1 | StatLink Autolinking | 1 | Complete ✓ | 2026-04-09 |
|
||||||
| 2 | Admin Panel Upgrade | 2 | Planning | - |
|
| 2 | Admin Panel Upgrade | 3 | Planning | - |
|
||||||
|
|
||||||
## Phase Details
|
## Phase Details
|
||||||
|
|
||||||
@@ -38,10 +38,12 @@ Phases: 1 of 2 complete
|
|||||||
- Widok /statlink z listą linkowanych artykułów
|
- Widok /statlink z listą linkowanych artykułów
|
||||||
- Zdalne wlaczanie/wylaczanie komentowania dla pojedynczej strony WordPress
|
- Zdalne wlaczanie/wylaczanie komentowania dla pojedynczej strony WordPress
|
||||||
- Lista komentarzy z danego serwisu z mozliwoscia usuwania
|
- Lista komentarzy z danego serwisu z mozliwoscia usuwania
|
||||||
|
- Masowe zamykanie komentarzy i pingow w istniejacych wpisach
|
||||||
|
|
||||||
**Plans:**
|
**Plans:**
|
||||||
- [ ] 02-01: Migrator + sidebar + widok StatLink
|
- [ ] 02-01: Migrator + sidebar + widok StatLink
|
||||||
- [ ] 02-02: Zdalne zarzadzanie komentarzami WordPress
|
- [ ] 02-02: Zdalne zarzadzanie komentarzami WordPress
|
||||||
|
- [ ] 02-03: Twarde zamykanie komentarzy w istniejacych wpisach
|
||||||
|
|
||||||
---
|
---
|
||||||
*Roadmap created: 2026-04-09*
|
*Roadmap created: 2026-04-09*
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 02-admin-panel-upgrade — In Progress
|
Phase: 02-admin-panel-upgrade — In Progress
|
||||||
Plan: 02-02 complete
|
Plan: 02-03 complete
|
||||||
Status: UNIFY complete. Loop complete — ready for next plan.
|
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
|
## Loop Position
|
||||||
|
|
||||||
@@ -16,6 +16,6 @@ PLAN ──▶ APPLY ──▶ UNIFY
|
|||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-04-24
|
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
|
Next action: paul_workflow('plan') for next plan
|
||||||
Resume file: .paul/phases/02-admin-panel-upgrade/02-02-SUMMARY.md
|
Resume file: .paul/phases/02-admin-panel-upgrade/02-03-SUMMARY.md
|
||||||
@@ -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
|
## Current Position
|
||||||
|
|
||||||
Milestone: v0.1 Initial Release
|
Phase: 02-admin-panel-upgrade — Planning
|
||||||
Phase: 2 of 2 (Admin Panel Upgrade) — Planning
|
Plan: 02-03 applied, awaiting UNIFY
|
||||||
Plan: 02-02 applied, awaiting UNIFY (depends on 02-01)
|
|
||||||
Status: APPLY complete — 3/3 PASS, ready for 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
|
Last activity: 2026-04-24 - APPLY complete for .paul/phases/02-admin-panel-upgrade/02-03-PLAN.md
|
||||||
|
|
||||||
Progress:
|
|
||||||
- Milestone: [████░░░░░░] 40%
|
|
||||||
- Phase 1: [██████████] 100% ✓
|
|
||||||
- Phase 2: [░░░░░░░░░░] 0%
|
|
||||||
|
|
||||||
## Loop Position
|
## Loop Position
|
||||||
|
|
||||||
**Phase 1 (StatLink Auto-Linking):**
|
Current loop state:
|
||||||
```
|
```
|
||||||
PLAN ──▶ APPLY ──▶ UNIFY
|
PLAN ──▶ APPLY ──▶ UNIFY
|
||||||
✓ ✓ ○ [APPLY complete, awaiting 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
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-04-09
|
Last session: 2026-04-24
|
||||||
Stopped at: Phase 2 Plan 02-02 APPLY complete
|
Stopped at: Plan 02-03 APPLY complete
|
||||||
Next action: Run $paul-unify .paul/phases/02-admin-panel-upgrade/02-02-PLAN.md
|
Next action: Run $paul-unify .paul/phases/02-admin-panel-upgrade/02-03-PLAN.md
|
||||||
Resume file: .paul/phases/02-admin-panel-upgrade/02-02-PLAN.md
|
Resume file: .paul/phases/02-admin-panel-upgrade/02-03-PLAN.md
|
||||||
|
|
||||||
---
|
|
||||||
*STATE.md — Updated after every significant action*
|
|
||||||
|
|||||||
@@ -2,15 +2,14 @@
|
|||||||
|
|
||||||
## Co zrobiono
|
## Co zrobiono
|
||||||
|
|
||||||
- [02-admin-panel-upgrade, Plan 02]
|
- [02-admin-panel-upgrade, Plan 03]
|
||||||
- Task 1: Rozszerzyc WordPressService o operacje komentarzy
|
- Task 1: Dodac operacje close_existing_comments do WordPressService i remote service
|
||||||
- Task 2: Dodac akcje kontrolera i trasy komentarzy
|
- Task 2: Dodac akcje kontrolera i trase masowego zamkniecia
|
||||||
- Task 3: Zbudowac UI komentarzy dla pojedynczej strony
|
- Task 3: Dodac UI hard-close w panelu komentarzy
|
||||||
|
|
||||||
## Zmienione pliki
|
## Zmienione pliki
|
||||||
|
|
||||||
- `src/Services/WordPressService.php`
|
- `src/Services/WordPressService.php`
|
||||||
- `src/Controllers/SiteController.php`
|
- `src/Controllers/SiteController.php`
|
||||||
- `config/routes.php`
|
- `config/routes.php`
|
||||||
- `templates/sites/dashboard.php`
|
|
||||||
- `templates/sites/comments.php`
|
- `templates/sites/comments.php`
|
||||||
188
.paul/phases/02-admin-panel-upgrade/02-03-PLAN.md
Normal file
188
.paul/phases/02-admin-panel-upgrade/02-03-PLAN.md
Normal file
@@ -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
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
## 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.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
## 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
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<acceptance_criteria>
|
||||||
|
|
||||||
|
## 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
|
||||||
|
```
|
||||||
|
|
||||||
|
</acceptance_criteria>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Dodac operacje close_existing_comments do WordPressService i remote service</name>
|
||||||
|
<files>src/Services/WordPressService.php</files>
|
||||||
|
<action>
|
||||||
|
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.
|
||||||
|
</action>
|
||||||
|
<verify>php -l src/Services/WordPressService.php</verify>
|
||||||
|
<done>AC-1, AC-2 i AC-3 maja warstwe zdalnej operacji WordPress.</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Dodac akcje kontrolera i trase masowego zamkniecia</name>
|
||||||
|
<files>src/Controllers/SiteController.php, config/routes.php</files>
|
||||||
|
<action>
|
||||||
|
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.
|
||||||
|
</action>
|
||||||
|
<verify>php -l src/Controllers/SiteController.php oraz php -l config/routes.php</verify>
|
||||||
|
<done>AC-1, AC-2 i AC-3 sa dostepne z panelu przez POST route.</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 3: Dodac UI hard-close w panelu komentarzy</name>
|
||||||
|
<files>templates/sites/comments.php</files>
|
||||||
|
<action>
|
||||||
|
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.
|
||||||
|
</action>
|
||||||
|
<verify>php -l templates/sites/comments.php</verify>
|
||||||
|
<done>AC-1 i AC-2 maja widoczny, potwierdzany interfejs uzytkownika.</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<boundaries>
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
</boundaries>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
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
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
- 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.
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.paul/phases/02-admin-panel-upgrade/02-03-SUMMARY.md`
|
||||||
|
</output>
|
||||||
38
.paul/phases/02-admin-panel-upgrade/02-03-SUMMARY.md
Normal file
38
.paul/phases/02-admin-panel-upgrade/02-03-SUMMARY.md
Normal file
@@ -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*
|
||||||
@@ -34,6 +34,7 @@ $router->post('/sites/{id}/test', 'SiteController', 'testConnection');
|
|||||||
$router->get('/sites/{id}/dashboard', 'SiteController', 'dashboard');
|
$router->get('/sites/{id}/dashboard', 'SiteController', 'dashboard');
|
||||||
$router->get('/sites/{id}/comments', 'SiteController', 'comments');
|
$router->get('/sites/{id}/comments', 'SiteController', 'comments');
|
||||||
$router->post('/sites/{id}/comments/settings', 'SiteController', 'updateCommentsEnabled');
|
$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}/comments/{commentId}/delete', 'SiteController', 'deleteComment');
|
||||||
$router->post('/sites/{id}/dashboard/permalinks/enable', 'SiteController', 'enablePrettyPermalinks');
|
$router->post('/sites/{id}/dashboard/permalinks/enable', 'SiteController', 'enablePrettyPermalinks');
|
||||||
$router->post('/sites/{id}/dashboard/remote-service/update', 'SiteController', 'updateRemoteService');
|
$router->post('/sites/{id}/dashboard/remote-service/update', 'SiteController', 'updateRemoteService');
|
||||||
|
|||||||
@@ -304,6 +304,35 @@ class SiteController extends Controller
|
|||||||
$this->redirect("/sites/{$id}/comments{$statusQuery}");
|
$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
|
public function seoPanel(string $id): void
|
||||||
{
|
{
|
||||||
Auth::requireLogin();
|
Auth::requireLogin();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class WordPressService
|
|||||||
{
|
{
|
||||||
private const BACKPRO_MU_PLUGIN_FILENAME = 'backpro-remote-tools.php';
|
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_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_SLUG = 'backpro-news-mag';
|
||||||
private const BACKPRO_NEWS_THEME_SOURCE_DIR = 'assets/wp-theme-backpro-news';
|
private const BACKPRO_NEWS_THEME_SOURCE_DIR = 'assets/wp-theme-backpro-news';
|
||||||
private Client $client;
|
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
|
public function ensureRemoteService(array $site): array
|
||||||
{
|
{
|
||||||
$siteData = $this->prepareRemoteServiceMetadata($site);
|
$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
|
private function formatWpRequestError(RequestException $e, string $fallback): string
|
||||||
{
|
{
|
||||||
$statusCode = $e->hasResponse() ? (int) $e->getResponse()->getStatusCode() : 0;
|
$statusCode = $e->hasResponse() ? (int) $e->getResponse()->getStatusCode() : 0;
|
||||||
@@ -1342,7 +1384,7 @@ if (!defined('ABSPATH')) {
|
|||||||
|
|
||||||
\$action = (string) (\$_POST['action'] ?? '');
|
\$action = (string) (\$_POST['action'] ?? '');
|
||||||
if (\$action === 'ping') {
|
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;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1463,6 +1505,48 @@ if (\$action === 'set_comment_settings') {
|
|||||||
exit;
|
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') {
|
if (\$action === 'cleanup') {
|
||||||
@unlink(__FILE__);
|
@unlink(__FILE__);
|
||||||
echo json_encode(['success' => true, 'message' => 'service_deleted']);
|
echo json_encode(['success' => true, 'message' => 'service_deleted']);
|
||||||
|
|||||||
@@ -77,6 +77,37 @@ $badgeClasses = [
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="card border-danger mb-4">
|
||||||
|
<div class="card-header bg-danger-subtle d-flex justify-content-between align-items-center">
|
||||||
|
<h5 class="mb-0 text-danger">Istniejace wpisy</h5>
|
||||||
|
<span class="badge bg-danger">Hard close</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p class="mb-2">
|
||||||
|
Ta operacja zamyka komentarze oraz pingi/trackbacki w juz opublikowanych tresciach tej strony.
|
||||||
|
</p>
|
||||||
|
<p class="small text-muted mb-3">
|
||||||
|
Uzyj jej po wylaczeniu komentowania nowych wpisow, gdy boty nadal dodaja komentarze pod starszymi artykulami.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form
|
||||||
|
method="post"
|
||||||
|
action="/sites/<?= (int) $site['id'] ?>/comments/close-existing"
|
||||||
|
data-confirm="Zamknac komentarze i pingi we wszystkich istniejacych wpisach tej strony WordPress?"
|
||||||
|
>
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input class="form-check-input" type="checkbox" name="delete_pending_comments" value="1" id="deletePendingComments">
|
||||||
|
<label class="form-check-label" for="deletePendingComments">
|
||||||
|
Usun oczekujace komentarze przy tej operacji
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-outline-danger">
|
||||||
|
<i class="bi bi-shield-slash me-1"></i>Zamknij komentarze w istniejacych wpisach
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header d-flex justify-content-between align-items-center">
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
<h5 class="mb-0">Lista komentarzy</h5>
|
<h5 class="mb-0">Lista komentarzy</h5>
|
||||||
|
|||||||
Reference in New Issue
Block a user