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:
208
.paul/phases/02-media-library-grid/02-01-PLAN.md
Normal file
208
.paul/phases/02-media-library-grid/02-01-PLAN.md
Normal file
@@ -0,0 +1,208 @@
|
||||
---
|
||||
phase: 02-media-library-grid
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: ["01-01"]
|
||||
files_modified:
|
||||
- wp-content/plugins/media-folder-pro/includes/class-ajax-handler.php
|
||||
- wp-content/plugins/media-folder-pro/includes/class-media-query.php
|
||||
- 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
|
||||
autonomous: true
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Goal
|
||||
Podlaczyc drzewko folderow do filtrowania biblioteki mediow WP oraz dodac drag & drop przypisywanie mediow do folderow. Po kliknieciu folderu — grid pokazuje tylko media z tego folderu. Przeciagniecie media na folder przypisuje je.
|
||||
|
||||
## Purpose
|
||||
Bez filtrowania i przypisywania foldery sa bezuzyteczne — to core feature pluginu.
|
||||
|
||||
## Output
|
||||
- Filtrowanie media grid po kliknieciu folderu w sidebar
|
||||
- AJAX endpoint do przypisywania mediow do folderow
|
||||
- Drag & drop mediow z grida na folder w drzewku
|
||||
- Aktualizacja counterow folderow po zmianach
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
## Project Context
|
||||
@.paul/PROJECT.md
|
||||
@.paul/ROADMAP.md
|
||||
|
||||
## Prior Work
|
||||
@.paul/phases/01-media-folders-plugin/01-01-SUMMARY.md
|
||||
- MFP_Taxonomy z media_folder taxonomy
|
||||
- MFP_Ajax_Handler z 5 CRUD endpoints
|
||||
- folder-tree.js dispatches CustomEvent 'mfp-folder-selected'
|
||||
- Sidebar z drzewkiem juz renderuje sie na upload.php
|
||||
|
||||
## Source Files
|
||||
@wp-content/plugins/media-folder-pro/media-folder-pro.php
|
||||
@wp-content/plugins/media-folder-pro/includes/class-ajax-handler.php
|
||||
@wp-content/plugins/media-folder-pro/includes/class-taxonomy.php
|
||||
@wp-content/plugins/media-folder-pro/assets/js/folder-tree.js
|
||||
@wp-content/plugins/media-folder-pro/assets/css/admin.css
|
||||
</context>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: Filtrowanie mediow po kliknieciu folderu
|
||||
```gherkin
|
||||
Given plugin aktywny, istnieja foldery z przypisanymi mediami
|
||||
When uzytkownik klika folder "Zdjecia produktow" w drzewku
|
||||
Then grid mediow pokazuje tylko attachmenty przypisane do tego folderu
|
||||
And klikniecie "Wszystkie media" przywraca pelna liste
|
||||
```
|
||||
|
||||
## AC-2: Przypisywanie mediow do folderow przez AJAX
|
||||
```gherkin
|
||||
Given plugin aktywny, istnieje folder i media bez folderu
|
||||
When wywolany zostaje AJAX mfp_assign_media z attachment_ids i folder_id
|
||||
Then attachmenty zostaja przypisane do taxonomy term media_folder
|
||||
And odpowiedz zawiera liczbe przypisanych mediow
|
||||
```
|
||||
|
||||
## AC-3: Drag & drop mediow na foldery
|
||||
```gherkin
|
||||
Given plugin aktywny, widoczny grid mediow i drzewko folderow
|
||||
When uzytkownik przeciaga miniature media na folder w drzewku
|
||||
Then media zostaje przypisane do tego folderu
|
||||
And counter folderu aktualizuje sie
|
||||
And grid odswieza sie jesli aktywny jest inny folder
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Server-side media query filter + assign endpoint</name>
|
||||
<files>wp-content/plugins/media-folder-pro/includes/class-media-query.php, wp-content/plugins/media-folder-pro/includes/class-ajax-handler.php, wp-content/plugins/media-folder-pro/media-folder-pro.php</files>
|
||||
<action>
|
||||
1. Utworzyc includes/class-media-query.php — klasa MFP_Media_Query:
|
||||
- Hook na 'ajax_query_attachments_args' (filtr WP uzywany przez media grid)
|
||||
- Jesli w $_REQUEST istnieje parametr 'media_folder' (int > 0):
|
||||
- Dodaj tax_query do args: taxonomy=media_folder, terms=[folder_id]
|
||||
- Jesli media_folder === -1 (uncategorized):
|
||||
- Dodaj tax_query z operator NOT EXISTS (media bez folderu)
|
||||
- Metoda register(): add_filter('ajax_query_attachments_args', ...)
|
||||
|
||||
2. W class-ajax-handler.php dodac nowy endpoint mfp_assign_media:
|
||||
- Parametry: attachment_ids (array int), folder_id (int, 0 = usun z folderow)
|
||||
- Dla kazdego attachment_id:
|
||||
- Jesli folder_id > 0: wp_set_object_terms($attachment_id, [$folder_id], 'media_folder')
|
||||
- Jesli folder_id === 0: wp_set_object_terms($attachment_id, [], 'media_folder')
|
||||
- Zwraca: {success: true, count: N, folder_counts: {id: count, ...}}
|
||||
- folder_counts: zaktualizowane countery wszystkich folderow (dla odswiezenia UI)
|
||||
- Dodac 'mfp_assign_media' do tablicy $actions w register_hooks()
|
||||
|
||||
3. W media-folder-pro.php:
|
||||
- require_once class-media-query.php
|
||||
- Utworzyc instancje MFP_Media_Query w konstruktorze
|
||||
- Wywolac register() w konstruktorze (nie potrzebuje hooka init)
|
||||
|
||||
Avoid: Nie modyfikowac globalnego WP_Query — tylko ajax_query_attachments_args.
|
||||
Avoid: Nie uzywac append=true w wp_set_object_terms — kazdy media ma dokladnie 1 folder (lub 0).
|
||||
</action>
|
||||
<verify>
|
||||
- AJAX query-attachments z parametrem media_folder=ID zwraca tylko media z tego folderu
|
||||
- AJAX mfp_assign_media przypisuje media i zwraca success
|
||||
- Bez parametru media_folder — zwraca wszystkie media (brak regresji)
|
||||
</verify>
|
||||
<done>AC-1 (server-side) + AC-2 satisfied: filtrowanie i przypisywanie dziala na backendzie</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Media filter JS + drag & drop</name>
|
||||
<files>wp-content/plugins/media-folder-pro/assets/js/media-filter.js, wp-content/plugins/media-folder-pro/assets/js/folder-tree.js, wp-content/plugins/media-folder-pro/assets/css/admin.css, wp-content/plugins/media-folder-pro/media-folder-pro.php</files>
|
||||
<action>
|
||||
1. Utworzyc assets/js/media-filter.js — integracja z WP media grid:
|
||||
- Nasluchuj na 'mfp-folder-selected' CustomEvent
|
||||
- Przy wyborze folderu:
|
||||
- Pobierz wp.media.frame (AttachmentsBrowser) jesli istnieje
|
||||
- Ustaw props modelu kolekcji: collection.props.set({media_folder: folderId})
|
||||
- To wymusi AJAX reload z nowym parametrem
|
||||
- Przy "Wszystkie media" (folderId === null):
|
||||
- collection.props.unset('media_folder') lub set media_folder do 0
|
||||
- Fallback: jesli wp.media nie istnieje (list view), uzyj window.location z query param
|
||||
|
||||
2. Drag & drop w media-filter.js:
|
||||
- Na elementach .attachment w grid: dodaj draggable=true
|
||||
- MutationObserver na kontenerze .attachments aby lapac nowo dodane elementy
|
||||
- dragstart: ustaw dataTransfer z attachment ID (z data-id atrybutu)
|
||||
- Dodaj klase 'mfp-dragging' na body
|
||||
- dragend: usun klase 'mfp-dragging'
|
||||
|
||||
3. W folder-tree.js dodac obsluge drop:
|
||||
- Na kazdym .mfp-folder__row: dragover (preventDefault + klasa 'mfp-drop-target')
|
||||
- dragleave: usun klase 'mfp-drop-target'
|
||||
- drop: odczytaj attachment ID z dataTransfer
|
||||
- Wywolaj AJAX mfp_assign_media
|
||||
- Po sukcesie: refreshTree() (odswiezy countery)
|
||||
- Jesli aktywny folder != docelowy: refresh grid (dispatchEvent)
|
||||
- Wyeksportuj refreshTree jako window.mfpRefreshTree aby media-filter.js moglo go wywolac
|
||||
|
||||
4. W admin.css dodac style:
|
||||
- .mfp-drop-target: niebieskie podswietlenie folderu podczas drag over
|
||||
- .mfp-dragging .mfp-folder__row: subtelny hover indicator
|
||||
- .attachment[draggable] cursor: grab
|
||||
|
||||
5. W media-folder-pro.php:
|
||||
- Enqueue media-filter.js z dependency ['media-views'] (WP media JS)
|
||||
- Dodac i18n strings: 'assignSuccess', 'assignError'
|
||||
|
||||
Avoid: Nie uzywac jQuery UI Draggable/Droppable — czysty HTML5 Drag & Drop API.
|
||||
Avoid: Nie modyfikowac WP core JS — tylko hookujemy sie przez props.set().
|
||||
</action>
|
||||
<verify>
|
||||
- Klikniecie folderu filtruje grid (widac tylko media z folderu)
|
||||
- Klikniecie "Wszystkie media" przywraca wszystko
|
||||
- Przeciagniecie miniaturki na folder przypisuje media
|
||||
- Counter folderu aktualizuje sie po drop
|
||||
- Brak JS errors w konsoli
|
||||
</verify>
|
||||
<done>AC-1 (client-side) + AC-3 satisfied: filtrowanie i drag & drop dzialaja w UI</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## DO NOT CHANGE
|
||||
- wp-content/plugins/elementor-pro/* (nie modyfikujemy Elementora)
|
||||
- wp-content/plugins/media-folder-pro/includes/class-taxonomy.php (stabilna z Phase 1)
|
||||
- Zadne pliki core WordPress
|
||||
|
||||
## SCOPE LIMITS
|
||||
- Brak integracji z media modal (Phase 3)
|
||||
- Brak bulk operations z UI (Phase 4)
|
||||
- Brak drag & drop folderow miedzy soba (juz jest w AJAX, UI w Phase 4)
|
||||
- List view (wp_list_table) — tylko grid view w tej fazie
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
Before declaring plan complete:
|
||||
- [ ] Klikniecie folderu filtruje media grid
|
||||
- [ ] "Wszystkie media" przywraca pelna liste
|
||||
- [ ] mfp_assign_media endpoint dziala z nonce verification
|
||||
- [ ] Drag & drop media na folder przypisuje i odswierza countery
|
||||
- [ ] Brak regresji: media grid dziala normalnie bez aktywnego filtra
|
||||
- [ ] Brak JS errors w konsoli przegladarki
|
||||
- [ ] Assets ladowane z poprawna kolejnoscia (media-views przed media-filter)
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Wszystkie taski ukonczone
|
||||
- Wszystkie verification checks przeszly
|
||||
- Brak bledow PHP i JS
|
||||
- Filtrowanie + drag & drop dzialaja plynnie
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.paul/phases/02-media-library-grid/02-01-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user