How to make existing public files private? Let's say I have a node type "Article" which has a field "File" which is set to handle public files. A lot of articles and files get added.

Now the specs suddenly change and the "Article" will move behind a login and therefore also the attached files must be changed to be not publicly accessible anymore.

I already found out how to change the file system for the file field from public to private pretty easily by reimporting the manually updated field.storage.node.field_file.yml config. But: this only affects new files that will be added after the switch. It doesn't work for existing files. They still are accessible publicly. Many thousand existing files would need to be manually reuploaded to also make them private.

Does anybody of you have solved that in D8 before? If so, then how?

As all I can think of right now is to programmatically query all "Article" nodes, then foreach through all nodes, get the files, temporarily store them somewhere else, empty the field out, then try to reupload the files programmatically (probably my next question) and then resave each node.

Does that sound reasonable? Or can you think of any other approach that might work here (in D8)?
Thanks a lot for the answers! FileField Paths definitely is the way to go.


Update the file field's field storage to handle private files.
Run FileField Paths' Retroactive update on your content type's file field.




Step 1. can be accomplished from within hook_update_N (if you use configuration management do that locally and then export the updated configuration and deploy the resulting *.yml):

$field_type = 'file';
$field_name = 'field_file';

if (!$field_storage_configs = \Drupal::entityManager()
  -&gt;getStorage('field_storage_config')
  -&gt;loadByProperties(['type' =&gt; $field_type])) {
  return;
}

foreach ($field_storage_configs as $field_storage) {
  // Note: These settings apply to the field_file field everywhere it is
  // used.
  if ($field_storage-&gt;getName() == $field_name) {
    $field_storage-&gt;setSetting('uri_scheme', 'private');
    $field_storage-&gt;enforceIsNew(FALSE);
    $field_storage-&gt;save();
  }
}


Alternatively, follow the manual config update and reimport as suggested in the question.



Step 2. is to go to your file field's edit screen and fire the Retroactive update upon saving the form: