I run a WordPress Multisite with seven sites. Think school forms, client PDFs, and a few videos for training. I wear the webmaster hat. I also make the coffee. On a rainy Tuesday, I found out our private files were getting shared by direct links. Not cool. I eventually pulled everything into a step-by-step case study—the full story lives here.
So I spent two weeks locking things down. I tried three paths. Some easy, some fussy, and one that was fast but rough around the edges. Here’s what I learned, the hard way.
My setup and the problem (in plain talk)
- WordPress Multisite with sub-sites like /hr/, /staff/, and /courses/.
- Shared media folder: wp-content/uploads/sites/2/, sites/3/, and so on.
- Staff PDFs, parent forms, and course videos.
- People pasted direct file links in chat. Guests could open them. Yikes.
I needed file links that check “who are you?” before they load. On every sub-site, not just one.
The fast fix: Prevent Direct Access Gold (works on Multisite)
First, I used Prevent Direct Access Gold (PDA Gold). I network-activated it. Then I went to each sub-site and marked files as “private.” Their detailed walkthrough on protecting media files across a WordPress Multisite was a lifesaver.
Real example:
- File: /wp-content/uploads/sites/3/2025/08/Staff-Handbook.pdf
- I clicked Protect in the Media Library.
- PDA gave me a private link like /?pda=staff-handbook-abc123.
- The old URL stopped working for guests. Logged-in staff could see it on that sub-site.
What I liked:
- It worked right away. No code. No tears.
- It shows a lock icon in Media Library. Handy when you’re half-awake.
What bugged me:
- Rules live per site. So I had to protect the file on each sub-site where I used it.
- Hotlinking from other sub-sites still tried to sneak around. PDA blocked most of it, but edge cases popped up.
- Thumbnails and attachment pages could leak info if I wasn’t careful.
Small note: I set a rule to protect only PDFs, DOCX, and ZIPs. I didn’t protect images used on public pages; that would break design.
The membership gate: MemberPress + files behind roles
On our courses site, I used MemberPress with “Teachers” and “Parents” roles. I set rules so only Teachers could view certain PDFs.
Real example:
- Course plan PDFs in /sites/4/.
- I added the file link to a page that only Teachers can view.
- The direct old URL still needed a block, so I kept PDA on too.
What I liked:
- Good for human logic: “if Teacher, show file.”
- Easy to explain to non-tech folks.
What didn’t fly:
- Rules don’t jump across sub-sites. Each site needs its own rules.
- If someone got the raw file URL, MemberPress alone didn’t stop it. It’s page-level, not file-level. So yes, I still needed PDA or server rules.
Cloud route: WP Offload Media to S3 + CloudFront signed URLs
For videos, I went cloud. I used WP Offload Media to push big MP4 files to Amazon S3 and served them with CloudFront. I turned on signed URLs so only allowed users can watch.
Real example:
- Video: lesson-3.mp4 on the courses site (site 4).
- Player: Presto Player worked well with signed URLs.
- The signed link expires. If a student shares it, it fails after a short time.
What I liked:
- Fast video. Less load on my server.
- Signed URLs felt solid. Like a bouncer at the door.
Trade-offs:
- Cost. Not huge, but not zero.
- Setup takes patience. The first time, I mixed up a policy and locked myself out. Fun.
- Domain mapping can confuse cookies. I kept a tight cookie path and it smoothed out.
Tip: If you use Cloudflare on top, bypass cache for signed URLs. I set a page rule to skip cache on /media/* and the timeouts stopped.
The nerdy bit: server rules that actually block files
I also tried server rules. On Apache, I blocked direct PDF hits and sent them to a PHP check. On Nginx, I used X-Accel-Redirect. Sounds fancy, but here’s the point: WordPress checks “who are you?” then the server streams the file. It’s faster than loading the whole file through PHP.
Real example:
- File: /wp-content/uploads/sites/2/policies/leave-policy.pdf
- If not logged in, you see a 403 page. If you’re HR staff, you get the file.
Good:
- It’s strong and fast once set.
- It works across all sub-sites with one rule, if you plan the paths.
But:
- Easy to break if you use a CDN wrong.
- You’ll need a tiny custom plugin or function to check roles. Not hard, but not click-and-go.
I still used PDA on top for quick toggles. A belt and suspenders thing.
What broke on me (and how I fixed it)
- Attachment pages: Even when files were blocked, the WordPress attachment page could leak the file name. I killed attachment pages with a small mu-plugin that redirects them to the parent post.
- Thumbnails: Some image thumbs stayed public. I didn’t care for images on public pages, but I did for scans of IDs. I kept those scans as PDFs and used PDA.
- Caching: One time, Cloudflare cached a private response. I set no-store headers for private links and made a cache bypass rule. Problem gone.
- Editors moving files: A team member replaced a file with the same name. The private link changed. I trained folks to re-copy the link after any replace. We also used “Enable Media Replace,” which helped.
What I ended up using (my real stack)
- PDA Gold for PDFs, DOCX, and ZIPs on all sub-sites.
- MemberPress for role logic on course pages.
- WP Offload Media + S3 + CloudFront for videos, with signed URLs.
- A tiny mu-plugin to disable attachment pages and block direct file access for sensitive types.
- Cloudflare rules that skip cache on private links and set no-store headers.
It’s not perfect. But it’s stable. And my support inbox is quiet now, which is priceless.
Step-by-step: How I’d set this up again
- Network-activate PDA Gold. Protect PDFs and ZIPs only.
- On each sub-site, mark private files in Media Library.
- Turn off attachment pages with a small mu-plugin.
- For courses, protect pages with MemberPress roles.
- For big files (video), offload to S3 and use signed URLs.
- Set CDN rules to bypass cache for private paths.
- Train editors: always use the private link, not the raw URL.
- Test as a logged-out user, on each sub-site, every time you change a rule.
Real examples you can picture
- HR site (site 2): Staff-Handbook.pdf is private. Only logged-in HR can view it. The old uploads URL throws a 403.
- School site (site 3): Parent-Form-2025.docx is private. Teachers see it on a locked page. Guests see a friendly “please log in.”
- Courses site (site 4): Lesson-3.mp4 streams from CloudFront with a signed URL that lasts 15 minutes. Students watch; shared links expire.
Tiny gotchas I wish someone told me
- Changing file names breaks private links. Keep names stable.
- Backups: make sure your backup tool can still copy protected files.
- Staging: protect rules on staging too, or you’ll think it’s broken when it’s not.
- Domain mapping: cookies can get weird across subsites. I used secure cookies and a consistent login page. It helped a lot.
- Revenue experiments: before you plan a blind drop-shipping side hustle, read this cautionary tale for a reality check.
If your network ever finds itself distributing 18-plus or explicit materials, you’ll need airtight user verification before anyone even sees a download button. To see how a high-traffic dating platform solves instant, location-based access control, check out this breakdown of how to get free sex tonight—hint: try this app. It walks through their friction-less onboarding flow, age-gate tactics, and privacy safeguards you can borrow for your own WordPress build.
In a similar vein, if you’re curious how a hyper-local sugar-dating network tightens access to seductive photos and chat logs, study the flow employed by Sugar Baby Georgetown—the article breaks down its selective onboarding, ID checks, and pay-walled media vault, offering blueprints you can translate to WordPress.
Alternatively, a hosted storefront like CandyPress bakes in secure file delivery so you can skip the Multisite wrangling altogether. If you’re eyeing