--- 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 After completion, create `.paul/phases/02-media-library-grid/02-01-SUMMARY.md`