---
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
---
## 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
## 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
## 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
```
Task 1: Server-side media query filter + assign endpoint
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
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).
- 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)
AC-1 (server-side) + AC-2 satisfied: filtrowanie i przypisywanie dziala na backendzie
Task 2: Media filter JS + drag & drop
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
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().
- 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
AC-1 (client-side) + AC-3 satisfied: filtrowanie i drag & drop dzialaja w UI
## 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
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)
- Wszystkie taski ukonczone
- Wszystkie verification checks przeszly
- Brak bledow PHP i JS
- Filtrowanie + drag & drop dzialaja plynnie