if ( ! empty( $data['id3v2']['APIC'] ) ) {
$image = reset( $data['id3v2']['APIC'] );
if ( ! empty( $image['data'] ) ) {
$metadata['image'] = array(
'data' => $image['data'],
'mime' => $image['image_mime'],
'width' => $image['image_width'],
'height' => $image['image_height'],
} elseif ( ! empty( $data['comments']['picture'] ) ) {
$image = reset( $data['comments']['picture'] );
if ( ! empty( $image['data'] ) ) {
$metadata['image'] = array(
'data' => $image['data'],
'mime' => $image['image_mime'],
* Retrieve metadata from a video file's ID3 tags
* @param string $file Path to file.
* @return array|false Returns array of metadata, if found.
function wp_read_video_metadata( $file ) {
if ( ! file_exists( $file ) ) {
if ( ! defined( 'GETID3_TEMP_DIR' ) ) {
define( 'GETID3_TEMP_DIR', get_temp_dir() );
if ( ! class_exists( 'getID3', false ) ) {
require ABSPATH . WPINC . '/ID3/getid3.php';
$data = $id3->analyze( $file );
if ( isset( $data['video']['lossless'] ) ) {
$metadata['lossless'] = $data['video']['lossless'];
if ( ! empty( $data['video']['bitrate'] ) ) {
$metadata['bitrate'] = (int) $data['video']['bitrate'];
if ( ! empty( $data['video']['bitrate_mode'] ) ) {
$metadata['bitrate_mode'] = $data['video']['bitrate_mode'];
if ( ! empty( $data['filesize'] ) ) {
$metadata['filesize'] = (int) $data['filesize'];
if ( ! empty( $data['mime_type'] ) ) {
$metadata['mime_type'] = $data['mime_type'];
if ( ! empty( $data['playtime_seconds'] ) ) {
$metadata['length'] = (int) round( $data['playtime_seconds'] );
if ( ! empty( $data['playtime_string'] ) ) {
$metadata['length_formatted'] = $data['playtime_string'];
if ( ! empty( $data['video']['resolution_x'] ) ) {
$metadata['width'] = (int) $data['video']['resolution_x'];
if ( ! empty( $data['video']['resolution_y'] ) ) {
$metadata['height'] = (int) $data['video']['resolution_y'];
if ( ! empty( $data['fileformat'] ) ) {
$metadata['fileformat'] = $data['fileformat'];
if ( ! empty( $data['video']['dataformat'] ) ) {
$metadata['dataformat'] = $data['video']['dataformat'];
if ( ! empty( $data['video']['encoder'] ) ) {
$metadata['encoder'] = $data['video']['encoder'];
if ( ! empty( $data['video']['codec'] ) ) {
$metadata['codec'] = $data['video']['codec'];
if ( ! empty( $data['audio'] ) ) {
unset( $data['audio']['streams'] );
$metadata['audio'] = $data['audio'];
if ( empty( $metadata['created_timestamp'] ) ) {
$created_timestamp = wp_get_media_creation_timestamp( $data );
if ( false !== $created_timestamp ) {
$metadata['created_timestamp'] = $created_timestamp;
wp_add_id3_tag_data( $metadata, $data );
$file_format = isset( $metadata['fileformat'] ) ? $metadata['fileformat'] : null;
* Filters the array of metadata retrieved from a video.
* In core, usually this selection is what is stored.
* More complete data can be parsed from the `$data` parameter.
* @param array $metadata Filtered Video metadata.
* @param string $file Path to video file.
* @param string $file_format File format of video, as analyzed by getID3.
* @param string $data Raw metadata from getID3.
return apply_filters( 'wp_read_video_metadata', $metadata, $file, $file_format, $data );
* Retrieve metadata from an audio file's ID3 tags.
* @param string $file Path to file.
* @return array|false Returns array of metadata, if found.
function wp_read_audio_metadata( $file ) {
if ( ! file_exists( $file ) ) {
if ( ! defined( 'GETID3_TEMP_DIR' ) ) {
define( 'GETID3_TEMP_DIR', get_temp_dir() );
if ( ! class_exists( 'getID3', false ) ) {
require ABSPATH . WPINC . '/ID3/getid3.php';
$data = $id3->analyze( $file );
if ( ! empty( $data['audio'] ) ) {
unset( $data['audio']['streams'] );
$metadata = $data['audio'];
if ( ! empty( $data['fileformat'] ) ) {
$metadata['fileformat'] = $data['fileformat'];
if ( ! empty( $data['filesize'] ) ) {
$metadata['filesize'] = (int) $data['filesize'];
if ( ! empty( $data['mime_type'] ) ) {
$metadata['mime_type'] = $data['mime_type'];
if ( ! empty( $data['playtime_seconds'] ) ) {
$metadata['length'] = (int) round( $data['playtime_seconds'] );
if ( ! empty( $data['playtime_string'] ) ) {
$metadata['length_formatted'] = $data['playtime_string'];
if ( empty( $metadata['created_timestamp'] ) ) {
$created_timestamp = wp_get_media_creation_timestamp( $data );
if ( false !== $created_timestamp ) {
$metadata['created_timestamp'] = $created_timestamp;
wp_add_id3_tag_data( $metadata, $data );
* Parse creation date from media metadata.
* The getID3 library doesn't have a standard method for getting creation dates,
* so the location of this data can vary based on the MIME type.
* @link https://github.com/JamesHeinrich/getID3/blob/master/structure.txt
* @param array $metadata The metadata returned by getID3::analyze().
* @return int|false A UNIX timestamp for the media's creation date if available
* or a boolean FALSE if a timestamp could not be determined.
function wp_get_media_creation_timestamp( $metadata ) {
if ( empty( $metadata['fileformat'] ) ) {
switch ( $metadata['fileformat'] ) {
if ( isset( $metadata['asf']['file_properties_object']['creation_date_unix'] ) ) {
$creation_date = (int) $metadata['asf']['file_properties_object']['creation_date_unix'];
if ( isset( $metadata['matroska']['comments']['creation_time']['0'] ) ) {
$creation_date = strtotime( $metadata['matroska']['comments']['creation_time']['0'] );
} elseif ( isset( $metadata['matroska']['info']['0']['DateUTC_unix'] ) ) {
$creation_date = (int) $metadata['matroska']['info']['0']['DateUTC_unix'];
if ( isset( $metadata['quicktime']['moov']['subatoms']['0']['creation_time_unix'] ) ) {
$creation_date = (int) $metadata['quicktime']['moov']['subatoms']['0']['creation_time_unix'];
* Encapsulates the logic for Attach/Detach actions.
* @global wpdb $wpdb WordPress database abstraction object.
* @param int $parent_id Attachment parent ID.
* @param string $action Optional. Attach/detach action. Accepts 'attach' or 'detach'.
function wp_media_attach_action( $parent_id, $action = 'attach' ) {
if ( ! current_user_can( 'edit_post', $parent_id ) ) {
wp_die( __( 'Sorry, you are not allowed to edit this post.' ) );
foreach ( (array) $_REQUEST['media'] as $attachment_id ) {
$attachment_id = (int) $attachment_id;
if ( ! current_user_can( 'edit_post', $attachment_id ) ) {
$ids_string = implode( ',', $ids );
if ( 'attach' === $action ) {
$result = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_parent = %d WHERE post_type = 'attachment' AND ID IN ( $ids_string )", $parent_id ) );
$result = $wpdb->query( "UPDATE $wpdb->posts SET post_parent = 0 WHERE post_type = 'attachment' AND ID IN ( $ids_string )" );
if ( isset( $result ) ) {
foreach ( $ids as $attachment_id ) {
* Fires when media is attached or detached from a post.
* @param string $action Attach/detach action. Accepts 'attach' or 'detach'.
* @param int $attachment_id The attachment ID.
* @param int $parent_id Attachment parent ID.
do_action( 'wp_media_attach_action', $action, $attachment_id, $parent_id );
clean_attachment_cache( $attachment_id );
$location = 'upload.php';
$referer = wp_get_referer();
if ( false !== strpos( $referer, 'upload.php' ) ) {
$location = remove_query_arg( array( 'attached', 'detach' ), $referer );
$key = 'attach' === $action ? 'attached' : 'detach';
$location = add_query_arg( array( $key => $result ), $location );
wp_redirect( $location );