feat(media-folder-pro): add virtual folder system for WordPress media library
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>
This commit is contained in:
239
.paul/phases/04-polish-ux/04-01-PLAN.md
Normal file
239
.paul/phases/04-polish-ux/04-01-PLAN.md
Normal file
@@ -0,0 +1,239 @@
|
||||
---
|
||||
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>
|
||||
130
.paul/phases/04-polish-ux/04-01-SUMMARY.md
Normal file
130
.paul/phases/04-polish-ux/04-01-SUMMARY.md
Normal file
@@ -0,0 +1,130 @@
|
||||
---
|
||||
phase: 04-polish-ux
|
||||
plan: 01
|
||||
subsystem: media
|
||||
tags: [wordpress, ux, bulk-assign, drag-drop, toast, empty-state]
|
||||
|
||||
requires:
|
||||
- phase: 03-media-modal
|
||||
provides: Full modal integration, all AJAX endpoints
|
||||
provides:
|
||||
- Bulk assign media to folders
|
||||
- Uncategorized filter
|
||||
- Folder drag & drop (hierarchy reorder)
|
||||
- Toast notification system
|
||||
- Empty state with CTA
|
||||
- CSS spinner loading
|
||||
affects: []
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [toast notification system, dual dataTransfer types for D&D disambiguation, MutationObserver for bulk button injection]
|
||||
|
||||
key-files:
|
||||
created: []
|
||||
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/media-folder-pro.php
|
||||
|
||||
key-decisions:
|
||||
- "Separate dataTransfer types: text/plain for media, application/mfp-folder for folders"
|
||||
- "Yellow outline for folder-on-folder D&D vs blue for media-on-folder"
|
||||
- "Toast auto-hide 3s with CSS slide-in/fade-out transition"
|
||||
- "confirm() kept for delete operations (destructive needs confirmation)"
|
||||
- "Bulk dropdown injected via MutationObserver on media-toolbar-secondary"
|
||||
|
||||
patterns-established:
|
||||
- "window.mfpToast(message, type) global toast API"
|
||||
- "mfp-media-dropped CustomEvent for cross-module media assignment"
|
||||
- "Tree root drop zone for moving folders to top level"
|
||||
|
||||
duration: ~15min
|
||||
started: 2026-03-28
|
||||
completed: 2026-03-28
|
||||
---
|
||||
|
||||
# Phase 4 Plan 01: Polish & UX Summary
|
||||
|
||||
**Bulk media assignment, uncategorized filter, folder hierarchy drag & drop, toast notifications replacing all alert() calls, and polished empty/loading states.**
|
||||
|
||||
## Performance
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Duration | ~15min |
|
||||
| Tasks | 2 completed |
|
||||
| Files modified | 4 |
|
||||
|
||||
## Acceptance Criteria Results
|
||||
|
||||
| Criterion | Status | Notes |
|
||||
|-----------|--------|-------|
|
||||
| AC-1: Bulk assign mediow do folderu | Pass | Button in toolbar, dropdown with hierarchy, multi-select assign |
|
||||
| AC-2: Filtr "Bez folderu" | Pass | Uncategorized link in sidebar, folderId=-1, NOT EXISTS query |
|
||||
| AC-3: Drag & drop folderow w drzewku | Pass | application/mfp-folder type, yellow visual, root drop zone |
|
||||
| AC-4: Toast notifications i empty states | Pass | All alert()→toast, CTA empty state, CSS spinner |
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- Bulk assign: "Przenies do folderu" button in WP media toolbar with hierarchical dropdown
|
||||
- "Bez folderu" filter in sidebar using folderId=-1 (MFP_Media_Query NOT EXISTS)
|
||||
- Folder drag & drop with separate dataTransfer type to avoid collision with media drag
|
||||
- Drop on tree root area moves folder to top level (parent=0)
|
||||
- Toast notification system (success/error/info) with 3s auto-hide and CSS animations
|
||||
- All alert() replaced with toast (confirm() kept for destructive delete)
|
||||
- Empty state with folder icon, text, and CTA button
|
||||
- CSS spinner replacing "..." loading text
|
||||
- 7 new i18n strings in both enqueue methods
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
| File | Change | Purpose |
|
||||
|------|--------|---------|
|
||||
| `assets/js/folder-tree.js` | Major rewrite | Toast system, uncategorized, folder D&D, empty CTA, spinner |
|
||||
| `assets/js/media-filter.js` | Major rewrite | Bulk assign, toast integration, mfp-media-dropped handler |
|
||||
| `assets/css/admin.css` | Extended | Uncategorized, folder D&D yellow, bulk dropdown, toasts, empty, spinner |
|
||||
| `media-folder-pro.php` | Modified | 7 new i18n strings in both enqueue methods |
|
||||
|
||||
## Decisions Made
|
||||
|
||||
| Decision | Rationale | Impact |
|
||||
|----------|-----------|--------|
|
||||
| Dual dataTransfer types | Prevent folder drag from triggering media assign | Clean D&D disambiguation |
|
||||
| Yellow vs blue D&D indicators | Visual distinction between operations | Clear UX feedback |
|
||||
| MutationObserver for bulk button | WP toolbar renders asynchronously | Reliable injection |
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None — plan executed exactly as written.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
None
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
**Milestone v0.1 Media Folders MVP is COMPLETE.**
|
||||
|
||||
All 4 phases delivered:
|
||||
1. Plugin foundation + taxonomy
|
||||
2. Media grid filtering + media D&D
|
||||
3. Modal integration + upload assign
|
||||
4. Bulk operations, UX polish, toast notifications
|
||||
|
||||
**Plugin feature summary:**
|
||||
- Virtual folder system via custom taxonomy
|
||||
- Sidebar folder tree with full CRUD
|
||||
- Media grid filtering by folder
|
||||
- Drag & drop media to folders
|
||||
- Modal dropdown filter + upload auto-assign
|
||||
- Bulk assign from WP toolbar
|
||||
- "Uncategorized" filter
|
||||
- Folder hierarchy D&D
|
||||
- Toast notifications
|
||||
- Empty states + loading spinners
|
||||
|
||||
---
|
||||
*Phase: 04-polish-ux, Plan: 01*
|
||||
*Completed: 2026-03-28*
|
||||
Reference in New Issue
Block a user