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>
9.3 KiB
9.3 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous
| phase | plan | type | wave | depends_on | files_modified | autonomous | |||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| 01-media-folders-plugin | 01 | execute | 1 |
|
true |
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
Source Files
Nowy plugin — brak istniejacych plikow. Tworzymy od zera.
<acceptance_criteria>
AC-1: Plugin aktywuje sie bez bledow
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
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
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
</acceptance_criteria>
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 handlers2. 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 <ul><li>
- 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)
<success_criteria>
- 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 </success_criteria>