Custom WordPress plugin that replaces the default flat media library with a structured folder view. Features: hierarchical folders via custom taxonomy, sidebar folder tree, drag & drop, modal integration with Elementor/builders, bulk assign, upload auto-assign, toast notifications. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
240 lines
9.3 KiB
Markdown
240 lines
9.3 KiB
Markdown
---
|
|
phase: 04-polish-ux
|
|
plan: 01
|
|
type: execute
|
|
wave: 1
|
|
depends_on: ["03-01"]
|
|
files_modified:
|
|
- wp-content/plugins/media-folder-pro/assets/js/folder-tree.js
|
|
- wp-content/plugins/media-folder-pro/assets/js/media-filter.js
|
|
- wp-content/plugins/media-folder-pro/assets/css/admin.css
|
|
- wp-content/plugins/media-folder-pro/includes/class-ajax-handler.php
|
|
- wp-content/plugins/media-folder-pro/media-folder-pro.php
|
|
autonomous: true
|
|
---
|
|
|
|
<objective>
|
|
## Goal
|
|
Dopracowac UX pluginu: bulk przypisywanie mediow do folderow, dynamiczne countery, "Uncategorized" filtr, potwierdzenia operacji, stany puste, oraz drag & drop folderow miedzy soba w drzewku.
|
|
|
|
## Purpose
|
|
Core features dzialaja — teraz potrzebny jest polish, ktory zamieni prototyp w uzyteczne narzedzie. Bez bulk operations i dobrych stanow pustych plugin bedzie frustrujacy w uzyciu.
|
|
|
|
## Output
|
|
- Bulk select + assign do folderu
|
|
- "Bez folderu" filtr (uncategorized media)
|
|
- Drag & drop folderow (zmiana hierarchii)
|
|
- Dynamiczne countery (live update)
|
|
- Toast notifications zamiast alert()
|
|
- Empty states i loading indicators
|
|
</objective>
|
|
|
|
<context>
|
|
## Project Context
|
|
@.paul/PROJECT.md
|
|
@.paul/ROADMAP.md
|
|
|
|
## Prior Work
|
|
@.paul/phases/03-media-modal/03-01-SUMMARY.md
|
|
- Pelna integracja: sidebar tree + grid filter + modal dropdown + upload assign
|
|
- 7 AJAX endpoints (create/rename/delete/move/get_folders/assign_media/upload_to_folder)
|
|
- HTML5 D&D media→folders dziala, mfp-folder-changed event sync
|
|
|
|
## Source Files
|
|
@wp-content/plugins/media-folder-pro/assets/js/folder-tree.js
|
|
@wp-content/plugins/media-folder-pro/assets/js/media-filter.js
|
|
@wp-content/plugins/media-folder-pro/assets/css/admin.css
|
|
@wp-content/plugins/media-folder-pro/includes/class-ajax-handler.php
|
|
@wp-content/plugins/media-folder-pro/media-folder-pro.php
|
|
</context>
|
|
|
|
<acceptance_criteria>
|
|
|
|
## AC-1: Bulk assign mediow do folderu
|
|
```gherkin
|
|
Given plugin aktywny, widok grid na upload.php
|
|
When uzytkownik zaznacza wiele mediow (WP bulk select) i wybiera "Przenies do folderu"
|
|
Then pojawia sie dropdown z folderami
|
|
And po wyborze folderu wszystkie zaznaczone media zostaja przypisane
|
|
And countery folderow aktualizuja sie
|
|
```
|
|
|
|
## AC-2: Filtr "Bez folderu" (uncategorized)
|
|
```gherkin
|
|
Given plugin aktywny, istnieja media bez przypisanego folderu
|
|
When uzytkownik klika "Bez folderu" w drzewku sidebar
|
|
Then grid pokazuje tylko media nieprzypisane do zadnego folderu
|
|
```
|
|
|
|
## AC-3: Drag & drop folderow w drzewku
|
|
```gherkin
|
|
Given plugin aktywny, istnieja foldery w drzewku
|
|
When uzytkownik przeciaga folder na inny folder
|
|
Then przeniesiony folder staje sie podfolderem docelowego
|
|
And drzewko odswierza sie z nowa hierarchia
|
|
And przenoszenie na root (poza drzewko) robi folder top-level
|
|
```
|
|
|
|
## AC-4: Toast notifications i empty states
|
|
```gherkin
|
|
Given plugin aktywny
|
|
When uzytkownik wykonuje operacje (assign, create, delete, move)
|
|
Then pojawia sie toast notification (nie alert()) z wynikiem
|
|
And po zakonczeniu toast znika po 3 sekundach
|
|
|
|
Given brak folderow w systemie
|
|
When uzytkownik otwiera upload.php
|
|
Then w sidebar widoczny jest empty state z CTA "Utworz pierwszy folder"
|
|
```
|
|
|
|
</acceptance_criteria>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Bulk assign + uncategorized filter + folder drag & drop</name>
|
|
<files>wp-content/plugins/media-folder-pro/assets/js/folder-tree.js, wp-content/plugins/media-folder-pro/assets/js/media-filter.js, wp-content/plugins/media-folder-pro/assets/css/admin.css, wp-content/plugins/media-folder-pro/media-folder-pro.php</files>
|
|
<action>
|
|
1. Bulk assign w media-filter.js:
|
|
- Dodaj button "Przenies do folderu" do WP bulk actions bar
|
|
- Hook na wp.media.view.AttachmentsBrowser lub na DOM (bulk select mode)
|
|
- Metoda: po kliknieciu pokaz dropdown z folderami (reuse flattenFolders z modala)
|
|
- Po wyborze folderu: zbierz IDs zaznaczonych mediow
|
|
- Uzyj wp.media.frame selection lub querySelectorAll('.attachment.selected')
|
|
- Wywolaj mfp_assign_media z tablica IDs
|
|
- Po sukcesie: refreshTree() + odswierz grid
|
|
|
|
2. "Bez folderu" w folder-tree.js:
|
|
- Dodaj pozycje "Bez folderu" pod "Wszystkie media" w sidebar
|
|
- Klikniecie dispatcha 'mfp-folder-selected' z folderId: -1
|
|
- W media-filter.js: jesli folderId === -1, ustaw media_folder: -1
|
|
(MFP_Media_Query juz obsluguje -1 jako NOT EXISTS)
|
|
- Dodaj ikone i styl (np. szary folder z ?)
|
|
|
|
3. Drag & drop folderow w folder-tree.js:
|
|
- Na kazdym .mfp-folder__row: draggable="true"
|
|
- dragstart: ustaw dataTransfer z type 'mfp-folder' + folder ID
|
|
- Uzyj innego MIME type niz media drag (np. 'application/mfp-folder')
|
|
- W drop handler: sprawdz typ danych
|
|
- Jesli 'application/mfp-folder': to folder move → wywolaj mfp_move_folder
|
|
- Jesli 'text/plain' (liczba): to media assign (istniejace zachowanie)
|
|
- Drop na root area (poza folderami): new_parent_id = 0 (top-level)
|
|
- Po sukcesie: refreshTree()
|
|
- Wizualne: inny styl drop target dla folder-on-folder (np. zolty outline)
|
|
|
|
4. W admin.css:
|
|
- Style dla "Bez folderu" linku
|
|
- Style dla folder drag (rozny od media drag)
|
|
- Style dla bulk assign dropdown/popup
|
|
- .mfp-folder-drop-target (zolty, rozny od mfp-drop-target niebieski)
|
|
|
|
5. W media-folder-pro.php:
|
|
- Dodaj i18n: 'uncategorized', 'moveToFolder', 'bulkAssigned'
|
|
|
|
Avoid: Nie komplikowac bulk assign — prosty dropdown popup wystarczy.
|
|
Avoid: Folder drag nie moze kolidowac z media drag — rozne dataTransfer types.
|
|
</action>
|
|
<verify>
|
|
- Zaznaczenie wielu mediow + bulk assign → przypisuje do wybranego folderu
|
|
- "Bez folderu" klikalny, filtruje nieprzypisane media
|
|
- Przeciaganie folderu na inny folder → zmiana hierarchii
|
|
- Brak kolizji miedzy media drag a folder drag
|
|
- Countery odswiezone po kazdej operacji
|
|
</verify>
|
|
<done>AC-1 + AC-2 + AC-3 satisfied: bulk, uncategorized, folder D&D</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Toast notifications + empty states + final polish</name>
|
|
<files>wp-content/plugins/media-folder-pro/assets/js/folder-tree.js, wp-content/plugins/media-folder-pro/assets/js/media-filter.js, wp-content/plugins/media-folder-pro/assets/css/admin.css</files>
|
|
<action>
|
|
1. System toast notifications:
|
|
- Dodaj funkcje showToast(message, type) w folder-tree.js
|
|
- type: 'success' (zielony), 'error' (czerwony), 'info' (niebieski)
|
|
- Renderuj div.mfp-toast w prawym gornym rogu (fixed)
|
|
- Auto-hide po 3s z CSS transition (fade out)
|
|
- Wyeksportuj jako window.mfpToast(message, type)
|
|
- Zamien WSZYSTKIE alert() i confirm() na:
|
|
- alert() → showToast()
|
|
- confirm() → natywny confirm() zostaje (jest OK dla destrukcji)
|
|
|
|
2. Zamien alert() w folder-tree.js:
|
|
- createFolder success → toast 'Folder utworzony'
|
|
- renameFolder success → toast 'Nazwa zmieniona'
|
|
- deleteFolder success → toast 'Folder usuniety'
|
|
- Errory → toast z type 'error'
|
|
|
|
3. Zamien alert() w media-filter.js:
|
|
- assignMedia success → toast 'Media przypisane'
|
|
- Errory → toast z type 'error'
|
|
|
|
4. Empty states w folder-tree.js:
|
|
- Obecny empty state juz istnieje ("Kliknij + aby utworzyc...")
|
|
- Ulepsz: dodaj ikone folderu, wieksza czcionka, przycisk CTA
|
|
- Loading state: zamien '...' na spinner CSS (animated)
|
|
|
|
5. CSS w admin.css:
|
|
- .mfp-toast: fixed position, right:20px, top:50px, z-index:10000
|
|
- .mfp-toast--success: zielone tlo
|
|
- .mfp-toast--error: czerwone tlo
|
|
- .mfp-toast--info: niebieskie tlo
|
|
- Animacja: slide-in + fade-out
|
|
- .mfp-empty ulepszone: ikona + CTA button
|
|
- .mfp-spinner: CSS-only spinner (border animation)
|
|
|
|
Avoid: Nie uzywac zewnetrznych bibliotek toast (np. toastr).
|
|
Avoid: Nie zastepowac confirm() przy usuwaniu — potrzebne jest potwierdzenie.
|
|
</action>
|
|
<verify>
|
|
- Tworzenie folderu → toast "Folder utworzony" (zielony, 3s auto-hide)
|
|
- Blad AJAX → toast z bledem (czerwony)
|
|
- Brak folderow → empty state z ikona i CTA
|
|
- Ladowanie folderow → spinner
|
|
- Brak alert() w kodzie (oprocz confirm dla delete)
|
|
- Brak JS errors w konsoli
|
|
</verify>
|
|
<done>AC-4 satisfied: toast notifications i empty states</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<boundaries>
|
|
|
|
## DO NOT CHANGE
|
|
- wp-content/plugins/elementor-pro/*
|
|
- wp-content/plugins/media-folder-pro/includes/class-taxonomy.php
|
|
- wp-content/plugins/media-folder-pro/includes/class-media-query.php
|
|
- wp-content/plugins/media-folder-pro/assets/js/modal-integration.js (stabilna)
|
|
|
|
## SCOPE LIMITS
|
|
- Brak keyboard navigation (nice-to-have, nie MVP)
|
|
- Brak accessibility ARIA (nice-to-have, nie MVP)
|
|
- Brak i18n .pot file (osobny task poza MVP)
|
|
- Brak settings page (nie potrzebna w MVP)
|
|
|
|
</boundaries>
|
|
|
|
<verification>
|
|
Before declaring plan complete:
|
|
- [ ] Bulk select + assign dziala
|
|
- [ ] "Bez folderu" filtruje uncategorized media
|
|
- [ ] Folder drag & drop zmienia hierarchie
|
|
- [ ] Toast notifications zamiast alert()
|
|
- [ ] Empty state z CTA gdy brak folderow
|
|
- [ ] Loading spinner podczas ladowania
|
|
- [ ] Brak regresji: wszystkie Phase 1-3 features dzialaja
|
|
- [ ] Brak JS errors w konsoli
|
|
- [ ] Brak PHP errors/warnings
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- Wszystkie taski ukonczone
|
|
- Plugin gotowy jako MVP v0.1
|
|
- Wszystkie 4 fazy dzialaja razem
|
|
- UX jest plynny i profesjonalny
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.paul/phases/04-polish-ux/04-01-SUMMARY.md`
|
|
</output>
|