257 lines
10 KiB
Markdown
257 lines
10 KiB
Markdown
---
|
|
phase: 03-miejsca-postojowe
|
|
plan: 01
|
|
type: execute
|
|
wave: 1
|
|
depends_on: []
|
|
files_modified:
|
|
- wp-content/plugins/elementor-addon/elementor-addon.php
|
|
- wp-content/plugins/elementor-addon/widgets/parking-spots.php
|
|
- wp-content/plugins/elementor-addon/assets/js/main.js
|
|
- wp-content/plugins/elementor-addon/assets/css/main.css
|
|
autonomous: false
|
|
---
|
|
|
|
<objective>
|
|
## Goal
|
|
Stworzyc widget Elementor "Miejsca postojowe" wyswietlajacy ceny dwoch typow miejsc (zwykle i rodzinne) z przyciskiem "Historia cen" oraz popup, a takze rozszerzyc cron, AJAX i XML export o dane parkingowe.
|
|
|
|
## Purpose
|
|
Deweloper musi prezentowac ceny miejsc postojowych na stronie oferty oraz raportowac je do dane.gov.pl zgodnie z ustawa o jawnosci cen.
|
|
|
|
## Output
|
|
- Nowy widget Elementor: `Elementor_Parking_Spots`
|
|
- Tabela DB: `wp_parking_price_history`
|
|
- Rozszerzony cron o zapis cen parkingowych
|
|
- Rozszerzony AJAX o historie cen parkingowych
|
|
- Rozszerzony XML export o miejsca postojowe
|
|
</objective>
|
|
|
|
<context>
|
|
## Project Context
|
|
@.paul/PROJECT.md
|
|
@.paul/ROADMAP.md
|
|
@.paul/STATE.md
|
|
|
|
## Source Files
|
|
@wp-content/plugins/elementor-addon/elementor-addon.php
|
|
@wp-content/plugins/elementor-addon/widgets/apartaments.php
|
|
@wp-content/plugins/elementor-addon/assets/js/main.js
|
|
@wp-content/plugins/elementor-addon/assets/css/main.css
|
|
|
|
## Existing Patterns
|
|
- Apartament widget: klasa Elementor_Apartaments w widgets/apartaments.php
|
|
- Historia cen popup: globalny overlay #price-history-overlay, wypelniany przez AJAX
|
|
- AJAX endpoint: wp_ajax_apartamenty_get_price_history → JSON {title, price, price_m2, history}
|
|
- Cron: apartamenty_record_prices → INSERT IGNORE do wp_price_history
|
|
- XML: apartamenty_generate_price_xml() → <lokale> z <lokal> per apartament
|
|
- ACF: parking prices sa w opcjach ACF (options page), klucze do odkrycia w DB
|
|
- Garage map: get_field('garage_spots', 'option') → parking-N → status
|
|
</context>
|
|
|
|
<skills>
|
|
No specialized flows configured.
|
|
</skills>
|
|
|
|
<acceptance_criteria>
|
|
|
|
## AC-1: Widget wyswietla ceny parkingowe
|
|
```gherkin
|
|
Given widget "Miejsca postojowe" jest dodany na stronie w Elementorze
|
|
When uzytkownik otwiera strone
|
|
Then widzi sekcje z dwoma typami: "Miejsce postojowe zwykle" i "Miejsce postojowe Rodzinne"
|
|
And kazdy typ ma wyswietlona aktualna cene z ACF
|
|
And kazdy typ ma przycisk "HISTORIA CEN"
|
|
```
|
|
|
|
## AC-2: Popup historia cen dziala dla miejsc postojowych
|
|
```gherkin
|
|
Given uzytkownik widzi widget miejsc postojowych
|
|
When klika przycisk "HISTORIA CEN" przy dowolnym typie
|
|
Then otwiera sie popup z aktualna cena i tabela historii zmian cen
|
|
And popup zamyka sie przyciskiem X, klikajac overlay lub klawiszem Escape
|
|
```
|
|
|
|
## AC-3: Cron zapisuje ceny parkingowe codziennie
|
|
```gherkin
|
|
Given WP Cron jest zaplanowany
|
|
When uruchamia sie dzienne zadanie
|
|
Then aktualne ceny obu typow miejsc postojowych sa zapisywane do wp_parking_price_history
|
|
And zapis jest idempotentny (INSERT IGNORE, jeden rekord na typ na dzien)
|
|
```
|
|
|
|
## AC-4: XML export zawiera miejsca postojowe
|
|
```gherkin
|
|
Given endpoint /ceny-mieszkan.xml jest dostepny
|
|
When uzytkownik pobiera XML
|
|
Then XML zawiera sekcje <miejsca_postojowe> z oboma typami
|
|
And kazdy typ ma aktualna cene i historie zmian
|
|
```
|
|
|
|
</acceptance_criteria>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Odkryj klucze ACF dla cen parkingowych i stworz tabele DB + cron + AJAX</name>
|
|
<files>wp-content/plugins/elementor-addon/elementor-addon.php</files>
|
|
<action>
|
|
1. **Odkryj ACF meta keys** — sprawdz w bazie (wp_options) jakie klucze ACF sa uzywane dla cen miejsc postojowych. Prawdopodobnie sa w opcjach ACF (get_field z 'option'). Poszukaj kluczy zawierajacych "parking", "postojow", "garage_price" lub podobnych.
|
|
|
|
2. **Stworz tabele wp_parking_price_history:**
|
|
```sql
|
|
CREATE TABLE wp_parking_price_history (
|
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
parking_type VARCHAR(50) NOT NULL, -- 'zwykle' lub 'rodzinne'
|
|
price VARCHAR(50) NOT NULL DEFAULT '',
|
|
recorded_at DATE NOT NULL,
|
|
UNIQUE KEY unique_daily (parking_type, recorded_at),
|
|
KEY idx_type (parking_type)
|
|
)
|
|
```
|
|
- Dodaj funkcje tworzaca tabele analogicznie do elementor_addon_create_price_history_table()
|
|
- Zaktualizuj elementor_addon_maybe_update_db() — zmien wersje DB na '1.1'
|
|
|
|
3. **Rozszerz cron** — w elementor_addon_record_prices() dodaj po petli apartamentow:
|
|
- Pobierz ceny parkingowe z ACF options (odkryte klucze)
|
|
- INSERT IGNORE do wp_parking_price_history dla kazdego typu
|
|
|
|
4. **Dodaj AJAX endpoint** — nowa funkcja `elementor_addon_get_parking_price_history_ajax()`:
|
|
- Akcja: wp_ajax_parking_get_price_history / wp_ajax_nopriv_parking_get_price_history
|
|
- Parametr: parking_type ('zwykle' lub 'rodzinne')
|
|
- Zwraca: JSON {type_label, price, history: [{recorded_at, price}]}
|
|
- Uzywa tego samego nonce co apartamenty
|
|
|
|
5. **Rozszerz XML** — w apartamenty_generate_price_xml() po zamknieciu </lokale>... nie, lepiej:
|
|
- Zmien root element na <nieruchomosci> opakowujacy <lokale> i nowy <miejsca_postojowe>
|
|
- LUB dodaj <miejsca_postojowe> wewnatrz <lokale> (prostsze)
|
|
- Kazdy typ: <miejsce_postojowe typ="zwykle">, <cena>, <historia_cen>
|
|
- Wyczysc transient po aktualizacji
|
|
|
|
Avoid:
|
|
- NIE zmieniaj istniejacego schematu wp_price_history (apartamenty)
|
|
- NIE usuwaj istniejacych endpointow XML — rozszerzaj
|
|
</action>
|
|
<verify>
|
|
- Tabela wp_parking_price_history istnieje po aktywacji/upgrade
|
|
- Reczne wywolanie crona zapisuje rekordy parkingowe
|
|
- AJAX endpoint zwraca poprawny JSON
|
|
- XML zawiera sekcje miejsca_postojowe
|
|
</verify>
|
|
<done>AC-3 i AC-4 satisfied: cron zapisuje ceny, XML eksportuje miejsca postojowe</done>
|
|
</task>
|
|
|
|
<task type="checkpoint:human-verify" gate="blocking">
|
|
<what-built>Backend: tabela DB, cron, AJAX endpoint, XML export dla miejsc postojowych</what-built>
|
|
<how-to-verify>
|
|
1. Sprawdz w wp-admin > Narzedzia > Jawnosc Cen czy XML zawiera miejsca postojowe
|
|
2. Otworz /ceny-mieszkan.xml w przegladarce i sprawdz sekcje miejsca_postojowe
|
|
3. Potwierdz ze ACF klucze zostaly poprawnie odkryte
|
|
</how-to-verify>
|
|
<resume-signal>Type "approved" to continue to widget, or describe issues</resume-signal>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Stworz widget Elementor "Miejsca postojowe" z przyciskiem historia cen</name>
|
|
<files>
|
|
wp-content/plugins/elementor-addon/widgets/parking-spots.php,
|
|
wp-content/plugins/elementor-addon/assets/js/main.js,
|
|
wp-content/plugins/elementor-addon/assets/css/main.css,
|
|
wp-content/plugins/elementor-addon/elementor-addon.php
|
|
</files>
|
|
<action>
|
|
1. **Stworz widgets/parking-spots.php** — klasa Elementor_Parking_Spots:
|
|
- get_name() → 'parking_spots'
|
|
- get_title() → 'Miejsca Postojowe'
|
|
- get_style_depends / get_script_depends → te same co apartaments
|
|
- render():
|
|
a) Pobierz ceny z ACF options (odkryte klucze)
|
|
b) Wyrenderuj dwie karty: "Miejsce postojowe zwykle" i "Miejsce postojowe Rodzinne"
|
|
c) Kazda karta: nazwa typu, cena, przycisk "HISTORIA CEN" z data-parking-type="zwykle/rodzinne"
|
|
d) Uzyj stylistyki zblizonej do apartament-card__info (tabela z cenami)
|
|
e) Wyrenderuj ten sam popup overlay co apartamenty (reuse #price-history-overlay)
|
|
— popup juz istnieje globalnie, wiec NIE renderuj go ponownie jesli jest na tej samej stronie
|
|
— dodaj warunek: renderuj popup tylko jesli nie ma go jeszcze w DOM
|
|
|
|
2. **Zarejestruj widget** w elementor-addon.php:
|
|
- W register_hello_world_widget() dodaj require + register dla Elementor_Parking_Spots
|
|
|
|
3. **Rozszerz main.js** — dodaj obsluge klikniecia .btn-parking-historia-cen:
|
|
- Analogicznie do .btn-historia-cen ale wysyla parking_type zamiast post_id
|
|
- Uzywa akcji 'parking_get_price_history'
|
|
- Wypelnia ten sam popup (reuse)
|
|
- Tabela historii: data, cena (bez ceny/m2 — uproszczona)
|
|
|
|
4. **Rozszerz main.css** — dodaj style dla widgetu parkingowego:
|
|
- Klasa .parking-spots z kartami
|
|
- Styl zbliżony do apartament-card ale uproszczony (bez galerii, dokumentow)
|
|
- Responsive
|
|
|
|
Avoid:
|
|
- NIE duplikuj popupa historia cen — uzyj istniejacego
|
|
- NIE zmieniaj stylow apartamentow
|
|
- NIE dodawaj Swipera/FancyBoxa — widget parkingowy ich nie potrzebuje
|
|
</action>
|
|
<verify>
|
|
- Widget pojawia sie w panelu Elementor w kategorii "basic"
|
|
- Po dodaniu na strone wyswietla dwa typy z cenami
|
|
- Klikniecie "Historia cen" otwiera popup z danymi
|
|
</verify>
|
|
<done>AC-1 i AC-2 satisfied: widget wyswietla ceny, popup historia cen dziala</done>
|
|
</task>
|
|
|
|
<task type="checkpoint:human-verify" gate="blocking">
|
|
<what-built>Widget Elementor "Miejsca Postojowe" z historia cen — design wg Figma Frame 16</what-built>
|
|
<how-to-verify>
|
|
1. Otworz Elementor na stronie /apartamenty/ lub testowej
|
|
2. Dodaj widget "Miejsca Postojowe"
|
|
3. Sprawdz czy wyswietla dwa typy z cenami
|
|
4. Kliknij "Historia cen" — sprawdz popup
|
|
5. Porownaj z designem na Figmie (Frame 16)
|
|
6. Sprawdz responsywnosc (mobile)
|
|
</how-to-verify>
|
|
<resume-signal>Type "approved" or describe visual/functional issues</resume-signal>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<boundaries>
|
|
|
|
## DO NOT CHANGE
|
|
- wp-content/plugins/elementor-addon/widgets/apartaments.php (widget apartamentow stabilny)
|
|
- wp-content/themes/hello-elementor/template-parts/garage-map.php (mapa garazowa)
|
|
- Istniejacy schemat tabeli wp_price_history (nie modyfikuj kolumn)
|
|
- Istniejace endpointy XML — rozszerzaj, nie usuwaj
|
|
|
|
## SCOPE LIMITS
|
|
- Tylko dwa typy miejsc postojowych: zwykle i rodzinne
|
|
- Brak galerii/dokumentow w widgecie parkingowym
|
|
- Brak edycji cen w widgecie — ceny z ACF options
|
|
- Strona admina Jawnosc Cen — nie modyfikuj (XML sam sie rozszerzy)
|
|
|
|
</boundaries>
|
|
|
|
<verification>
|
|
Before declaring plan complete:
|
|
- [ ] Widget "Miejsca Postojowe" renderuje dwa typy z cenami ACF
|
|
- [ ] Przycisk "Historia cen" otwiera popup z danymi z AJAX
|
|
- [ ] Cron zapisuje ceny parkingowe do wp_parking_price_history
|
|
- [ ] /ceny-mieszkan.xml zawiera sekcje z miejscami postojowymi
|
|
- [ ] Brak bledow PHP (WP_DEBUG=true)
|
|
- [ ] Istniejace funkcjonalnosci apartamentow nie naruszone
|
|
- [ ] All acceptance criteria met
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- All tasks completed
|
|
- All verification checks pass
|
|
- No PHP errors or warnings introduced
|
|
- Widget dostepny w Elementor i poprawnie renderuje
|
|
- Historia cen popup dziala identycznie jak dla apartamentow
|
|
- XML export zawiera miejsca postojowe z historia
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.paul/phases/03-miejsca-postojowe/03-01-SUMMARY.md`
|
|
</output>
|