{"id":383079,"date":"2026-10-10T05:46:19","date_gmt":"2026-10-10T05:46:19","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/jelly-folders\/"},"modified":"2026-10-12T09:26:11","modified_gmt":"2026-10-12T09:26:11","slug":"jelly-folders","status":"publish","type":"plugin","link":"https:\/\/arg.wordpress.org\/plugins\/jelly-folders\/","author":23540346,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.1.0","stable_tag":"1.1.0","tested":"7.1.3","requires":"6.6","requires_php":"8.0","requires_plugins":null,"header_name":"Jelly Folders \u2013 Media Library Folders & Organizer","header_author":"DevStine","header_description":"Virtual folders for the Media Library \u2014 organizes your media in a drag-and-drop folder tree without moving physical files.","assets_banners_color":"7a28b6","last_updated":"2026-10-12 09:26:11","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/jellyfolders.com","header_author_uri":"https:\/\/devstine.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":119,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"devstine","date":"2026-10-10 05:46:07","revision":3737636},"1.1.0":{"tag":"1.1.0","author":"devstine","date":"2026-10-12 09:26:11","revision":3740960}},"upgrade_notice":{"1.1.0":"<p>Security release: SVGs uploaded through WordPress&#039; own upload routes are now sanitized or refused. SVGs already in your Media Library are not changed. Updating is recommended.<\/p>","1.0.0":"<p>Initial release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3737633,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3737633,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3737633,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3737633,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{"blueprint.json":{"filename":"blueprint.json","revision":3740960,"resolution":false,"location":"assets","locale":"","contents":"{\"$schema\":\"https:\\\/\\\/playground.wordpress.net\\\/blueprint-schema.json\",\"meta\":{\"title\":\"Jelly Folders\",\"author\":\"devstine\",\"description\":\"Try the folder tree in the Media Library: drag a file into a folder.\"},\"landingPage\":\"\\\/wp-admin\\\/upload.php\",\"preferredVersions\":{\"php\":\"8.2\",\"wp\":\"latest\"},\"steps\":[{\"step\":\"login\"},{\"step\":\"installPlugin\",\"pluginData\":{\"resource\":\"wordpress.org\\\/plugins\",\"slug\":\"jelly-folders\"},\"options\":{\"activate\":true}},{\"step\":\"runPHP\",\"code\":\"<?php\\nrequire '\\\/wordpress\\\/wp-load.php';\\nrequire_once ABSPATH . 'wp-admin\\\/includes\\\/image.php';\\n\\n\\\/\\\/ Choose \\\"Skip\\\" on the connect screen for the visitor: nothing is shared and no account is created.\\nif ( function_exists( 'jellyfolders_fs' ) ) {\\n\\tjellyfolders_fs()->skip_connection();\\n}\\n\\n$tax = 'jellyfolders_folder_attachment';\\n\\n\\\/\\\/ Name, colour, parent index (-1 for top level).\\n$folders = array(\\n\\tarray( 'Photos', '#3B82F6', -1 ),\\n\\tarray( 'Travel', '#22C55E', 0 ),\\n\\tarray( 'Food', '#EF4444', 0 ),\\n\\tarray( 'Brand', '#64748B', -1 ),\\n\\tarray( 'Logos', '#3B82F6', 3 ),\\n\\tarray( 'Team', '#22C55E', -1 ),\\n);\\n$ids = array();\\nforeach ( $folders as $i => $folder ) {\\n\\t$term = wp_insert_term( $folder[0], $tax, array( 'parent' => $folder[2] < 0 ? 0 : $ids[ $folder[2] ] ) );\\n\\tif ( is_wp_error( $term ) ) {\\n\\t\\tcontinue;\\n\\t}\\n\\t$ids[ $i ] = $term['term_id'];\\n\\tupdate_term_meta( $term['term_id'], '_jellyfolders_color', $folder[1] );\\n\\tupdate_term_meta( $term['term_id'], '_jellyfolders_order', $i );\\n}\\n\\n\\\/\\\/ Title, folder index (-1 for unfiled), gradient start and end colours.\\n$images = array(\\n\\tarray( 'Beach at sunset', 1, array( 249, 115, 22 ), array( 190, 24, 93 ) ),\\n\\tarray( 'Mountain lake', 1, array( 14, 165, 233 ), array( 21, 128, 61 ) ),\\n\\tarray( 'City skyline', 1, array( 71, 85, 105 ), array( 30, 64, 175 ) ),\\n\\tarray( 'Fresh pasta', 2, array( 250, 204, 21 ), array( 220, 38, 38 ) ),\\n\\tarray( 'Morning coffee', 2, array( 120, 53, 15 ), array( 217, 119, 6 ) ),\\n\\tarray( 'Logo, dark', 4, array( 15, 23, 42 ), array( 71, 85, 105 ) ),\\n\\tarray( 'Logo, light', 4, array( 226, 232, 240 ), array( 148, 163, 184 ) ),\\n\\tarray( 'Team offsite', 5, array( 34, 197, 94 ), array( 16, 185, 129 ) ),\\n\\tarray( 'Product shot', -1, array( 168, 85, 247 ), array( 59, 130, 246 ) ),\\n\\tarray( 'Blog header', -1, array( 244, 63, 94 ), array( 251, 146, 60 ) ),\\n\\tarray( 'Event poster', -1, array( 13, 148, 136 ), array( 37, 99, 235 ) ),\\n\\tarray( 'Press kit cover', -1, array( 100, 116, 139 ), array( 15, 23, 42 ) ),\\n);\\n$upload = wp_upload_dir();\\nforeach ( $images as $n => $image ) {\\n\\tlist( $title, $folder, $from, $to ) = $image;\\n\\t$w    = 960;\\n\\t$h    = 640;\\n\\t$im   = imagecreatetruecolor( $w, $h );\\n\\tfor ( $y = 0; $y < $h; $y++ ) {\\n\\t\\t$t = $y \\\/ $h;\\n\\t\\t$c = imagecolorallocate(\\n\\t\\t\\t$im,\\n\\t\\t\\t(int) ( $from[0] + ( $to[0] - $from[0] ) * $t ),\\n\\t\\t\\t(int) ( $from[1] + ( $to[1] - $from[1] ) * $t ),\\n\\t\\t\\t(int) ( $from[2] + ( $to[2] - $from[2] ) * $t )\\n\\t\\t);\\n\\t\\timageline( $im, 0, $y, $w, $y, $c );\\n\\t}\\n\\t$file = trailingslashit( $upload['path'] ) . sanitize_title( $title ) . '.png';\\n\\timagepng( $im, $file );\\n\\t$id = wp_insert_attachment(\\n\\t\\tarray(\\n\\t\\t\\t'post_mime_type' => 'image\\\/png',\\n\\t\\t\\t'post_title'     => $title,\\n\\t\\t\\t'post_status'    => 'inherit',\\n\\t\\t\\t'post_date'      => gmdate( 'Y-m-d H:i:s', time() - $n * 60 ),\\n\\t\\t),\\n\\t\\t$file\\n\\t);\\n\\twp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) );\\n\\tif ( $folder >= 0 && isset( $ids[ $folder ] ) ) {\\n\\t\\twp_set_object_terms( $id, array( (int) $ids[ $folder ] ), $tax );\\n\\t}\\n}\\n\"}]}"}},"all_blocks":[],"tagged_versions":["1.0.0","1.1.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3737633,"resolution":"1","location":"assets","locale":"","width":1600,"height":1000},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3737633,"resolution":"2","location":"assets","locale":"","width":1600,"height":1000},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3737633,"resolution":"3","location":"assets","locale":"","width":1600,"height":1000},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3737633,"resolution":"4","location":"assets","locale":"","width":1600,"height":1000},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3737633,"resolution":"5","location":"assets","locale":"","width":1600,"height":1000},"screenshot-6.gif":{"filename":"screenshot-6.gif","revision":3740960,"resolution":"6","location":"assets","locale":"","width":800,"height":500}},"screenshots":{"1":"The folder tree beside the Media Library grid, with colours and new-file badges.","2":"Dragging files into a folder.","3":"The right-click menu on a folder.","4":"Choosing an upload destination from the upload panel.","5":"The folder tree inside the insert-media modal while editing a post.","6":"Animated: selecting several files with Bulk select and moving them to a folder in one drag."}},"plugin_section":[],"plugin_tags":[9747,84,130330,233,193262],"plugin_category":[50,57],"plugin_contributors":[285477],"plugin_business_model":[],"class_list":["post-383079","plugin","type-plugin","status-publish","hentry","plugin_tags-folders","plugin_tags-media","plugin_tags-media-folders","plugin_tags-media-library","plugin_tags-organize-media","plugin_category-media","plugin_category-taxonomy","plugin_contributors-devstine","plugin_committers-devstine"],"banners":{"banner":"https:\/\/ps.w.org\/jelly-folders\/assets\/banner-772x250.png?rev=3737633","banner_2x":"https:\/\/ps.w.org\/jelly-folders\/assets\/banner-1544x500.png?rev=3737633","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/jelly-folders\/assets\/icon-128x128.png?rev=3737633","icon_2x":"https:\/\/ps.w.org\/jelly-folders\/assets\/icon-256x256.png?rev=3737633","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/jelly-folders\/assets\/screenshot-1.png?rev=3737633","caption":"The folder tree beside the Media Library grid, with colours and new-file badges."},{"src":"https:\/\/ps.w.org\/jelly-folders\/assets\/screenshot-2.png?rev=3737633","caption":"Dragging files into a folder."},{"src":"https:\/\/ps.w.org\/jelly-folders\/assets\/screenshot-3.png?rev=3737633","caption":"The right-click menu on a folder."},{"src":"https:\/\/ps.w.org\/jelly-folders\/assets\/screenshot-4.png?rev=3737633","caption":"Choosing an upload destination from the upload panel."},{"src":"https:\/\/ps.w.org\/jelly-folders\/assets\/screenshot-5.png?rev=3737633","caption":"The folder tree inside the insert-media modal while editing a post."},{"src":"https:\/\/ps.w.org\/jelly-folders\/assets\/screenshot-6.gif?rev=3740960","caption":"Animated: selecting several files with Bulk select and moving them to a folder in one drag."}],"raw_content":"<!--section=description-->\n<p>Jelly Folders adds a folder tree to the WordPress Media Library. Drag files into folders, nest folders as deeply as you like, and find things without scrolling through a thousand thumbnails.<\/p>\n\n<p><strong>Folders are virtual<\/strong>, and that is the important part. Jelly Folders never moves, renames or reorganizes anything under <code>wp-content\/uploads\/<\/code>. Folders are a database layer built on a WordPress taxonomy, so every file URL keeps working exactly as before: in published posts, in caches, in CDNs, in emails you sent last year. Deactivate the plugin and every link still resolves.<\/p>\n\n<h4>What you get<\/h4>\n\n<ul>\n<li><strong>Unlimited folders, unlimited nesting.<\/strong> No cap, no counter.<\/li>\n<li><strong>Drag and drop.<\/strong> Drag files into folders, drag folders to reorder or reparent them. Multi-select and move a whole batch at once.<\/li>\n<li><strong>Right-click menu<\/strong> on any folder: add a subfolder, rename, change colour, delete.<\/li>\n<li><strong>Folder colours<\/strong>, to make a long tree scannable at a glance.<\/li>\n<li><strong>A resizable, collapsible sidebar<\/strong> that remembers its width per user.<\/li>\n<li><strong>New-file badges<\/strong> showing what has arrived since you last looked, per folder or rolled up through the tree.<\/li>\n<li><strong>Safe delete.<\/strong> Deleting a folder never deletes files: they move to Uncategorized.<\/li>\n<li><strong>Upload straight into a folder<\/strong>, with a destination picker in the upload panel.<\/li>\n<li><strong>Bulk select and bulk move<\/strong>, in both grid and list view.<\/li>\n<li><strong>Folders inside the insert-media modal<\/strong>, so the tree is there while you are writing a post, not only while you are managing files.<\/li>\n<li><strong>SVG upload with sanitization.<\/strong> SVGs are scrubbed of scripts, event handlers and external references before they are stored.<\/li>\n<li><strong>Translation ready<\/strong>, with WPML and Polylang support for per-language folder names.<\/li>\n<li><strong>Right-to-left layouts<\/strong> supported.<\/li>\n<\/ul>\n\n<h4>Built on WordPress, not around it<\/h4>\n\n<p>The folder tree mounts inside core's own media browser instead of replacing it. Page builders and blocks that use the standard WordPress media modal get the folder sidebar automatically, and anything reading the media selection keeps working, because nothing about the underlying data changed.<\/p>\n\n<h4>Third-party services<\/h4>\n\n<p>Jelly Folders bundles the <a href=\"https:\/\/freemius.com\/\">Freemius<\/a> WordPress SDK, which handles the upgrade, checkout and license flow for the paid version.<\/p>\n\n<p>The SDK does not run its usage tracking, and does not send your account or site details, until you explicitly opt in on the connect screen shown after activation (or, in the paid version, until you enter a license key). Choosing <strong>Skip<\/strong> there leaves the plugin fully functional and shares no usage data, user details or plugin list. Three things you do yourself still contact Freemius after a Skip: opening <strong>Media &gt; Upgrade<\/strong> loads pricing from the Freemius API, and every such request carries your site's address in its user agent; starting a checkout from there puts your WordPress user's first and last name, email address and your site's address in the checkout link; and submitting the feedback form shown when you deactivate the plugin sends Freemius an anonymous uninstall event with the reason you gave. If you opt in, the SDK shares: your WordPress user's first and last name and email address; your site's homepage URL and title, WordPress and PHP versions and site language; the plugin and SDK versions and whether the plugin is active or uninstalled; and the names, slugs, versions and active state of your installed plugins and themes. A license activation shares your WordPress user's first and last name and email address (unless the license already has a known owner), the homepage URL, plugin and SDK versions and plugin state, plus the diagnostic details (WordPress and PHP versions, site language and title), which are ticked by default and can be unticked, and the plugin\/theme list, which is unticked by default. To stop sharing, open the <strong>Plugins<\/strong> screen and click <strong>Opt Out<\/strong> under Jelly Folders; this stops future sharing and does not recall what was already sent. If you chose Skip, the same place offers <strong>Opt In<\/strong> should you change your mind. In the paid version, the Opt Out link appears once a license is active.<\/p>\n\n<ul>\n<li>Freemius terms of service: <a href=\"https:\/\/freemius.com\/terms\/\">https:\/\/freemius.com\/terms\/<\/a><\/li>\n<li>Freemius privacy policy: <a href=\"https:\/\/freemius.com\/privacy\/\">https:\/\/freemius.com\/privacy\/<\/a><\/li>\n<\/ul>\n\n<h4>Source code<\/h4>\n\n<p>Jelly Folders is GPL licensed. Your site loads the minified files (<code>build\/index.min.js<\/code>, <code>build\/style-index.min.css<\/code> and the per-block ones). The readable, unobfuscated form of every one ships beside it in the same folder (<code>build\/index.js<\/code>, <code>build\/style-index.css<\/code>, and so on): the scripts with readable identifiers and formatting, and the stylesheets in expanded, multi-line form. Each <code>.min<\/code> file is plain minification of the readable file next to it, so no separate source download is required to review the code. Add <code>define( 'SCRIPT_DEBUG', true );<\/code> to <code>wp-config.php<\/code> to load the readable files instead.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin to <code>\/wp-content\/plugins\/jelly-folders\/<\/code>, or install it through <strong>Plugins \u2192 Add New<\/strong>.<\/li>\n<li>Activate it through the <strong>Plugins<\/strong> screen.<\/li>\n<li>Go to <strong>Media \u2192 Library<\/strong>. The folder sidebar appears beside your files.<\/li>\n<\/ol>\n\n<p>There is no separate settings page. Everything \u2014 creating folders, colours, upload destination, SVG uploads \u2014 lives in the Media Library screen itself, behind the gear icon above the folder tree.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"will%20this%20move%20or%20rename%20my%20files%3F\"><h3>Will this move or rename my files?<\/h3><\/dt>\n<dd><p>No. Folders exist only in the database. Nothing under <code>wp-content\/uploads\/<\/code> is touched, so every existing file URL keeps working.<\/p><\/dd>\n<dt id=\"what%20happens%20if%20i%20deactivate%20or%20delete%20the%20plugin%3F\"><h3>What happens if I deactivate or delete the plugin?<\/h3><\/dt>\n<dd><p>Your files are untouched and every URL still resolves. Folder assignments stay in the database on deactivation, so reactivating restores your tree. On deletion, folder data is purged only if you have explicitly opted in to that setting.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20i%20delete%20a%20folder%3F\"><h3>What happens when I delete a folder?<\/h3><\/dt>\n<dd><p>The folder is removed and its files move to Uncategorized. Deleting a folder never deletes files.<\/p><\/dd>\n<dt id=\"is%20there%20a%20limit%20on%20how%20many%20folders%20i%20can%20create%3F\"><h3>Is there a limit on how many folders I can create?<\/h3><\/dt>\n<dd><p>No. There is no cap on folders, no cap on uploads, and no time limit on anything in this plugin.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20page%20builders%3F\"><h3>Does it work with page builders?<\/h3><\/dt>\n<dd><p>If the builder uses the standard WordPress media modal \u2014 most do \u2014 the folder sidebar appears there automatically, because Jelly Folders extends core's media browser rather than replacing it.<\/p><\/dd>\n<dt id=\"is%20svg%20upload%20safe%3F\"><h3>Is SVG upload safe?<\/h3><\/dt>\n<dd><p>SVG files are sanitized on upload using <a href=\"https:\/\/github.com\/darylldoyle\/svg-sanitizer\">svg-sanitize<\/a>, which strips <code>&lt;script&gt;<\/code> elements, event handler attributes and external references. SVG upload is switched off by default and limited to users who can manage options.<\/p><\/dd>\n<dt id=\"can%20i%20translate%20folder%20names%3F\"><h3>Can I translate folder names?<\/h3><\/dt>\n<dd><p>Yes. Folder names are your data, not plugin strings, so they are translated through WPML's and Polylang's taxonomy term translation. A folder can have a different name in each language.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Security: SVG files uploaded through WordPress' own upload routes are now sanitized or refused. Uploads in the Media Library, uploads sent as a raw request body and sideloads are cleaned or refused, and uploads over XML-RPC are refused.<\/li>\n<li>SVG files already in your Media Library are not changed by this update, and files that another plugin writes to disk itself are outside this fix.<\/li>\n<li>SVG files that declare custom DOCTYPE entities are now refused.<\/li>\n<li>Fixed: the folder menu stays on screen on phones and small windows, clear of the admin bar.<\/li>\n<li>Updated the bundled SVG sanitizer to 1.0.0.<\/li>\n<li>The listing is now called \"Jelly Folders \u2013 Media Library Folders &amp; Organizer\" and is tagged \"organize media\", so it is easier to find. Nothing changes in how the plugin works.<\/li>\n<li>The listing has an animated screenshot of moving several files into a folder at once.<\/li>\n<li>After a week of use and five or more folders, a dismissible note in the admin asks once for an honest review. \"Maybe later\" hides it for 30 days and \"I already did\" hides it for good.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<\/ul>","raw_excerpt":"Organize the Media Library into drag-and-drop folders. Nothing moves on disk, so your file URLs never change.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/arg.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/383079","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/arg.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/arg.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/arg.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=383079"}],"author":[{"embeddable":true,"href":"https:\/\/arg.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/devstine"}],"wp:attachment":[{"href":"https:\/\/arg.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=383079"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/arg.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=383079"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/arg.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=383079"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/arg.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=383079"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/arg.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=383079"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/arg.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=383079"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}