{"id":400122,"date":"2026-11-12T00:59:52","date_gmt":"2026-11-12T00:59:52","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/birim-private-files\/"},"modified":"2026-11-12T01:14:48","modified_gmt":"2026-11-12T01:14:48","slug":"birim-private-files","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/birim-private-files\/","author":23595763,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.0","stable_tag":"1.0.0","tested":"7.1.4","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"Birim Private Files","header_author":"Birim","header_description":"Make files and pages open only for logged-in users, chosen roles or the people you share them with, including direct links. Checks that protection really works on your server.","last_updated":"2026-11-12 01:14:48","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/birimone.pages.dev\/private-files\/","header_author_uri":"https:\/\/birimone.pages.dev\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":91,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"birimone","date":"2026-11-12 01:14:48","revision":3797322}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3797315,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3797315,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon.svg":{"filename":"icon.svg","revision":3797315,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3797315,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3797315,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3797315,"resolution":"1","location":"assets","locale":"","width":2560,"height":1720},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3797315,"resolution":"2","location":"assets","locale":"","width":2560,"height":1720},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3797315,"resolution":"3","location":"assets","locale":"","width":2560,"height":1720},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3797315,"resolution":"4","location":"assets","locale":"","width":2560,"height":1720}},"screenshots":{"1":"Settings &gt; Private Files: the status check confirms files are protected on this server. Here files open only for the people each one is shared with.","2":"Share a file with a client from the media library: type their username or email in \"Shared with\".","3":"The \"Who can view\" box in the page editor: this page is visible only to editors and authors.","4":"What a client sees: their \"My files\" page lists only the files shared with them."}},"plugin_section":[],"plugin_tags":[88,6307,84,870,183913],"plugin_category":[50,58],"plugin_contributors":[289670],"plugin_business_model":[],"class_list":["post-400122","plugin","type-plugin","status-publish","hentry","plugin_tags-files","plugin_tags-intranet","plugin_tags-media","plugin_tags-private","plugin_tags-protect-uploads","plugin_category-media","plugin_category-user-management","plugin_contributors-birimone","plugin_committers-birimone"],"banners":{"banner":"https:\/\/ps.w.org\/birim-private-files\/assets\/banner-772x250.png?rev=3797315","banner_2x":"https:\/\/ps.w.org\/birim-private-files\/assets\/banner-1544x500.png?rev=3797315","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/birim-private-files\/assets\/icon.svg?rev=3797315","icon":"https:\/\/ps.w.org\/birim-private-files\/assets\/icon.svg?rev=3797315","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/birim-private-files\/assets\/screenshot-1.png?rev=3797315","caption":"Settings &gt; Private Files: the status check confirms files are protected on this server. Here files open only for the people each one is shared with."},{"src":"https:\/\/ps.w.org\/birim-private-files\/assets\/screenshot-2.png?rev=3797315","caption":"Share a file with a client from the media library: type their username or email in \"Shared with\"."},{"src":"https:\/\/ps.w.org\/birim-private-files\/assets\/screenshot-3.png?rev=3797315","caption":"The \"Who can view\" box in the page editor: this page is visible only to editors and authors."},{"src":"https:\/\/ps.w.org\/birim-private-files\/assets\/screenshot-4.png?rev=3797315","caption":"What a client sees: their \"My files\" page lists only the files shared with them."}],"raw_content":"<!--section=description-->\n<p>WordPress stores uploads in <code>\/wp-content\/uploads\/<\/code>, and every file there is a public URL. Making a page private, or putting your site behind a login, does not protect the files on it: anyone with the link can open them.<\/p>\n\n<p>Birim Private Files routes every request for an uploaded file through WordPress and only serves it to people who are allowed to see it.<\/p>\n\n<ul>\n<li><strong>Three ways to decide who opens files<\/strong>: any logged-in user, only the roles you choose, or <strong>only the people each file is shared with<\/strong> (the uploader, people you add in the file's \"Shared with\" field, editors and administrators).<\/li>\n<li><strong>Private pages too<\/strong>: a \"Who can view\" box in the page editor (block editor and classic editor) sets each page or post to Everyone, Logged-in users or chosen roles. Restricted pages send logged-out visitors to the login page, and their text is hidden in search results, archives, feeds and the REST API, and left out of the sitemap.<\/li>\n<li><strong>Files follow their page<\/strong>: in per-file mode, files uploaded to a restricted page open for whoever can view that page.<\/li>\n<li><strong>A \"My files\" list<\/strong>: put <code>[birim_my_files]<\/code> on a page and each person sees the files they uploaded or that were shared with them.<\/li>\n<li><strong>Direct links are protected<\/strong>, not just pages. Logged-out visitors who open a file link are sent to the login page and come back to the file after logging in.<\/li>\n<li><strong>It checks that protection really works.<\/strong> After you turn it on, the plugin requests a test file from your site as a logged-out visitor and tells you the result: Protected, Not protected, or Could not check. Until protection is confirmed, administrators see a warning. Many file protection setups fail silently on nginx servers; this one tells you.<\/li>\n<li><strong>Apache<\/strong>: rules are added to <code>wp-content\/uploads\/.htaccess<\/code> automatically, and removed when you deactivate the plugin.<\/li>\n<li><strong>nginx<\/strong>: the settings page shows the exact two-line rule to add for your site.<\/li>\n<li><strong>Public exceptions<\/strong>: keep chosen files public, such as a logo, with simple patterns like <code>public\/*<\/code>.<\/li>\n<li>Files are served with private caching headers (so CDNs and shared caches do not store them), conditional requests and byte ranges, so video seeking works.<\/li>\n<li>Script files are never served from uploads, and paths outside the uploads folder are refused.<\/li>\n<li>Lightweight: one file, no tracking, no external requests, no ads.<\/li>\n<\/ul>\n\n<h4>What you can do with it<\/h4>\n\n<ul>\n<li><strong>Staff intranet<\/strong>: share HR policies, handbooks, rotas and internal reports on WordPress. Only staff who log in can open them, even if a link is forwarded outside the company.<\/li>\n<li><strong>Client portal<\/strong>: agencies, freelancers, accountants and lawyers share each contract, design or report with one client, who sees it in their \"My files\" page. Other clients cannot open it, even with the link.<\/li>\n<li><strong>Members-only content<\/strong>: sell or share course PDFs, e-books, worksheets and videos without the download link being passed around. Video seeking still works.<\/li>\n<li><strong>Schools, clubs and charities<\/strong>: keep photos of children, member lists and meeting minutes visible to parents and members only.<\/li>\n<li><strong>Forms that collect documents<\/strong>: CVs, ID scans and signed forms uploaded through form plugins usually land in the public uploads folder. Keep them away from anyone who guesses or finds the link.<\/li>\n<li><strong>Staging and pre-launch sites<\/strong>: stop unreleased product images and documents from leaking or showing up in Google Images.<\/li>\n<\/ul>\n\n<h4>What it does not do<\/h4>\n\n<ul>\n<li>Titles of restricted pages can still appear in menus and archive lists; only their text is hidden.<\/li>\n<li>WordPress's public REST API lists media items (titles and links) to anyone. The files themselves stay protected, but to hide the list as well, use a REST API lockdown plugin such as Birim REST Lock.<\/li>\n<li>It does not encrypt files on the server or make your site compliant with any regulation on its own. It controls who can open them.<\/li>\n<\/ul>\n\n<h4>For developers<\/h4>\n\n<ul>\n<li><code>birim_private_files_can_access<\/code> filter: <code>( bool $allowed, string $relative_path )<\/code> to make your own access decisions, for example per file or per user.<\/li>\n<li><code>birim_private_files_served<\/code> action: <code>( string $relative_path, string $absolute_path )<\/code>, fired just before an allowed file is sent, for example to log downloads.<\/li>\n<li><code>birim_private_files_serve( $path, array( 'download' =&gt; true ) )<\/code> sends a file as a download (attachment) instead of inline.<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Install from Plugins &gt; Add New, or upload the <code>birim-private-files<\/code> folder to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>Activate the plugin. Nothing changes until you turn protection on.<\/li>\n<li>Go to Settings &gt; Private Files, tick \"Make uploaded files private\" and save.<\/li>\n<li>Check the status. On nginx, add the rule shown, reload nginx and click \"Check again\".<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"will%20images%20on%20my%20public%20pages%20break%3F\"><h3>Will images on my public pages break?<\/h3><\/dt>\n<dd><p>Yes, for logged-out visitors, unless the files match a public exception. This plugin is meant for sites where the content is private too. Use the public exceptions for files that must stay visible, such as a logo.<\/p><\/dd>\n<dt id=\"the%20status%20says%20%22not%20protected%22.\"><h3>The status says \"Not protected\".<\/h3><\/dt>\n<dd><p>Your web server is serving files directly without asking WordPress. On nginx, add the rule shown on the settings page. On Apache, your host may not allow <code>.htaccess<\/code> rewrite rules, or it may run nginx in front of Apache; send your host the rule shown on the settings page.<\/p><\/dd>\n<dt id=\"the%20status%20says%20%22could%20not%20check%22.\"><h3>The status says \"Could not check\".<\/h3><\/dt>\n<dd><p>Your server could not make a request to its own website, which some hosts block. Check manually: copy the link of an uploaded file, open a private browser window and paste it. You should see the login page or \"This file is private\".<\/p><\/dd>\n<dt id=\"does%20it%20slow%20down%20my%20site%3F\"><h3>Does it slow down my site?<\/h3><\/dt>\n<dd><p>Each file request now starts WordPress to check the login, so files are served a little slower than directly by the web server. Logged-in browsers cache files for an hour.<\/p><\/dd>\n<dt id=\"i%20use%20a%20cdn.\"><h3>I use a CDN.<\/h3><\/dt>\n<dd><p>Files are sent with <code>Cache-Control: private<\/code>, which CDNs respect by default. If your CDN is set to cache everything regardless of headers, exclude <code>\/wp-content\/uploads\/<\/code> from that rule.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20i%20deactivate%20the%20plugin%3F\"><h3>What happens when I deactivate the plugin?<\/h3><\/dt>\n<dd><p>On Apache the rules are removed and files are public again. On nginx, remove the rule you added, or file links will stop working.<\/p><\/dd>\n<dt id=\"does%20it%20work%20on%20multisite%3F\"><h3>Does it work on multisite?<\/h3><\/dt>\n<dd><p>Not yet. Multisite support is planned.<\/p><\/dd>\n<dt id=\"how%20do%20i%20report%20a%20security%20issue%3F\"><h3>How do I report a security issue?<\/h3><\/dt>\n<dd><p>Please email security@birim.one instead of posting in the forum. See https:\/\/birimone.pages.dev\/security\/ for the full policy.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>First release.<\/li>\n<\/ul>","raw_excerpt":"Protect uploaded files and pages: open only for logged-in users, chosen roles or people you share them with, even by direct link. Checks it works.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/400122","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=400122"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/birimone"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=400122"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=400122"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=400122"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=400122"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=400122"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=400122"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}