Media Files (Images) in WordPress

When uploading an image, WP saves data in the database: it adds data to the wp_posts table and sets metadata.

That is, the data of the images is stored in the same place as the posts, but the logic of storing, processing, and using the table fields is significantly different, so I extracted this type of entity into a separate type.

Below, let's look at how WordPress stores attachments in the database (images or files), i.e. let's examine the structure of images (media files) and how images are stored in WordPress.

When uploading an image to the site, the following data is added to the wp_posts table:

global $wpdb;
$po = $wpdb->get_row( "SELECT * from $wpdb->posts where ID = 16754" );
print_r( $po );

/*
stdClass Object (
	[ID] => 16754
	[post_author] => 1
	[post_date] => 2024-01-14 08:15:42
	[post_date_gmt] => 2024-01-14 03:15:42
	[post_content] => Description text
	[post_title] => Image title text
	[post_excerpt] => Caption text
	[post_status] => inherit
	[comment_status] => open
	[ping_status] => closed
	[post_password] =>
	[post_name] => clipboard-image-845920
	[to_ping] =>
	[pinged] =>
	[post_modified] => 2024-01-19 07:33:23
	[post_modified_gmt] => 2024-01-19 02:33:23
	[post_content_filtered] =>
	[post_parent] => 12014
	[guid] => //example.com/wp-content/uploads/2024/01/clipboard-image-845920.png
	[menu_order] => 0
	[post_type] => attachment
	[post_mime_type] => image/png
	[comment_count] => 0
)
*/

Useful fields in this table are few, such as:

  • post_title — Title.
  • post_content — Description (specified in the admin panel).
  • post_excerpt — Caption.
  • post_mime_type — MIME type.
  • post_type — Always "attachment".
  • post_date, post_date_gmt — Date of attachment addition.
  • guid — File URL. But it's not always reliable to trust this field; it's more reliable to get the URL through the function wp_get_attachment_url().

ALT attribute value

Stored in the meta-field table wp_postmeta, in the meta-field _wp_attachment_image_alt.

WordPress does not have a special function for retrieving the image alt attribute (valid for WP 6.4).

To retrieve the alt attribute, use the following code:

$alt_text = get_post_meta( $post->ID, '_wp_attachment_image_alt', true );

Example with resizing (WP 5.3)

An example when an image was uploaded and edited in the editor (cropping was done).

After this, the modified image completely replaces the original. The original (file) is not deleted, and the only mention of it is saved in the _wp_attachment_backup_sizes meta-field.

$attach_id = 1821;
echo 'wp_get_original_image_url(): '. wp_get_original_image_url( $attach_id )."\n";
echo 'wp_get_original_image_path(): '. wp_get_original_image_path( $attach_id )."\n";
echo 'get_attached_file(): '. get_attached_file( $attach_id )."\n";
echo "\npost_meta -------------\n";
print_r( get_post_meta( $attach_id ) );
echo "\nwp_get_attachment_metadata -------------\n";
print_r( wp_get_attachment_metadata( $attach_id ) );
echo "\n_wp_attachment_backup_sizes -------------\n";
print_r( get_post_meta( $attach_id, '_wp_attachment_backup_sizes', true ) );

