How to wp_upload_bits() to a sub-folder?

wp_upload_bits() uses wp_upload_dir() which fires the upload_dir filter allowing you to modify the upload directory’s path, sub-directory and URL.

So you can use that filter to “force” wp_upload_bits() to use a custom path by doing something like:

// Demo to get the image data.
$url="https://logo.clearbit.com/starcomww.com";
$content = file_get_contents( $url );

$_filter = true; // For the anonymous filter callback below.
add_filter( 'upload_dir', function( $arr ) use( &$_filter ){
    if ( $_filter ) {
        $folder="/org_logos"; // No trailing slash at the end.
        $arr['path'] .= $folder;
        $arr['url'] .= $folder;
        $arr['subdir'] .= $folder;
    }

    return $arr;
} );

$filename = wp_basename( $url ) . '.png';
$ret = wp_upload_bits( $filename, null, $content );
var_dump( $ret ); // For testing.

$_filter = false; // Disables the filter.

Or you can use a named callback:

function my_org_logos_upload_dir( $arr ) {
    $folder="/org_logos"; // No trailing slash at the end.

    $arr['path'] .= $folder;
    $arr['url'] .= $folder;
    $arr['subdir'] .= $folder;

    return $arr;
}

// Demo to get the image data.
$url="https://logo.clearbit.com/starcomww.com";
$content = file_get_contents( $url );

add_filter( 'upload_dir', 'my_org_logos_upload_dir' );

$filename = wp_basename( $url ) . '.png';
$ret = wp_upload_bits( $filename, null, $content );
var_dump( $ret ); // For testing.

remove_filter( 'upload_dir', 'my_org_logos_upload_dir' );

UPDATE

(In reply to your comments)

So, as a filter on wp_upload_dir(), that would apply to any file
getting uploaded via wp_upload_dir(), is that right?

Yes, it would.

But the issue can be prevented by adding/enabling the filter only when you call wp_upload_bits() and that you want it to use your custom upload path, and then remove/disable the filter after it’s applied — to prevent the upload path from being changed when wp_upload_dir() is called from other functions or code.

And for that reason, these are my approaches as you have seen in the original answer:

// First variant of the code - using an anonymous function.
$_filter = true;  // enables the filter
$_filter = false; // disables the filter

// Second variant of the code - using a named function.
remove_filter( 'upload_dir', 'my_org_logos_upload_dir' ); // enables the filter
add_filter( 'upload_dir', 'my_org_logos_upload_dir' );    // disables the filter

should the second property of wp_insert_attachment() be $filename,
$content or some property of $ret[here]?

The second parameter of the wp_insert_attachment() function is the full absolute path to the file that’s to be attached to the post.

And on success, wp_upload_bits() returns an array with file being one of the keys, where the value is the full absolute path of the file that was saved by wp_upload_bits(). (You can check the function’s reference or this note for the other keys.)

So the answer is $ret['file']:

wp_insert_attachment( array(...), $ret['file'] );

Leave a Comment