Drupal is a registered trademark of Dries Buytaert

file_unpublish

1 sites No security coverage
View on drupal.org

Hide (unpublish) public files when their parent media entities become unpublished.

The module provides the ability to keep public files of unpublished media entities unavailable until the media entity becomes published and available for the public. Media entity files are all files referred by that entity via file fields.

A Use Case

One of the common use cases is setting up an editorial workflow, where the content is not publicly available (not published) initially.Or where the content needs to be archived and hidden from the public but still preserved on the site. To have a complete solution for such a workflow, content editors would need to make sure the media entities associated with a given content entity are unpublished as well.

This, however, is not preventing the public from accessing the underlying files: by default, files stored in the public file system (having public:// file system wrapper) are always available to the public via direct URLs like https://mysite.com/sites/default/files/my-file.pdf. There is no default Drupal-native method of making public files inaccessible when their parent entities are not publicly accessible.

It might be tempting to store all files in the private file system, but that could quickly become a bottleneck and bring the site down. Private files, as opposed to public files, require Drupal to process each file download request.

The Solution

The Unpublish Public Files module aims to solve this problem in two ways:
- keeps the public files public, without moving them around,
- outsource access check to the web server to avoid bootstrapping Drupal.

At the forefront of the solution is a small web-server configuration snippet, which instructs the web-server to check the presence of a special filesystem marker for each file request. If the marker file is present, then the access to the requested file is denied; otherwise, the file request is processed as normal.

At the back-end, the module takes care of creating filesystem markers when media entities are unpublished, as well as removing them when media entities become published again.

The filesystem marker is an empty file found next to the original file and baring the same name with added preconfigured extensions, e.g. x410:

my-unpublished-file.pdf
my-unpublished-file.pdf.x410

When the my-unpublished-file.pdf is requested, the webserver will check for my-unpublished-file.pdf.x410 file before serving the requested file.

Webserver Configuration

Apache

The configuration snippet provided below is recommended to be pre-pended to Drupal's .htaccess file.

Prerequisites:
- ability to adjust server configuration,
- Mod Rewrite enabled.

# mod_rewrite is required.
<IfModule mod_rewrite.c>
  RewriteEngine on

# This is a required part of the functionality which allows unpublishing,
# or masking, media source files. As part of that solution, files which have
# special marked in the file system are not served by the server, and 410
# HTTP status code is returned instead. The special marker is an empty file
# named after the original file, with the addition of a special extension.
# In the example below, the masker extension is ".x410", e.g.
# for the "/path/to/file.pdf" file a corresponding marker file
# would be  "/path/to/file.pdf.x410".
#
# Note: the [G] flag forces the server to return a "410 Gone" status.
# This could be adjusted to match the specific needs.
RewriteRule ^(.*)\.x410$ /$1 [L,R=301]
RewriteCond %{REQUEST_URI} ^/sites/(.*)/files/(.*)$
RewriteCond %{DOCUMENT_ROOT}/sites/%1/files/%2.x410 -f
RewriteRule .* - [G,L]

</IfModule>

Nginx and other servers

Drupal doesn't come with a default Nginx configuration file. While Drupal is often deployed with Nginx, you need to create your own configuration file or use a community-provided one. You can then implement Nginx config alternative functionally similar to the one provided above.

When Using Composer

The config snippet can be added to the .thaccess automatically with the help of the drupal/core-composer-scaffold plugin, with the following configuration:

{
  "extra": {
    "drupal-scaffold": {
      "file-mapping": {
        "[web-root]/.htaccess": {
          "prepend": "path/to/htaccess.prepend.conf"
        }
      }
    }
  }
}

Activity

Total releases
2
First release
Jul 2025
Latest release
7 months ago
Release cadence
0 days
Stability
0% stable

Releases

Version Type Release date
1.0.0-alpha1 Pre-release Jul 8, 2025
1.x-dev Dev Jul 8, 2025