/*
wp_get_original_image_url(): http://example.com/wp-content/uploads/2020/03/medium-img-e1583064965160.jpg
wp_get_original_image_path(): /home/sites/example.com/wp-content/uploads/2020/03/medium-img-e1583064965160.jpg
get_attached_file(): /home/sites/example.com/wp-content/uploads/2020/03/medium-img-e1583064965160.jpg

post_meta -------------
Array
(
	[_wp_attached_file] => Array (
		[0] => 2020/03/medium-img-e1583064965160.jpg
	)

	[_wp_attachment_metadata] => Array (
		[0] => a:5:{s:5:"width";i:672;s:6:"height";i:422;s:4:"file";s:44:"2020/03/medium-img-e1583064965160.jpg";
s:5:"sizes";a:4:{s:6:"medium";a:4:{s:4:"file";s:44:"medium-img-e1583064965160-300x188.jpg";
s:5:"width";i:300;s:6:"height";i:188;s:9:"mime-type";s:10:"image/jpeg";}
s:5:"large";a:4:{s:4:"file";s:30:"medium-img-1024x576.jpg";s:5:"width";i:1024;s:6:"height";
i:576;s:9:"mime-type";s:10:"image/jpeg";}s:9:"thumbnail";a:4:{s:4:"file";s:44:"medium-img-e1583064965160-150x150.jpg";
s:5:"width";i:150;s:6:"height";i:150;s:9:"mime-type";s:10:"image/jpeg";}
s:12:"medium_large";a:4:{s:4:"file";s:29:"medium-img-768x432.jpg";s:5:"width";i:768;
s:6:"height";i:432;s:9:"mime-type";s:10:"image/jpeg";}}s:10:"image_meta";
a:12:{s:8:"aperture";s:1:"0";s:6:"credit";s:0:"";s:6:"camera";s:0:"";s:7:"caption";s:0:"";s:17:"created_timestamp";s:1:"0";
s:9:"copyright";s:0:"";s:12:"focal_length";s:1:"0";s:3:"iso";s:1:"0";s:13:"shutter_speed";s:1:"0";s:5:"title";
s:0:"";s:11:"orientation";s:1:"0";s:8:"keywords";a:0:{}}}
	)

	[_edit_lock] => Array (
		[0] => 1583080079:1
	)

	[_edit_last] => Array (
		[0] => 1
	)

	[_wp_attachment_image_alt] => Array (
		[0] => ALT attribute Text
	)

	[_wp_attachment_backup_sizes] => Array (
		[0] => a:5:{s:9:"full-orig";a:3:{s:5:"width";i:1280;s:6:"height";i:720;s:4:"file";s:21:"medium-img.jpg";}
s:14:"thumbnail-orig";a:4:{s:4:"file";s:29:"medium-img-150x150.jpg";
s:5:"width";i:150;s:6:"height";i:150;s:9:"mime-type";s:10:"image/jpeg";}s:11:"medium-orig";
a:4:{s:4:"file";s:29:"medium-img-300x169.jpg";s:5:"width";i:300;s:6:"height";i:169;s:9:"mime-type";s:10:"image/jpeg";}
s:17:"medium_large-orig";a:4:{s:4:"file";s:29:"medium-img-768x432.jpg";s:5:"width";i:768;
s:6:"height";i:432;s:9:"mime-type";s:10:"image/jpeg";}s:10:"large-orig";a:4:{s:4:"file";
s:30:"medium-img-1024x576.jpg";s:5:"width";i:1024;s:6:"height";i:576;s:9:"mime-type";s:10:"image/jpeg";}}
	)

)

wp_get_attachment_metadata -------------
Array
(
	[width] => 672
	[height] => 422
	[file] => 2020/03/medium-img-e1583064965160.jpg
	[sizes] => Array (
		[medium] => Array (
			[file] => medium-img-e1583064965160-300x188.jpg
			[width] => 300
			[height] => 188
			[mime-type] => image/jpeg
		)

		[large] => Array (
			[file] => medium-img-1024x576.jpg
			[width] => 1024
			[height] => 576
			[mime-type] => image/jpeg
		)

		[thumbnail] => Array (
			[file] => medium-img-e1583064965160-150x150.jpg
			[width] => 150
			[height] => 150
			[mime-type] => image/jpeg
		)

		[medium_large] => Array (
			[file] => medium-img-768x432.jpg
			[width] => 768
			[height] => 432
			[mime-type] => image/jpeg
		)

	)

	[image_meta] => Array (
		[aperture] => 0
		[credit] =>
		[camera] =>
		[caption] =>
		[created_timestamp] => 0
		[copyright] =>
		[focal_length] => 0
		[iso] => 0
		[shutter_speed] => 0
		[title] =>
		[orientation] => 0
		[keywords] => Array()
	)

)

_wp_attachment_backup_sizes -------------
Array
(
	[full-orig] => Array (
			[width] => 1280
			[height] => 720
			[file] => medium-img.jpg
		)

	[thumbnail-orig] => Array (
			[file] => medium-img-150x150.jpg
			[width] => 150
			[height] => 150
			[mime-type] => image/jpeg
		)

	[medium-orig] => Array (
			[file] => medium-img-300x169.jpg
			[width] => 300
			[height] => 169
			[mime-type] => image/jpeg
		)

	[medium_large-orig] => Array (
			[file] => medium-img-768x432.jpg
			[width] => 768
			[height] => 432
			[mime-type] => image/jpeg
		)

	[large-orig] => Array (
			[file] => medium-img-1024x576.jpg
			[width] => 1024
			[height] => 576
			[mime-type] => image/jpeg
		)

)
*/

Example with a large image -scaled (WP 5.3)

For more information about scaled sizes, read here.

Simply uploaded a large image from which all possible sizes were created.

