Drupal is a registered trademark of Dries Buytaert

file_visibility

30 sites Security covered
View on drupal.org

Keeps public files of a publicly inaccessible entity in the private filesystem until the entity becomes available for the public. Entity files are all files referred by the entity, either via entity reference fields or uploaded and embedded in text blobs.

Why?

Say, you're building an editorial workflow where, initially, the content is not public, to avoid spam. Even your new node is unpublished by default if there's at least a file field with scheme defaulting to the public file system; a spammer-uploaded file is still available for the public. Following this path, a spammer is able to manipulate the search engines. This process is called Spamdexing.

The site builder might be tempted to set the private file system as the default scheme for all uploaded files. But this is not recommended, as Drupal might crash in heavy traffic. Actually, for each file the webserver, PHP, and Drupal will have to do heavy processing. While a public file is served directly by the webserver, and 90% of the time is retrieved either from the frontend cache or even from the browser's cache.

Conclusion: we need a way to keep files private as long as there's no public content using that file. As soon as, at least, public content is using the file, the file should be moved to the public file system.

The original idea comes from a Drupal core issue.

Terminology

File
A file entity attached to an entity which is subject to visibility protection according to this module's scope.
Source entity
A content entity that refers to a file entity directly or via some different entities that are located in the middle. The reference could be an entity reference field, a file uploaded and linked via CKEditor, and so on. For instance, a node might expose a paragraph field which contains a text paragraph which embeds a file media entity. In this case the source entity is the node; and paragraph and media are traversable entities.
Traversable entity
An entity that is placed in the middle, between the source entity and the files, e.g., paragraphs, media, etc. Such entities can be traversed to find the source-used files.
Path
The path shows the trail from the source entity to the file entity. The path starts with the source entity followed by the traversable entities. The order from source to file is preserved.

How does it work?

To be able to move a file from public to private filesystem and vice versa, the module should be able to determine which are the source entities for a certain file and determine their visibility for anonymous users. But checking the source entity visibility is not enough; it should follow the path from the source entity to the file destination and check the visibility of each traversable entity on the way. This is achieved by the Drupal\file_visibility\FileVisibility service. The service interrogates all FileVisibility plugins and collects paths from source entities to the file. If at least one path has all entities publicly visible, then we consider that the file is in use and should be publickly accessible under its original public file system. If there's no path that can be traversed by an anonymous user, the file is moved under the private file system.

The main module, file_visibility, offers the FileVisibility plugin type. This plugin type knows how to determine the relation between a file and its source entity, including all paths from source to the file. By default, the module only provides the plugin discovery attributes, the manager and the interface, but no plugin class. But there is the file_visibility_track_usage submodule that ships a plugin which computes such relation by extracting data from the Track Usage module.

Third-party modules can provide their own plugins using different methods.

Configuration

This section covers the configuration when using the file_visibility_track_usage submodule.

Configure the Track Usage module first. Note that this is critical for the module to work, and it's crucial to understand how Track Usage works and how to track the relation between source entities, such as Content (node), and File (file) entities.

  • Visit /admin/config/system/track-usage/settings and add a new tracking configuration, dedicated for File Visibility.
  • After adding a label, you can restrict some tracker plugins from being used. If not sure, leave all unchecked.
  • If your site is publicly exposing the source entity revisions, you might want to check the "Track only the active entity revision" checkbox.
  • Check "Record entity changes in real time"
  • Pay attention to the Source entity types section and check the entities acting as source entities. Usually, the node entity type should be checked.
  • If your site is using a complex, nested structure with paragraphs and/media, make sure you do the proper selection under the Traversable entity types section.
  • Select the File (file) entity type under Target entity types section.
  • It's time to configure the file visibility settings. On a complex setup you might have more than one file visibility plugins. On the /admin/config/file-visibility page you can restrict the plugins to be used. For now just leave all unchecked.
  • Visit /admin/config/file-visibility/track-usage page, select the Track Usage configuration you've just created, and press the Save configuration button.
  • Now it's time to create the initial track usage records with Drush. From the console run drush track_usage:update <config-machine-name>, where <config-machine-name> is the name of the Track Usage configuration you've just created. To get some help on the command, run drush track_usage:update --help.

You're done! Drupal will automatically track and record file usages and will move files accordingly between the public and the private filesystem.

Recommendation

Until a node is saved, the uploaded file is temporary, but its URL is still reachable. It's recommended to configure the upload location under private://file-visibility/, so even a temporary spam file cannot be used. Note that private://file-visibility/ is the location under which the files are moved when they need to be protected from public access.

Contribute

DDEV, a Docker-based PHP development tool for a streamlined and unified development process, is the recommended tool for contributing to the module. The DDEV Drupal Contrib addon makes it easy to develop a Drupal module by offering the tools to set up and test the module.

Install DDEV

  • Install a Docker provider by following DDEV Docker Installation instructions for your Operating System.
  • Install DDEV, use the documentation that best fits your OS.
  • DDEV is used mostly via CLI commands. Configure shell completion & autocomplete according to your environment.
  • Configure your IDE to take advantage of the DDEV features. This is a critical step to be able to test and debug your module. Remember, the website runs inside Docker, so pay attention to these configurations:

Checkout the module

Normally, you check out the code form an issue fork:

git clone [email protected]:issue/file_visibility-[issue number].git
cd file_visibility-[issue number]

Start DDEV

Inside the cloned project run:

ddev start

This command will fire up the Docker containers and add all configurations.

Install dependencies

ddev poser

This will install the PHP dependencies. Note that this is a replacement for Composer install command that knows how to bundle together Drupal core and the module. Read more about this command at https://github.com/ddev/ddev-drupal-contrib?tab=readme-ov-file#commands

ddev symlink-project

This symlinks the module inside web/modules/custom. Read more about this command at https://github.com/ddev/ddev-drupal-contrib?tab=readme-ov-file#commands. Note that as soon as vendor/autoload.php has been generated, this command runs automatically on every ddev start.

This command should also be run when adding new directories or files to the root of the module.

ddev exec "cd web/core && yarn install"

Install Node dependencies. This is needed for the ddev eslint command.

Install Drupal

ddev install

This will install Drupal and will enable the module.

Changing the Drupal core version

  • Create a file .ddev/config.local.yaml
  • In the new config file, set the desired Drupal core version. E.g.,
      web_environment:
        - DRUPAL_CORE=^10.4
    
  • Run ddev restart

Refer to the original documentation: Changing the Drupal core version

Run tests

  • ddev phpunit: run PHPUnit tests
  • ddev phpcs: run PHP coding standards checks
  • ddev phpcbf: fix coding standards findings
  • ddev phpstan: run PHP static analysis
  • ddev eslint: Run ESLint on Javascript and YAML files.

Activity

Total releases
10
First release
Apr 2025
Latest release
6 months ago
Release cadence
13 days
Stability
0% stable

Release Timeline

Releases

Version Type Release date
1.0.0-alpha9 Pre-release Aug 12, 2025
1.0.0-alpha8 Pre-release Jun 16, 2025
1.0.0-alpha7 Pre-release Jun 13, 2025
1.0.0-alpha6 Pre-release Jun 10, 2025
1.0.0-alpha5 Pre-release Jun 10, 2025
1.0.0-alpha4 Pre-release Jun 10, 2025
1.0.0-alpha3 Pre-release May 12, 2025
1.0.0-alpha2 Pre-release Apr 30, 2025
1.0.0-alpha1 Pre-release Apr 30, 2025
1.x-dev Dev Apr 21, 2025