Медиафайлы (картинки) в WordPress

При загрузке картинки WP сохраняет данные в базу данных: добавляет данные в таблицу wp_posts и устанавливает метаданные.

Т.е. данные картинок хранятся там же где хранятся записи (посты), но логика хранения, обработки и использования полей таблицы сильно отличается, поэтому я вынес этот тип сущностей в отдельный тип.

Ниже рассмотрим как WordPress хранит вложения в БД (картинки или файлы), т.е рассмотрим структуру картинок (медиа-файлов) и то, как хранятся картинки в ВордПресс.

При загрузке картинки на сайт в таблицу wp_posts добавляется следующие данные:

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
)
*/

Полезных полей в этой таблице не много, это:

  • post_title — Заголовок.
  • post_content — Описание (указывается в админке).
  • post_excerpt — Подпись caption.
  • post_mime_type — MIME тип.
  • post_type — Всегда "attachment".
  • post_date, post_date_gmt — Дата добавления вложения.
  • guid — URL файла. Но доверять этому полю не всегда можно, надежнее получить URL через функцию wp_get_attachment_url().

Значение ALT атрибута

Хранится в таблице метаполей wp_postmeta, в мета-поле _wp_attachment_image_alt.

В WordPress нет специальной функции для получения alt атрибута картинки (справедливо для WP 6.4).

Чтобы получить alt атрибут используйте такой код:

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

Пример с ресайзом (WP 5.3)

Пример когда изображение было загружено и отредактировано в редакторе (было сделано кадрирование).

После этого измененная картинка полностью заменяет оригинал. Оригинал (файл) при этом не удаляется, а единственное упоминание о нём сохраняется в метаполе _wp_attachment_backup_sizes.

$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
		)

)
*/

Пример с большой фоткой -scaled (WP 5.3)

Просто загружена большая фотка с которой создались все возможные размеры.

/*
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 -------------
пусто
*/

Пример с изменением ориентации -rotated (WP 5.3)

Если при загрузке картинки в её EXIF данных указанна ориентация и она отличается от 1. То это значит что физический фйал картинки имеет нестандартную ориентацию (ориентация картинки нарушена) и ВП это исправляет на основе указанных данных.

Как ВП обрабатывает ориентацию можно посмотреть в функции 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.

Рассмотрим на примере.

Допустим мы загрузили картинку Landscape_2.jpg у которой указаны такие exif данные:
Данные берутся функцией 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
)

После загрузки данные ВП создаст копию загруженного изображения с суффикcом -rotated. Т.е. по итогу в папке загрузок будет лежать оригинальная картинка и измененная картинка. Измененная картинка, станет основной, а оригинальная будет указана в метаданных в ключе original_image:

Данные из таблицы wp_posts:

+-----------------------+--------------------------------------------------------------+
| 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                                                            |
+-----------------------+--------------------------------------------------------------+

Данные из таблицы wp_postmeta:

+---------+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
| 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                                                                                                                                           |
+---------+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+

Массив: _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',
]

WP не всегда правильно изменяет ориентацию картинки, чтобы все работало правильно есть плагин: https://github.com/gagan0123/fix-image-rotation

PHP Функции Получения вложений

Функции отвечающие за URL и пути вложений. Показана иерархия использования функций друг другом.

wp_get_attachment_url()

get_attached_file()

PHP Функции Получения картинок

Показана иерархия использования функций друг другом.

the_post_thumbnail()

wp_get_attachment_image_url()

  • { wp_get_attachment_image_src() }

wp_get_attachment_image_src()

PHP Функции Загрузки файлов (медиа)

Показана иерархия использования функций друг другом.

media_handle_upload()

media_handle_sideload()