feat(media-folder-pro): add virtual folder system for WordPress media library

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>
This commit is contained in:
2026-03-28 14:08:49 +01:00
parent 4ad3303b18
commit 5014b9108f
19 changed files with 3692 additions and 0 deletions

View File

@@ -0,0 +1,211 @@
---
phase: 03-media-modal
plan: 01
type: execute
wave: 1
depends_on: ["02-01"]
files_modified:
- wp-content/plugins/media-folder-pro/assets/js/modal-integration.js
- wp-content/plugins/media-folder-pro/assets/css/admin.css
- wp-content/plugins/media-folder-pro/media-folder-pro.php
- wp-content/plugins/media-folder-pro/includes/class-ajax-handler.php
autonomous: true
---
<objective>
## Goal
Zintegrowac drzewko folderow z modalem WP media (wp.media modal) — tym samym, ktory otwiera sie w edytorze blokowym, klasycznym edytorze, Elementorze i innych pluginach uzywajacych wp.media. Uzytkownik moze filtrowac media po folderze wewnatrz modala oraz przypisac folder podczas uploadu.
## Purpose
Modal mediow to glowny punkt interakcji z biblioteka — bez integracji uzytkownik nie moze korzystac z folderow podczas wstawiania mediow do tresci.
## Output
- Dropdown/sidebar z folderami wewnatrz modala media
- Filtrowanie mediow w modalu po wybranym folderze
- Mozliwosc wyboru folderu docelowego przy uploadzie nowych plikow
</objective>
<context>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
## Prior Work
@.paul/phases/02-media-library-grid/02-01-SUMMARY.md
- MFP_Media_Query z filtrem ajax_query_attachments_args (juz dziala dla modala tez!)
- mfp_assign_media endpoint gotowy
- media-filter.js z wzorcem library.props.set({media_folder: id})
## Source Files
@wp-content/plugins/media-folder-pro/media-folder-pro.php
@wp-content/plugins/media-folder-pro/assets/js/media-filter.js
@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/assets/css/admin.css
</context>
<acceptance_criteria>
## AC-1: Dropdown folderow widoczny w modalu media
```gherkin
Given plugin aktywny, istnieja foldery
When uzytkownik otwiera modal media (np. "Dodaj media" w edytorze)
Then w pasku narzedzi modala widoczny jest dropdown z lista folderow
And dropdown zawiera opcje "Wszystkie media" + lista folderow hierarchicznie
```
## AC-2: Filtrowanie mediow w modalu po folderze
```gherkin
Given modal media otwarty, istnieja foldery z mediami
When uzytkownik wybiera folder z dropdown
Then grid mediow w modalu pokazuje tylko media z wybranego folderu
And wybranie "Wszystkie media" przywraca pelna liste
```
## AC-3: Przypisanie folderu przy uploadzie
```gherkin
Given modal media otwarty, wybrany folder "Zdjecia produktow"
When uzytkownik uploaduje nowy plik przez zakladke "Wyslij pliki"
Then nowo uploadowany plik zostaje automatycznie przypisany do aktywnego folderu
And plik pojawia sie w filtrowanym widoku tego folderu
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Modal folder dropdown + filtering</name>
<files>wp-content/plugins/media-folder-pro/assets/js/modal-integration.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/modal-integration.js:
- Hook na wp.media.view.AttachmentsBrowser:
- Nadpisz (extend) domyslny AttachmentsBrowser
- W metodzie createToolbar() dodaj customowy dropdown filter
- Dropdown budowany z danych folderow (AJAX mfp_get_folders przy otwarciu)
- Opcje: "Wszystkie media" (value=0) + foldery z wciecia dla hierarchii
- Np: "Zdjecia", "— Produkty", "— — Elektronika" (hierarchia przez prefiks)
- Przy zmianie dropdown:
- library.props.set({media_folder: selectedFolderId})
- To uzyje istniejacego MFP_Media_Query filtra server-side
- Przechowuj aktywny folder w zmiennej modulu (potrzebne dla upload)
2. Hook na wp.media.view.UploaderInline (upload tab):
- Po uplywie uploadu (wp.Uploader 'upload-success' lub 'wp-upload-complete'):
- Jesli aktywny folder > 0:
- Wywolaj AJAX mfp_assign_media z nowym attachment_id i aktywnym folderem
- Alternatywnie: hook na wp.media.model.Attachment po dodaniu do kolekcji
3. Podejscie do hookowania WP media views:
- Uzyj wp.media.view.AttachmentsBrowser.extend() do nadpisania createToolbar
- LUB: uzyj filtra 'AttachmentsBrowser:ready' jesli dostepny
- LUB: monkey-patch wp.media.view.AttachmentsBrowser.prototype.createToolbar
- Wybierz podejscie ktore NIE wymaga modyfikacji core WP JS
- Najstabilniejszy pattern: nadpisz prototype.createToolbar, wywolaj original,
potem dodaj swoj element do this.toolbar
4. W admin.css dodac style dla:
- .mfp-modal-filter — select dropdown w toolbarze modala
- Styl opcji z wciecia (hierarchia folderow)
- Dopasowanie do domyslnego stylu WP media toolbar
5. W media-folder-pro.php:
- Enqueue modal-integration.js globalnie w admin (nie tylko upload.php)
bo modal moze byc otwarty z dowolnej strony admina
- Dependency: ['media-views']
- Warunek: enqueue tylko jesli wp_script_is('media-views', 'enqueued')
lub laduj z wp_enqueue_media hook
Avoid: Nie modyfikowac core WP JS — tylko extend/override prototypow.
Avoid: Nie ladowac pelnego folder-tree.js w modalu — uzyj lekkiego dropdown.
Avoid: Nie uzywac jQuery UI — czysty select element lub custom dropdown.
</action>
<verify>
- Otwarcie modala media w edytorze pokazuje dropdown folderow
- Wybranie folderu filtruje media w modalu
- Upload pliku z aktywnym folderem przypisuje go do folderu
- Modal dziala normalnie bez folderow (brak regresji)
- Dropdown laduje hierarchie poprawnie (wciety subfoldery)
</verify>
<done>AC-1 + AC-2 + AC-3 satisfied: modal z dropdown, filtrowanie, upload do folderu</done>
</task>
<task type="auto">
<name>Task 2: Auto-assign uploaded media + refresh counters</name>
<files>wp-content/plugins/media-folder-pro/includes/class-ajax-handler.php, wp-content/plugins/media-folder-pro/assets/js/modal-integration.js</files>
<action>
1. W class-ajax-handler.php dodac nowy endpoint mfp_upload_to_folder:
- Parametry: attachment_id (int), folder_id (int)
- Prostszy niz mfp_assign_media (pojedynczy plik, nie tablica)
- wp_set_object_terms($attachment_id, [$folder_id], 'media_folder')
- Zwraca: {success: true}
- Dodac do tablicy $actions w register_hooks()
- Ten endpoint jest dedykowany dla upload flow (szybszy, bez folder_counts)
2. W modal-integration.js:
- Po AJAX uplywie uploadu nowego pliku:
- Nasluchuj na wp.Uploader events lub Attachment collection events
- Pattern: wp.media.model.Attachments on('add') — nowy attachment dodany
- Jesli aktywny folder: wywolaj mfp_upload_to_folder
- Po przypisaniu: dispatch 'mfp-folder-changed' event
(zeby upload.php folder tree tez sie odswieszyl jesli otwarty)
3. Synchronizacja z upload.php:
- Jesli modal otwarty z upload.php (media library page):
- Po zamknieciu modala: dispatch 'mfp-folder-changed'
- folder-tree.js nasluchuje i wywoluje refreshTree()
- Dodac listener w folder-tree.js na 'mfp-folder-changed'
Avoid: Nie duplikuj logiki mfp_assign_media — mfp_upload_to_folder to uproszczona wersja.
Avoid: Nie refreshuj counterow w modalu (zbyt ciezkie) — tylko po zamknieciu.
</action>
<verify>
- Upload pliku z aktywnym folderem przypisuje automatycznie
- Po zamknieciu modala countery folderow na upload.php sa aktualne
- Upload bez aktywnego folderu nie przypisuje do zadnego folderu
- Brak duplikatow przypisania (jeden upload = jedna operacja)
</verify>
<done>AC-3 reinforced: upload flow roboczy z auto-assign i sync counterow</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)
- wp-content/plugins/media-folder-pro/includes/class-media-query.php (stabilna, juz filtruje modal)
- Zadne pliki core WordPress
## SCOPE LIMITS
- Brak drag & drop w modalu (tylko dropdown filter)
- Brak tworzenia folderow z modala (tylko wybor istniejacych)
- Brak bulk operations (Phase 4)
- Elementor-specific hooks NIE sa potrzebne — Elementor uzywa standardowego wp.media
</boundaries>
<verification>
Before declaring plan complete:
- [ ] Dropdown folderow widoczny w modalu media
- [ ] Filtrowanie dziala: wybor folderu → tylko media z folderu
- [ ] "Wszystkie media" przywraca pelna liste
- [ ] Upload z aktywnym folderem → auto-assign do folderu
- [ ] Upload bez folderu → brak przypisania (normalne zachowanie)
- [ ] Po zamknieciu modala → countery na upload.php odswiezone
- [ ] Modal otwierany z roznych stron (post edit, page edit) dziala
- [ ] Brak regresji: modal bez folderow dziala normalnie
- [ ] Brak JS errors w konsoli
</verification>
<success_criteria>
- Wszystkie taski ukonczone
- Wszystkie verification checks przeszly
- Modal media w pelni zintegrowany z folderami
- Brak bledow PHP i JS
</success_criteria>
<output>
After completion, create `.paul/phases/03-media-modal/03-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,121 @@
---
phase: 03-media-modal
plan: 01
subsystem: media
tags: [wordpress, media-modal, backbone-extend, upload-hook, wp-uploader]
requires:
- phase: 02-media-library-grid
provides: MFP_Media_Query filter, mfp_assign_media endpoint
provides:
- Folder dropdown in wp.media modal
- Modal filtering via backbone props
- Auto-assign uploads to active folder
- mfp_upload_to_folder lightweight endpoint
affects: [04-polish-ux]
tech-stack:
added: []
patterns: [wp.media.view.AttachmentsBrowser.extend, wp.Uploader.queue hook, modal close hook, foldersCache pattern]
key-files:
created:
- wp-content/plugins/media-folder-pro/assets/js/modal-integration.js
modified:
- wp-content/plugins/media-folder-pro/includes/class-ajax-handler.php
- 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
key-decisions:
- "Extend AttachmentsBrowser.prototype.createToolbar — call original then add dropdown"
- "Flat <select> dropdown instead of full tree in modal — lightweight, less DOM"
- "Hierarchical indent via em-space prefix in option labels"
- "Cache folders per modal open, invalidate on close"
- "Dual upload hook: wp.Uploader.queue + Attachment.sync override for reliability"
- "enqueue_modal_assets on all admin pages except upload.php (handled separately)"
patterns-established:
- "mfp-folder-changed CustomEvent for cross-module sync"
- "Modal close → foldersCache invalidation + counter refresh"
- "Inline script registration (wp_register_script false) for mfpData on non-media pages"
duration: ~10min
started: 2026-03-28
completed: 2026-03-28
---
# Phase 3 Plan 01: Media Upload Modal Integration Summary
**Folder dropdown filter in wp.media modal with auto-assign on upload, using AttachmentsBrowser.extend and wp.Uploader hooks.**
## Performance
| Metric | Value |
|--------|-------|
| Duration | ~10min |
| Tasks | 2 completed |
| Files created | 1 |
| Files modified | 4 |
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: Dropdown folderow widoczny w modalu | Pass | AttachmentsBrowser toolbar extended with select |
| AC-2: Filtrowanie mediow w modalu | Pass | library.props.set via same MFP_Media_Query filter |
| AC-3: Przypisanie folderu przy uploadzie | Pass | wp.Uploader.queue + Attachment.sync hooks |
## Accomplishments
- Extended `wp.media.view.AttachmentsBrowser.createToolbar` to inject folder dropdown
- Hierarchical folder list with em-space indent and counts in dropdown options
- Upload auto-assign via dual hooks (wp.Uploader.queue change:status + Attachment.sync)
- `mfp_upload_to_folder` lightweight single-file endpoint
- Modal close triggers `mfp-folder-changed` event → folder-tree.js refreshes counters
- `enqueue_modal_assets()` loads on all admin pages where media-views is present
## Files Created/Modified
| File | Change | Purpose |
|------|--------|---------|
| `assets/js/modal-integration.js` | Created | Modal dropdown, filtering, upload auto-assign, close sync |
| `includes/class-ajax-handler.php` | Modified | Added mfp_upload_to_folder endpoint |
| `assets/js/folder-tree.js` | Modified | Added mfp-folder-changed listener |
| `assets/css/admin.css` | Modified | Modal dropdown styles |
| `media-folder-pro.php` | Modified | enqueue_modal_assets + modal JS enqueue on upload.php |
## Decisions Made
| Decision | Rationale | Impact |
|----------|-----------|--------|
| Extend prototype vs filter hook | More reliable, works across all modal instances | Robust integration |
| Flat select vs tree in modal | Modal space is limited, select is native WP pattern | Consistent UX |
| Dual upload hooks | Different WP versions trigger differently | Reliable across WP 6.0+ |
## Deviations from Plan
None — plan executed exactly as written.
## Issues Encountered
None
## Next Phase Readiness
**Ready:**
- Full modal integration operational
- All 7 AJAX endpoints in place
- Core feature set complete for MVP
- Phase 4 can focus purely on UX polish
**Concerns:**
- List view (table mode) still unhandled
- No keyboard navigation in modal dropdown
**Blockers:**
- None
---
*Phase: 03-media-modal, Plan: 01*
*Completed: 2026-03-28*