$response['filesizeInBytes'] = $bytes;
$response['filesizeHumanReadable'] = size_format( $bytes );
$context = get_post_meta( $attachment->ID, '_wp_attachment_context', true );
$response['context'] = ( $context ) ? $context : '';
if ( current_user_can( 'edit_post', $attachment->ID ) ) {
$response['nonces']['update'] = wp_create_nonce( 'update-post_' . $attachment->ID );
$response['nonces']['edit'] = wp_create_nonce( 'image_editor-' . $attachment->ID );
$response['editLink'] = get_edit_post_link( $attachment->ID, 'raw' );
if ( current_user_can( 'delete_post', $attachment->ID ) ) {
$response['nonces']['delete'] = wp_create_nonce( 'delete-post_' . $attachment->ID );
if ( $meta && ( 'image' === $type || ! empty( $meta['sizes'] ) ) ) {
/** This filter is documented in wp-admin/includes/media.php */
$possible_sizes = apply_filters(
'image_size_names_choose',
'thumbnail' => __( 'Thumbnail' ),
'medium' => __( 'Medium' ),
'large' => __( 'Large' ),
'full' => __( 'Full Size' ),
unset( $possible_sizes['full'] );
* Loop through all potential sizes that may be chosen. Try to do this with some efficiency.
* First: run the image_downsize filter. If it returns something, we can use its data.
* If the filter does not return something, then image_downsize() is just an expensive way
* to check the image metadata, which we do second.
foreach ( $possible_sizes as $size => $label ) {
/** This filter is documented in wp-includes/media.php */
$downsize = apply_filters( 'image_downsize', false, $attachment->ID, $size );
if ( empty( $downsize[3] ) ) {
'height' => $downsize[2],
'orientation' => $downsize[2] > $downsize[1] ? 'portrait' : 'landscape',
} elseif ( isset( $meta['sizes'][ $size ] ) ) {
// Nothing from the filter, so consult image metadata if we have it.
$size_meta = $meta['sizes'][ $size ];
// We have the actual image size, but might need to further constrain it if content_width is narrower.
// Thumbnail, medium, and full sizes are also checked against the site's height/width options.
list( $width, $height ) = image_constrain_size_for_editor( $size_meta['width'], $size_meta['height'], $size, 'edit' );
'url' => $base_url . $size_meta['file'],
'orientation' => $height > $width ? 'portrait' : 'landscape',
if ( 'image' === $type ) {
if ( ! empty( $meta['original_image'] ) ) {
$response['originalImageURL'] = wp_get_original_image_url( $attachment->ID );
$response['originalImageName'] = wp_basename( wp_get_original_image_path( $attachment->ID ) );
$sizes['full'] = array( 'url' => $attachment_url );
if ( isset( $meta['height'], $meta['width'] ) ) {
$sizes['full']['height'] = $meta['height'];
$sizes['full']['width'] = $meta['width'];
$sizes['full']['orientation'] = $meta['height'] > $meta['width'] ? 'portrait' : 'landscape';
$response = array_merge( $response, $sizes['full'] );
} elseif ( $meta['sizes']['full']['file'] ) {
'url' => $base_url . $meta['sizes']['full']['file'],
'height' => $meta['sizes']['full']['height'],
'width' => $meta['sizes']['full']['width'],
'orientation' => $meta['sizes']['full']['height'] > $meta['sizes']['full']['width'] ? 'portrait' : 'landscape',
$response = array_merge( $response, array( 'sizes' => $sizes ) );
if ( $meta && 'video' === $type ) {
if ( isset( $meta['width'] ) ) {
$response['width'] = (int) $meta['width'];
if ( isset( $meta['height'] ) ) {
$response['height'] = (int) $meta['height'];
if ( $meta && ( 'audio' === $type || 'video' === $type ) ) {
if ( isset( $meta['length_formatted'] ) ) {
$response['fileLength'] = $meta['length_formatted'];
$response['fileLengthHumanReadable'] = human_readable_duration( $meta['length_formatted'] );
$response['meta'] = array();
foreach ( wp_get_attachment_id3_keys( $attachment, 'js' ) as $key => $label ) {
$response['meta'][ $key ] = false;
if ( ! empty( $meta[ $key ] ) ) {
$response['meta'][ $key ] = $meta[ $key ];
$id = get_post_thumbnail_id( $attachment->ID );
list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'full' );
$response['image'] = compact( 'src', 'width', 'height' );
list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'thumbnail' );
$response['thumb'] = compact( 'src', 'width', 'height' );
$src = wp_mime_type_icon( $attachment->ID );
$response['image'] = compact( 'src', 'width', 'height' );
$response['thumb'] = compact( 'src', 'width', 'height' );
if ( function_exists( 'get_compat_media_markup' ) ) {
$response['compat'] = get_compat_media_markup( $attachment->ID, array( 'in_modal' => true ) );
if ( function_exists( 'get_media_states' ) ) {
$media_states = get_media_states( $attachment );
if ( ! empty( $media_states ) ) {
$response['mediaStates'] = implode( ', ', $media_states );
* Filters the attachment data prepared for JavaScript.
* @param array $response Array of prepared attachment data. @see wp_prepare_attachment_for_js().
* @param WP_Post $attachment Attachment object.
* @param array|false $meta Array of attachment meta data, or false if there is none.
return apply_filters( 'wp_prepare_attachment_for_js', $response, $attachment, $meta );
* Enqueues all scripts, styles, settings, and templates necessary to use
* @global int $content_width
* @global wpdb $wpdb WordPress database abstraction object.
* @global WP_Locale $wp_locale WordPress date and time locale object.
* Arguments for enqueuing media scripts.
* @type int|WP_Post A post object or ID.
function wp_enqueue_media( $args = array() ) {
// Enqueue me just once per page, please.
if ( did_action( 'wp_enqueue_media' ) ) {
global $content_width, $wpdb, $wp_locale;
$args = wp_parse_args( $args, $defaults );
// We're going to pass the old thickbox media tabs to `media_upload_tabs`
// to ensure plugins will work. We will then unset those tabs.
// handler action suffix => tab label
/** This filter is documented in wp-admin/includes/media.php */
$tabs = apply_filters( 'media_upload_tabs', $tabs );
unset( $tabs['type'], $tabs['type_url'], $tabs['gallery'], $tabs['library'] );
'link' => get_option( 'image_default_link_type' ), // DB default is 'file'.
'align' => get_option( 'image_default_align' ), // Empty default.
'size' => get_option( 'image_default_size' ), // Empty default.
$exts = array_merge( wp_get_audio_extensions(), wp_get_video_extensions() );
$mimes = get_allowed_mime_types();
foreach ( $exts as $ext ) {
foreach ( $mimes as $ext_preg => $mime_match ) {
if ( preg_match( '#' . $ext . '#i', $ext_preg ) ) {
$ext_mimes[ $ext ] = $mime_match;
* Allows showing or hiding the "Create Audio Playlist" button in the media library.
* By default, the "Create Audio Playlist" button will always be shown in
* the media library. If this filter returns `null`, a query will be run
* to determine whether the media library contains any audio items. This
* was the default behavior prior to version 4.8.0, but this query is
* expensive for large media libraries.
* @since 4.8.0 The filter's default value is `true` rather than `null`.
* @link https://core.trac.wordpress.org/ticket/31071
* @param bool|null $show Whether to show the button, or `null` to decide based
* on whether any audio files exist in the media library.
$show_audio_playlist = apply_filters( 'media_library_show_audio_playlist', true );
if ( null === $show_audio_playlist ) {
$show_audio_playlist = $wpdb->get_var(
WHERE post_type = 'attachment'
AND post_mime_type LIKE 'audio%'
* Allows showing or hiding the "Create Video Playlist" button in the media library.
* By default, the "Create Video Playlist" button will always be shown in
* the media library. If this filter returns `null`, a query will be run
* to determine whether the media library contains any video items. This
* was the default behavior prior to version 4.8.0, but this query is
* expensive for large media libraries.
* @since 4.8.0 The filter's default value is `true` rather than `null`.
* @link https://core.trac.wordpress.org/ticket/31071
* @param bool|null $show Whether to show the button, or `null` to decide based
* on whether any video files exist in the media library.
$show_video_playlist = apply_filters( 'media_library_show_video_playlist', true );
if ( null === $show_video_playlist ) {
$show_video_playlist = $wpdb->get_var(
WHERE post_type = 'attachment'
AND post_mime_type LIKE 'video%'
* Allows overriding the list of months displayed in the media library.
* By default (if this filter does not return an array), a query will be
* run to determine the months that have media items. This query can be
* expensive for large media libraries, so it may be desirable for sites to
* override this behavior.
* @link https://core.trac.wordpress.org/ticket/31071
* @param array|null $months An array of objects with `month` and `year`
* properties, or `null` (or any other non-array value)
$months = apply_filters( 'media_library_months_with_files', null );
if ( ! is_array( $months ) ) {
$months = $wpdb->get_results(
SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
foreach ( $months as $month_year ) {
$month_year->text = sprintf(
/* translators: 1: Month, 2: Year. */
$wp_locale->get_month( $month_year->month ),
'tabUrl' => add_query_arg( array( 'chromeless' => true ), admin_url( 'media-upload.php' ) ),
'mimeTypes' => wp_list_pluck( get_post_mime_types(), 0 ),
/** This filter is documented in wp-admin/includes/media.php */
'captions' => ! apply_filters( 'disable_captions', '' ),
'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ),
'setAttachmentThumbnail' => wp_create_nonce( 'set-attachment-thumbnail' ),
'defaultProps' => $props,
'attachmentCounts' => array(
'audio' => ( $show_audio_playlist ) ? 1 : 0,
'video' => ( $show_video_playlist ) ? 1 : 0,
'oEmbedProxyUrl' => rest_url( 'oembed/1.0/proxy' ),
'embedMimes' => $ext_mimes,
'contentWidth' => $content_width,
'mediaTrash' => MEDIA_TRASH ? 1 : 0,
if ( isset( $args['post'] ) ) {
$post = get_post( $args['post'] );
$settings['post'] = array(
'nonce' => wp_create_nonce( 'update-post_' . $post->ID ),
$thumbnail_support = current_theme_supports( 'post-thumbnails', $post->post_type ) && post_type_supports( $post->post_type, 'thumbnail' );
if ( ! $thumbnail_support && 'attachment' === $post->post_type && $post->post_mime_type ) {
if ( wp_attachment_is( 'audio', $post ) ) {
$thumbnail_support = post_type_supports( 'attachment:audio', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:audio' );
} elseif ( wp_attachment_is( 'video', $post ) ) {
$thumbnail_support = post_type_supports( 'attachment:video', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:video' );
if ( $thumbnail_support ) {
$featured_image_id = get_post_meta( $post->ID, '_thumbnail_id', true );
$settings['post']['featuredImageId'] = $featured_image_id ? $featured_image_id : -1;
$post_type_object = get_post_type_object( $post->post_type );
$post_type_object = get_post_type_object( 'post' );
'mediaFrameDefaultTitle' => __( 'Media' ),
'addMedia' => __( 'Add media' ),
'search' => __( 'Search' ),
'select' => __( 'Select' ),
'cancel' => __( 'Cancel' ),
'update' => __( 'Update' ),
'replace' => __( 'Replace' ),
'remove' => __( 'Remove' ),
* translators: This is a would-be plural string used in the media manager.
* If there is not a word you can use in your language to avoid issues with the
* lack of plural support here, turn it into "selected: %d" then translate it.
'selected' => __( '%d selected' ),
'dragInfo' => __( 'Drag and drop to reorder media files.' ),
'uploadFilesTitle' => __( 'Upload files' ),
'uploadImagesTitle' => __( 'Upload images' ),
'mediaLibraryTitle' => __( 'Media Library' ),
'insertMediaTitle' => __( 'Add media' ),
'createNewGallery' => __( 'Create a new gallery' ),
'createNewPlaylist' => __( 'Create a new playlist' ),
'createNewVideoPlaylist' => __( 'Create a new video playlist' ),
'returnToLibrary' => __( '← Go to library' ),
'allMediaItems' => __( 'All media items' ),
'allDates' => __( 'All dates' ),
'noItemsFound' => __( 'No items found.' ),
'insertIntoPost' => $post_type_object->labels->insert_into_item,
'unattached' => __( 'Unattached' ),
'mine' => _x( 'Mine', 'media items' ),
'trash' => _x( 'Trash', 'noun' ),
'uploadedToThisPost' => $post_type_object->labels->uploaded_to_this_item,
'warnDelete' => __( "You are about to permanently delete this item from your site.\nThis action cannot be undone.\n 'Cancel' to stop, 'OK' to delete." ),
'warnBulkDelete' => __( "You are about to permanently delete these items from your site.\nThis action cannot be undone.\n 'Cancel' to stop, 'OK' to delete." ),
'warnBulkTrash' => __( "You are about to trash these items.\n 'Cancel' to stop, 'OK' to delete." ),
'bulkSelect' => __( 'Bulk select' ),
'trashSelected' => __( 'Move to Trash' ),
'restoreSelected' => __( 'Restore from Trash' ),
'deletePermanently' => __( 'Delete permanently' ),
'apply' => __( 'Apply' ),
'filterByDate' => __( 'Filter by date' ),
'filterByType' => __( 'Filter by type' ),
'searchLabel' => __( 'Search' ),
'searchMediaLabel' => __( 'Search media' ), // Backward compatibility pre-5.3.
'searchMediaPlaceholder' => __( 'Search media items...' ), // Placeholder (no ellipsis), backward compatibility pre-5.3.
'mediaFound' => __( 'Number of media items found: %d' ),
'mediaFoundHasMoreResults' => __( 'Number of media items displayed: %d. Scroll the page for more results.' ),
'noMedia' => __( 'No media items found.' ),
'noMediaTryNewSearch' => __( 'No media items found. Try a different search.' ),
'attachmentDetails' => __( 'Attachment details' ),
'insertFromUrlTitle' => __( 'Insert from URL' ),
'setFeaturedImageTitle' => $post_type_object->labels->featured_image,
'setFeaturedImage' => $post_type_object->labels->set_featured_image,
'createGalleryTitle' => __( 'Create gallery' ),
'editGalleryTitle' => __( 'Edit gallery' ),
'cancelGalleryTitle' => __( '← Cancel gallery' ),
'insertGallery' => __( 'Insert gallery' ),
'updateGallery' => __( 'Update gallery' ),
'addToGallery' => __( 'Add to gallery' ),
'addToGalleryTitle' => __( 'Add to gallery' ),
'reverseOrder' => __( 'Reverse order' ),
'imageDetailsTitle' => __( 'Image details' ),
'imageReplaceTitle' => __( 'Replace image' ),
'imageDetailsCancel' => __( 'Cancel edit' ),
'editImage' => __( 'Edit image' ),
'chooseImage' => __( 'Choose image' ),
'selectAndCrop' => __( 'Select and crop' ),
'skipCropping' => __( 'Skip cropping' ),
'cropImage' => __( 'Crop image' ),
'cropYourImage' => __( 'Crop your image' ),
'cropping' => __( 'Cropping…' ),
/* translators: 1: Suggested width number, 2: Suggested height number. */
'suggestedDimensions' => __( 'Suggested image dimensions: %1$s by %2$s pixels.' ),
'cropError' => __( 'There has been an error cropping your image.' ),
'audioDetailsTitle' => __( 'Audio details' ),
'audioReplaceTitle' => __( 'Replace audio' ),
'audioAddSourceTitle' => __( 'Add audio source' ),
'audioDetailsCancel' => __( 'Cancel edit' ),
'videoDetailsTitle' => __( 'Video details' ),
'videoReplaceTitle' => __( 'Replace video' ),
'videoAddSourceTitle' => __( 'Add video source' ),
'videoDetailsCancel' => __( 'Cancel edit' ),
'videoSelectPosterImageTitle' => __( 'Select poster image' ),
'videoAddTrackTitle' => __( 'Add subtitles' ),
'playlistDragInfo' => __( 'Drag and drop to reorder tracks.' ),
'createPlaylistTitle' => __( 'Create audio playlist' ),
'editPlaylistTitle' => __( 'Edit audio playlist' ),
'cancelPlaylistTitle' => __( '← Cancel audio playlist' ),
'insertPlaylist' => __( 'Insert audio playlist' ),
'updatePlaylist' => __( 'Update audio playlist' ),
'addToPlaylist' => __( 'Add to audio playlist' ),
'addToPlaylistTitle' => __( 'Add to Audio Playlist' ),
'videoPlaylistDragInfo' => __( 'Drag and drop to reorder videos.' ),