Okay, I had a bit of time to test this today on one of my test sites. And this is what worked.
I created a directory in my /wp-content/uploads/ directory named /private/
And I created an .xls file named test.xls and uploaded it to that /private/ directory.
I also create an .htaccess file with the following contents:
# BEGIN file lock-downs
<ifModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} .+\.xls [NC]
RewriteCond %{HTTP_COOKIE} !wordpress_logged_in_
RewriteRule ^ - [F]
</ifModule>
# END file lock-downs
And I also placed it in the /private/ directory along with the test.xls file.
Since I was already logged into this WordPress site, I went directly to the test.xls file in that directory:
https://example.com/wp-content/uploads/private/test.xls
And it let me download the file.
I then opened up a new private window (incognito in Google Chrome – or you could just try to open it up in a new browser where you haven’t logged into the site). And tried again, but this time it presented me with a 403 Forbidden page. So the above worked as expected on my test site.
If that presents a problem with your site, it’s possible there is an issue/conflict somewhere else. So you might try removing the ifModules as they are just there for portability. The ifModules just tell the server if that module is not activated or doesn’t exist, please die silently.
# BEGIN file lock-downs
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} .+\.xls [NC]
RewriteCond %{HTTP_COOKIE} !wordpress_logged_in_
RewriteRule ^ - [F]
# END file lock-downs
Also, please remember this separate .htaccess file needs to go in the directory with the files that you are trying to restrict access to.
If your server allows using .htaccess files in directories further from the root, they should override what’s in the root .htaccess file.
Also, I need to mention, you don’t want to do it like this:
RewriteCond %{SCRIPT_FILENAME} /wp-content/uploads/Private/.+\.xls [NC]
RewriteCond %{REQUEST_FILENAME} /wp-content/uploads/Private/.+\.xls [NC]
As that says, this condition AND this condition must be met. You only want to try one or the other condition for this operation and for what you are trying to achieve. I just wasn’t sure which condition might work better.
So your root .htaccess file would like like so:
# BEGIN WordPress
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress
# BEGIN file lock-downs
RewriteCond %{SCRIPT_FILENAME} /wp-content/uploads/Private/.+\.xls [NC]
RewriteCond %{HTTP_COOKIE} !wordpress_logged_in_
RewriteRule ^ - [F]
# END file lock-downs
And I placed that in my site for my root .htaccess file and it worked as well. Please note, when trying to access the file directly in your browser, it makes a difference if the ‘p’ in /Private/ is lower case or upper case, so please make sure it’s how you have it set up when placing the URL in a browser. (I always just make sure that all letters in my directory names are always lower case so that I don’t have to worry about that.)