WordPress is a web application like many others. It means that we can use standard approaches to work with media files:
we can send files using the POST method, receive them from the $_FILES array, store them anywhere and so on.
But let’s see what WordPress offers us.
Media library
The Media Library in WordPress is a central hub for managing all media files (images, videos, audio files, documents) that have been uploaded to the website. It provides a convenient interface where users can upload, view, edit, and organize their media content.
Key Features of the WordPress Media Library:
- We can upload files directly from the computer by dragging and dropping them into the media library or by selecting files from your device.
- Media files are stored in a directory structure based on the date they were uploaded (e.g.,
wp-content/uploads/yyyy/mm/). - The library allows us to view all the media in either a grid or list format.
- We can click on individual media files to view their details, edit file information (such as title, alt text, and description), and make basic modifications like cropping, resizing, or rotating images.
- We can easily insert images, videos, and other media files into posts or pages using the “Add Media” button in the post editor.
- When inserting media, we can select from various image sizes (thumbnail, medium, large, full size) based on what’s been automatically generated during the upload process.
Attachment Post Type
Each media file uploaded to the Media Library is stored as an attachment post type in the WordPress database, and it is treated similarly to a post with its own metadata and attributes.
Attachments are stored as posts in the wp_posts table, with the post_type set to attachment.
Each attachment post stores essential metadata about the file, such as file path, file type, date uploaded, and author.
Relationship to Parent Post
- Attachments can be associated with other post types like posts or pages. For example, when you upload an image directly while editing a post, that image attachment is “attached” to that post.
- You can view this relationship in the Media Library by seeing which post or page the attachment is associated with.
Image Sizes
When you upload an image to the Media Library, WordPress creates several sizes for this image (thumbnail, medium, large, full-size). Information about these files is stored as metadata associated with the attachment post and can be accessed and used throughout the website.
Attachments and Custom Fields
Just like regular posts, attachments can have custom fields. This makes it possible to extend the data stored for an attachment, adding fields like copyright information, author credits, or any other custom metadata relevant to your needs.
Attachment API
Developers can programmatically interact with attachments using WordPress functions:
wp_get_attachment_image_src( $attachment_id, 'full' ): gets an image source. Note that it open_in_new returns an array .wp_get_attachment_image( $attachment_id, 'thumbnail' ): gets an HTML img element representing an image attachment.wp_get_attachment_url( $attachment_id ): get a file URL. It works with any file, not only images.
Featured images
Featured images are typically used as the main image for a post or page and help visually communicate the theme or subject of the content. They are widely used in themes, especially in blog layouts, to give users a visual cue about the content before they read it.
In the WordPress block editor (Gutenberg), there is a Featured Image section in the sidebar where you can upload or choose an existing image from the media library.
Once a featured image is set, it will be associated with that specific post or page.
The feature was introduced in version 2.9 under the name Post Thumbnails and renamed to Featured Images in 3.0, which is why both names still appear in the API and in the documentation.
Theme Support
Not all WordPress themes support featured images out of the box, but most modern themes do. If a theme supports featured images, the feature will be enabled by default.
Developers can add support for featured images in their custom themes by adding this line of code in the functions.php file:
add_theme_support('post-thumbnails');
The second argument limits the support to particular post types:
add_theme_support( 'post-thumbnails', [ 'page' ] ); // only for pages
add_theme_support( 'post-thumbnails', [ 'client' ] ); // only for a custom post type
Once enabled, developers can display featured images in templates using the_post_thumbnail(). Example:
<?php if ( has_post_thumbnail() ) : ?>
<div class="post-thumbnail">
<?php the_post_thumbnail('large'); // or 'thumbnail', 'medium', 'full' ?>
</div>
<?php endif; ?>
the_post_thumbnail() prints the image; get_the_post_thumbnail() returns it instead, which is what you
need when the markup has to be modified or stored:
the_post_thumbnail( 'medium' ); // size is the 1st parameter
get_the_post_thumbnail( null, 'success-story-thumb' ); // ...and the 2nd one here
The output is a complete img tag:
<img width="304" height="167" src=".../image.png" class="attachment-post-thumbnail wp-post-image" alt="" />
Registering custom sizes
The default image sizes of WordPress are:
| Name | Size |
|---|---|
thumbnail (and its alias thumb) |
150px × 150px |
medium |
300px × 300px |
medium_large |
768px × 0px |
large |
1024px × 1024px |
full |
the original file |
These sizes can be configured in the administration area under Settings → Media.
A theme can register sizes of its own with add_image_size():
add_image_size( $name, $width, $height, $crop );
add_action( 'after_setup_theme', 'set_thumbnail_sizes' );
function set_thumbnail_sizes() {
add_image_size( 'category-thumb', 300 ); // 300 pixels wide (and unlimited height)
add_image_size( 'homepage-thumb', 220, 180, true ); // cropped
}
There is one more standard size, called post-thumbnail, which exists specifically to be set
programmatically. If it is defined, it becomes the default size used by the_post_thumbnail():
set_post_thumbnail_size( $width, $height, $crop );
Removing the width and height attributes
The hardcoded dimensions in the generated tag get in the way of responsive layouts. They can be stripped with a filter:
add_filter( 'post_thumbnail_html', 'remove_thumbnail_dimensions' );
function remove_thumbnail_dimensions( $html, $post_id, $post_image_id ) {
$html = preg_replace( '/(width|height)=\"\d*\"\s/', "", $html );
return $html;
}
If a post type needs a second image next to the featured one, see the custom featured image box in the meta boxes article.
wp_upload_bits()
The wp_upload_bits function in WordPress is used to handle the uploading of files to the WordPress media library.
Note that wp_upload_bits() is useful when you already have the file content and want to upload it directly without relying on a form submission.
// You can use only file name (not path). The function will make it unique.
$upload = wp_upload_bits($file_name, null, $file_content);
This function only uploads the file and returns the file info. Nothing is stored in the DB.
Returns array:
[
'file' => '/var/www/wp-content/uploads/2010/03/example.pdf',
'url' => 'http://example.com/wp-content/uploads/2010/03/example.pdf',
'type' => 'application/pdf',
'error' => false,
]
media_handle_upload()
Saves a file submitted from a POST request and create an attachment post for it.
This function uses the below functions:
wp_handle_upload().wp_insert_attachment().wp_update_attachment_metadata().
wp_insert_attachment()
Creates a post type (attachment) record based on the passing parameters. This functions is like wp_insert_post().
// Insert the attachment.
$attach_id = wp_insert_attachment( $attachment, $filename, $parent_post_id );
No files are added. It’s just created a record in the DB.
First parameter should contain the necessary fields:
[
'guid' => $file_path, // We can pass the file path.
'post_mime_type' => $filetype['type'],
'post_title' => 'My picture',
'post_content' => '', // We pass an empty string.
'post_status' => 'inherit'
]
Usually after this function we call wp_generate_attachment_metadata() to generates attachment meta data and create image sub-sizes for images.
$attachment_data = wp_generate_attachment_metadata( $attachment_id, $uploaded_file_data[ 'file' ] );
wp_update_attachment_metadata( $attachment_id, $attachment_data );
wp_handle_upload()
This function is used by WordPress core and is not intended for use by plugin or theme developers.
Helpers
wp_upload_dir() - returns an array containing the current upload directory’s path and URL.
$upload_dir = wp_upload_dir();
$upload_path = $upload_dir['path'];
wp_unique_filename() - gets a filename that is sanitized and unique for the given directory.
If the filename is not unique, then a number will be added to the filename before the extension, and will continue adding numbers until the filename is unique.
$file_name = wp_unique_filename($upload_path, 'file.txt');
wp_check_filetype() - retrieves the file type from the file name.
$filetype = wp_check_filetype('image.jpg');
echo $filetype['ext']; // will output "jpg"
echo $filetype['type']; // will output "image/jpeg"
My function for uploading images
/**
* Upload an image.
*
* @param $image_url
* @param $name
* @param $parent_post_id
* @return bool
*/
public static function upload_image( $image_url, $name, $parent_post_id )
{
$file_info = wp_check_filetype( $image_url );
$file_extension = $file_info[ 'ext' ];
$file_mime_type = $file_info[ 'type' ];
if ( ! $file_extension || ! $file_mime_type ) {
$file_headers = get_headers( $image_url, true );
if ( ! $file_headers ) {
return false;
}
if ( ! isset( $file_headers[ 'Content-Type' ] ) ) {
return false;
}
$file_mime_type = $file_headers[ 'Content-Type' ];
$file_extension = wp_get_default_extension_for_mime_type( $file_mime_type );
if ( ! $file_mime_type || ! $file_extension ) {
return false;
}
}
$file_name = uniqid() . '.' . $file_extension;
$image_data = file_get_contents( $image_url );
if ( ! $image_data ) {
return false;
}
$uploaded_file_data = wp_upload_bits( $file_name, null, $image_data );
if ( $uploaded_file_data[ 'error' ] ) {
return false;
}
$attachment_id = wp_insert_attachment( [
'guid' => $uploaded_file_data[ 'file' ],
'post_mime_type' => $file_mime_type,
'post_title' => $name,
'post_content' => '', // We pass an empty string.
'post_status' => 'inherit'
], $uploaded_file_data[ 'file' ], $parent_post_id );
$attachment_data = wp_generate_attachment_metadata( $attachment_id, $uploaded_file_data[ 'file' ] );
wp_update_attachment_metadata( $attachment_id, $attachment_data );
return true;
}
Andrew Dorokhov