wppaste
WordPress

wp_get_attachment_metadata( int $attachment_id = 0, bool $unfiltered = false ): array|false

Since
2.1.0, 6.0.0, 7.1.0
Source
wp-includes/post.php:7101

Reads the array stored in an attachment's _wp_attachment_metadata post meta, covering width, height, file path, registered sizes, and image metadata. Returns false when no attachment can be resolved or when the stored value isn't an array, and skips the wp_get_attachment_metadata filter entirely when the $unfiltered argument is true. Pair it with wp_generate_attachment_metadata() when you need to create or refresh that stored array rather than just read it.

Retrieves attachment metadata for attachment ID.

Compatibility

WordPress
since 7.1.0
PHP
7.4–8.6-dev
  • 6.7.7
  • 6.8.8
  • 6.9.7
  • 7.0.4
  • 7.1.0

Present in every tracked release (6.7.7 to 7.1.0), and compiles on PHP 7.4 through 8.6-dev.

Parameters

$attachment_idintoptional
Attachment post ID. Defaults to global $post.Default: 0
$unfilteredbooloptional
If true, filters are not run. Default false.Default: false

Return value

array|false
Attachment metadata. False on failure.
  • $widthint

    The width of the attachment.
  • $heightint

    The height of the attachment.
  • $filestring

    The file path relative to wp-content/uploads.
  • $sizesarray

    Keys are size slugs, each value is an array containing 'file', 'width', 'height', and 'mime-type'.
  • $image_metaarray

    Image metadata.
  • $filesizeint

    File size of the attachment.

Code examples

Every example is editable and runs in a real WordPress booted in your browser by WordPress Playground. Press Run, then edit the code: clicking away re-runs it. Nothing is sent anywhere until you do.

Get the width, height, and file path of an image attachment

Look up a sample image attachment and print the dimensions and relative file path stored in its metadata.

$attachments = get_posts( array(
	'post_type'      => 'attachment',
	'title'          => 'Mountain Sunrise',
	'posts_per_page' => 1,
) );

if ( $attachments ) {
	$metadata = wp_get_attachment_metadata( $attachments[0]->ID );

	if ( $metadata ) {
		printf(
			'Image is %d by %d pixels, stored at %s',
			(int) $metadata['width'],
			(int) $metadata['height'],
			esc_html( $metadata['file'] )
		);
	} else {
		echo 'No metadata found for this attachment.';
	}
} else {
	echo 'Attachment not found.';
}

In a real upload this metadata array would come from wp_generate_attachment_metadata() instead of being written by hand.

Add a custom field to attachment metadata via the filter, and see it disappear with $unfiltered

Register a filter that appends a photographer credit to every attachment's metadata, then compare the filtered and unfiltered results for the same attachment.

add_filter(
	'wp_get_attachment_metadata',
	function ( $data, $attachment_id ) {
		$data['photographer_credit'] = 'J. Rivera';
		return $data;
	},
	10,
	2
);

$attachments = get_posts( array(
	'post_type'      => 'attachment',
	'title'          => 'Studio Portrait',
	'posts_per_page' => 1,
) );

if ( $attachments ) {
	$id = $attachments[0]->ID;

	$filtered   = wp_get_attachment_metadata( $id );
	$unfiltered = wp_get_attachment_metadata( $id, true );

	echo 'Filtered credit: ' . esc_html( $filtered['photographer_credit'] ?? '(missing)' ) . '<br>';
	echo 'Unfiltered credit: ' . esc_html( $unfiltered['photographer_credit'] ?? '(missing)' );
} else {
	echo 'Attachment not found.';
}

The unfiltered call passes true as the second argument, so it returns the raw stored array and never sees the added key.

Common problems and fixes · 4

Why does wp_get_attachment_metadata return false for an attachment I know exists?

The function returns false whenever the '_wp_attachment_metadata' post meta is missing or isn't an array, which happens for attachments whose metadata was never generated (non-image files, failed imports, or rows inserted manually without that meta key).

Why am I getting the wrong data when I call this without an ID inside a template?

Passing 0, or omitting $attachment_id, casts to 0 and falls back to global $post. Inside loops or filters where $post isn't the attachment you meant, the function silently reads the wrong post's meta or returns false because that post has no attachment metadata.

Why did my sizes array get wiped out after adding a filter on wp_get_attachment_metadata?

After running the wp_get_attachment_metadata filter, the function checks the 'sizes' key: if it exists but isn't an array, it's forcibly reset to an empty array. A filter callback that returns a non-array value for 'sizes' loses that data.

Why isn't my filter's extra data showing up when I call this function?