/*
wp_get_original_image_url(): http://example.com/wp-content/uploads/2020/03/jpg-big-image.jpeg
wp_get_original_image_path(): C:\sites\example.com\www/wp-content/uploads/2020/03/jpg-big-image.jpeg
get_attached_file(): C:\sites\example.com\www/wp-content/uploads/2020/03/jpg-big-image-scaled.jpeg

post_meta -------------
Array
(
	[_wp_attached_file] => Array
		(
			[0] => 2020/03/jpg-big-image-scaled.jpeg
		)

	[_wp_attachment_metadata] => Array
		(
			[0] => a:6:{s:5:"width";i:2560;s:6:"height";i:1707;s:4:"file";s:33:"2020/03/jpg-big-image-scaled.jpeg";s:5:"sizes";
a:6:{s:6:"medium";a:4:{s:4:"file";s:26:"jpg-big-image-300x200.jpeg";s:5:"width";i:300;s:6:"height";i:200;s:9:"mime-type";s:10:"image/jpeg";}
s:5:"large";a:4:{s:4:"file";s:27:"jpg-big-image-1024x683.jpeg";s:5:"width";i:1024;s:6:"height";i:683;s:9:"mime-type";s:10:"image/jpeg";}
s:9:"thumbnail";a:4:{s:4:"file";s:26:"jpg-big-image-150x150.jpeg";s:5:"width";i:150;s:6:"height";i:150;s:9:"mime-type";s:10:"image/jpeg";}
s:12:"medium_large";a:4:{s:4:"file";s:26:"jpg-big-image-768x512.jpeg";s:5:"width";i:768;s:6:"height";i:512;s:9:"mime-type";s:10:"image/jpeg";}
s:9:"1536x1536";a:4:{s:4:"file";s:28:"jpg-big-image-1536x1024.jpeg";s:5:"width";i:1536;s:6:"height";i:1024;s:9:"mime-type";s:10:"image/jpeg";}
s:9:"2048x2048";a:4:{s:4:"file";s:28:"jpg-big-image-2048x1365.jpeg";s:5:"width";i:2048;s:6:"height";i:1365;s:9:"mime-type";s:10:"image/jpeg";}}
s:10:"image_meta";a:12:{s:8:"aperture";s:2:"11";s:6:"credit";s:0:"";s:6:"camera";s:11:"NIKON D5300";s:7:"caption";s:0:"";s:17:"created_timestamp";
s:10:"1413130422";s:9:"copyright";s:0:"";s:12:"focal_length";s:2:"31";s:3:"iso";s:3:"320";s:13:"shutter_speed";s:5:"0.002";s:5:"title";s:0:"";s:11:"orientation";
s:1:"1";s:8:"keywords";a:0:{}}s:14:"original_image";s:18:"jpg-big-image.jpeg";}
		)

	[_edit_lock] => Array
		(
			[0] => 1583088196:1
		)

)

wp_get_attachment_metadata -------------
Array
(
	[width] => 2560
	[height] => 1707
	[file] => 2020/03/jpg-big-image-scaled.jpeg
	[sizes] => Array
		(
			[medium] => Array
				(
					[file] => jpg-big-image-300x200.jpeg
					[width] => 300
					[height] => 200
					[mime-type] => image/jpeg
				)

			[large] => Array
				(
					[file] => jpg-big-image-1024x683.jpeg
					[width] => 1024
					[height] => 683
					[mime-type] => image/jpeg
				)

			[thumbnail] => Array
				(
					[file] => jpg-big-image-150x150.jpeg
					[width] => 150
					[height] => 150
					[mime-type] => image/jpeg
				)

			[medium_large] => Array
				(
					[file] => jpg-big-image-768x512.jpeg
					[width] => 768
					[height] => 512
					[mime-type] => image/jpeg
				)

			[1536x1536] => Array
				(
					[file] => jpg-big-image-1536x1024.jpeg
					[width] => 1536
					[height] => 1024
					[mime-type] => image/jpeg
				)

			[2048x2048] => Array
				(
					[file] => jpg-big-image-2048x1365.jpeg
					[width] => 2048
					[height] => 1365
					[mime-type] => image/jpeg
				)

		)

	[image_meta] => Array (
			[aperture] => 11
			[credit] =>
			[camera] => NIKON D5300
			 =>
			[created_timestamp] => 1413130422
			[copyright] =>
			[focal_length] => 31
			[iso] => 320
			[shutter_speed] => 0.002
			[title] =>
			[orientation] => 1
			[keywords] => Array()
		)

	[original_image] => jpg-big-image.jpeg
)

_wp_attachment_backup_sizes -------------
empty
*/

