Plugin Pulse Beta
← 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.

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.

⚠ Stale⚠ Likely abandoned

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.

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

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

Details

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

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

Most to gain: Update recency

Update recency 0/100

Updated 4638 days ago, past the ~180 days where wp.org starts discounting

WP compatibility 2/100

Tested up to WordPress 3.7.41; the current branch is 6.8

Rating quality 84/100

4.4★ over 27 reviews, smoothed to 4.21★

Listing tuning 100/100

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 →

Daily downloads

Since 5 Oct 2022 · 1,488 days · wp.org + Plugin Pulse archive

— vs prior 30d
1131 Oct 2026

30-day downloads

Rolling 30-day volume · peak 209 · peaks are release surges

20931 Oct 2026

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 · #7615youSafe SVG · #54NinjaFirewall (WP Ed · #344NinjaScanner · #905

Rating trend

Star average over time · dips mark rough releases

4.431 Oct 2026

Health trend

Composite health score, snapshotted daily

4831 Oct 2026

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.

26131 Oct 2026

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.7y ago

latest release · v0.8.12 · 18 Feb 2014

12

tagged releases on record

Recent releases

0.8.12 · 18 Feb 20140.8.11 · 14 Feb 20140.8.10 · 11 Feb 20140.8.7 · 20 Jan 20140.8.9 · 20 Jan 20140.8.8 · 1 Jan 20140.8.6 · 6 Dec 20130.8.5 · 3 Dec 20130.8 · 31 Oct 20130.7.1 · 20 Oct 20130.7 · 18 Oct 20130.6 · 18 Oct 2013

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 ≈850

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

80031 Oct 2026

Recent reviews

All reviews on wp.org ↗
  1. ★★★★★ maxeyle
    6.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 ↗
  2. ★★★★★ fatheroftime
    7.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 ↗
  3. ★★★★★ jtvie
    10.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().'">&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.5y 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.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 ↗
  6. ★★★★★ wyzyncom
    11.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 ↗
  7. ★★★★★ Martin Sauter
    11.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 ↗
  8. ★★★★★ thunksalot
    11.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 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

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 2026

Can 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

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

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