Plugin Pulse
← Pulse
M

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.

⚠ Stale⚠ Likely abandoned
How scoring works →
48 Health · D
Maintenance 3/100
Rating quality 83/100
Support 70/100

48 health vs 59 average across 2,206 Media plugins

High removal-risk signals

63/100

Maintenance 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.

44 / 100

Under-optimized

Biggest win: Update recency

Update recency 0/100
WP compatibility 2/100
Rating quality 84/100
Listing tuning 100/100

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

+51% vs prior 30d
11Downloads · Aug 26

30-day downloads

Rolling 30-day volume · peaks are release surges

110

now · peak 137

10930d downloads · Aug 26

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

Media Vault · #7677 you Safe SVG · #54 NinjaFirewall (WP Ed · #350 Protect Uploads · #920

Rating trend

Star average over time · dips mark rough releases

4.4Stars · Aug 26

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.

136per 1k installs · Aug 26

Release cadence

No release in a year
from wp.org release tags

How 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

0.8.12 · 12.5y ago0.8.11 · 12.5y ago0.8.10 · 12.6y ago0.8.7 · 12.6y ago0.8.9 · 12.6y ago0.8.8 · 12.7y ago0.8.6 · 12.7y ago0.8.5 · 12.7y ago0.8 · 12.8y ago0.7.1 · 12.9y ago0.7 · 12.9y ago0.6 · 12.9y ago

What its installed base runs

via wordpress.org

Share 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.

v0.8 100%

Estimated active installs

The public count shows “800+”. Our estimate pins where the real number sits.

tracked estimate
800–900 ≈860

Refined from the date this plugin crossed into its current band.

Install history · since 2015-09-19 · 1,427 observations

800Installs · Aug 26

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

N/A

Est. acquisition value

N/A

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

Version
0.8.12
Last updated
12.5y ago
Added
2013-10-18 · 12 yrs old
Requires WP
3.5.0
Tested up to
3.7.41
Requires PHP

Recent reviews

All reviews on wp.org ↗
  1. maxeyle
    6.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 ↗
  2. fatheroftime
    6.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 ↗
  3. jtvie
    10.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().'">&larr;'.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 ↗
  4. dimgord
    10.4y ago

    Found it while looking for restriction view access – it’s just what I needed, thanks a lot!

    Read on wp.org ↗
  5. mojamba
    10.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 ↗
  6. wyzyncom
    10.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 ↗
  7. Martin Sauter
    10.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 ↗
  8. thunksalot
    11.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 Hive

Automated install-time checks, tested on PHP 7.2.16 · WP 5.3

Low memory footprint
Low page-speed impact
Runs on latest PHP + WP
No PHP errors
No JS errors
Activates cleanly
No resource errors
No external HTTP errors
Optimized database use
Frequently updated

Growth timeline

Install-tier crossings we have observed, and how long each tier took to outgrow

  1. 2026-01-11 900+ → 800+ down after 237 days in tier
  2. 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).

Compare head to head →

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>
Preview card ↗

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