Hey, I finally made a mixed setup.
I used Custom Upload Dir plugin, it hasn't been updated since 3 years, but it seems that the author is still giving support and it has more then 8.000 active installs. It is a quite simple plugin that uses standard WP functions, so it is not a buggy plugin.
I used it to force the uploads to a specific directory for each user. It gives the option to build a custom path like /uploads/username/, but I wasn't satisfied with it, so I customized a little the plugin. I added a couple of functions to build a path like this: /uploads/user_role/user_id/.
This way I could set different security logic for different roles (for example I wanted administrator files completely public and subscriber files private), then I preferred user_id, so the username of my users is not shared on a public URL.
The second step is based on this code suggestions:
https://wordpress.stackexchange.com/questions/37144/how-to-protect-uploads-if-user-is-not-logged-in
hidden link
To make all subscribers files private I've added this to main .htaccess:
# block directory
<IfModule mod_rewrite.c>
RewriteBase /
RewriteCond %{REQUEST_FILENAME} -s
RewriteRule ^wp-content/uploads/(subscriber/.*)$ dl-file.php?file=$1 [QSA,L]
</IfModule>
And then I added a dl-file.php on the same root directory with this code:
<?php
// Protect uploaded files with login.
require_once('wp-load.php');
require_once ABSPATH . WPINC . '/formatting.php';
require_once ABSPATH . WPINC . '/capabilities.php';
require_once ABSPATH . WPINC . '/user.php';
require_once ABSPATH . WPINC . '/meta.php';
require_once ABSPATH . WPINC . '/post.php';
require_once ABSPATH . WPINC . '/pluggable.php';
wp_cookie_constants();
ob_end_clean();
ob_end_flush();
if ( is_user_logged_in() ) {
list($basedir) = array_values(array_intersect_key(wp_upload_dir(), array('basedir' => 1)))+array(NULL);
$file = rtrim($basedir,'/').'/'.str_replace('..', '', isset($_GET[ 'file' ])?$_GET[ 'file' ]:'');
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"" . basename($file) . "\"");
readfile($file);
}
else {
wp_redirect( home_url(), 301 );
exit;
}
Now if an administrator publish any media file on backend or frontend they are public.
If a subscriber uploads files by a Toolset Form on the frontend it is not public and only the subscriber owner can view it using the direct URL.
I also restricted access to guests to media attachments CPTs with Toolset Access.
I finally added WPFront User Role Editor that can easily redirect wp-admin login form to a specific URL and hide admin bar for the selected role.