Passing true as the second argument ($unfiltered) skips the apply_filters( 'wp_get_attachment_metadata', ... ) call entirely, so anything added by filters (including plugins) never runs for that call.

Alternatives and related functions

wp_generate_attachment_metadata
When you need to create or regenerate the metadata array itself (for example after a new upload or a manual regeneration), rather than just read what's already stored.
wp_update_attachment_metadata
When you need to write a modified metadata array back to the '_wp_attachment_metadata' meta key instead of reading it.
wp_get_attachment_image_src
When you just need a usable URL, width, and height for one registered image size rather than the full stored metadata array.
wp_get_attachment_url
When you only need the attachment's file URL and don't care about dimensions, sizes, or image metadata.

Performance profile

How much work a call to wp_get_attachment_metadata() does, and what it touches: the algorithmic scaling, the Zend instruction count per call across PHP versions, the hooks it hands control to, and the core code that calls it. Measured from the compiled opcodes, not a stopwatch, so every number is identical on any machine running the same PHP version, and every function in core is ranked by cost.

Cost class
Heavy

Reaches the database via get_post().

Scaling
Constant

No loop in the body: the same number of instructions runs whatever you pass in.

Instructions
10–36

Executed per call on PHP 8.5, depending on the branch taken. The body compiles to 40.

Plugin surface
1 hook

Third-party callbacks on 'wp_get_attachment_metadata' run inside this call, and their cost is not bounded by anything here.

Called by
43

43 places in core call this, so the cost is paid more often than your own code shows.

What it touches

  • querycontent queryget_post()called directly
  • hookthird-party callbacksapply_filters()called directly

Further down the call graph this can also reach cache, serialize, option and transient. Those are the worst case, several calls deep and usually down an error path, not what a normal call pays.

What one call costs · 5 distinct outcomes

One number would be a lie: the work depends on which branch runs. These are every distinct cost wp_get_attachment_metadata() can have, taken from its control-flow graph on PHP 8.5.

WhenInstructionsCalls it makes
always10get_post()
always14–16get_post_meta()
always19–21get_post(), get_post_meta()
is_array($data)24–31get_post_meta(), apply_filters()
is_array($data)29–36get_post(), get_post_meta(), apply_filters()

Across PHP versions

Compiles the same on PHP 7.4, 8.1, 8.2, 8.3, 8.4, 8.5 and 8.6-dev: 40 instructions, 10–36 executed per call, 8 branches. The work does not change between versions.

An instruction is not a fixed amount of time, so a matching count is not necessarily the same speed; what it rules out is a difference in the work itself.

Hooks and filters fired · 1

One hook fires while wp_get_attachment_metadata() runs, in this order:

  1. apply_filters( wp_get_attachment_metadata )filterline 7132 (+31 into the body)

    Filters the attachment meta data.

Uses · 3

  • get_post()Retrieves post data given a post ID or post object.
  • get_post_meta()Retrieves a post meta field for the given post ID.
  • apply_filters()Calls the callback functions that have been added to a filter hook.

Used by · 43

Show all 43

Source code

function wp_get_attachment_metadata( $attachment_id = 0, $unfiltered = false ) {	$attachment_id = (int) $attachment_id; 	if ( ! $attachment_id ) {		$post = get_post(); 		if ( ! $post ) {			return false;		} 		$attachment_id = $post->ID;	} 	$data = get_post_meta( $attachment_id, '_wp_attachment_metadata', true ); 	if ( ! is_array( $data ) || ! $data ) {		return false;	} 	if ( $unfiltered ) {		return $data;	} 	/**	 * Filters the attachment meta data.	 *	 * @since 2.1.0	 *	 * @param array $data          Array of meta data for the given attachment.	 * @param int   $attachment_id Attachment post ID.	 */	$data = apply_filters( 'wp_get_attachment_metadata', $data, $attachment_id ); 	if ( ! is_array( $data ) ) {		return false;	} 	if ( array_key_exists( 'sizes', $data ) && ! is_array( $data['sizes'] ) ) {		$data['sizes'] = array();	} 	return $data;}

Changelog

Introduced in 2.1.0. Unchanged from 6.7.7 through 7.1.0.

  1. 6.7.7
  2. 6.8.8
  3. 6.9.7
  4. 7.0.4
  5. 7.1.0

Signature, return type and hooks compared across 5 parsed releases.

7.1.0
false is now returned if the metadata is not an array, and when the result is filtered the sizes key is always an array when present.from the docblock
6.0.0
The $filesize value was added to the returned array.from the docblock
2.1.0
Introduced.from the docblock

About this page

Parsed data
Generated from the wordpress-develop 7.1.0 tag, from src/wp-includes/post.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it.
Corrections
Something wrong on this page? Report it and it gets fixed in the next regeneration.