--- phase: 01-media-folders-plugin plan: 01 type: execute wave: 1 depends_on: [] files_modified: - wp-content/plugins/media-folder-pro/media-folder-pro.php - wp-content/plugins/media-folder-pro/includes/class-taxonomy.php - wp-content/plugins/media-folder-pro/includes/class-ajax-handler.php - wp-content/plugins/media-folder-pro/assets/css/admin.css - wp-content/plugins/media-folder-pro/assets/js/folder-tree.js autonomous: true --- ## Goal Stworzyc fundament pluginu WordPress "RM2 Media Folders" — rejestracja custom taxonomy `media_folder` dla attachment post type, CRUD folderow przez AJAX, oraz bazowy UI drzewka folderow w panelu admina. ## Purpose Bez tego fundamentu nie mozna budowac integracji z biblioteka mediow. Taxonomy to core mechanizm organizacji. ## Output Dzialajacy plugin z: - Custom taxonomy `media_folder` (hierarchiczna, niewidoczna publicznie) - AJAX endpoints: tworzenie, zmiana nazwy, usuwanie, przenoszenie folderow - Bazowe drzewko folderow renderowane w JS ## Project Context @.paul/PROJECT.md @.paul/ROADMAP.md ## Source Files Nowy plugin — brak istniejacych plikow. Tworzymy od zera. ## AC-1: Plugin aktywuje sie bez bledow ```gherkin Given WordPress 6.x z PHP 8.0+ When uzytkownik aktywuje plugin "RM2 Media Folders" Then plugin aktywuje sie bez bledow i warnings And w bazie danych pojawia sie taxonomy "media_folder" ``` ## AC-2: CRUD folderow dziala przez AJAX ```gherkin Given plugin jest aktywny When uzytkownik tworzy folder "Zdjecia produktow" przez UI Then folder zostaje zapisany jako term w taxonomy media_folder And odpowiedz AJAX zawiera id i nazwe nowego folderu Given istniejacy folder "Zdjecia produktow" When uzytkownik zmienia nazwe na "Produkty 2026" Then term name i slug zostaja zaktualizowane Given istniejacy pusty folder When uzytkownik usuwa folder Then term zostaje usuniety z bazy Given istniejacy folder When uzytkownik przenosi go jako subfolder innego folderu Then term parent zostaje zaktualizowany ``` ## AC-3: Drzewko folderow renderuje sie poprawnie ```gherkin Given plugin jest aktywny i istnieja foldery z podfolderami When uzytkownik otwiera strone Media w panelu admina Then widoczne jest drzewko folderow z hierarchia And foldery mozna rozwijac/zwijac And klikniecie folderu filtruje liste mediow ``` Task 1: Core plugin file + taxonomy registration wp-content/plugins/rm2-media-folders/rm2-media-folders.php, wp-content/plugins/rm2-media-folders/includes/class-taxonomy.php 1. Utworzyc glowny plik pluginu rm2-media-folders.php: - Plugin header (Name: RM2 Media Folders, Version: 0.1.0) - Autoload includes/ - Hook init: rejestracja taxonomy - Hook admin_enqueue_scripts: ladowanie CSS/JS na stronach media - Hook wp_ajax_*: rejestracja AJAX handlers 2. Utworzyc includes/class-taxonomy.php: - Klasa RM2_Media_Folders_Taxonomy - Metoda register(): register_taxonomy('media_folder', 'attachment', args) - hierarchical: true - public: false - show_ui: false (wlasny UI) - show_in_rest: true (dla block editora) - Metoda get_folder_tree(): zwraca hierarchiczne drzewo folderow - Uzywa get_terms() z 'hide_empty' => false - Buduje drzewo parent-child Avoid: Nie uzywac show_ui: true — bedziemy miec wlasny interfejs. Avoid: Nie rejestrowac taxonomy dla innych post types niz attachment. - Plugin pojawia sie na liscie pluginow WP - Po aktywacji: wp term list media_folder --format=json (WP-CLI) nie zwraca bledu - Taxonomy istnieje: taxonomy_exists('media_folder') === true AC-1 satisfied: Plugin aktywuje sie, taxonomy zarejestrowana Task 2: AJAX handler for folder CRUD wp-content/plugins/rm2-media-folders/includes/class-ajax-handler.php Utworzyc includes/class-ajax-handler.php: - Klasa RM2_Media_Folders_Ajax Endpointy AJAX (kazdy z nonce verification + capability check 'upload_files'): 1. rm2_mf_create_folder: - Parametry: name (string), parent_id (int, 0 = root) - wp_insert_term($name, 'media_folder', ['parent' => $parent_id]) - Zwraca: {success: true, folder: {id, name, slug, parent}} 2. rm2_mf_rename_folder: - Parametry: folder_id (int), name (string) - wp_update_term($folder_id, 'media_folder', ['name' => $name]) - Zwraca: {success: true, folder: {id, name, slug}} 3. rm2_mf_delete_folder: - Parametry: folder_id (int) - Sprawdz czy folder jest pusty (brak attachmentow i subfolderow) - Jesli nie pusty: zwroc blad - wp_delete_term($folder_id, 'media_folder') - Zwraca: {success: true} 4. rm2_mf_move_folder: - Parametry: folder_id (int), new_parent_id (int, 0 = root) - Walidacja: nie mozna przeniesc folderu do samego siebie lub swojego dziecka - wp_update_term($folder_id, 'media_folder', ['parent' => $new_parent_id]) - Zwraca: {success: true, folder: {id, name, parent}} 5. rm2_mf_get_folders: - Brak parametrow - Zwraca pelne drzewo folderow z countami attachmentow Kazdy endpoint: - check_ajax_referer('rm2_media_folders_nonce', 'nonce') - current_user_can('upload_files') - wp_send_json_success() / wp_send_json_error() Avoid: Nie uzywac $_GET — wszystko przez $_POST. Avoid: Nie usuwac folderow z dziecmi — wymuszaj pusty folder. - AJAX call do rm2_mf_create_folder zwraca 200 z JSON {success: true} - Utworzony term widoczny w get_terms('media_folder') - Proba bez nonce zwraca 403 - Proba bez uprawnien zwraca blad AC-2 satisfied: CRUD folderow dziala przez AJAX z walidacja Task 3: Admin assets + folder tree UI wp-content/plugins/rm2-media-folders/assets/css/admin.css, wp-content/plugins/rm2-media-folders/assets/js/folder-tree.js 1. admin.css: - Styl dla sidebar drzewka folderow (lewy panel, 250px szerokosci) - Style dla elementow drzewka: folder icon, nazwa, expand/collapse arrow - Styl aktywnego folderu (podswietlenie) - Style dla context menu (prawy klik: rename, delete, new subfolder) - Style dla inline edit (zmiana nazwy folderu) - Responsywnosc: na mniejszych ekranach sidebar chowa sie 2. folder-tree.js (vanilla JS, bez jQuery dependency): - Klasa RM2FolderTree - init(): fetch folderow z AJAX (rm2_mf_get_folders), renderuj drzewo - renderTree(folders, container): rekurencyjny render z
  • - toggleFolder(folderId): expand/collapse children - selectFolder(folderId): podswietl + wyslij event 'rm2-folder-selected' - createFolder(parentId): prompt nazwa → AJAX create - renameFolder(folderId): inline edit → AJAX rename - deleteFolder(folderId): confirm → AJAX delete - moveFolder(folderId, newParentId): AJAX move (drag & drop w nastepnej fazie) Toolbar nad drzewkiem: - Przycisk "+" (nowy folder w root) - Przycisk "All Media" (reset filtra) Context menu (prawy klik na folder): - New subfolder - Rename - Delete Localization: uzyj wp_localize_script z rm2MediaFolders object: - ajaxUrl, nonce, i18n strings 3. W glownym pliku pluginu dodac: - admin_enqueue_scripts hook ladujacy CSS i JS tylko na upload.php i media-new.php - wp_localize_script z nonce i ajax URL - Hook na admin_footer (upload.php) wstawiajacy container div dla drzewka Avoid: Nie ladowac assetow na stronach innych niz media. Avoid: Nie uzywac jQuery — czysty vanilla JS. - Na stronie Media > Library widoczny sidebar z drzewkiem - Klikniecie "+" otwiera prompt, po wpisaniu nazwy folder sie pojawia - Prawy klik na folder pokazuje context menu - Klikniecie folderu podswietla go - CSS nie koliduje z domyslnymi stylami WP admin AC-3 satisfied: Drzewko folderow renderuje sie z CRUD operacjami ## DO NOT CHANGE - wp-content/plugins/elementor-pro/* (nie modyfikujemy Elementora) - Zadne pliki core WordPress ## SCOPE LIMITS - Brak drag & drop mediow do folderow (Phase 2) - Brak integracji z media modal (Phase 3) - Brak bulk operations (Phase 4) - Brak filtrowania listy mediow po kliknieciu folderu (bedzie placeholder, pelna implementacja w Phase 2) Before declaring plan complete: - [ ] Plugin aktywuje sie bez bledow PHP - [ ] Taxonomy media_folder zarejestrowana i hierarchiczna - [ ] Wszystkie 5 AJAX endpointow odpowiada poprawnie - [ ] Nonce verification dziala (odrzuca requesty bez nonce) - [ ] Drzewko folderow wyswietla sie na stronie Media - [ ] Tworzenie/usuwanie/zmiana nazwy folderu dziala z UI - [ ] Assets ladowane tylko na stronach media (nie na innych) - Wszystkie taski ukonczone - Wszystkie verification checks przeszly - Brak bledow PHP (error_log czysty) - Brak JS errors w konsoli przegladarki - Plugin gotowy jako baza do Phase 2 After completion, create `.paul/phases/01-media-folders-plugin/01-01-SUMMARY.md`