wp_upload_dir( string|null $time = null, bool $create_dir = true, bool $refresh_cache = false ): array

Returns an array containing the current upload directory’s path and URL.

Description

Checks the ‘upload_path’ option, which should be from the web root folder, and if it isn’t empty it will be used. If it is empty, then the path will be ‘WP_CONTENT_DIR/uploads’. If the ‘UPLOADS’ constant is defined, then it will override the ‘upload_path’ option and ‘WP_CONTENT_DIR/uploads’ path.

The upload URL path is set either by the ‘upload_url_path’ option or by using the ‘WP_CONTENT_URL’ constant and appending ‘/uploads’ to the path.

If the ‘uploads_use_yearmonth_folders’ is set to true (checkbox if checked in the administration settings panel), then the time will be used. The format will be year first and then month.

If the path couldn’t be created, then an error will be returned with the key ‘error’ containing the error message. The error suggests that the parent directory is not writable by the server.

Parameters

$timestring|nulloptional
Time formatted in 'yyyy/mm'.

Default:null

$create_dirbooloptional
Whether to check and create the uploads directory.
Default true for backward compatibility.

Default:true

$refresh_cachebooloptional
Whether to refresh the cache.

Default:false

Return

array Array of information about the upload directory.
  • path string
    Base directory and subdirectory or full path to upload directory.
  • url string
    Base URL and subdirectory or absolute URL to upload directory.
  • subdir string
    Subdirectory if uploads use year/month folders option is on.
  • basedir string
    Path without subdir.
  • baseurl string
    URL path without subdir.
  • error string|false
    False or error message.

More Information

Note that using this function will create a subfolder in your Uploads folder corresponding to the queried month (or current month, if no $time argument is provided), if that folder is not already there. You don’t have to upload anything in order for this folder to be created.

For creating custom folder for users

$current_user = wp_get_current_user();
$upload_dir   = wp_upload_dir();

if ( isset( $current_user->user_login ) && ! empty( $upload_dir['basedir'] ) ) {
$user_dirname = $upload_dir['basedir'].'/'.$current_user->user_login;
if ( ! file_exists( $user_dirname ) ) {
wp_mkdir_p( $user_dirname );
}
}

Folder Name

In case you want to move the /uploads folder, you’ll have to use the UPLOADS constant. It normally shouldn’t get used, as it only get’s defined when ms_default_constants() is run (only multisite), but you can simply set:

define( 'UPLOADS', trailingslashit( WP_CONTENT_DIR ) . 'custom_uploads_name' );

in a single site install and it will just work, as the public directory structure function wp_upload_dir() sets it up, when it was defined:

$dir = ABSPATH . UPLOADS;

Note: You can extract the folder name with the following line:

// returns `false` if the UPLOADS constant is not defined
$upload_dir_name = false;
if ( defined( 'UPLOADS' ) ) {
str_replace( trailingslashit( WP_CONTENT_DIR ), '', untrailingslashit( UPLOADS ) );
}

Source

function wp_upload_dir( $time = null, $create_dir = true, $refresh_cache = false ) {
	static $cache = array(), $tested_paths = array();

	$key = sprintf( '%d-%s', get_current_blog_id(), (string) $time );

	if ( $refresh_cache || empty( $cache[ $key ] ) ) {
		$cache[ $key ] = _wp_upload_dir( $time );
	}

	/**
	 * Filters the uploads directory data.
	 *
	 * @since 2.0.0
	 *
	 * @param array $uploads {
	 *     Array of information about the upload directory.
	 *
	 *     @type string       $path    Base directory and subdirectory or full path to upload directory.
	 *     @type string       $url     Base URL and subdirectory or absolute URL to upload directory.
	 *     @type string       $subdir  Subdirectory if uploads use year/month folders option is on.
	 *     @type string       $basedir Path without subdir.
	 *     @type string       $baseurl URL path without subdir.
	 *     @type string|false $error   False or error message.
	 * }
	 */
	$uploads = apply_filters( 'upload_dir', $cache[ $key ] );

	if ( $create_dir ) {
		$path = $uploads['path'];

		if ( array_key_exists( $path, $tested_paths ) ) {
			$uploads['error'] = $tested_paths[ $path ];
		} else {
			if ( ! wp_mkdir_p( $path ) ) {
				if ( str_starts_with( $uploads['basedir'], ABSPATH ) ) {
					$error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir'];
				} else {
					$error_path = wp_basename( $uploads['basedir'] ) . $uploads['subdir'];
				}

				$uploads['error'] = sprintf(
					/* translators: %s: Directory path. */
					__( 'Unable to create directory %s. Is its parent directory writable by the server?' ),
					esc_html( $error_path )
				);
			}

			$tested_paths[ $path ] = $uploads['error'];
		}
	}

	return $uploads;
}

