For a plugin I am developing I need image uploads from a Custom Post Type to go to ./wp-content/uploads/clients instead of ./wp-content/uploads/{YYYY}/{MM}.

I managed to solve this with the following filter:

function client_photo_dir( $param ) {

    if ( isset( $_REQUEST['post_ID'] ) ) {
    $id = $_REQUEST['post_ID'];
    $parent_id = get_post( $id )->post_parent;

    if ( "client" == get_post_type( $id ) || "client" == get_post_type( $parent_id ) ) {
        $args['path'] = CLIENT__UPLOADSDIR;
        $args['url'] = CLIENT__UPLOADSURL;
        $args['basedir'] = CLIENT__UPLOADSDIR;
        $args['baseurl'] = CLIENT__UPLOADSURL;

return $args;
add_filter( 'upload_dir', 'client_photo_dir' );

Files are properly being uploaded to wp-content/plugins/client-plugin/uploads as I want them to and they are being added to the Media Library. The problem that has cropped up with this is that the Media Library will show a grey tile instead of a thumbnail of the image and when I click to look at the attachment itself, it shows nothing and the URL field is incorrect.

Instead of giving http://wpdev.localhost/wp-content/plugins/client-plugin/uploads/filename.ext it is just giving http://wpdev.localhost/wp-content/uploads/filename.ext so it can not obviously find it.

The code that handles the upload is:

if ( ! empty( $_FILES[$field_name]['name'] ) ) {
    require_once( ABSPATH . 'wp-admin/includes/file.php' );
    $override['action'] = 'editpost';

    $file_name = $_FILES[$field_name]['name'];
    $attachment_file = wp_handle_upload( $_FILES[$field_name], $override );
    $post_id = $post->ID;

    $attachment = array(
        'post_title'     => $file_name,
        'post_content'   => '',
        'post_type'      => 'attachment',
        'post_parent'    => $post_id,
        'post_mime_type' => $_FILES[$field_name]['type'],
        'guid'           => $attachment_file['url'],

    // Check if file is a JPEG or PNG and require wp-admin/includes/image.php
    if ( $_FILES[$field_name]['type'] == 'image/jpeg' || $_FILES[$field_name]['type'] == 'image/png' ) {
        require_once( ABSPATH . 'wp-admin/includes/image.php' );

        // Temporarily Disable All Defined Image Sizes & Change Upload Directory
        add_filter( 'upload_dir', 'client_photo_dir' );
        add_filter( 'intermediate_image_sizes_advanced', 'remove_image_sizes', 10, 2 );

    $id = wp_insert_attachment( $attachment, $attachment_file['file'], $post_id );
    wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $attachment_file['file'] ) );

    // Set metadata value to save to database
    $metadata = $attachment_file['url'];

    if ( $_FILES[$field_name]['type'] == 'image/jpeg' || $_FILES[$field_name]['type'] == 'image/png' ) {
        remove_filter( 'upload_dir', 'client_photo_dir' );
        remove_filter( 'intermediate_image_sizes_advanced', 'remove_image_sizes' );

I dumped a print_r() of both $attachment_file and $attachment to the error_log() and the ['file']/['url'] and['guid'] values are correctly set respectively.

How do I change that generated URL?

  • How are you doing the actual upload? Are these uploads supports to appear in the media library? – Jacob Peattie Mar 18 '18 at 4:36
  • And is this related to your previous question? It really sounds like you're doing the upload the wrong way if you want none of the normal media features. – Jacob Peattie Mar 18 '18 at 4:38
  • @JacobPeattie I updated the question with the part of the save method that checks for files and handles uploading them. It doesn't matter if they are added to the media library or not but I do want to keep them in a separate folder. As for the removal of image sizes, I did find the solution to that one with a simple filter that simply returns nothing for the predefined sized. – Cedon Mar 18 '18 at 11:45
  • You should read this: tommcfarlin.com/uploading-files-to-a-custom-directory – Jacob Peattie Mar 18 '18 at 11:52
  • @JacobPeattie - I actually found a solution that worked using a filter. It's actually very similar to what I originally had but I was able to move it out of the class' save() method and add it as a straight up filter for that's always in place based on the post_type. It did introduce a new problem though with the resulting attachment post though. – Cedon Mar 18 '18 at 14:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.