Custom Meta Boxes and Fields for WordPress: Change directory upload based on user-edit page

I figured it out myself so I will post the answer here, please note that the original answer can also be found on StackOverflow. If the mods feel like this should be deleted from here and only remain, please go ahead. I thought it might be useful on both places.

First the correct code, then an explaination:

// Here we add a new user role, "cliente".
add_role( 'cliente', 'Cliente' );

// These are the filters we need to add in order to modify the default upload path.
add_filter('wp_handle_upload_prefilter', 'my_upload_prefilter');
add_filter('wp_handle_upload', 'my_upload_postfilter');

function my_upload_prefilter( $file ) {
    add_filter('upload_dir', 'custom_upload_dir');
    return $file;
}
function my_upload_postfilter( $fileinfo ) {
    remove_filter('upload_dir', 'custom_upload_dir');
    return $fileinfo;
}

function custom_upload_dir( $path ) {
    // When uploading, the file gets sent to upload_async.php, so we need to take the referral page in order to be able to get the user_id we need. We then take the query string, pass it through parse_str and store it in a $query_array. Took me a while to figure it out, but now it works like a charm.
    $actual_page = $_SERVER['HTTP_REFERER'];
    parse_str( parse_url($actual_page, PHP_URL_QUERY), $query_array );

    // Check if we are uploading from the user-edit.php page.
    if ( strpos($actual_page, 'user-edit.php') ) {
        // Set the role we want to change the path for.
        $role_to_check = 'cliente';
        // Get a bunch of user info for later use
        $user_id = filter_var( $query_array['user_id'], FILTER_SANITIZE_NUMBER_INT );
        $meta = get_user_meta( $user_id );
        $roles = unserialize( $meta['wp_capabilities'][0] );
        // If we are on the chosen role page, set the $customdir to first_name + last_name
        if ( !empty($roles[$role_to_check]) ) {
            $customdir="/docs/" . $meta['first_name'][0] . $meta['last_name'][0];

            // If there is any error, just return the $path and abort the rest.
            if ( !empty( $path['error'] ) ) {
                return $path;
            }

            // Here we set the new $path with the $customdir set above
            $new_subdir = $customdir . $path['subdir'];
            $path['path']    = str_replace( $path['subdir'], $new_subdir, $path['path'] );
            $path['url']     = str_replace( $path['subdir'], $new_subdir, $path['url'] );
            $path['subdir']  = $new_subdir;
            return $path;
        }
    } else {
        // We are not uploading from user-edit.php, so go ahead as per default.
        return $path;
    }
}

The problem was that when uploading via Ajax, $pagenow correctly stores the async-upload.php page, rather than the url we’re in. I simply had to retrieve the referral page via php $_SERVER['HTTP_REFERER'] (please, note that the referer typo is there because of a legacy typo in the http spec, funny stuff).

Please also note that the PHP specs discourage the use of HTTP_REFERER because it could yield unexpected results based on server configurations, but in this case I should have full control over the server, so it should not be a problem. If you encounter any issue, I would suggest to check that out.

Once I have the correct url I am able to parse it and check if we are on user-edit.php, if we are, get the user_id from the query string and proceed from there.

Took me a while to figure it out, but in hindsight it was quite easy.

Hope it helps somebody else in the future.