Drupal is a registered trademark of Dries Buytaert
drupal 11.4.1 Update released for Drupal core (11.4.1)! drupal 11.4.0 Update released for Drupal core (11.4.0)! drupal 10.6.12 Update released for Drupal core (10.6.12)! drupal 11.3.13 Update released for Drupal core (11.3.13)! drupal 10.6.11 Update released for Drupal core (10.6.11)! drupal 11.3.12 Update released for Drupal core (11.3.12)! drupal 11.2.14 Update released for Drupal core (11.2.14)! drupal 10.5.12 Update released for Drupal core (10.5.12)! cms 2.1.3 Update released for Drupal core (2.1.3)! drupal 10.5.11 Update released for Drupal core (10.5.11)! drupal 11.3.11 Update released for Drupal core (11.3.11)! drupal 11.2.13 Update released for Drupal core (11.2.13)! drupal 10.6.10 Update released for Drupal core (10.6.10)! cms 2.1.2 Update released for Drupal core (2.1.2)! drupal 11.1.10 Update released for Drupal core (11.1.10)! drupal 10.5.10 Update released for Drupal core (10.5.10)! drupal 10.4.10 Update released for Drupal core (10.4.10)! drupal 11.2.12 Update released for Drupal core (11.2.12)! drupal 11.3.10 Update released for Drupal core (11.3.10)! drupal 10.6.9 Update released for Drupal core (10.6.9)!

form_file_usage

50 sites Security covered
View on drupal.org

Automatically manages file status (temporary / permanent) and tracking (file.usage) for custom forms built with the Drupal Form API.

The Problem

When you use managed_file or text_format (CKEditor) elements in custom forms (e.g., Configuration forms, Block plugins, Custom states), uploaded files and inline images are initially saved with a temporary status.

Unlike standard Entity fields, custom Form API elements do not automatically bind files to a storage context. As a result, Drupal core is unaware of their usage, and cron will eventually delete these files.

Developers usually have to write tedious boilerplate code in submitForm() using the file.usage service and manual HTML parsing for CKEditor UUIDs to fix this.

The Solution

The Form File Usage module completely automates this process using a State Synchronization approach. Instead of tracking historical form values, it directly cross-references current form inputs with active records in the database {file_usage} table.

It automatically promotes newly added files to permanent, registers their exact context usage, and safely cleans up references when they are removed.

Features

  • Zero Boilerplate: No need to write manual file tracking or config-comparison code in your submit handlers anymore.
  • State Synchronization: Idempotent logic that relies purely on database reality. It doesn't need to know where or how your form saves data (Config API, State API, or custom tables).
  • Advanced Garbage Collection: When a file is removed, the module unregisters its usage. If no other parts of the website are using that file, it automatically demotes it to temporary, allowing Drupal cron to safely free up server space.
  • CKEditor 5 Support: Parses text formats to extract inline image UUIDs (data-entity-uuid) and tracks them natively.
  • Automatic Config Detection: Automatically discovers configuration names for forms inheriting from ConfigFormBase.
  • Developer-Friendly API: Provides a highly streamlined service with a single public method to manually sync file usage inside complex structures like Block plugins, Commerce panes, or custom DB structures.

How to Use

1. In Configuration Forms (Automatic)

Simply add #track_file_usage => TRUE to your element. The module will automatically detect your configuration object name:

$form['promo_text'] = [
  '#type' => 'text_format',
  '#title' => $this->t('Promo text'),
  '#default_value' => $config->get('promo_text.value'),
  '#format' => $config->get('promo_text.format') ?? 'full_html',
  '#track_file_usage' => TRUE, // Active state tracking enabled!
];

2. Custom Forms / Complex Storage

If your form doesn't use ConfigFormBase (e.g., saves data into State API or custom tables), specify your storage ID explicitly:

$form['badge_image'] = [
  '#type' => 'managed_file',
  '#title' => $this->t('Badge Image'),
  '#default_value' => $config->get('badge_image'),
  '#file_usage_config' => 'my_module.custom_storage_key', // Explicit tracking context
];

3. Inside Plugins (Manual API)

For fields embedded inside Block plugins, Layout Builder, or custom entities where automatic form altering isn't ideal, invoke the synchronization service directly in your submission method.

Note: Always pass the value directly (even if it's empty) to let the manager clear out removed files properly.

// Inside your plugin's submit method (e.g., blockSubmit):
$text_value = $form_state->getValue(['my_text_element', 'value']) ?? '';

\Drupal::service('form_file_usage.manager')->syncUsage(
  $text_value,
  'text_format',
  'my_module',
  'block:' . $this->getDerivativeId() . ':my_text_element'
);

Activity

Total releases
3
First release
May 2026
Latest release
2 weeks ago
Release cadence
15 days
Stability
67% stable

Release Timeline

Releases

Version Type Release date
1.1.0 Stable Jun 19, 2026
1.0.0 Stable May 27, 2026
1.x-dev Dev May 20, 2026