Although this is related to Advanced Custom Fields, this function uses all native WP features, so I think this is appropriate to ask here. Where is the extra "/uploads/" in path is coming from here?

In the back-end, I see correct links to uploaded files (domain.com/wp-content/member-files/name.pdf), but on the front-end, the URLs display with an extra "/uploads/" in path (domain.com/wp-content/uploads/member-files/name.pdf), and of course produces a 404 for the file.

// file upload to custom location

add_filter( 'acf/upload_prefilter/name=protected_files',
'protected_upload_prefilter' );
add_filter( 'acf/prepare_field/name=protected_files', 
'protected_files_field_display' );
function protected_upload_prefilter( $errors ) {

add_filter( 'upload_dir', 'protected_upload_directory' );

return $errors;


function protected_upload_directory( $param ) {

  $folder = '/member-files';

  $param['path'] = WP_CONTENT_DIR . $folder;
  $param['url'] = WP_CONTENT_URL . $folder;
  $param['subdir'] = $folder;
  $param['basedir'] = WP_CONTENT_DIR;
  $param['baseurl'] = WP_CONTENT_URL;

  return $param;


// front-end display

function protected_files_field_display( $field ) {

  // update paths accordingly before displaying link to file
  add_filter( 'upload_dir', 'protected_upload_directory' );

  return $field;


Used with a repeater field, output file links like this:

       // check if the repeater field has rows of data
        if( have_rows('protected_uploads') ):

            // loop through the rows of data
            while ( have_rows('protected_uploads') ) : the_row(); 
            $file_url = get_sub_field('protected_files'); 

           <p><a href="<?php echo $file_url; ?>">
                <?php the_sub_field('date'); ?> Appendix</a>

* EDIT *

Removing this line has no effect on anything at all:

$param['subdir'] = $folder;

* EDIT 2 *

I've tried changing $param to WP_PLUGIN_DIR and WP_PLUGIN_URL. Again, that would show the correct URLs in the back-end (now changed to the /plugins/ directory instead of /uploads/), but curiously, on the front-end all file links point to domain.com/wp-content/uploads/file.pdf

Which confirms that it's set by the upload_dir bit in the second part. So, I've kind of narrowed it down. With what should it be replaced to get the actual upload directory? At this point I'd be ok with even hard-coding the location of the uploaded files.

  • How are you outputting the URL on the front-end? Jun 21, 2018 at 2:30
  • Edited original post to include the front-end output code
    – Phantasmix
    Jun 21, 2018 at 2:34
  • I've experimented with the function (um no solution yet though) and I think that's where the solution lies. Something up with the font-end part.
    – Phantasmix
    Jun 21, 2018 at 2:36

1 Answer 1


Resolved in a completely different way. Googled this, so technically not my own answer, but does the job:

// ACF upload prefilter
function gist_acf_upload_dir_prefilter($errors, $file, $field) {

    // This filter changes directory just for item being uploaded
    add_filter('upload_dir', 'gist_acf_upload_dir');

// ACF hook, set to field key of your file upload field
add_filter('acf/upload_prefilter/key=field_5b2b0326ea0e1', 'gist_acf_upload_dir_prefilter');

// Custom upload directory function, trigger by prefilter
function gist_acf_upload_dir($param) {

    // Set to whatever directory you want the ACF file field to upload to
    $custom_dir = '/uploads/member-files';
    $param['path'] = WP_CONTENT_DIR . $custom_dir;
    $param['url'] = WP_CONTENT_URL . $custom_dir;
    return $param;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.