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.
48 health vs 59 average across 2,206 Media plugins
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.
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
Biggest win: Update recency
To rank higher: Last updated 4575 days ago — ship an update; wp.org decays a listing's search weight after ~180 days.
Get the full rank-higher report →Daily downloads
Since 2022-10-05 · 1,424 days · wp.org + Plugin Pulse archive
30-day downloads
Rolling 30-day volume · peaks are release surges
110
now · peak 137
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
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.5y ago
latest release · v0.8.12
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.
Refined from the date this plugin crossed into its current band.
Install history · since 2015-09-19 · 1,427 observations
Estimated value
What this plugin might earn a year, and what it might sell for. Modeled from public signals; we don't see anyone's books.
Est. annual revenue
Est. acquisition value
No paid tier is visible, so we don't put a figure on revenue or sale value: that would be guessing. The install base is a real asset to an acquirer, just not one public data lets us price. A small install base leaves thin data to model from.
Details
Recent reviews
All reviews on wp.org ↗- ★★★★★ maxeyle6.6y 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 ↗ - ★★★★★ fatheroftime6.9y 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.1y 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.4y ago
Found it while looking for restriction view access – it’s just what I needed, thanks a lot!
Read on wp.org ↗ - ★★★★★ mojamba10.7y 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 ↗ - ★★★★★ wyzyncom10.8y 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 Sauter10.8y 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.0y 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
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 -
Protect Uploads 30K+ installs · 4.4★ · 2 shared tags A -
NinjaScanner – Virus & Malware scan 30K+ installs · 4.1★ · 2 shared tags B -
Zero Spam for WordPress 20K+ installs · 4.1★ · 2 shared tags B
- U Unique Headers 10K+ installs · 4.9★ · 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-08-29. https://plugins.wpmayor.com/plugin/media-vault