When WordPress processes an image upload it generates multiple thumbnail sizes and stores detailed metadata about each one in the wp_postmeta table under the key _wp_attachment_metadata. This metadata includes the original file’s dimensions, the relative file path, and an array of every generated sub-size with its file name, width, height, and whether it was cropped. wp_get_attachment_metadata() retrieves this array, giving plugins and themes access to everything WordPress knows about an image attachment — without hitting the filesystem. Common uses include: validating that an image meets minimum dimensions before it can be selected, listing all available image sizes for a given attachment, reading EXIF data stored in the metadata array, and programmatically updating metadata after an external image manipulation process.
Problem: A plugin needs to ensure that a product image selected in a meta box is at least 800×800 px before allowing the selection, and also needs to read whether a specific thumbnail size was successfully generated for that attachment.
Solution: Call wp_get_attachment_metadata() to retrieve the metadata array, read ['width'] and ['height'] for the original dimensions, and check ['sizes'] for generated thumbnail entries.
<?php
$attachment_id = 42; // ID of the attachment post
// ── Get full metadata array ───────────────────────────────────────────
$meta = wp_get_attachment_metadata( $attachment_id );
// $meta structure:
// [
// 'width' => 2000,
// 'height' => 2000,
// 'file' => '2021/04/product.jpg', // relative to uploads dir
// 'filesize' => 524288,
// 'sizes' => [
// 'thumbnail' => [ 'file' => 'product-150x150.jpg', 'width' => 150, 'height' => 150, 'mime-type' => 'image/jpeg' ],
// 'medium' => [ 'file' => 'product-300x300.jpg', 'width' => 300, 'height' => 300, 'mime-type' => 'image/jpeg' ],
// 'product-main' => [ 'file' => 'product-800x800.jpg', 'width' => 800, 'height' => 800, 'mime-type' => 'image/jpeg' ],
// ],
// 'image_meta' => [ 'aperture' => '2.8', 'camera' => 'Canon EOS R5', ... ],
// ]
// ── Validate minimum dimensions ────────────────────────────────────────
function attachment_meets_minimum_size( int $attachment_id, int $min_w, int $min_h ): bool {
$meta = wp_get_attachment_metadata( $attachment_id );
if ( ! is_array( $meta ) ) return false;
return ( $meta['width'] ?? 0 ) >= $min_w && ( $meta['height'] ?? 0 ) >= $min_h;
}
if ( ! attachment_meets_minimum_size( $attachment_id, 800, 800 ) ) {
wp_send_json_error( [ 'message' => 'Image must be at least 800×800 px.' ] );
}
// ── Check if a specific size was generated ────────────────────────────
$sizes = $meta['sizes'] ?? [];
if ( isset( $sizes['product-main'] ) ) {
$size_info = $sizes['product-main'];
echo esc_html( $size_info['file'] ); // product-800x800.jpg
echo (int) $size_info['width']; // 800
echo (int) $size_info['height']; // 800
}
// ── Build the full URL for a specific generated size ──────────────────
$upload_dir = wp_upload_dir();
$base_dir = $meta['file'] ? dirname( $upload_dir['basedir'] . '/' . $meta['file'] ) : $upload_dir['basedir'];
$base_url = $meta['file'] ? dirname( $upload_dir['baseurl'] . '/' . $meta['file'] ) : $upload_dir['baseurl'];
$size_url = isset( $sizes['product-main']['file'] )
? $base_url . '/' . $sizes['product-main']['file']
: '';
// ── Update metadata after external processing ─────────────────────────
// If you resize an image externally, update the stored metadata:
$meta['width'] = 1600;
$meta['height'] = 900;
wp_update_attachment_metadata( $attachment_id, $meta );
// ── List all registered image sizes and their availability ────────────
$registered = wp_get_registered_image_subsizes(); // all sizes known to WP
foreach ( $registered as $size_name => $size_args ) {
$generated = isset( $sizes[ $size_name ] );
printf( "%s: %dx%d — %s
",
esc_html( $size_name ),
(int) $size_args['width'],
(int) $size_args['height'],
$generated ? 'generated' : 'MISSING'
);
}
NOTE: wp_get_attachment_metadata() returns false (not an empty array) for non-image attachments like PDFs and videos. Always check is_array() on the result before accessing array keys. Also, the 'file' key in the top-level metadata is a relative path from the uploads base directory — not an absolute path. To get the full filesystem path, prepend wp_upload_dir()['basedir'] . '/'. The 'sizes' sub-array only lists sizes that were actually generated — a size will be absent if it was registered after the image was uploaded, or if the image was too small for that size to be created.