Media Vault
by Max GJ Panas · Media
Protect attachment files from direct access using powerful and flexible restrictions. Offer safe download links for any file in your uploads folder.
Try it live opens a temporary test site in your browser, which can take about 20 seconds to load. Plugins that rely on outside services or a full server may not work completely there.
Health
D 48/100
Stale · Likely abandoned
Active installs
800+
≈850 estimated
Momentum
—
no download trend yet
Biggest opportunity: “attachments”, “downloads” and “media” aren't earning a slot. You list them, but you're not in the first 24 results for those searches. WordPress.org counts only your first five tags, so free the slot for a search you can win.
48 health vs 62 average across 3,278 Media plugins
Install conversion
How it's measured →4.4%
of downloads still active
At least 800 of 18K lifetime downloads are still running, above its category: the median Media plugin keeps 0.8%, across 2,317 plugins.
Downloads count every update, not just first installs, so older and more frequently released plugins read lower. Compare against other Media plugins, not across the directory. wp.org reports active installs as the bottom of a band, so the real rate is this or higher.
High removal-risk signals
63/100Maintenance and integrity signals that tend to precede a WordPress.org removal. Not an official status, a heads-up to act.
- Long abandoned. No update in 12+ years — the top precursor to removal once a vulnerability is found.
- Compatibility drift. Tested only up to WordPress 3.7.41, well behind 6.8.
Details
Directory ranking optimization
How it's scored →How well this listing is tuned to rank in WordPress.org search, on the factors an owner controls. Not popularity, optimization.
Under-optimized
Most to gain: Update recency
Updated 4638 days ago, past the ~180 days where wp.org starts discounting
Tested up to WordPress 3.7.41; the current branch is 6.8
4.4★ over 27 reviews, smoothed to 4.21★
5 of 5 tags set · short description in place
To rank higher: Last updated 4638 days ago — ship an update; wp.org decays a listing's search weight after ~180 days.
Get the full rank-higher report →Search visibility
How it's tracked →Directory searches this plugin turns up in, and which way each one is moving. WordPress.org publishes no history of search positions, so this starts the day we first tracked a keyword and never backfills.
Not enough tracked days yet to call a direction. Momentum needs at least three keywords measured a week or more apart.
wp.org is where the directory puts the plugin for that search. On merit is where it would sit if results were ranked on rating, support and updates, without the install boost. The last column is how far the wp.org position moved, from our first reading in the last 90 days to the latest.
| Keyword | wp.org | On merit | wp.org move, 90 days |
|---|---|---|---|
| attachments your tag | Not in the top 24 | ||
| downloads your tag | Not in the top 24 | ||
| media your tag | Not in the top 24 | ||
| protection your tag | Not in the top 24 | ||
| security your tag | Not in the top 24 | ||
1 search this plugin appeared in over the last 90 days, 0 listed. 1 left out as unrelated or noise (years, numbers, stray words). 5 of its tags aren't in the top 24 for their own search.
What to do about it
- “attachments”, “downloads” and “media” aren't earning a slot. You list them, but you're not in the first 24 results for those searches. WordPress.org counts only your first five tags, so free the slot for a search you can win.
Daily downloads
Since 5 Oct 2022 · 1,488 days · wp.org + Plugin Pulse archive
30-day downloads
Rolling 30-day volume · peak 209 · peaks are release surges
Directory rank vs rivals
wp.org popularity rank over time · higher is better · when a rival's line climbs above yours, they've overtaken you
Rating trend
Star average over time · dips mark rough releases
Health trend
Composite health score, snapshotted daily
Update activity
How busy the existing users are, measured as downloads in the last 30 days for every 1,000 active sites. A spike means a new release everyone's pulling; a long, slow decline means an aging user base that updates less.
Release cadence
No release in a yearHow often this plugin actually ships. A steady rhythm is the maintenance signal a single "last updated" date can't show.
0
releases in the last 12 months
12.7y ago
latest release · v0.8.12 · 18 Feb 2014
12
tagged releases on record
Recent releases
What its installed base runs
via wordpress.orgShare of active installs on each version of this plugin · 100% run the current release. Green is the current release; a big slice on older versions is a user base that has stopped updating.
Estimated active installs
The public count shows “800+”. Our estimate pins where the real number sits.
Crossed into this band 10 months ago; a band this size takes about a year or more to cross, which places it about 50% of the way through.
Install history since 19 Sep 2015
Recent reviews
All reviews on wp.org ↗- ★★★★★ maxeyle6.8y ago
I spent untold hours trying to solve the seemingly simple task of restricting access to certain media uploads to logged in users. All I needed was a way to check a box that would keep people from using a direct url to view private documents, and this finally gave me that function. However, my celebration was short-lived because I realized it was blocking the media url for everyone – including logged in users. So close… This topic was modified 6 years, 6 months ago by maxeyle.
Read on wp.org ↗ - ★★★★★ fatheroftime7.0y ago
This plugin no longer works, but it WOULD do everything I need it to do. Broken things: Doesn’t protect PDFs Doesn’t protect media files by default Can still access files through a direct link This topic was modified 6 years, 9 months ago by fatheroftime.
Read on wp.org ↗ - ★★★★★ jtvie10.2y ago
Use it to secure some of my contents on a mid sized Page. Did some additional stuff to it: Woocommerce membership (checks if a user already payed for chosen content or is subscriber) Add options to the Divi theme&Builder to restrict access to sections/blocks the same way as the media vault would do rewritten file serve code to handle ranged/streamed video and or other big data packages action added to use an s3 as primary file delivery as private links and the media vault as fallback (fileOnS3?header location s3:serve file) If requested i’ll assist on similar topics. If anybody is interested in the rewritten file serving php thing: the following code is a part of the “mv-file-handler.php” file – there where no actions to overrule so i had to modify the original source: function mgjp_mv_get_file($rel_file, $action = ''){ // $rel_file = path to the file to view/download, // relative to the WP uploads folder // (eg:'/media-vault/2013/10/media-vault-150x150.jpg') $upload_dir = wp_upload_dir(); // only files in the WP uploads directory are allowed to be accessed: $file = rtrim($upload_dir['basedir'], '/').str_replace('..', '', isset($rel_file)?$rel_file:''); //---Basic Checks----------------------------------------------------// if(!$upload_dir['basedir'] || !is_file($file)){ status_header(404); wp_die('404. File not found.'); } $mime = wp_check_filetype($file); // Check filetype against allowed filetypes if(isset($mime['type']) && $mime['type']){ $mimetype = $mime['type']; }else{ status_header(403); wp_die(__('403. Forbidden.<br/>You cannot directly access files of this type in this directory on this server. Please contact the website administrator.')); } //---Permission Checks-----------------------------------------------// $file_info = pathinfo($rel_file); // check if file is protected by checking // if it is in the protected folder before // doing any permission checks if(0 === stripos($file_info['dirname'].'/', mgjp_mv_upload_dir('/', true))){ // disable caching of this page by caching plugins ------// if(!defined('DONOTCACHEPAGE')) define('DONOTCACHEPAGE', 1); if(!defined('DONOTCACHEOBJECT')) define('DONOTCACHEOBJECT', 1); if(!defined('DONOTMINIFY')) define('DONOTMINIFY', 1); //-------------------------------------------------------// // try and get attachment id from url -------------------// global $wpdb; $attachments = $wpdb->get_results( $wpdb->prepare( " SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value LIKE %s ", '_wp_attachment_metadata', '%'.$file_info['basename'].'%' ), ARRAY_A ); $attachment_id = false; foreach($attachments as $attachment){ $meta_value = unserialize($attachment['meta_value']); if(ltrim(dirname($meta_value['file']), '/') == ltrim($file_info['dirname'], '/')){ $attachment_id = $attachment['post_id']; break; } } // ------------------------------------------------------// if(!$permission = mgjp_mv_get_the_permission($attachment_id)) $permission = get_option('mgjp_mv_default_permission', 'logged-in'); $permissions = mgjp_mv_get_the_permissions(); // permission set up error detection $standard_error_txt = ' '.esc_html__('Therefore for safety and privacy reasons this file is unavailable. Please contact the website administrator.', 'media-vault').'<p><a href="'.home_url().'">←'.esc_html__('Return to homepage', 'media-vault').'</a></p>'; if(!isset($permissions[$permission])) wp_die(__('The permissions set for this file are not recognized.', 'media-vault').$standard_error_txt); if(!isset($permissions[$permission]['logged_in'])) $errors[] = 'logged_in'; if(!isset($permissions[$permission]['cb'])) $errors[] = 'cb'; if(isset($errors)){ $error_txt = __('The permissions set for this file have left the following important parameters undefined:', 'media-vault') .'<ul><li>\''.implode('\'</li><li>\'', $errors).'\'</li></ul>' .'<p>'.$standard_error_txt.'</p>'; wp_die($error_txt); } if($permissions[$permission]['logged_in']) is_user_logged_in() || auth_redirect(); // using is_user_logged_in is lighter than using just auth_redirect if(false !== $permissions[$permission]['cb']){ if(!is_callable($permissions[$permission]['cb'])) wp_die(__('The permission checking function set in this file\'s permissions is not callable.', 'media-vault').$standard_error_txt); $permission_check = call_user_func_array($permissions[$permission]['cb'], array($attachment_id, $rel_file, $file)); if(is_wp_error($permission_check)) wp_die($permission_check->get_error_message().$standard_error_txt); if(true !== $permission_check) wp_die(__('You do not have sufficient permissions to view this file.', 'media-vault').$standard_error_txt); } if(function_exists('attachment_get_remote_url') && $remote_url = attachment_get_remote_url($attachment_id)){ header("Location: ".$remote_url,TRUE,307); } } // end of permission checks //-------------------------------------------------------------------// $filesize = filesize($file); header('Content-Type: '.$mimetype); // always send this if(false === strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS')) header('Content-Length: '.$filesize); if('safeforce' !== $action){ //--OPEN FILE IN BROWSER functions-------------// $last_modified = gmdate('D, d M Y H:i:s', filemtime($file)); $etag = '"'.md5($last_modified).'"'; header("Last-Modified: $last_modified GMT"); header('ETag: '.$etag); header('Cache-Control: no-store, no-cache, must-revalidate'); // HTTP 1.1. header('Pragma: no-cache'); // HTTP 1.0. header('Expires: Thu, 01 Dec 1994 16:00:00 GMT'); // Proxies // Support for Conditional GET $client_etag = isset($_SERVER['HTTP_IF_NONE_MATCH'])?stripslashes($_SERVER['HTTP_IF_NONE_MATCH']):false; if(!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) $_SERVER['HTTP_IF_MODIFIED_SINCE'] = false; $client_last_modified = trim($_SERVER['HTTP_IF_MODIFIED_SINCE']); // If string is empty, return 0. If not, attempt to parse into a timestamp $client_modified_timestamp = $client_last_modified?strtotime($client_last_modified):0; // Make a timestamp for our most recent modification... $modified_timestamp = strtotime($last_modified); if(($client_last_modified && $client_etag) ?(($client_modified_timestamp >= $modified_timestamp) && ($client_etag == $etag)) :(($client_modified_timestamp >= $modified_timestamp) || ($client_etag == $etag)) ){ status_header(304); exit; } }else{ //--FORCE DOWNLOAD Functions-----------------------// // required for IE, otherwise Content-disposition is ignored if(ini_get('zlib.output_compression')) ini_set('zlib.output_compression', 'Off'); header('Pragma: public'); // required header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Cache-Control: private', false); // required for certain browsers header('Content-Disposition: attachment; filename="'.$file_info['basename'].'";'); header('Content-Transfer-Encoding: binary'); } // If we made it this far, just serve the file if(ob_get_length()) ob_clean(); $filesize = filesize($file); //Handel partial request header("Accept-Ranges: 0-$filesize"); $buffer_size = 1024 * 1024; //1MB #bigger = more ram usage but less cpu if(isset($_SERVER['HTTP_RANGE'])){ preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches); $offset = intval($matches[1]); $length = intval(isset($matches[2])?intval($matches[2]) - $offset:$filesize - $offset); if($length < 1) $length = $filesize - $offset; if($length > $buffer_size*10) $length = $buffer_size*10;//limit max partial *will trigger a ERR_CONTENT_LENGTH_MISMATCH on client but will perform better... header('HTTP/1.1 206 Partial Content'); header('Content-Range: bytes '.$offset.'-'.($offset + $length).'/'.$filesize); $file = fopen($file, 'r'); // seek to the requested offset, this is 0 if it's not a partial content request fseek($file, $offset); //split the file so we could <code>stream</code> just the range we need while($length > 0 && !feof($file)){ if($length > $buffer_size) $bytes_to_read = $buffer_size; else $bytes_to_read = $length; $length -= $bytes_to_read; echo fread($file, $bytes_to_read); flush(); } fclose($file); exit; } flush(); readfile($file); exit; }
Read on wp.org ↗ - ★★★★★ dimgord10.5y ago
Found it while looking for restriction view access – it’s just what I needed, thanks a lot!
Read on wp.org ↗ - ★★★★★ mojamba10.8y ago
Recently installed and started using this plugin and it works wonderfully. But, seeing how long it has been since last being updated, I do worry if it will break in some future WP update. For now, all good. Let’s hope someone keeps this plugin active as I didn’t see any other plugin trying to solve this problem (which, itself, was a huge surprise).
Read on wp.org ↗ - ★★★★★ wyzyncom11.0y ago
Good plugin for securing / hiding media files (PDF’s and images) that are only to be seen in the member area by logged-in users. Member management plugins like Ultimate Member don’t offer this option. Result is that files which are imported into a member page are still publicly visible and accessable. Not good, because the member area and all its components should be visible by logged on members only. A big flaw in WordPress, as far as I’m concerned. But this plugin solves the problem easy and in an intuitive way. Why not a 5 star rating? Because I think it’s a pitty that this plugin hasn’t been updated for a long time. Really hope the developer will restart his project. I would wanna pay for this plugin.
Read on wp.org ↗ - ★★★★★ Martin Sauter11.0y ago
I installed this plug-in 2 minutes ago, it was absolutely straigh forward and does exactly what I expected. This plug-in deserves more attention from the WordPress community since it solves a major security problem of WordPress. Hopefully the developer continues his work. And yes: We would pay for this plug-in as well!
Read on wp.org ↗ - ★★★★★ thunksalot11.2y ago
I would gladly pay for a working version of this plugin. If someone resurrects it, please let me know. In the meantime, it’s totally unreliable. Works for some files, not others. Works for a little while, then you notice the next week that it has stopped working. It’s problems are probably mostly related to being 2 years and many updates behind the development of WP core. In any case, don’t waste your time unless you have a lot of time to waste.
Read on wp.org ↗
Behavioral tests
via WP HiveAutomated install-time checks, tested on PHP 7.2.16 · WP 5.3
AI assistants
How it's measured →Whether ChatGPT and Claude name this plugin when asked the category question, and whether the readme gives them something to quote.
Not measured yet for this plugin’s topics. Its tracked searches are not among the measured topics. See the topics measured so far.
Readme readiness
7 of 8 pass · checked 31 Oct 2026Can an assistant quote this readme? Eight deterministic checks over the wp.org listing, no model involved.
- ✓ Says what it does "Protect attachment files from direct access using powerful and flexible restrictions. Offer safe download l..."
- ✓ Has a FAQ 3 questions in the FAQ.
- ✓ FAQ asks real questions 3 of 3 read like questions a user would type.
- ! Names who it is for Never says who the plugin is for or what they use it for.
- ✓ Names what it works with Mentions Multisite.
- ✓ Headings and lists 2 headings and 1 list.
- ✓ Enough to quote 2,003 characters of description.
- ✓ Tags match the text All 5 tags appear in the text.
Growth timeline
Install-tier crossings we have observed, and how long each tier took to outgrow
- 2026-01-11 900+ → 800+ down after 237 days in tier
- 2025-05-19 1K+ → 900+ down
Competes with
The plugins that solve the same job, ranked by shared tags then reach, closest match first. The letter on the right is each plugin's health grade (A best, F worst).
-
Safe SVG 1M+ installs · 4.7★ · 2 shared tags A -
NinjaFirewall (WP Edition) – Advanced Security Plugin and Firewall 100K+ installs · 4.8★ · 2 shared tags A -
NinjaScanner – Virus & Malware scan 40K+ installs · 4.0★ · 2 shared tags A -
Zero Spam for WordPress 20K+ installs · 4.1★ · 2 shared tags B - U Unique Headers 10K+ installs · 4.9★ · 2 shared tags A
-
Prevent Direct Access – Protect WordPress Files 10K+ installs · 4.6★ · 2 shared tags A
Embed this report card
Drop a live Pulse card for Media Vault into a readme, a review or a deck. It updates itself.
<iframe src="https://plugins.wpmayor.com/embed/media-vault" width="480" height="300" style="border:0" loading="lazy" title="Media Vault — Plugin Pulse"></iframe> Media Vault: 800+ active installs, 4.4★ (27 reviews). Plugin Pulse (WP Mayor), as of 2026-10-31. https://plugins.wpmayor.com/plugin/media-vault
Spotted a number that looks wrong? Report a data issue and we'll check it against the source.