---
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>