Hooks

apply_filters( ‘upload_dir’, array $uploads )

Filters the uploads directory data.

Changelog

VersionDescription
2.0.0Introduced.

User Contributed Notes

  1. Skip to note 9 content

    More in-depth break down of the data returned.

    <?php
    $upload_dir = wp_upload_dir(); // Array of key => value pairs
    /*
        $upload_dir now contains something like the following (if successful)
        Array (
            [path] => C:\path\to\wordpress\wp-content\uploads\2010\05
            [url] => http://example.com/wp-content/uploads/2010/05
            [subdir] => /2010/05
            [basedir] => C:\path\to\wordpress\wp-content\uploads
            [baseurl] => http://example.com/wp-content/uploads
            [error] =>
        )
        // Descriptions
        [path] - base directory and sub directory or full path to upload directory.
        [url] - base url and sub directory or absolute URL to upload directory.
        [subdir] - sub directory if uploads use year/month folders option is on.
        [basedir] - path without subdir.
        [baseurl] - URL path without subdir.
        [error] - set to false.
    */
    
    echo $upload_dir['path'] . '<br />';
    echo $upload_dir['url'] . '<br />';
    echo $upload_dir['subdir'] . '<br />';
    echo $upload_dir['basedir'] . '<br />';
    echo $upload_dir['baseurl'] . '<br />';
    echo $upload_dir['error'] . '<br />';
    
    $upload_url = ( $upload_dir['url'] );
    $upload_url_alt = ( $upload_dir['baseurl'] . $upload_dir['subdir'] );
    
    // Now echo the final result
    echo $upload_url . '<br />'; // Output - http://example.com/wp-content/uploads/2010/05
    
    // Using year and month based folders, the below will be the same as the line above.
    echo $upload_url_alt . '<br />'; // Output - http://example.com/wp-content/uploads/2010/05
    ?>
  2. Skip to note 10 content

    Strangely wp_upload_dir doesn’t return https for SSL websites. Hopefully they fix the issue soon. Here is the code below where you can get the upload dir and url in right way:

    /**
     * Get the upload URL/path in right way (works with SSL).
     *
     * @param $param string "basedir" or "baseurl"
     * @return string
     */
    function fn_get_upload_dir_var( $param, $subfolder = '' ) {
    	$upload_dir = wp_upload_dir();
    	$url = $upload_dir[ $param ];
    
    	if ( $param === 'baseurl' && is_ssl() ) {
    		$url = str_replace( 'http://', 'https://', $url );
    	}
    
    	return $url . $subfolder;
    }

    Example:

    // Get wp-content/uploads/myfolder by URL
    fn_get_upload_dir_var( 'baseurl', 'myfolder' );
    
    // Now get full path of the same folder
    fn_get_upload_dir_var( 'basedir', 'myfolder' );
  3. Skip to note 12 content

    I needed to NOT rely on Gravatar at all, and just use the buddypress profile avatar. Here is the result.

    $avatar_url = bp_core_fetch_avatar(array('item_id'=>$user->ID,'html'=>false));        
    if (strpos($avatar_url, 'www.gravatar.com/avatar') !== false) {
    	$upload_dir = wp_upload_dir();
        $avatar_url = $upload_dir['baseurl'] . '/avatars/pi-gravatar.jpg';
    }
  4. Skip to note 14 content

    If you want to create a directory in wp-contents/uploads folder at the time of WordPress PlugIn activation, here is the code:

    function yourprojectname_activate() {
     
        $upload = wp_upload_dir();
        $upload_dir = $upload['basedir'];
        $upload_dir = $upload_dir . '/your-project-name';
        if (! is_dir($upload_dir)) {
           mkdir( $upload_dir, 0700 );
        }
    }
  5. Skip to note 15 content

    In case this helps anyone, on a multisite instance, the site and site number are appended to the end of the paths.

    $upload_dir = wp_upload_dir();
    
    // Single Site
    $upload_dir['baseurl']; // http://example.com/wp-content/uploads
    
    // Multisite
    $upload_dir['baseurl']; // http://example.com/wp-content/uploads/sites/site_no
    // Where site_no = Site ID

    It’s important to note that the [‘subdir’] key still returns the year/month structure, but all other related paths add the above directories in a Multisite environment.

  6. Skip to note 16 content

    In case helps anyone want to make define constants, moving and rename the multisite UPLOADS file.

    //If planned rename UPLOADS file from wp-content/uploads to wp-content/pics
    //If NOT PLANNED force all uploads shared in one folder
    //Add define constants define ('UPLOADS', WP_CONTENT_DIR . '/' . 'pics'); in .htaccess
    //Sub-directories (like year/month) will still exist (if the network setting is enabled)
    //Register a filter for "upload_dir"
    
    add_filter( 'upload_dir', 'ms_upload_dir' );
    
    function ms_upload_dir( $dirs ) {
        $dirs['baseurl'] = network_site_url( '/wp-content/pics') . '/sites/'.get_current_blog_id();
        $dirs['basedir'] = ABSPATH . 'wp-content/pics' . '/sites/'.get_current_blog_id();
        $dirs['path'] = $dirs['basedir'] . $dirs['subdir'];
        $dirs['url'] = $dirs['baseurl'] . $dirs['subdir'];
    
        return $dirs;
    }
    
    //If planned rename UPLOADS file from wp-content/uploads to wp-content/pics
    //If PLANNED force all uploads shared in one folder
    //Add define constants define ('UPLOADS', WP_CONTENT_DIR . '/' . 'pics'); in .htaccess
    //Sub-directories (like year/month) will still exist (if the network setting is enabled)
    //Register a filter for "upload_dir"
    
    add_filter( 'upload_dir', 'ms_upload_dir' );
    
    function ms_upload_dir( $dirs ) {
        $dirs['baseurl'] = network_site_url( '/wp-content/pics');
        $dirs['basedir'] = ABSPATH . 'wp-content/pics';
        $dirs['path'] = $dirs['basedir'] . $dirs['subdir'];
        $dirs['url'] = $dirs['baseurl'] . $dirs['subdir'];
    
        return $dirs;
    }
    
    //If planned moving (and rename) UPLOADS file out from wp-content
    //If NOT PLANNED force all uploads shared in one folder
    //Add define constants define ('UPLOADS', 'pics'); in .htaccess
    //Sub-directories (like year/month) will still exist (if the network setting is enabled)
    //Register a filter for "upload_dir"
    
    add_filter( 'upload_dir', 'ms_upload_dir' );
    
    function ms_upload_dir( $dirs ) {
        $dirs['baseurl'] = network_site_url( '/pics') . '/sites/'.get_current_blog_id();
        $dirs['basedir'] = ABSPATH . 'pics' . '/sites/'.get_current_blog_id();
        $dirs['path'] = $dirs['basedir'] . $dirs['subdir'];
        $dirs['url'] = $dirs['baseurl'] . $dirs['subdir'];
    
        return $dirs;
    }
    
    //If planned moving (and rename) UPLOADS file out from wp-content
    //If PLANNED force all uploads shared in one folder
    //Add define constants define ('UPLOADS', 'pics'); in .htaccess
    //Sub-directories (like year/month) will still exist (if the network setting is enabled)
    //Register a filter for "upload_dir"
    
    add_filter( 'upload_dir', 'ms_upload_dir' );
    
    function ms_upload_dir( $dirs ) {
        $dirs['baseurl'] = network_site_url( '/pics');
        $dirs['basedir'] = ABSPATH . 'pics';
        $dirs['path'] = $dirs['basedir'] . $dirs['subdir'];
        $dirs['url'] = $dirs['baseurl'] . $dirs['subdir'];
    
        return $dirs;
    }

You must log in before being able to contribute a note or feedback.