Paid Memberships Pro (PMPro) is a fantastic membership plugin — and one of the reasons I personally love it is because it’s family-owned. There’s something genuinely refreshing about working with a company that isn’t over-commercialized. They care deeply about their product, and it shows. On top of that, PMPro is open-source, which means you can use it completely free if you don’t need premium support.
PMPro has been around for decades and is packed with features to help you run, manage, and protect your membership site. However, one drawback of its longevity is that some of its documentation hasn’t kept pace with modern WordPress development.
In a recent project, I needed to protect files located outside the default WordPress directories. PMPro does offer a code snippet for this — but unfortunately, the recipe on their website hadn’t been updated since 2013. Naturally, it no longer works as expected in today’s environment.
The client had thousands of files spread across various directories on their hosting account. Reorganizing everything into a PMPro-friendly structure would’ve been a nightmare — not to mention terrible for SEO, since all the existing file URLs were already indexed by Google. I wanted to avoid setting up complex redirect rules, so I ended up writing a custom solution instead.
Table of Contents
Protect and secure your files for Members only
Running a membership site with Paid Memberships Pro (PMPro) offers robust content protection within WordPress. However, safeguarding files stored outside the WordPress directory—like PDFs, audio files, or entire folders—requires additional steps. This guide provides a comprehensive walkthrough to help you protect such external files using PMPro, ensuring only authorized members can access them.
Understanding PMPro's File Protection
PMPro primarily protects content within WordPress posts and pages. However, files uploaded to the media library or stored in other directories aren’t automatically secured. To protect these files, especially those outside the WordPress installation, you’ll need to implement custom solutions involving server configurations and PHP scripts.
Why Protect External Files?
Protecting external files ensures that only authorized members can access premium content, such as:
PDFs: eBooks, whitepapers, or reports
Audio Files: Podcasts or music tracks
Videos: Tutorials or webinars
Documents: Word or Excel files
Without proper protection, these files can be accessed directly via their URLs, bypassing membership restrictions.
Setting Up .htaccess Rewrite Rules
To route file requests through PMPro’s access control, add the following rewrite rule to your .htaccess file, placing it before the WordPress rules:
RewriteRule ^content/(.*)$ /?pmpro_getfile=$1 [QSA,L]
Replace protected-files with the name of your directory containing the files you wish to protect.
Implementing the PMPro File Access Script
Next, add a PHP script to handle file access. You can place this code in your theme’s functions.php file or use a plugin like WPCode to manage custom snippets:
add_action('init', function () { if (!isset($_GET['pmpro_getfile'])) return; // Check which directory to use based on a new parameter if (isset($_GET['source']) && $_GET['source'] === 'premium') { $protected_dir = '/home/howie007/public_html/content/'; } // Change this to your folder path $relative_path = wp_normalize_path($_GET['pmpro_getfile']); $relative_path = ltrim($relative_path, '/'); $file_path = wp_normalize_path($protected_dir . $relative_path); // Prevent path traversal (e.g. ../../etc/passwd) if (strpos($file_path, $protected_dir) !== 0) { wp_die('Invalid file path.'); } // Validate file extension $allowed_extensions = ['pdf', 'docx', 'jpg', 'mp3', 'zip']; $extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION)); if (!in_array($extension, $allowed_extensions)) { wp_die('File type not allowed.'); } // Restrict to logged-in members if (!is_user_logged_in() || !pmpro_hasMembershipLevel([1])) { $message = ' You do not have permission to access this file.
'; wp_die($message); } if (file_exists($file_path)) { $mime_type = mime_content_type($file_path); // Ensure correct MIME type for MP3 files if ($extension === 'mp3') { $mime_type = 'audio/mpeg'; } header('Content-Type: ' . $mime_type); header('Content-Disposition: inline; filename="' . basename($file_path) . '"'); header('Content-Length: ' . filesize($file_path)); readfile($file_path); exit; } else { wp_die('File not found.'); }
}); Ensure you update $protected_dir with the absolute path to your protected files directory.
Validating File Access and Security
The script performs several checks:
Path Validation: Ensures the requested file resides within the protected directory.
File Extension Check: Allows only specified file types.
Membership Verification: Confirms the user is logged in and has the appropriate membership level.
These checks prevent unauthorized access and potential security breaches.
Restricting Access by Membership Level
The function pmpro_hasMembershipLevel([1]) checks if the user has a specific membership level (in this case, level 1). Modify the array to include the membership levels that should have access to the files.
Serving Files Inline vs. as Attachments
By default, the script serves files inline, allowing them to open in the browser. To force downloads instead, change the Content-Disposition header:
header('Content-Disposition: attachment; filename="' . basename($file_path) . '"');
Protecting Specific File Types (PDFs, MP3s, etc.)
The $allowed_extensions array in the script defines which file types are permitted. Add or remove extensions based on the types of files you wish to protect.
Troubleshooting Common Issues
Files Not Found: Check that the file paths are correct and that the files exist in the specified directory.
Access Denied Errors: Ensure the user is logged in and has the appropriate membership level.
Server Errors: Review server logs for memory issues or misconfigurations in
.htaccess.
FAQ
Q: Can I protect files uploaded via the WordPress media library?
A: Yes, but additional configurations are needed to prevent direct URL access.
Q: Is it possible to restrict access to specific membership levels?
A: Absolutely. Modify the
pmpro_hasMembershipLevel()function to include the desired levels.Q: What if I’m not comfortable editing code?
A: Consider using the Download Monitor plugin, which offers a more straightforward, code-free approach. However, please note that you will not be able to protect easily your current uploads as all the links have to be rewritten.
Q: Can you iplement this for us?
A: Sure, we will be able to code this into your PMPro website. Reach out to us using the links bellow.

