How Can I Organize the Uploads Folder by Slug (or ID, or FileType, or Author)?

I want to store all attachments (media) in folders named with each post title.

Example: /wp-content/uploads/my-post-about-stuff/

Read More

The folder should contain all media attached to that post.

Is that possible?

Related posts

Leave a Reply

3 comments

  1. Disclaimer

    • Tracking the way to do the same using the post_id
    • Having already answered one question about separating PDF’s from the rest
    • Found disperse questions about this matter
    • Decided to adopt this Q as the venue to publish this.

    Follow the instructions in the comments, and this code can be adapted to organize the uploads folder by post_name (aka: slug), post_author, post_id or media type.

    add_filter('wp_handle_upload_prefilter', 'wpse_25894_handle_upload_prefilter');
    add_filter('wp_handle_upload', 'wpse_25894_handle_upload');
    
    function wpse_25894_handle_upload_prefilter( $file )
    {
        add_filter('upload_dir', 'wpse_25894_custom_upload_dir');
        return $file;
    }
    
    function wpse_25894_handle_upload( $fileinfo )
    {
        remove_filter('upload_dir', 'wpse_25894_custom_upload_dir');
        return $fileinfo;
    }
    
    function wpse_25894_custom_upload_dir($path)
    {   
        /*
         * Determines if uploading from inside a post/page/cpt - if not, default Upload folder is used
         */
        $use_default_dir = ( isset($_REQUEST['post_id'] ) && $_REQUEST['post_id'] == 0 ) ? true : false; 
        if( !empty( $path['error'] ) || $use_default_dir )
            return $path; //error or uploading not from a post/page/cpt 
        
        /*
         * Save uploads in ID based folders 
         *
         */
        
        /*
         $customdir = '/' . $_REQUEST['post_id'];
        */
    
    
        /*
         * Save uploads in SLUG based folders 
         *
         */
        
         $the_post = get_post($_REQUEST['post_id']);
         $customdir = '/' . $the_post->post_name;
    
    
        /*
         * Save uploads in AUTHOR based folders 
         *
         * ATTENTION, CAUTION REQUIRED: 
         * This one may have security implications as you will be exposing the user names in the media paths
         * Here, the *display_name* is being used, but normally it is the same as *user_login*
         *
         * The right thing to do would be making the first/last name mandatories
         * And use:
         * $customdir = '/' . $the_author->first_name . $the_author->last_name;
         *
         */
        
        /* 
          $the_post = get_post($_REQUEST['post_id']);
          $the_author = get_user_by('id', $the_post->post_author);
          $customdir = '/' . $the_author->data->display_name;
        */
        
        
        /*
         * Save uploads in FILETYPE based folders 
         * when using this method, you may want to change the check for $use_default_dir
         *
         */
        
        /*
         $extension = substr( strrchr( $_POST['name'], '.' ), 1 );
         switch( $extension )
         {
            case 'jpg':
            case 'png':
            case 'gif':
                $customdir = '/images';
                break;
                
            case 'mp4':
            case 'm4v':
                $customdir = '/videos';
                break;
            
            case 'txt':
            case 'doc':
            case 'pdf':
                $customdir = '/documents';
                break;
         
            default:
                $customdir = '/others';
                break;
         }
        */
        
        $path['path']    = str_replace($path['subdir'], '', $path['path']); //remove default subdir (year/month)
        $path['url']     = str_replace($path['subdir'], '', $path['url']);      
        $path['subdir']  = $customdir;
        $path['path']   .= $customdir; 
        $path['url']    .= $customdir;  
    
        return $path;
    }
    
  2. For our internal webpage, we used the code from here and made it use the top level parent if the upload is from a page. Since it is internal, we didn’t care about the username being visible. This allowed us to break up the uploads by something close to departments.

    function wpse_25894_custom_upload_dir( $path ) {   
        /*
         * Determine if uploading from inside a page - if not, use the username
         */
        if ( ( strpos( $_SERVER['HTTP_REFERER'], 'wp-admin/upload' ) !== false ) || 
            ( strpos( $_SERVER['HTTP_REFERER'], 'wp-admin/media-new' ) !== false ) ) 
        {  
            $current_user = wp_get_current_user();    
            $customdir = '/' . $current_user->user_login;   
        } else {
            $post = get_post( $_REQUEST['post_id'] );    
            /* 
             * If there is a parent page, then get the hierarchy array, 
             * reverse it and use the first one to get the top level parent
             */
            if ( $post->post_parent ) {
                $parent = array_reverse( get_post_ancestors( $post->ID ) );
                $first_parent = get_page( $parent[0] );
                $customdir  = '/' . $first_parent->post_name;
            }
            /* 
             * Check if it is not a page (post or attachment page)
             * If it is, then use the username
             */
            elseif (strcmp ( 'page', $page->type ) == false ) {
                $current_user = wp_get_current_user();    
                $customdir = '/' . $current_user->user_login;
            }
            /*
             * Otherwise it is a top level parent page and just use the page name
             */
            else {
                $the_post = get_post( $_REQUEST['post_id'] );
                $customdir = '/' . $the_post->post_name;
            }
        }
        // Format the variables into a useable path
        $path['path']    = str_replace( $path['subdir'], '', $path['path'] ); // Remove default subdir (year/month)
        $path['url']     = str_replace( $path['subdir'], '', $path['url'] );      
        $path['subdir']  = $customdir;
        $path['path']   .= $customdir; 
        $path['url']    .= $customdir;  
        return $path;
    }