Virtual Media Folders
Virtual folder organization and smart management for the WordPress Media Library.
Way back in 2006 (almost 20 years ago!), I released ImageManager 2.0, a popular WordPress plugin for image management and editing. Virtual Media Folders is my modern take on media organization for WordPress, built with React and modern tooling.
Description
Virtual Media Folders brings virtual folder organization to your WordPress Media Library. Organize your media files into hierarchical folders without moving files on diskβfolders are virtual, so your URLs never change.
Features
- Virtual Folders: Create hierarchical folder structures to organize media
- **Drag &β¦
Virtual Media Folders
Virtual folder organization and smart management for the WordPress Media Library.
Way back in 2006 (almost 20 years ago!), I released ImageManager 2.0, a popular WordPress plugin for image management and editing. Virtual Media Folders is my modern take on media organization for WordPress, built with React and modern tooling.
Description
Virtual Media Folders brings virtual folder organization to your WordPress Media Library. Organize your media files into hierarchical folders without moving files on diskβfolders are virtual, so your URLs never change.
Features
- Virtual Folders: Create hierarchical folder structures to organize media
- Drag & Drop: Easily move media between folders with drag and drop
- Sticky Sidebar: Folder navigation stays visible while scrolling through media
- Gutenberg Integration: Filter media by folder directly in the block editor
- Bulk Actions: Move multiple media items at once
- Keyboard Accessible: Full keyboard navigation support
- Internationalized: Ready for translation (Norwegian BokmΓ₯l included)
Requirements
- WordPress 6.8 or higher
- PHP 8.3 or higher
Installation
- Download virtual-media-folders.zip
- Upload via Plugins > Add New > Upload Plugin
- Activate the plugin.
Plugin updates are handled automatically via GitHub. No need to manually download and install updates.
Development
# Add via Composer
composer require soderlind/virtual-media-folders
# Install dependencies
composer install
npm install
# Start development build with watch
npm run start
# Build for production
npm run build
# Run PHP tests
composer test
# Run JavaScript tests
npm test
Usage
Organizing Media
- Go to Media > Library in your WordPress admin
- Click the folder icon next to the view switcher to show the folder sidebar
- Use the + button to create new folders
- Drag and drop media items onto folders to organize them
- Click a folder to filter the media library view
Settings
Go to Media > Folder Settings to configure:
- Show "All Media" β Display the "All Media" option in the folder sidebar [I prefer to keep this disabled]
- Show "Uncategorized" β Display the "Uncategorized" folder for media without a folder
- Jump to folder after move β Automatically navigate to the target folder after moving media
- Default folder for uploads β Automatically assign new uploads to a specific folder
Gutenberg Block Editor
When inserting media in the block editor:
- Open the Media Library modal from a block (e.g., Image or Gallery block etc.)
- Use the folder sidebar to filter by folder
- Select your media as usual
Folder Structure
virtual-media-folders/
βββ build/ # Compiled assets
βββ docs/ # Documentation
βββ languages/ # Translation files
βββ src/
β βββ Admin.php # Media Library integration
β βββ Editor.php # Gutenberg integration
β βββ RestApi.php # REST API endpoints
β βββ Settings.php # Settings page
β βββ Suggestions.php # Smart suggestions
β βββ Taxonomy.php # Custom taxonomy
β βββ admin/ # Media Library UI
β β βββ components/ # React components
β β βββ styles/ # CSS
β βββ editor/ # Gutenberg integration
β βββ shared/ # Shared components & hooks
βββ tests/
β βββ js/ # Vitest tests
β βββ php/ # PHPUnit tests
βββ uninstall.php # Cleanup on uninstall
βββ virtual-media-folders.php # Main plugin file
REST API
The plugin provides REST API endpoints under vmf/v1:
Folders
GET /folders- List all foldersPOST /folders- Create a folderGET /folders/{id}- Get a folderPUT /folders/{id}- Update a folderDELETE /folders/{id}- Delete a folderPOST /folders/{id}/media- Add media to folderDELETE /folders/{id}/media- Remove media from folder
Hooks & Filters
Actions
vmf_folder_created- Fired when a folder is createdvmf_folder_deleted- Fired when a folder is deletedvmf_media_moved- Fired when media is moved to a folder
Settings Filters
vmf_default_settings
Filter the default settings values.
add_filter( 'vmf_default_settings', function( $defaults ) {
// Change default values
$defaults['show_all_media'] = true;
$defaults['show_uncategorized'] = true;
$defaults['jump_to_folder_after_move'] = false;
$defaults['default_folder'] = 0;
return $defaults;
} );
vmf_settings
Filter all settings at once after loading from the database.
add_filter( 'vmf_settings', function( $options ) {
// Force jump to folder after move for all users
$options['jump_to_folder_after_move'] = true;
return $options;
} );
vmf_setting_{$key}
Filter a specific setting value. Available keys:
show_all_media- Show "All Media" in sidebarshow_uncategorized- Show "Uncategorized" in sidebarjump_to_folder_after_move- Navigate to folder after moving filesdefault_folder- Default folder for new uploads (0 = none)
// Hide "All Media" option for non-administrators
add_filter( 'vmf_setting_show_all_media', function( $value, $key, $options ) {
if ( ! current_user_can( 'manage_options' ) ) {
return false;
}
return $value;
}, 10, 3 );
// Always show uncategorized for editors
add_filter( 'vmf_setting_show_uncategorized', function( $value ) {
if ( current_user_can( 'edit_others_posts' ) ) {
return true;
}
return $value;
} );
Note: At least one of
show_all_mediaorshow_uncategorizedmust betrue. If both are set tofalsevia filters,show_all_mediawill automatically be set totrue.
Preconfiguring Folders
You can programmatically create folders using the WordPress taxonomy API. Use the after_setup_theme or init hook with a one-time check to avoid creating duplicates:
add_action( 'init', function() {
// Only run once - use an option flag
if ( get_option( 'my_theme_vmf_folders_created' ) ) {
return;
}
// Make sure the taxonomy exists
if ( ! taxonomy_exists( 'media_folder' ) ) {
return;
}
// Define your folder structure
$folders = [
'Photos' => [
'Events',
'Products',
'Team',
],
'Documents' => [
'Reports',
'Presentations',
],
'Videos',
'Logos',
];
// Create folders
foreach ( $folders as $parent => $children ) {
if ( is_array( $children ) ) {
// Parent folder with children
$parent_term = wp_insert_term( $parent, 'media_folder' );
if ( ! is_wp_error( $parent_term ) ) {
foreach ( $children as $child ) {
wp_insert_term( $child, 'media_folder', [
'parent' => $parent_term['term_id'],
] );
}
}
} else {
// Top-level folder (no children)
wp_insert_term( $children, 'media_folder' );
}
}
// Mark as done so it only runs once
update_option( 'my_theme_vmf_folders_created', true );
}, 20 ); // Priority 20 to run after taxonomy registration
You can also set the custom folder order using term meta:
// Set custom order for folders (lower numbers appear first)
update_term_meta( $term_id, 'vmf_order', 0 ); // First position
update_term_meta( $term_id, 'vmf_order', 1 ); // Second position
Other Filters
vmf_suggestion_matchers- Customize suggestion matching logicvmf_folder_capabilities- Modify capability requirements
Translation
Generate translation files:
# Generate POT file
npm run i18n:make-pot
# Generate JSON files for JavaScript
npm run i18n:make-json
# Generate PHP files for faster loading
npm run i18n:make-php
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Write tests for new functionality
- Ensure all tests pass
- Submit a pull request
Copyright and License
Virtual Media Folders is copyright 2025 Per Soderlind
Virtual Media Folders is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
Virtual Media Folders is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with the Extension. If not, see http://www.gnu.org/licenses/.