]> scripts.mit.edu Git - autoinstalls/wordpress.git/blobdiff - wp-includes/media.php
Wordpress 3.7
[autoinstalls/wordpress.git] / wp-includes / media.php
index 8235d460676b38d4de7fef500f7283412f10f0dd..14972380c8b239f824511145c23049ec8d9a83a5 100644 (file)
@@ -138,16 +138,16 @@ function image_downsize($id, $size = 'medium') {
        if ( !wp_attachment_is_image($id) )
                return false;
 
+       // plugins can use this to provide resize services
+       if ( $out = apply_filters( 'image_downsize', false, $id, $size ) )
+               return $out;
+
        $img_url = wp_get_attachment_url($id);
        $meta = wp_get_attachment_metadata($id);
        $width = $height = 0;
        $is_intermediate = false;
        $img_url_basename = wp_basename($img_url);
 
-       // plugins can use this to provide resize services
-       if ( $out = apply_filters('image_downsize', false, $id, $size) )
-               return $out;
-
        // try for a new style intermediate size
        if ( $intermediate = image_get_intermediate_size($id, $size) ) {
                $img_url = str_replace($img_url_basename, $intermediate['file'], $img_url);
@@ -164,7 +164,7 @@ function image_downsize($id, $size = 'medium') {
                        $is_intermediate = true;
                }
        }
-       if ( !$width && !$height && isset($meta['width'], $meta['height']) ) {
+       if ( !$width && !$height && isset( $meta['width'], $meta['height'] ) ) {
                // any other type: use the real image
                $width = $meta['width'];
                $height = $meta['height'];
@@ -284,8 +284,9 @@ function wp_constrain_dimensions( $current_width, $current_height, $max_width=0,
                // The larger ratio fits, and is likely to be a more "snug" fit.
                $ratio = $larger_ratio;
 
-       $w = intval( $current_width  * $ratio );
-       $h = intval( $current_height * $ratio );
+       // Very small dimensions may result in 0, 1 should be the minimum.
+       $w = max ( 1, intval( $current_width  * $ratio ) );
+       $h = max ( 1, intval( $current_height * $ratio ) );
 
        // Sometimes, due to rounding, we'll end up with a result like this: 465x700 in a 177x177 box is 117x176... a pixel short
        // We also have issues with recursive calls resulting in an ever-changing result. Constraining to the result of a constraint should yield the original result.
@@ -539,6 +540,7 @@ function wp_get_attachment_image_src($attachment_id, $size='thumbnail', $icon =
  * @param int $attachment_id Image attachment ID.
  * @param string $size Optional, default is 'thumbnail'.
  * @param bool $icon Optional, default is false. Whether it is an icon.
+ * @param mixed $attr Optional, attributes for the image markup.
  * @return string HTML img element or empty string on failure.
  */
 function wp_get_attachment_image($attachment_id, $size = 'thumbnail', $icon = false, $attr = '') {
@@ -639,20 +641,49 @@ function img_caption_shortcode($attr, $content = null) {
        if ( $output != '' )
                return $output;
 
-       extract(shortcode_atts(array(
-               'id'    => '',
-               'align' => 'alignnone',
-               'width' => '',
+       $atts = shortcode_atts( array(
+               'id'      => '',
+               'align'   => 'alignnone',
+               'width'   => '',
                'caption' => ''
-       ), $attr));
+       ), $attr, 'caption' );
 
-       if ( 1 > (int) $width || empty($caption) )
+       $atts['width'] = (int) $atts['width'];
+       if ( $atts['width'] < 1 || empty( $atts['caption'] ) )
                return $content;
 
-       if ( $id ) $id = 'id="' . esc_attr($id) . '" ';
-
-       return '<div ' . $id . 'class="wp-caption ' . esc_attr($align) . '" style="width: ' . (10 + (int) $width) . 'px">'
-       . do_shortcode( $content ) . '<p class="wp-caption-text">' . $caption . '</p></div>';
+       if ( ! empty( $atts['id'] ) )
+               $atts['id'] = 'id="' . esc_attr( $atts['id'] ) . '" ';
+
+       $caption_width = 10 + $atts['width'];
+
+       /**
+        * Filter the width of an image's caption.
+        *
+        * By default, the caption is 10 pixels greater than the width of the image,
+        * to prevent post content from running up against a floated image.
+        *
+        * @since 3.7.0
+        *
+        * @param int $caption_width Width in pixels. To remove this inline style, return zero.
+        * @param array $atts {
+        *     The attributes of the caption shortcode.
+        *
+        *     @type string 'id'      The ID of the div element for the caption.
+        *     @type string 'align'   The class name that aligns the caption. Default 'alignnone'.
+        *     @type int    'width'   The width of the image being captioned.
+        *     @type string 'caption' The image's caption.
+        * }
+        * @param string $content The image element, possibly wrapped in a hyperlink.
+        */
+       $caption_width = apply_filters( 'img_caption_shortcode_width', $caption_width, $atts, $content );
+
+       $style = '';
+       if ( $caption_width )
+               $style = 'style="width: ' . (int) $caption_width . 'px" ';
+
+       return '<div ' . $atts['id'] . $style . 'class="wp-caption ' . esc_attr( $atts['align'] ) . '">'
+       . do_shortcode( $content ) . '<p class="wp-caption-text">' . $atts['caption'] . '</p></div>';
 }
 
 add_shortcode('gallery', 'gallery_shortcode');
@@ -696,15 +727,16 @@ function gallery_shortcode($attr) {
        extract(shortcode_atts(array(
                'order'      => 'ASC',
                'orderby'    => 'menu_order ID',
-               'id'         => $post->ID,
+               'id'         => $post ? $post->ID : 0,
                'itemtag'    => 'dl',
                'icontag'    => 'dt',
                'captiontag' => 'dd',
                'columns'    => 3,
                'size'       => 'thumbnail',
                'include'    => '',
-               'exclude'    => ''
-       ), $attr));
+               'exclude'    => '',
+               'link'       => ''
+       ), $attr, 'gallery'));
 
        $id = intval($id);
        if ( 'RAND' == $order )
@@ -735,6 +767,15 @@ function gallery_shortcode($attr) {
 
        $itemtag = tag_escape($itemtag);
        $captiontag = tag_escape($captiontag);
+       $icontag = tag_escape($icontag);
+       $valid_tags = wp_kses_allowed_html( 'post' );
+       if ( ! isset( $valid_tags[ $itemtag ] ) )
+               $itemtag = 'dl';
+       if ( ! isset( $valid_tags[ $captiontag ] ) )
+               $captiontag = 'dd';
+       if ( ! isset( $valid_tags[ $icontag ] ) )
+               $icontag = 'dt';
+
        $columns = intval($columns);
        $itemwidth = $columns > 0 ? floor(100/$columns) : 100;
        $float = is_rtl() ? 'right' : 'left';
@@ -760,20 +801,31 @@ function gallery_shortcode($attr) {
                        #{$selector} .gallery-caption {
                                margin-left: 0;
                        }
-               </style>
-               <!-- see gallery_shortcode() in wp-includes/media.php -->";
+                       /* see gallery_shortcode() in wp-includes/media.php */
+               </style>";
        $size_class = sanitize_html_class( $size );
        $gallery_div = "<div id='$selector' class='gallery galleryid-{$id} gallery-columns-{$columns} gallery-size-{$size_class}'>";
        $output = apply_filters( 'gallery_style', $gallery_style . "\n\t\t" . $gallery_div );
 
        $i = 0;
        foreach ( $attachments as $id => $attachment ) {
-               $link = isset($attr['link']) && 'file' == $attr['link'] ? wp_get_attachment_link($id, $size, false, false) : wp_get_attachment_link($id, $size, true, false);
+               if ( ! empty( $link ) && 'file' === $link )
+                       $image_output = wp_get_attachment_link( $id, $size, false, false );
+               elseif ( ! empty( $link ) && 'none' === $link )
+                       $image_output = wp_get_attachment_image( $id, $size, false );
+               else
+                       $image_output = wp_get_attachment_link( $id, $size, true, false );
+
+               $image_meta  = wp_get_attachment_metadata( $id );
+
+               $orientation = '';
+               if ( isset( $image_meta['height'], $image_meta['width'] ) )
+                       $orientation = ( $image_meta['height'] > $image_meta['width'] ) ? 'portrait' : 'landscape';
 
                $output .= "<{$itemtag} class='gallery-item'>";
                $output .= "
-                       <{$icontag} class='gallery-icon'>
-                               $link
+                       <{$icontag} class='gallery-icon {$orientation}'>
+                               $image_output
                        </{$icontag}>";
                if ( $captiontag && trim($attachment->post_excerpt) ) {
                        $output .= "
@@ -793,6 +845,314 @@ function gallery_shortcode($attr) {
        return $output;
 }
 
+/**
+ * Provide a No-JS Flash fallback as a last resort for audio / video
+ *
+ * @since 3.6.0
+ *
+ * @param string $url
+ * @return string Fallback HTML
+ */
+function wp_mediaelement_fallback( $url ) {
+       return apply_filters( 'wp_mediaelement_fallback', sprintf( '<a href="%1$s">%1$s</a>', esc_url( $url ) ), $url );
+}
+
+/**
+ * Return a filtered list of WP-supported audio formats
+ *
+ * @since 3.6.0
+ * @return array
+ */
+function wp_get_audio_extensions() {
+       return apply_filters( 'wp_audio_extensions', array( 'mp3', 'ogg', 'wma', 'm4a', 'wav' ) );
+}
+
+/**
+ * The Audio shortcode.
+ *
+ * This implements the functionality of the Audio Shortcode for displaying
+ * WordPress mp3s in a post.
+ *
+ * @since 3.6.0
+ *
+ * @param array  $attr    Attributes of the shortcode.
+ * @param string $content Optional. Shortcode content.
+ * @return string HTML content to display audio.
+ */
+function wp_audio_shortcode( $attr, $content = '' ) {
+       $post_id = get_post() ? get_the_ID() : 0;
+
+       static $instances = 0;
+       $instances++;
+
+       /**
+        * Override the default audio shortcode.
+        *
+        * @since 3.7.0
+        *
+        * @param null              Empty variable to be replaced with shortcode markup.
+        * @param array  $attr      Attributes of the shortcode.
+        * @param string $content   Shortcode content.
+        * @param int    $instances Unique numeric ID of this audio shortcode instance.
+        */
+       $html = apply_filters( 'wp_audio_shortcode_override', '', $attr, $content, $instances );
+       if ( '' !== $html )
+               return $html;
+
+       $audio = null;
+
+       $default_types = wp_get_audio_extensions();
+       $defaults_atts = array(
+               'src'      => '',
+               'loop'     => '',
+               'autoplay' => '',
+               'preload'  => 'none'
+       );
+       foreach ( $default_types as $type )
+               $defaults_atts[$type] = '';
+
+       $atts = shortcode_atts( $defaults_atts, $attr, 'audio' );
+       extract( $atts );
+
+       $primary = false;
+       if ( ! empty( $src ) ) {
+               $type = wp_check_filetype( $src, wp_get_mime_types() );
+               if ( ! in_array( strtolower( $type['ext'] ), $default_types ) )
+                       return sprintf( '<a class="wp-embedded-audio" href="%s">%s</a>', esc_url( $src ), esc_html( $src ) );
+               $primary = true;
+               array_unshift( $default_types, 'src' );
+       } else {
+               foreach ( $default_types as $ext ) {
+                       if ( ! empty( $$ext ) ) {
+                               $type = wp_check_filetype( $$ext, wp_get_mime_types() );
+                               if ( strtolower( $type['ext'] ) === $ext )
+                                       $primary = true;
+                       }
+               }
+       }
+
+       if ( ! $primary ) {
+               $audios = get_attached_media( 'audio', $post_id );
+               if ( empty( $audios ) )
+                       return;
+
+               $audio = reset( $audios );
+               $src = wp_get_attachment_url( $audio->ID );
+               if ( empty( $src ) )
+                       return;
+
+               array_unshift( $default_types, 'src' );
+       }
+
+       $library = apply_filters( 'wp_audio_shortcode_library', 'mediaelement' );
+       if ( 'mediaelement' === $library && did_action( 'init' ) ) {
+               wp_enqueue_style( 'wp-mediaelement' );
+               wp_enqueue_script( 'wp-mediaelement' );
+       }
+
+       $atts = array(
+               'class'    => apply_filters( 'wp_audio_shortcode_class', 'wp-audio-shortcode' ),
+               'id'       => sprintf( 'audio-%d-%d', $post_id, $instances ),
+               'loop'     => $loop,
+               'autoplay' => $autoplay,
+               'preload'  => $preload,
+               'style'    => 'width: 100%',
+       );
+
+       // These ones should just be omitted altogether if they are blank
+       foreach ( array( 'loop', 'autoplay', 'preload' ) as $a ) {
+               if ( empty( $atts[$a] ) )
+                       unset( $atts[$a] );
+       }
+
+       $attr_strings = array();
+       foreach ( $atts as $k => $v ) {
+               $attr_strings[] = $k . '="' . esc_attr( $v ) . '"';
+       }
+
+       $html = '';
+       if ( 'mediaelement' === $library && 1 === $instances )
+               $html .= "<!--[if lt IE 9]><script>document.createElement('audio');</script><![endif]-->\n";
+       $html .= sprintf( '<audio %s controls="controls">', join( ' ', $attr_strings ) );
+
+       $fileurl = '';
+       $source = '<source type="%s" src="%s" />';
+       foreach ( $default_types as $fallback ) {
+               if ( ! empty( $$fallback ) ) {
+                       if ( empty( $fileurl ) )
+                               $fileurl = $$fallback;
+                       $type = wp_check_filetype( $$fallback, wp_get_mime_types() );
+                       $html .= sprintf( $source, $type['type'], esc_url( $$fallback ) );
+               }
+       }
+
+       if ( 'mediaelement' === $library )
+               $html .= wp_mediaelement_fallback( $fileurl );
+       $html .= '</audio>';
+
+       return apply_filters( 'wp_audio_shortcode', $html, $atts, $audio, $post_id, $library );
+}
+add_shortcode( 'audio', 'wp_audio_shortcode' );
+
+/**
+ * Return a filtered list of WP-supported video formats
+ *
+ * @since 3.6.0
+ * @return array
+ */
+function wp_get_video_extensions() {
+       return apply_filters( 'wp_video_extensions', array( 'mp4', 'm4v', 'webm', 'ogv', 'wmv', 'flv' ) );
+}
+
+/**
+ * The Video shortcode.
+ *
+ * This implements the functionality of the Video Shortcode for displaying
+ * WordPress mp4s in a post.
+ *
+ * @since 3.6.0
+ *
+ * @param array  $attr    Attributes of the shortcode.
+ * @param string $content Optional. Shortcode content.
+ * @return string HTML content to display video.
+ */
+function wp_video_shortcode( $attr, $content = '' ) {
+       global $content_width;
+       $post_id = get_post() ? get_the_ID() : 0;
+
+       static $instances = 0;
+       $instances++;
+
+       /**
+        * Override the default video shortcode.
+        *
+        * @since 3.7.0
+        *
+        * @param null              Empty variable to be replaced with shortcode markup.
+        * @param array  $attr      Attributes of the shortcode.
+        * @param string $content   Shortcode content.
+        * @param int    $instances Unique numeric ID of this video shortcode instance.
+        */
+       $html = apply_filters( 'wp_video_shortcode_override', '', $attr, $content, $instances );
+       if ( '' !== $html )
+               return $html;
+
+       $video = null;
+
+       $default_types = wp_get_video_extensions();
+       $defaults_atts = array(
+               'src'      => '',
+               'poster'   => '',
+               'loop'     => '',
+               'autoplay' => '',
+               'preload'  => 'metadata',
+               'height'   => 360,
+               'width'    => empty( $content_width ) ? 640 : $content_width,
+       );
+
+       foreach ( $default_types as $type )
+               $defaults_atts[$type] = '';
+
+       $atts = shortcode_atts( $defaults_atts, $attr, 'video' );
+       extract( $atts );
+
+       $w = $width;
+       $h = $height;
+       if ( is_admin() && $width > 600 )
+               $w = 600;
+       elseif ( ! is_admin() && $w > $defaults_atts['width'] )
+               $w = $defaults_atts['width'];
+
+       if ( $w < $width )
+               $height = round( ( $h * $w ) / $width );
+
+       $width = $w;
+
+       $primary = false;
+       if ( ! empty( $src ) ) {
+               $type = wp_check_filetype( $src, wp_get_mime_types() );
+               if ( ! in_array( strtolower( $type['ext'] ), $default_types ) )
+                       return sprintf( '<a class="wp-embedded-video" href="%s">%s</a>', esc_url( $src ), esc_html( $src ) );
+               $primary = true;
+               array_unshift( $default_types, 'src' );
+       } else {
+               foreach ( $default_types as $ext ) {
+                       if ( ! empty( $$ext ) ) {
+                               $type = wp_check_filetype( $$ext, wp_get_mime_types() );
+                               if ( strtolower( $type['ext'] ) === $ext )
+                                       $primary = true;
+                       }
+               }
+       }
+
+       if ( ! $primary ) {
+               $videos = get_attached_media( 'video', $post_id );
+               if ( empty( $videos ) )
+                       return;
+
+               $video = reset( $videos );
+               $src = wp_get_attachment_url( $video->ID );
+               if ( empty( $src ) )
+                       return;
+
+               array_unshift( $default_types, 'src' );
+       }
+
+       $library = apply_filters( 'wp_video_shortcode_library', 'mediaelement' );
+       if ( 'mediaelement' === $library && did_action( 'init' ) ) {
+               wp_enqueue_style( 'wp-mediaelement' );
+               wp_enqueue_script( 'wp-mediaelement' );
+       }
+
+       $atts = array(
+               'class'    => apply_filters( 'wp_video_shortcode_class', 'wp-video-shortcode' ),
+               'id'       => sprintf( 'video-%d-%d', $post_id, $instances ),
+               'width'    => absint( $width ),
+               'height'   => absint( $height ),
+               'poster'   => esc_url( $poster ),
+               'loop'     => $loop,
+               'autoplay' => $autoplay,
+               'preload'  => $preload,
+       );
+
+       // These ones should just be omitted altogether if they are blank
+       foreach ( array( 'poster', 'loop', 'autoplay', 'preload' ) as $a ) {
+               if ( empty( $atts[$a] ) )
+                       unset( $atts[$a] );
+       }
+
+       $attr_strings = array();
+       foreach ( $atts as $k => $v ) {
+               $attr_strings[] = $k . '="' . esc_attr( $v ) . '"';
+       }
+
+       $html = '';
+       if ( 'mediaelement' === $library && 1 === $instances )
+               $html .= "<!--[if lt IE 9]><script>document.createElement('video');</script><![endif]-->\n";
+       $html .= sprintf( '<video %s controls="controls">', join( ' ', $attr_strings ) );
+
+       $fileurl = '';
+       $source = '<source type="%s" src="%s" />';
+       foreach ( $default_types as $fallback ) {
+               if ( ! empty( $$fallback ) ) {
+                       if ( empty( $fileurl ) )
+                               $fileurl = $$fallback;
+                       $type = wp_check_filetype( $$fallback, wp_get_mime_types() );
+                       // m4v sometimes shows up as video/mpeg which collides with mp4
+                       if ( 'm4v' === $type['ext'] )
+                               $type['type'] = 'video/m4v';
+                       $html .= sprintf( $source, $type['type'], esc_url( $$fallback ) );
+               }
+       }
+       if ( 'mediaelement' === $library )
+               $html .= wp_mediaelement_fallback( $fileurl );
+       $html .= '</video>';
+
+       $html = sprintf( '<div style="width: %dpx; max-width: 100%%;">%s</div>', $width, $html );
+       return apply_filters( 'wp_video_shortcode', $html, $atts, $video, $post_id, $library );
+}
+add_shortcode( 'video', 'wp_video_shortcode' );
+
 /**
  * Display previous image link that has the same post parent.
  *
@@ -1042,7 +1402,7 @@ function wp_oembed_add_provider( $format, $provider, $regex = false ) {
 /**
  * Removes an oEmbed provider.
  *
- * @since 3.5
+ * @since 3.5.0
  * @see WP_oEmbed
  *
  * @uses _wp_oembed_get_object()
@@ -1074,6 +1434,8 @@ function wp_maybe_load_embeds() {
        if ( ! apply_filters( 'load_default_embeds', true ) )
                return;
        wp_embed_register_handler( 'googlevideo', '#http://video\.google\.([A-Za-z.]{2,5})/videoplay\?docid=([\d-]+)(.*?)#i', 'wp_embed_handler_googlevideo' );
+       wp_embed_register_handler( 'audio', '#^https?://.+?\.(' . join( '|', wp_get_audio_extensions() ) . ')$#i', apply_filters( 'wp_audio_embed_handler', 'wp_embed_handler_audio' ), 9999 );
+       wp_embed_register_handler( 'video', '#^https?://.+?\.(' . join( '|', wp_get_video_extensions() ) . ')$#i', apply_filters( 'wp_video_embed_handler', 'wp_embed_handler_video' ), 9999 );
 }
 
 /**
@@ -1101,12 +1463,49 @@ function wp_embed_handler_googlevideo( $matches, $attr, $url, $rawattr ) {
 }
 
 /**
- * {@internal Missing Short Description}}
+ * Audio embed handler callback.
+ *
+ * @since 3.6.0
+ *
+ * @param array $matches The regex matches from the provided regex when calling {@link wp_embed_register_handler()}.
+ * @param array $attr Embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array $rawattr The original unmodified attributes.
+ * @return string The embed HTML.
+ */
+function wp_embed_handler_audio( $matches, $attr, $url, $rawattr ) {
+       $audio = sprintf( '[audio src="%s" /]', esc_url( $url ) );
+       return apply_filters( 'wp_embed_handler_audio', $audio, $attr, $url, $rawattr );
+}
+
+/**
+ * Video embed handler callback.
+ *
+ * @since 3.6.0
+ *
+ * @param array $matches The regex matches from the provided regex when calling {@link wp_embed_register_handler()}.
+ * @param array $attr Embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array $rawattr The original unmodified attributes.
+ * @return string The embed HTML.
+ */
+function wp_embed_handler_video( $matches, $attr, $url, $rawattr ) {
+       $dimensions = '';
+       if ( ! empty( $rawattr['width'] ) && ! empty( $rawattr['height'] ) ) {
+               $dimensions .= sprintf( 'width="%d" ', (int) $rawattr['width'] );
+               $dimensions .= sprintf( 'height="%d" ', (int) $rawattr['height'] );
+       }
+       $video = sprintf( '[video %s src="%s" /]', $dimensions, esc_url( $url ) );
+       return apply_filters( 'wp_embed_handler_video', $video, $attr, $url, $rawattr );
+}
+
+/**
+ * Converts a shorthand byte value to an integer byte value.
  *
  * @since 2.3.0
  *
- * @param unknown_type $size
- * @return unknown
+ * @param string $size A shorthand byte value.
+ * @return int An integer byte value.
  */
 function wp_convert_hr_to_bytes( $size ) {
        $size  = strtolower( $size );
@@ -1121,27 +1520,11 @@ function wp_convert_hr_to_bytes( $size ) {
 }
 
 /**
- * {@internal Missing Short Description}}
- *
- * @since 2.3.0
- *
- * @param unknown_type $bytes
- * @return unknown
- */
-function wp_convert_bytes_to_hr( $bytes ) {
-       $units = array( 0 => 'B', 1 => 'kB', 2 => 'MB', 3 => 'GB' );
-       $log   = log( $bytes, 1024 );
-       $power = (int) $log;
-       $size  = pow( 1024, $log - $power );
-       return $size . $units[$power];
-}
-
-/**
- * {@internal Missing Short Description}}
+ * Determine the maximum upload size allowed in php.ini.
  *
  * @since 2.5.0
  *
- * @return unknown
+ * @return int Allowed upload size.
  */
 function wp_max_upload_size() {
        $u_bytes = wp_convert_hr_to_bytes( ini_get( 'upload_max_filesize' ) );
@@ -1164,7 +1547,7 @@ function wp_get_image_editor( $path, $args = array() ) {
        $args['path'] = $path;
 
        if ( ! isset( $args['mime_type'] ) ) {
-               $file_info  = wp_check_filetype( $args['path'] );
+               $file_info = wp_check_filetype( $args['path'] );
 
                // If $file_info['type'] is false, then we let the editor attempt to
                // figure out the file type, rather than forcing a failure based on extension.
@@ -1193,7 +1576,7 @@ function wp_get_image_editor( $path, $args = array() ) {
  * @since 3.5.0
  * @access public
  *
- * @param string|array $args Array of requirements.  Accepts { 'mime_type'=>string, 'methods'=>{string, string, ...} }
+ * @param string|array $args Array of requirements. Accepts { 'mime_type'=>string, 'methods'=>{string, string, ...} }
  * @return boolean true if an eligible editor is found; false otherwise
  */
 function wp_image_editor_supports( $args = array() ) {
@@ -1326,7 +1709,7 @@ function wp_prepare_attachment_for_js( $attachment ) {
        $response = array(
                'id'          => $attachment->ID,
                'title'       => $attachment->post_title,
-               'filename'    => basename( $attachment->guid ),
+               'filename'    => wp_basename( $attachment->guid ),
                'url'         => $attachment_url,
                'link'        => get_attachment_link( $attachment->ID ),
                'alt'         => get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true ),
@@ -1361,6 +1744,7 @@ function wp_prepare_attachment_for_js( $attachment ) {
 
        if ( $meta && 'image' === $type ) {
                $sizes = array();
+               /** This filter is documented in wp-admin/includes/media.php */
                $possible_sizes = apply_filters( 'image_size_names_choose', array(
                        'thumbnail' => __('Thumbnail'),
                        'medium'    => __('Medium'),
@@ -1391,13 +1775,8 @@ function wp_prepare_attachment_for_js( $attachment ) {
                                $size_meta = $meta['sizes'][ $size ];
 
                                // We have the actual image size, but might need to further constrain it if content_width is narrower.
-                               // This is not necessary for thumbnails and medium size.
-                               if ( 'thumbnail' == $size || 'medium' == $size ) {
-                                       $width = $size_meta['width'];
-                                       $height = $size_meta['height'];
-                               } else {
-                                       list( $width, $height ) = image_constrain_size_for_editor( $size_meta['width'], $size_meta['height'], $size, 'edit' );
-                               }
+                               // 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' );
 
                                $sizes[ $size ] = array(
                                        'height'      => $height,
@@ -1408,14 +1787,25 @@ function wp_prepare_attachment_for_js( $attachment ) {
                        }
                }
 
-               $sizes['full'] = array(
-                       'height'      => $meta['height'],
-                       'width'       => $meta['width'],
-                       'url'         => $attachment_url,
-                       'orientation' => $meta['height'] > $meta['width'] ? 'portrait' : 'landscape',
-               );
+               $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, array( 'sizes' => $sizes ), $sizes['full'] );
+       } elseif ( $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'];
        }
 
        if ( function_exists('get_compat_media_markup') )
@@ -1431,6 +1821,11 @@ function wp_prepare_attachment_for_js( $attachment ) {
  * @since 3.5.0
  */
 function wp_enqueue_media( $args = array() ) {
+
+       // Enqueue me just once per page, please.
+       if ( did_action( 'wp_enqueue_media' ) )
+               return;
+
        $defaults = array(
                'post' => null,
        );
@@ -1449,6 +1844,12 @@ function wp_enqueue_media( $args = array() ) {
        $tabs = apply_filters( 'media_upload_tabs', $tabs );
        unset( $tabs['type'], $tabs['type_url'], $tabs['gallery'], $tabs['library'] );
 
+       $props = array(
+               '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
+       );
+
        $settings = array(
                'tabs'      => $tabs,
                'tabUrl'    => add_query_arg( array( 'chromeless' => true ), admin_url('media-upload.php') ),
@@ -1460,6 +1861,8 @@ function wp_enqueue_media( $args = array() ) {
                'post'    => array(
                        'id' => 0,
                ),
+               'defaultProps' => $props,
+               'embedExts'    => array_merge( wp_get_audio_extensions(), wp_get_video_extensions() ),
        );
 
        $post = null;
@@ -1542,3 +1945,147 @@ function wp_enqueue_media( $args = array() ) {
 
        do_action( 'wp_enqueue_media' );
 }
+
+/**
+ * Retrieve media attached to the passed post
+ *
+ * @since 3.6.0
+ *
+ * @param string $type (Mime) type of media desired
+ * @param mixed $post Post ID or object
+ * @return array Found attachments
+ */
+function get_attached_media( $type, $post = 0 ) {
+       if ( ! $post = get_post( $post ) )
+               return array();
+
+       $args = array(
+               'post_parent' => $post->ID,
+               'post_type' => 'attachment',
+               'post_mime_type' => $type,
+               'posts_per_page' => -1,
+               'orderby' => 'menu_order',
+               'order' => 'ASC',
+       );
+
+       $args = apply_filters( 'get_attached_media_args', $args, $type, $post );
+
+       $children = get_children( $args );
+
+       return (array) apply_filters( 'get_attached_media', $children, $type, $post );
+}
+
+/**
+ * Check the content blob for an <audio>, <video> <object>, <embed>, or <iframe>
+ *
+ * @since 3.6.0
+ *
+ * @param string $content A string which might contain media data.
+ * @param array $types array of media types: 'audio', 'video', 'object', 'embed', or 'iframe'
+ * @return array A list of found HTML media embeds
+ */
+function get_media_embedded_in_content( $content, $types = null ) {
+       $html = array();
+       $allowed_media_types = array( 'audio', 'video', 'object', 'embed', 'iframe' );
+       if ( ! empty( $types ) ) {
+               if ( ! is_array( $types ) )
+                       $types = array( $types );
+               $allowed_media_types = array_intersect( $allowed_media_types, $types );
+       }
+
+       foreach ( $allowed_media_types as $tag ) {
+               if ( preg_match( '#' . get_tag_regex( $tag ) . '#', $content, $matches ) ) {
+                       $html[] = $matches[0];
+               }
+       }
+
+       return $html;
+}
+
+/**
+ * Retrieve galleries from the passed post's content
+ *
+ * @since 3.6.0
+ *
+ * @param mixed $post Optional. Post ID or object.
+ * @param boolean $html Whether to return HTML or data in the array
+ * @return array A list of arrays, each containing gallery data and srcs parsed
+ *             from the expanded shortcode
+ */
+function get_post_galleries( $post, $html = true ) {
+       if ( ! $post = get_post( $post ) )
+               return array();
+
+       if ( ! has_shortcode( $post->post_content, 'gallery' ) )
+               return array();
+
+       $galleries = array();
+       if ( preg_match_all( '/' . get_shortcode_regex() . '/s', $post->post_content, $matches, PREG_SET_ORDER ) ) {
+               foreach ( $matches as $shortcode ) {
+                       if ( 'gallery' === $shortcode[2] ) {
+                               $srcs = array();
+                               $count = 1;
+
+                               $gallery = do_shortcode_tag( $shortcode );
+                               if ( $html ) {
+                                       $galleries[] = $gallery;
+                               } else {
+                                       preg_match_all( '#src=([\'"])(.+?)\1#is', $gallery, $src, PREG_SET_ORDER );
+                                       if ( ! empty( $src ) ) {
+                                               foreach ( $src as $s )
+                                                       $srcs[] = $s[2];
+                                       }
+
+                                       $data = shortcode_parse_atts( $shortcode[3] );
+                                       $data['src'] = array_values( array_unique( $srcs ) );
+                                       $galleries[] = $data;
+                               }
+                       }
+               }
+       }
+
+       return apply_filters( 'get_post_galleries', $galleries, $post );
+}
+
+/**
+ * Check a specified post's content for gallery and, if present, return the first
+ *
+ * @since 3.6.0
+ *
+ * @param mixed $post Optional. Post ID or object.
+ * @param boolean $html Whether to return HTML or data
+ * @return string|array Gallery data and srcs parsed from the expanded shortcode
+ */
+function get_post_gallery( $post = 0, $html = true ) {
+       $galleries = get_post_galleries( $post, $html );
+       $gallery = reset( $galleries );
+
+       return apply_filters( 'get_post_gallery', $gallery, $post, $galleries );
+}
+
+/**
+ * Retrieve the image srcs from galleries from a post's content, if present
+ *
+ * @since 3.6.0
+ *
+ * @param mixed $post Optional. Post ID or object.
+ * @return array A list of lists, each containing image srcs parsed
+ *             from an expanded shortcode
+ */
+function get_post_galleries_images( $post = 0 ) {
+       $galleries = get_post_galleries( $post, false );
+       return wp_list_pluck( $galleries, 'src' );
+}
+
+/**
+ * Check a post's content for galleries and return the image srcs for the first found gallery
+ *
+ * @since 3.6.0
+ *
+ * @param mixed $post Optional. Post ID or object.
+ * @return array A list of a gallery's image srcs in order
+ */
+function get_post_gallery_images( $post = 0 ) {
+       $gallery = get_post_gallery( $post, false );
+       return empty( $gallery['src'] ) ? array() : $gallery['src'];
+}