WordPress stores uploaded files as attachment posts — post type attachment — with the original file URL in the guid field and intermediate sizes registered as post meta under _wp_attachment_metadata. The media helper functions form a complete API for working with these attachments: retrieving URLs, getting image tags with srcset, checking whether an attachment is an image, getting MIME types, and finding which post an attachment is attached to. Knowing which function to use for which purpose is essential for theme developers (displaying featured images with proper srcset attributes), plugin developers (handling file uploads, generating download links), and anyone building galleries or media-heavy templates. The most common confusion is between wp_get_attachment_url() (returns the original file URL), wp_get_attachment_image() (returns a complete <img> tag with srcset), and wp_get_attachment_image_src() (returns an array of URL, width, height for a specific size).
Problem: A custom post type has a gallery meta field that stores an array of attachment IDs. You need to output each image as an accessible <img> tag with srcset for responsive loading, and provide a link to the original full-resolution file for download.
Solution: Use wp_get_attachment_image() for the responsive <img> tag and wp_get_attachment_url() for the original file download link. Use wp_get_attachment_image_src() when you need the URL and dimensions for a specific named size.
<?php
$attachment_ids = get_post_meta( get_the_ID(), 'gallery_ids', true ) ?: [];
foreach ( $attachment_ids as $att_id ) {
$att_id = absint( $att_id );
// ── Full <img> tag with srcset, sizes, width, height, loading="lazy" ──
echo wp_get_attachment_image( $att_id, 'large', false, [
'class' => 'gallery__item',
'loading' => 'lazy',
'alt' => esc_attr( get_post_meta( $att_id, '_wp_attachment_image_alt', true ) ),
] );
// ── URL of the original uploaded file (for download link) ─────────────
$original_url = wp_get_attachment_url( $att_id );
// ── Array of [ url, width, height, is_intermediate ] for a named size ─
$thumb = wp_get_attachment_image_src( $att_id, 'thumbnail' );
if ( $thumb ) {
[ $url, $width, $height ] = $thumb;
printf( '<img src="%s" width="%d" height="%d">', esc_url( $url ), $width, $height );
}
// ── All registered sizes with full metadata ─────────────────────────
$meta = wp_get_attachment_metadata( $att_id );
// $meta['width'], $meta['height'] = original dimensions
// $meta['sizes'] = array of registered intermediate sizes
// $meta['file'] = relative path from uploads dir
// ── MIME type check ────────────────────────────────────────────────
$mime = get_post_mime_type( $att_id ); // e.g. 'image/jpeg', 'application/pdf'
$is_image = wp_attachment_is_image( $att_id ); // true/false
// ── Download link to original file ────────────────────────────────
printf(
'<a href="%s" download>%s</a>',
esc_url( $original_url ),
esc_html__( 'Download original', 'textdomain' )
);
}
Finding which post an attachment belongs to, and getting the attachment ID from a URL:
<?php
// Get the parent post ID of an attachment
$parent_id = wp_get_post_parent_id( $attachment_id );
// Get attachment ID from a URL (reverse lookup)
$attachment_id = attachment_url_to_postid( 'https://example.com/wp-content/uploads/2020/12/photo.jpg' );
// Get the post that set this image as featured
global $wpdb;
$post_id = $wpdb->get_var( $wpdb->prepare(
"SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_thumbnail_id' AND meta_value = %d",
$attachment_id
) );
NOTE: attachment_url_to_postid() is convenient but performs a database query and is slow when called in a loop. Cache its results or use a single $wpdb query to batch-resolve multiple URLs. wp_get_attachment_image() is the preferred function for outputting images — it automatically adds width, height, srcset, sizes, and loading="lazy" attributes, which plain wp_get_attachment_url() in an <img src> tag does not.