Example with orientation change -rotated (WP 5.3)

If the image's EXIF data specifies an orientation different from 1 when it is uploaded, it means that the physical file of the image has a non-standard orientation (the image's orientation is disrupted) and WordPress corrects this based on the specified data.

You can see how WordPress handles the orientation in the function wp_create_image_subsizes() > WP_Image_Editor::maybe_exif_rotate():

  • 2 - Flip horizontally.
  • 3 - Rotate 180 degrees or flip horizontally and vertically.
  • 4 - Flip vertically.
  • 5 - Rotate 90 degrees counter-clockwise and flip vertically.
  • 6 - Rotate 90 degrees clockwise (270 counter-clockwise).
  • 7 - Rotate 90 degrees counter-clockwise and flip horizontally.
  • 8 - Rotate 90 degrees counter-clockwise.

Let's consider an example.

Suppose we have uploaded the image Landscape_2.jpg with the following EXIF data:
The data is obtained using the function exif_read_data():

$exif_data = exif_read_data( ABSPATH .'../wp-content/uploads/2022/06/Landscape_2.jpg' );

print_r( $exif_data );

/*
Array (
	[FileName] => Landscape_2.jpg
	[FileDateTime] => 1656265839
	[FileSize] => 349209
	[FileType] => 2
	[MimeType] => image/jpeg
	[SectionsFound] => ANY_TAG, IFD0
	[COMPUTED] => Array
		(
			[html] => width="1800" height="1200"
			[Height] => 1200
			[Width] => 1800
			[IsColor] => 1
			[ByteOrderMotorola] => 1
		)

	[Orientation] => 2
	[XResolution] => 72/1
	[YResolution] => 72/1
	[ResolutionUnit] => 2
	[YCbCrPositioning] => 1
)

After the upload, WordPress will create a copy of the uploaded image with the suffix -rotated. So, in the uploads folder, there will be the original image and the modified image. The modified image will become the main one, and the original will be specified in the metadata under the key original_image:

Data from the wp_posts table:

+-----------------------+--------------------------------------------------------------+
| Field                 | Value                                                        |
+-----------------------+--------------------------------------------------------------+
| ID                    | 1863                                                         |
| post_author           | 1                                                            |
| post_date             | 2022-06-26 17:50:39                                          |
| post_date_gmt         | 2022-06-26 17:50:39                                          |
| post_content          |                                                              |
| post_title            | Landscape_2                                                  |
| post_excerpt          |                                                              |
| post_status           | inherit                                                      |
| comment_status        | open                                                         |
| ping_status           | closed                                                       |
| post_password         |                                                              |
| post_name             | landscape_2                                                  |
| to_ping               |                                                              |
| pinged                |                                                              |
| post_modified         | 2022-06-26 17:50:39                                          |
| post_modified_gmt     | 2022-06-26 17:50:39                                          |
| post_content_filtered |                                                              |
| post_parent           | 0                                                            |
| guid                  | http://wptest.loc/wp-content/uploads/2022/06/Landscape_2.jpg |
| menu_order            | 0                                                            |
| post_type             | attachment                                                   |
| post_mime_type        | image/jpeg                                                   |
| comment_count         | 0                                                            |
+-----------------------+--------------------------------------------------------------+

Data from the wp_postmeta table:

+---------+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
| post_id | meta_key                | meta_value                                                                                                                                             |
+---------+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
| 1863    | _wp_attached_file       | 2022/06/Landscape_2-rotated.jpg                                                                                                                        |
| 1863    | _wp_attachment_metadata | a:7:{s:5:"width";i:1800;s:6:"height";i:1200;s:4:"file";s:31:"2022/06/Landscape_2-rotated.jpg";s:8:"filesize";i:400881;s:5:"sizes";a:6:{s:6:"medium";a: |
|         |                         | 5:{s:4:"file";s:23:"Landscape_2-300x200.jpg";s:5:"width";i:300;s:6:"height";i:200;s:9:"mime-type";s:10:"image/jpeg";s:8:"filesize";i:14295;}s:5:"large |
|         |                         | ";a:5:{s:4:"file";s:24:"Landscape_2-1024x683.jpg";s:5:"width";i:1024;s:6:"height";i:683;s:9:"mime-type";s:10:"image/jpeg";s:8:"filesize";i:130033;}s:9 |
|         |                         | :"thumbnail";a:5:{s:4:"file";s:23:"Landscape_2-150x150.jpg";s:5:"width";i:150;s:6:"height";i:150;s:9:"mime-type";s:10:"image/jpeg";s:8:"filesize";i:60 |
|         |                         | 50;}s:12:"medium_large";a:5:{s:4:"file";s:23:"Landscape_2-768x512.jpg";s:5:"width";i:768;s:6:"height";i:512;s:9:"mime-type";s:10:"image/jpeg";s:8:"fil |
|         |                         | esize";i:75295;}s:9:"1536x1536";a:5:{s:4:"file";s:25:"Landscape_2-1536x1024.jpg";s:5:"width";i:1536;s:6:"height";i:1024;s:9:"mime-type";s:10:"image/jp |
|         |                         | eg";s:8:"filesize";i:283925;}s:14:"post-thumbnail";a:5:{s:4:"file";s:25:"Landscape_2-1568x1045.jpg";s:5:"width";i:1568;s:6:"height";i:1045;s:9:"mime-t |
|         |                         | ype";s:10:"image/jpeg";s:8:"filesize";i:295929;}}s:10:"image_meta";a:12:{s:8:"aperture";s:1:"0";s:6:"credit";s:0:"";s:6:"camera";s:0:"";s:7:"caption"; |
|         |                         | s:0:"";s:17:"created_timestamp";s:1:"0";s:9:"copyright";s:0:"";s:12:"focal_length";s:1:"0";s:3:"iso";s:1:"0";s:13:"shutter_speed";s:1:"0";s:5:"title"; |
|         |                         | s:0:"";s:11:"orientation";i:1;s:8:"keywords";a:0:{}}s:14:"original_image";s:15:"Landscape_2.jpg";}                                                     |
| 1863    | _edit_lock              | 1656265849:1                                                                                                                                           |
+---------+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+

Array: _wp_attachment_metadata:

[
	'width' => 1800,
	'height' => 1200,
	'file' => '2022/06/Landscape_2-rotated.jpg',
	'filesize' => 400881,
	'sizes' =>
		[
			'medium'         =>
				[
					'file'      => 'Landscape_2-300x200.jpg',
					'width'     => 300,
					'height'    => 200,
					'mime-type' => 'image/jpeg',
					'filesize'  => 14295,
				],
			'large'          =>
				[
					'file'      => 'Landscape_2-1024x683.jpg',
					'width'     => 1024,
					'height'    => 683,
					'mime-type' => 'image/jpeg',
					'filesize'  => 130033,
				],
			'thumbnail'      =>
				[
					'file'      => 'Landscape_2-150x150.jpg',
					'width'     => 150,
					'height'    => 150,
					'mime-type' => 'image/jpeg',
					'filesize'  => 6050,
				],
			'medium_large'   =>
				[
					'file'      => 'Landscape_2-768x512.jpg',
					'width'     => 768,
					'height'    => 512,
					'mime-type' => 'image/jpeg',
					'filesize'  => 75295,
				],
			'1536x1536'      =>
				[
					'file'      => 'Landscape_2-1536x1024.jpg',
					'width'     => 1536,
					'height'    => 1024,
					'mime-type' => 'image/jpeg',
					'filesize'  => 283925,
				],
			'post-thumbnail' =>
				[
					'file'      => 'Landscape_2-1568x1045.jpg',
					'width'     => 1568,
					'height'    => 1045,
					'mime-type' => 'image/jpeg',
					'filesize'  => 295929,
				],
		],
	'image_meta' =>
		[
			'aperture'          => '0',
			'credit'            => '',
			'camera'            => '',
			'caption'           => '',
			'created_timestamp' => '0',
			'copyright'         => '',
			'focal_length'      => '0',
			'iso'               => '0',
			'shutter_speed'     => '0',
			'title'             => '',
			'orientation'       => 1,
			'keywords'          =>
				[
				],
		],
	'original_image' => 'Landscape_2.jpg',
]

WordPress does not always correctly change the image orientation. To ensure everything works correctly, there is a plugin available: https://github.com/gagan0123/fix-image-rotation

PHP Functions for Attachment Getting

Functions for getting attachment URLs and paths. The hierarchy of function usage is shown.

wp_get_attachment_url()

get_attached_file()

PHP Functions for Image Getting

The hierarchy of function usage is shown.

the_post_thumbnail()

wp_get_attachment_image_url()

  • { wp_get_attachment_image_src() }

wp_get_attachment_image_src()

PHP Functions for File Upload (Media)

Shown is the hierarchy of functions using each other.

media_handle_upload()

media_handle_sideload()