* @param string $file The URL of the image to download.
$allowed_extensions = apply_filters( 'image_sideload_extensions', $allowed_extensions, $file );
$allowed_extensions = array_map( 'preg_quote', $allowed_extensions );
// Set variables for storage, fix file filename for query strings.
preg_match( '/[^\?]+\.(' . implode( '|', $allowed_extensions ) . ')\b/i', $file, $matches );
return new WP_Error( 'image_sideload_failed', __( 'Invalid image URL.' ) );
$file_array['name'] = wp_basename( $matches[0] );
// Download file to temp location.
$file_array['tmp_name'] = download_url( $file );
// If error storing temporarily, return the error.
if ( is_wp_error( $file_array['tmp_name'] ) ) {
return $file_array['tmp_name'];
// Do the validation and storage stuff.
$id = media_handle_sideload( $file_array, $post_id, $desc );
// If error storing permanently, unlink.
if ( is_wp_error( $id ) ) {
@unlink( $file_array['tmp_name'] );
// Store the original attachment source in meta.
add_post_meta( $id, '_source_url', $file );
// If attachment ID was requested, return it.
if ( 'id' === $return ) {
$src = wp_get_attachment_url( $id );
// Finally, check to make sure the file has been saved, then return the HTML.
if ( 'src' === $return ) {
$alt = isset( $desc ) ? esc_attr( $desc ) : '';
$html = "<img src='$src' alt='$alt' />";
return new WP_Error( 'image_sideload_failed' );
* Retrieves the legacy media uploader form in an iframe.
function media_upload_gallery() {
if ( ! empty( $_POST ) ) {
$return = media_upload_form_handler();
if ( is_string( $return ) ) {
if ( is_array( $return ) ) {
wp_enqueue_script( 'admin-gallery' );
return wp_iframe( 'media_upload_gallery_form', $errors );
* Retrieves the legacy media library form in an iframe.
function media_upload_library() {
if ( ! empty( $_POST ) ) {
$return = media_upload_form_handler();
if ( is_string( $return ) ) {
if ( is_array( $return ) ) {
return wp_iframe( 'media_upload_library_form', $errors );
* Retrieve HTML for the image alignment radio buttons with the specified one checked.
function image_align_input_fields( $post, $checked = '' ) {
if ( empty( $checked ) ) {
$checked = get_user_setting( 'align', 'none' );
'center' => __( 'Center' ),
'right' => __( 'Right' ),
if ( ! array_key_exists( (string) $checked, $alignments ) ) {
foreach ( $alignments as $name => $label ) {
$name = esc_attr( $name );
$out[] = "<input type='radio' name='attachments[{$post->ID}][align]' id='image-align-{$name}-{$post->ID}' value='$name'" .
( $checked == $name ? " checked='checked'" : '' ) .
" /><label for='image-align-{$name}-{$post->ID}' class='align image-align-{$name}-label'>$label</label>";
return implode( "\n", $out );
* Retrieve HTML for the size radio buttons with the specified one checked.
* @param bool|string $check
function image_size_input_fields( $post, $check = '' ) {
* Filters the names and labels of the default image sizes.
* @param string[] $size_names Array of image size labels keyed by their name. Default values
* include 'Thumbnail', 'Medium', 'Large', and 'Full Size'.
$size_names = apply_filters(
'image_size_names_choose',
'thumbnail' => __( 'Thumbnail' ),
'medium' => __( 'Medium' ),
'large' => __( 'Large' ),
'full' => __( 'Full Size' ),
$check = get_user_setting( 'imgsize', 'medium' );
foreach ( $size_names as $size => $label ) {
$downsize = image_downsize( $post->ID, $size );
// Is this size selectable?
$enabled = ( $downsize[3] || 'full' === $size );
$css_id = "image-size-{$size}-{$post->ID}";
// If this size is the default but that's not available, don't select it.
$checked = " checked='checked'";
} elseif ( ! $check && $enabled && 'thumbnail' !== $size ) {
* If $check is not enabled, default to the first available size
* that's bigger than a thumbnail.
$checked = " checked='checked'";
$html = "<div class='image-size-item'><input type='radio' " . disabled( $enabled, false, false ) . "name='attachments[$post->ID][image-size]' id='{$css_id}' value='{$size}'$checked />";
$html .= "<label for='{$css_id}'>$label</label>";
// Only show the dimensions if that choice is available.
$html .= " <label for='{$css_id}' class='help'>" . sprintf( '(%d × %d)', $downsize[1], $downsize[2] ) . '</label>';
'html' => implode( "\n", $out ),
* Retrieve HTML for the Link URL buttons with the default link type as specified.
* @param string $url_type
function image_link_input_fields( $post, $url_type = '' ) {
$file = wp_get_attachment_url( $post->ID );
$link = get_attachment_link( $post->ID );
if ( empty( $url_type ) ) {
$url_type = get_user_setting( 'urlbutton', 'post' );
if ( 'file' === $url_type ) {
} elseif ( 'post' === $url_type ) {
<input type='text' class='text urlfield' name='attachments[$post->ID][url]' value='" . esc_attr( $url ) . "' /><br />
<button type='button' class='button urlnone' data-link-url=''>" . __( 'None' ) . "</button>
<button type='button' class='button urlfile' data-link-url='" . esc_attr( $file ) . "'>" . __( 'File URL' ) . "</button>
<button type='button' class='button urlpost' data-link-url='" . esc_attr( $link ) . "'>" . __( 'Attachment Post URL' ) . '</button>
* Output a textarea element for inputting an attachment caption.
* @param WP_Post $edit_post Attachment WP_Post object.
* @return string HTML markup for the textarea element.
function wp_caption_input_textarea( $edit_post ) {
// Post data is already escaped.
$name = "attachments[{$edit_post->ID}][post_excerpt]";
return '<textarea name="' . $name . '" id="' . $name . '">' . $edit_post->post_excerpt . '</textarea>';
* Retrieves the image attachment fields to edit form fields.
* @param array $form_fields
function image_attachment_fields_to_edit( $form_fields, $post ) {
* Retrieves the single non-image attachment fields to edit form fields.
* @param array $form_fields An array of attachment form fields.
* @param WP_Post $post The WP_Post attachment object.
* @return array Filtered attachment form fields.
function media_single_attachment_fields_to_edit( $form_fields, $post ) {
unset( $form_fields['url'], $form_fields['align'], $form_fields['image-size'] );
* Retrieves the post non-image attachment fields to edit form fields.
* @param array $form_fields An array of attachment form fields.
* @param WP_Post $post The WP_Post attachment object.
* @return array Filtered attachment form fields.
function media_post_single_attachment_fields_to_edit( $form_fields, $post ) {
unset( $form_fields['image_url'] );
* Filters input from media_upload_form_handler() and assigns a default
* post_title from the file name if none supplied.
* Illustrates the use of the {@see 'attachment_fields_to_save'} filter
* which can be used to add default values to any field before saving to DB.
* @param array $post The WP_Post attachment object converted to an array.
* @param array $attachment An array of attachment metadata.
* @return array Filtered attachment post object.
function image_attachment_fields_to_save( $post, $attachment ) {
if ( 'image' === substr( $post['post_mime_type'], 0, 5 ) ) {
if ( strlen( trim( $post['post_title'] ) ) == 0 ) {
$attachment_url = ( isset( $post['attachment_url'] ) ) ? $post['attachment_url'] : $post['guid'];
$post['post_title'] = preg_replace( '/\.\w+$/', '', wp_basename( $attachment_url ) );
$post['errors']['post_title']['errors'][] = __( 'Empty Title filled from filename.' );
* Retrieves the media element HTML to send to the editor.
* @param int $attachment_id
* @param array $attachment
function image_media_send_to_editor( $html, $attachment_id, $attachment ) {
$post = get_post( $attachment_id );
if ( 'image' === substr( $post->post_mime_type, 0, 5 ) ) {
$url = $attachment['url'];
$align = ! empty( $attachment['align'] ) ? $attachment['align'] : 'none';
$size = ! empty( $attachment['image-size'] ) ? $attachment['image-size'] : 'medium';
$alt = ! empty( $attachment['image_alt'] ) ? $attachment['image_alt'] : '';
$rel = ( strpos( $url, 'attachment_id' ) || get_attachment_link( $attachment_id ) === $url );
return get_image_send_to_editor( $attachment_id, $attachment['post_excerpt'], $attachment['post_title'], $align, $url, $rel, $size, $alt );
* Retrieves the attachment fields to edit form fields.
function get_attachment_fields_to_edit( $post, $errors = null ) {
$post = get_post( $post );
if ( is_array( $post ) ) {
$post = new WP_Post( (object) $post );
$image_url = wp_get_attachment_url( $post->ID );
$edit_post = sanitize_post( $post, 'edit' );
'label' => __( 'Title' ),
'value' => $edit_post->post_title,
'label' => __( 'Caption' ),
'html' => wp_caption_input_textarea( $edit_post ),
'label' => __( 'Description' ),
'value' => $edit_post->post_content,
'label' => __( 'Link URL' ),
'html' => image_link_input_fields( $post, get_option( 'image_default_link_type' ) ),
'helps' => __( 'Enter a link URL or click above for presets.' ),
'label' => __( 'Order' ),
'value' => $edit_post->menu_order,
'label' => __( 'File URL' ),
'html' => "<input type='text' class='text urlfield' readonly='readonly' name='attachments[$post->ID][url]' value='" . esc_attr( $image_url ) . "' /><br />",
'value' => wp_get_attachment_url( $post->ID ),
'helps' => __( 'Location of the uploaded file.' ),
foreach ( get_attachment_taxonomies( $post ) as $taxonomy ) {
$t = (array) get_taxonomy( $taxonomy );
if ( ! $t['public'] || ! $t['show_ui'] ) {
if ( empty( $t['label'] ) ) {
if ( empty( $t['args'] ) ) {
$terms = get_object_term_cache( $post->ID, $taxonomy );
if ( false === $terms ) {
$terms = wp_get_object_terms( $post->ID, $taxonomy, $t['args'] );
foreach ( $terms as $term ) {
$t['value'] = implode( ', ', $values );
$form_fields[ $taxonomy ] = $t;
* Merge default fields with their errors, so any key passed with the error
* (e.g. 'error', 'helps', 'value') will replace the default.
* The recursive merge is easily traversed with array casting:
* foreach ( (array) $things as $thing )
$form_fields = array_merge_recursive( $form_fields, (array) $errors );
// This was formerly in image_attachment_fields_to_edit().
if ( 'image' === substr( $post->post_mime_type, 0, 5 ) ) {
$alt = get_post_meta( $post->ID, '_wp_attachment_image_alt', true );
$form_fields['post_title']['required'] = true;
$form_fields['image_alt'] = array(
'label' => __( 'Alternative Text' ),
'helps' => __( 'Alt text for the image, e.g. “The Mona Lisa”' ),
$form_fields['align'] = array(
'label' => __( 'Alignment' ),
'html' => image_align_input_fields( $post, get_option( 'image_default_align' ) ),
$form_fields['image-size'] = image_size_input_fields( $post, get_option( 'image_default_size', 'medium' ) );
unset( $form_fields['image_alt'] );
* Filters the attachment fields to edit.
* @param array $form_fields An array of attachment form fields.
* @param WP_Post $post The WP_Post attachment object.
$form_fields = apply_filters( 'attachment_fields_to_edit', $form_fields, $post );