+
+ if ( empty( $attachments ) ) {
+ return '';
+ }
+
+ if ( is_feed() ) {
+ $output = "\n";
+ foreach ( $attachments as $att_id => $attachment ) {
+ $output .= wp_get_attachment_link( $att_id ) . "\n";
+ }
+ return $output;
+ }
+
+ $outer = 22; // default padding and border of wrapper
+
+ $default_width = 640;
+ $default_height = 360;
+
+ $theme_width = empty( $content_width ) ? $default_width : ( $content_width - $outer );
+ $theme_height = empty( $content_width ) ? $default_height : round( ( $default_height * $theme_width ) / $default_width );
+
+ $data = compact( 'type' );
+
+ // don't pass strings to JSON, will be truthy in JS
+ foreach ( array( 'tracklist', 'tracknumbers', 'images', 'artists' ) as $key ) {
+ $data[$key] = filter_var( $$key, FILTER_VALIDATE_BOOLEAN );
+ }
+
+ $tracks = array();
+ foreach ( $attachments as $attachment ) {
+ $url = wp_get_attachment_url( $attachment->ID );
+ $ftype = wp_check_filetype( $url, wp_get_mime_types() );
+ $track = array(
+ 'src' => $url,
+ 'type' => $ftype['type'],
+ 'title' => $attachment->post_title,
+ 'caption' => $attachment->post_excerpt,
+ 'description' => $attachment->post_content
+ );
+
+ $track['meta'] = array();
+ $meta = wp_get_attachment_metadata( $attachment->ID );
+ if ( ! empty( $meta ) ) {
+
+ foreach ( wp_get_attachment_id3_keys( $attachment ) as $key => $label ) {
+ if ( ! empty( $meta[ $key ] ) ) {
+ $track['meta'][ $key ] = $meta[ $key ];
+ }
+ }
+
+ if ( 'video' === $type ) {
+ if ( ! empty( $meta['width'] ) && ! empty( $meta['height'] ) ) {
+ $width = $meta['width'];
+ $height = $meta['height'];
+ $theme_height = round( ( $height * $theme_width ) / $width );
+ } else {
+ $width = $default_width;
+ $height = $default_height;
+ }
+
+ $track['dimensions'] = array(
+ 'original' => compact( 'width', 'height' ),
+ 'resized' => array(
+ 'width' => $theme_width,
+ 'height' => $theme_height
+ )
+ );
+ }
+ }
+
+ if ( $images ) {
+ $id = get_post_thumbnail_id( $attachment->ID );
+ if ( ! empty( $id ) ) {
+ list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'full' );
+ $track['image'] = compact( 'src', 'width', 'height' );
+ list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'thumbnail' );
+ $track['thumb'] = compact( 'src', 'width', 'height' );
+ } else {
+ $src = wp_mime_type_icon( $attachment->ID );
+ $width = 48;
+ $height = 64;
+ $track['image'] = compact( 'src', 'width', 'height' );
+ $track['thumb'] = compact( 'src', 'width', 'height' );
+ }
+ }
+
+ $tracks[] = $track;
+ }
+ $data['tracks'] = $tracks;
+
+ $safe_type = esc_attr( $type );
+ $safe_style = esc_attr( $style );
+
+ ob_start();
+
+ if ( 1 === $instance ) {
+ /**
+ * Print and enqueue playlist scripts, styles, and JavaScript templates.
+ *
+ * @since 3.9.0
+ *
+ * @param string $type Type of playlist. Possible values are 'audio' or 'video'.
+ * @param string $style The 'theme' for the playlist. Core provides 'light' and 'dark'.
+ */
+ do_action( 'wp_playlist_scripts', $type, $style );
+ } ?>
+<div class="wp-playlist wp-<?php echo $safe_type ?>-playlist wp-playlist-<?php echo $safe_style ?>">
+ <?php if ( 'audio' === $type ): ?>
+ <div class="wp-playlist-current-item"></div>
+ <?php endif ?>
+ <<?php echo $safe_type ?> controls="controls" preload="none" width="<?php
+ echo (int) $theme_width;
+ ?>"<?php if ( 'video' === $safe_type ):
+ echo ' height="', (int) $theme_height, '"';
+ else:
+ echo ' style="visibility: hidden"';
+ endif; ?>></<?php echo $safe_type ?>>
+ <div class="wp-playlist-next"></div>
+ <div class="wp-playlist-prev"></div>
+ <noscript>
+ <ol><?php
+ foreach ( $attachments as $att_id => $attachment ) {
+ printf( '<li>%s</li>', wp_get_attachment_link( $att_id ) );
+ }
+ ?></ol>
+ </noscript>
+ <script type="application/json"><?php echo json_encode( $data ) ?></script>
+</div>
+ <?php
+ return ob_get_clean();
+}
+add_shortcode( 'playlist', 'wp_playlist_shortcode' );
+
+/**
+ * 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 ) {
+ /**
+ * Filter the Mediaelement fallback output for no-JS.
+ *
+ * @since 3.6.0
+ *
+ * @param string $output Fallback output for no-JS.
+ * @param string $url Media file 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() {
+ /**
+ * Filter the list of supported audio formats.
+ *
+ * @since 3.6.0
+ *
+ * @param array $extensions An array of support audio formats. Defaults are
+ * 'mp3', 'ogg', 'wma', 'm4a', 'wav'.
+ */
+ return apply_filters( 'wp_audio_extensions', array( 'mp3', 'ogg', 'wma', 'm4a', 'wav' ) );
+}
+
+/**
+ * Return useful keys to use to lookup data from an attachment's stored metadata.
+ *
+ * @since 3.9.0
+ *
+ * @param WP_Post $attachment The current attachment, provided for context.
+ * @param string $context The context. Accepts 'edit', 'display'. Default 'display'.
+ * @return array Key/value pairs of field keys to labels.
+ */
+function wp_get_attachment_id3_keys( $attachment, $context = 'display' ) {
+ $fields = array(
+ 'artist' => __( 'Artist' ),
+ 'album' => __( 'Album' ),
+ );
+
+ if ( 'display' === $context ) {
+ $fields['genre'] = __( 'Genre' );
+ $fields['year'] = __( 'Year' );
+ $fields['length_formatted'] = _x( 'Length', 'video or audio' );
+ }
+
+ /**
+ * Filter the editable list of keys to look up data from an attachment's metadata.
+ *
+ * @since 3.9.0
+ *
+ * @param array $fields Key/value pairs of field keys to labels.
+ * @param WP_Post $attachment Attachment object.
+ * @param string $context The context. Accepts 'edit', 'display'. Default 'display'.
+ */
+ return apply_filters( 'wp_get_attachment_id3_keys', $fields, $attachment, $context );
+}
+/**
+ * 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 audio shortcode.
+ *
+ * @type string $src URL to the source of the audio file. Default empty.
+ * @type string $loop The 'loop' attribute for the `<audio>` element. Default empty.
+ * @type string $autoplay The 'autoplay' attribute for the `<audio>` element. Default empty.
+ * @type string $preload The 'preload' attribute for the `<audio>` element. Default empty.
+ * @type string $class The 'class' attribute for the `<audio>` element. Default 'wp-audio-shortcode'.
+ * @type string $id The 'id' attribute for the `<audio>` element. Default 'audio-{$post_id}-{$instances}'.
+ * @type string $style The 'style' attribute for the `<audio>` element. Default 'width: 100%'.
+ * }
+ * @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++;
+
+ /**
+ * Filter the default audio shortcode output.
+ *
+ * If the filtered output isn't empty, it will be used instead of generating the default audio template.
+ *
+ * @since 3.6.0
+ *
+ * @param string $html Empty variable to be replaced with shortcode markup.
+ * @param array $attr Attributes of the shortcode. @see wp_audio_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' );
+ }
+
+ /**
+ * Filter the media library used for the audio shortcode.
+ *
+ * @since 3.6.0
+ *
+ * @param string $library Media library used for the audio shortcode.
+ */
+ $library = apply_filters( 'wp_audio_shortcode_library', 'mediaelement' );
+ if ( 'mediaelement' === $library && did_action( 'init' ) ) {
+ wp_enqueue_style( 'wp-mediaelement' );
+ wp_enqueue_script( 'wp-mediaelement' );
+ }
+
+ /**
+ * Filter the class attribute for the audio shortcode output container.
+ *
+ * @since 3.6.0
+ *
+ * @param string $class CSS class or list of space-separated classes.
+ */
+ $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%; visibility: hidden;',
+ );
+
+ // 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() );
+ $url = add_query_arg( '_', $instances, $$fallback );
+ $html .= sprintf( $source, $type['type'], esc_url( $url ) );
+ }
+ }
+
+ if ( 'mediaelement' === $library )
+ $html .= wp_mediaelement_fallback( $fileurl );
+ $html .= '</audio>';
+
+ /**
+ * Filter the audio shortcode output.
+ *
+ * @since 3.6.0
+ *
+ * @param string $html Audio shortcode HTML output.
+ * @param array $atts Array of audio shortcode attributes.
+ * @param string $audio Audio file.
+ * @param int $post_id Post ID.
+ * @param string $library Media library used for the audio shortcode.
+ */
+ 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() {
+ /**
+ * Filter the list of supported video formats.
+ *
+ * @since 3.6.0
+ *
+ * @param array $extensions An array of support video formats. Defaults are
+ * 'mp4', 'm4v', 'webm', 'ogv', 'wmv', 'flv'.
+ */
+ 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.
+ *
+ * @type string $src URL to the source of the video file. Default empty.
+ * @type int $height Height of the video embed in pixels. Default 360.
+ * @type int $width Width of the video embed in pixels. Default $content_width or 640.
+ * @type string $poster The 'poster' attribute for the `<video>` element. Default empty.
+ * @type string $loop The 'loop' attribute for the `<video>` element. Default empty.
+ * @type string $autoplay The 'autoplay' attribute for the `<video>` element. Default empty.
+ * @type string $preload The 'preload' attribute for the `<video>` element.
+ * Default 'metadata'.
+ * @type string $class The 'class' attribute for the `<video>` element.
+ * Default 'wp-video-shortcode'.
+ * @type string $id The 'id' attribute for the `<video>` element.
+ * Default 'video-{$post_id}-{$instances}'.
+ * }
+ * @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++;
+
+ /**
+ * Filter the default video shortcode output.
+ *
+ * If the filtered output isn't empty, it will be used instead of generating
+ * the default video template.
+ *
+ * @since 3.6.0
+ *
+ * @see wp_video_shortcode()
+ *
+ * @param string $html Empty variable to be replaced with shortcode markup.
+ * @param array $attr Attributes of the video shortcode.
+ * @param string $content Video 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',
+ 'width' => 640,
+ 'height' => 360,
+ );
+
+ foreach ( $default_types as $type )
+ $defaults_atts[$type] = '';
+
+ $atts = shortcode_atts( $defaults_atts, $attr, 'video' );
+ extract( $atts );
+
+ if ( is_admin() ) {
+ // shrink the video so it isn't huge in the admin
+ if ( $width > $defaults_atts['width'] ) {
+ $height = round( ( $height * $defaults_atts['width'] ) / $width );
+ $width = $defaults_atts['width'];
+ }
+ } else {
+ // if the video is bigger than the theme
+ if ( ! empty( $content_width ) && $width > $content_width ) {
+ $height = round( ( $height * $content_width ) / $width );
+ $width = $content_width;
+ }
+ }
+
+ $yt_pattern = '#^https?://(:?www\.)?(:?youtube\.com/watch|youtu\.be/)#';
+
+ $primary = false;
+ if ( ! empty( $src ) ) {
+ if ( ! preg_match( $yt_pattern, $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' );
+ }
+
+ /**
+ * Filter the media library used for the video shortcode.
+ *
+ * @since 3.6.0
+ *
+ * @param string $library Media library used for the video shortcode.
+ */
+ $library = apply_filters( 'wp_video_shortcode_library', 'mediaelement' );
+ if ( 'mediaelement' === $library && did_action( 'init' ) ) {
+ wp_enqueue_style( 'wp-mediaelement' );
+ wp_enqueue_script( 'wp-mediaelement' );
+ }
+
+ /**
+ * Filter the class attribute for the video shortcode output container.
+ *
+ * @since 3.6.0
+ *
+ * @param string $class CSS class or list of space-separated classes.
+ */
+ $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;
+
+ if ( 'src' === $fallback && preg_match( $yt_pattern, $src ) ) {
+ $type = array( 'type' => 'video/youtube' );
+ } else {
+ $type = wp_check_filetype( $$fallback, wp_get_mime_types() );
+ }
+ $url = add_query_arg( '_', $instances, $$fallback );
+ $html .= sprintf( $source, $type['type'], esc_url( $url ) );
+ }
+ }
+
+ if ( ! empty( $content ) ) {
+ if ( false !== strpos( $content, "\n" ) )
+ $content = str_replace( array( "\r\n", "\n", "\t" ), '', $content );
+
+ $html .= trim( $content );
+ }
+
+ if ( 'mediaelement' === $library )
+ $html .= wp_mediaelement_fallback( $fileurl );
+ $html .= '</video>';
+
+ $html = sprintf( '<div style="width: %dpx; max-width: 100%%;" class="wp-video">%s</div>', $width, $html );
+
+ /**
+ * Filter the output of the video shortcode.
+ *
+ * @since 3.6.0
+ *
+ * @param string $html Video shortcode HTML output.
+ * @param array $atts Array of video shortcode attributes.
+ * @param string $video Video file.
+ * @param int $post_id Post ID.
+ * @param string $library Media library used for the video shortcode.
+ */
+ 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.
+ *
+ * @since 2.5.0
+ * @param string $size Optional, default is 'thumbnail'. Size of image, either array or string. 0 or 'none' will default to post_title or $text;
+ * @param string $text Optional, default is false. If included, link will reflect $text variable.
+ * @return string HTML content.
+ */
+function previous_image_link($size = 'thumbnail', $text = false) {
+ adjacent_image_link(true, $size, $text);
+}
+
+/**
+ * Display next image link that has the same post parent.
+ *
+ * @since 2.5.0
+ * @param string $size Optional, default is 'thumbnail'. Size of image, either array or string. 0 or 'none' will default to post_title or $text;
+ * @param string $text Optional, default is false. If included, link will reflect $text variable.
+ * @return string HTML content.
+ */
+function next_image_link($size = 'thumbnail', $text = false) {
+ adjacent_image_link(false, $size, $text);
+}
+
+/**
+ * Display next or previous image link that has the same post parent.
+ *
+ * Retrieves the current attachment object from the $post global.
+ *
+ * @since 2.5.0
+ *
+ * @param bool $prev Optional. Default is true to display previous link, false for next.
+ */
+function adjacent_image_link($prev = true, $size = 'thumbnail', $text = false) {
+ $post = get_post();
+ $attachments = array_values( get_children( array( 'post_parent' => $post->post_parent, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order ID' ) ) );
+
+ foreach ( $attachments as $k => $attachment )
+ if ( $attachment->ID == $post->ID )
+ break;
+
+ $k = $prev ? $k - 1 : $k + 1;
+
+ $output = $attachment_id = null;
+ if ( isset( $attachments[ $k ] ) ) {
+ $attachment_id = $attachments[ $k ]->ID;
+ $output = wp_get_attachment_link( $attachment_id, $size, true, false, $text );
+ }
+
+ $adjacent = $prev ? 'previous' : 'next';
+
+ /**
+ * Filter the adjacent image link.
+ *
+ * The dynamic portion of the hook name, $adjacent, refers to the type of adjacency,
+ * either 'next', or 'previous'.
+ *
+ * @since 3.5.0
+ *
+ * @param string $output Adjacent image HTML markup.
+ * @param int $attachment_id Attachment ID
+ * @param string $size Image size.
+ * @param string $text Link text.
+ */
+ echo apply_filters( "{$adjacent}_image_link", $output, $attachment_id, $size, $text );
+}
+
+/**
+ * Retrieve taxonomies attached to the attachment.
+ *
+ * @since 2.5.0
+ *
+ * @param int|array|object $attachment Attachment ID, Attachment data array, or Attachment data object.
+ * @return array Empty array on failure. List of taxonomies on success.
+ */
+function get_attachment_taxonomies($attachment) {
+ if ( is_int( $attachment ) )
+ $attachment = get_post($attachment);
+ else if ( is_array($attachment) )
+ $attachment = (object) $attachment;
+
+ if ( ! is_object($attachment) )
+ return array();
+
+ $filename = basename($attachment->guid);
+
+ $objects = array('attachment');
+
+ if ( false !== strpos($filename, '.') )
+ $objects[] = 'attachment:' . substr($filename, strrpos($filename, '.') + 1);
+ if ( !empty($attachment->post_mime_type) ) {
+ $objects[] = 'attachment:' . $attachment->post_mime_type;
+ if ( false !== strpos($attachment->post_mime_type, '/') )
+ foreach ( explode('/', $attachment->post_mime_type) as $token )
+ if ( !empty($token) )
+ $objects[] = "attachment:$token";
+ }
+
+ $taxonomies = array();
+ foreach ( $objects as $object )
+ if ( $taxes = get_object_taxonomies($object) )
+ $taxonomies = array_merge($taxonomies, $taxes);
+
+ return array_unique($taxonomies);
+}
+
+/**
+ * Return all of the taxonomy names that are registered for attachments.
+ *
+ * Handles mime-type-specific taxonomies such as attachment:image and attachment:video.
+ *
+ * @since 3.5.0
+ * @see get_attachment_taxonomies()
+ * @uses get_taxonomies()
+ *
+ * @param string $output The type of output to return, either taxonomy 'names' or 'objects'. 'names' is the default.
+ * @return array The names of all taxonomy of $object_type.
+ */
+function get_taxonomies_for_attachments( $output = 'names' ) {
+ $taxonomies = array();
+ foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy ) {
+ foreach ( $taxonomy->object_type as $object_type ) {
+ if ( 'attachment' == $object_type || 0 === strpos( $object_type, 'attachment:' ) ) {
+ if ( 'names' == $output )
+ $taxonomies[] = $taxonomy->name;
+ else
+ $taxonomies[ $taxonomy->name ] = $taxonomy;
+ break;
+ }
+ }
+ }
+
+ return $taxonomies;
+}
+
+/**
+ * Create new GD image resource with transparency support
+ * @TODO: Deprecate if possible.
+ *
+ * @since 2.9.0
+ *
+ * @param int $width Image width
+ * @param int $height Image height
+ * @return image resource
+ */
+function wp_imagecreatetruecolor($width, $height) {
+ $img = imagecreatetruecolor($width, $height);
+ if ( is_resource($img) && function_exists('imagealphablending') && function_exists('imagesavealpha') ) {
+ imagealphablending($img, false);
+ imagesavealpha($img, true);
+ }
+ return $img;
+}
+
+/**
+ * Register an embed handler. This function should probably only be used for sites that do not support oEmbed.
+ *
+ * @since 2.9.0
+ * @see WP_Embed::register_handler()
+ */
+function wp_embed_register_handler( $id, $regex, $callback, $priority = 10 ) {
+ global $wp_embed;
+ $wp_embed->register_handler( $id, $regex, $callback, $priority );
+}
+
+/**
+ * Unregister a previously registered embed handler.
+ *
+ * @since 2.9.0
+ * @see WP_Embed::unregister_handler()
+ */
+function wp_embed_unregister_handler( $id, $priority = 10 ) {
+ global $wp_embed;
+ $wp_embed->unregister_handler( $id, $priority );
+}
+
+/**
+ * Create default array of embed parameters.
+ *
+ * The width defaults to the content width as specified by the theme. If the
+ * theme does not specify a content width, then 500px is used.
+ *
+ * The default height is 1.5 times the width, or 1000px, whichever is smaller.
+ *
+ * The 'embed_defaults' filter can be used to adjust either of these values.
+ *
+ * @since 2.9.0
+ *
+ * @return array Default embed parameters.
+ */
+function wp_embed_defaults() {
+ if ( ! empty( $GLOBALS['content_width'] ) )
+ $width = (int) $GLOBALS['content_width'];
+
+ if ( empty( $width ) )
+ $width = 500;
+
+ $height = min( ceil( $width * 1.5 ), 1000 );
+
+ /**
+ * Filter the default array of embed dimensions.
+ *
+ * @since 2.9.0
+ *
+ * @param int $width Width of the embed in pixels.
+ * @param int $height Height of the embed in pixels.
+ */
+ return apply_filters( 'embed_defaults', compact( 'width', 'height' ) );
+}
+
+/**
+ * Based on a supplied width/height example, return the biggest possible dimensions based on the max width/height.
+ *
+ * @since 2.9.0
+ * @uses wp_constrain_dimensions() This function passes the widths and the heights.
+ *
+ * @param int $example_width The width of an example embed.
+ * @param int $example_height The height of an example embed.
+ * @param int $max_width The maximum allowed width.
+ * @param int $max_height The maximum allowed height.
+ * @return array The maximum possible width and height based on the example ratio.
+ */
+function wp_expand_dimensions( $example_width, $example_height, $max_width, $max_height ) {
+ $example_width = (int) $example_width;
+ $example_height = (int) $example_height;
+ $max_width = (int) $max_width;
+ $max_height = (int) $max_height;
+
+ return wp_constrain_dimensions( $example_width * 1000000, $example_height * 1000000, $max_width, $max_height );
+}
+
+/**
+ * Attempts to fetch the embed HTML for a provided URL using oEmbed.
+ *
+ * @since 2.9.0
+ * @see WP_oEmbed
+ *
+ * @uses _wp_oembed_get_object()
+ * @uses WP_oEmbed::get_html()
+ *
+ * @param string $url The URL that should be embedded.
+ * @param array $args Additional arguments and parameters.
+ * @return bool|string False on failure or the embed HTML on success.
+ */
+function wp_oembed_get( $url, $args = '' ) {
+ require_once( ABSPATH . WPINC . '/class-oembed.php' );
+ $oembed = _wp_oembed_get_object();
+ return $oembed->get_html( $url, $args );
+}
+
+/**
+ * Adds a URL format and oEmbed provider URL pair.
+ *
+ * @since 2.9.0
+ * @see WP_oEmbed
+ *
+ * @uses _wp_oembed_get_object()
+ *
+ * @param string $format The format of URL that this provider can handle. You can use asterisks as wildcards.
+ * @param string $provider The URL to the oEmbed provider.
+ * @param boolean $regex Whether the $format parameter is in a regex format.
+ */
+function wp_oembed_add_provider( $format, $provider, $regex = false ) {
+ require_once( ABSPATH . WPINC . '/class-oembed.php' );
+ $oembed = _wp_oembed_get_object();
+ $oembed->providers[$format] = array( $provider, $regex );
+}
+
+/**
+ * Removes an oEmbed provider.
+ *
+ * @since 3.5.0
+ * @see WP_oEmbed
+ *
+ * @uses _wp_oembed_get_object()
+ *
+ * @param string $format The URL format for the oEmbed provider to remove.
+ */
+function wp_oembed_remove_provider( $format ) {
+ require_once( ABSPATH . WPINC . '/class-oembed.php' );
+
+ $oembed = _wp_oembed_get_object();
+
+ if ( isset( $oembed->providers[ $format ] ) ) {
+ unset( $oembed->providers[ $format ] );
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Determines if default embed handlers should be loaded.
+ *
+ * Checks to make sure that the embeds library hasn't already been loaded. If
+ * it hasn't, then it will load the embeds library.
+ *
+ * @since 2.9.0
+ */
+function wp_maybe_load_embeds() {
+ /**
+ * Filter whether to load the default embed handlers.
+ *
+ * Returning a falsey value will prevent loading the default embed handlers.
+ *
+ * @since 2.9.0
+ *
+ * @param bool $maybe_load_embeds Whether to load the embeds library. Default true.
+ */
+ 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' );
+
+ /**
+ * Filter the audio embed handler callback.
+ *
+ * @since 3.6.0
+ *
+ * @param callback $handler Audio embed handler callback function.
+ */
+ wp_embed_register_handler( 'audio', '#^https?://.+?\.(' . join( '|', wp_get_audio_extensions() ) . ')$#i', apply_filters( 'wp_audio_embed_handler', 'wp_embed_handler_audio' ), 9999 );
+
+ /**
+ * Filter the video embed handler callback.
+ *
+ * @since 3.6.0
+ *
+ * @param callback $handler Video embed handler callback function.
+ */
+ wp_embed_register_handler( 'video', '#^https?://.+?\.(' . join( '|', wp_get_video_extensions() ) . ')$#i', apply_filters( 'wp_video_embed_handler', 'wp_embed_handler_video' ), 9999 );
+}
+
+/**
+ * The Google Video embed handler callback. Google Video does not support oEmbed.
+ *
+ * @see WP_Embed::register_handler()
+ * @see WP_Embed::shortcode()
+ *
+ * @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_googlevideo( $matches, $attr, $url, $rawattr ) {
+ // If the user supplied a fixed width AND height, use it
+ if ( !empty($rawattr['width']) && !empty($rawattr['height']) ) {
+ $width = (int) $rawattr['width'];
+ $height = (int) $rawattr['height'];
+ } else {
+ list( $width, $height ) = wp_expand_dimensions( 425, 344, $attr['width'], $attr['height'] );
+ }
+
+ /**
+ * Filter the Google Video embed output.
+ *
+ * @since 2.9.0
+ *
+ * @param string $html Google Video HTML embed markup.
+ * @param array $matches The regex matches from the provided regex.
+ * @param array $attr An array of embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array $rawattr The original unmodified attributes.
+ */
+ return apply_filters( 'embed_googlevideo', '<embed type="application/x-shockwave-flash" src="http://video.google.com/googleplayer.swf?docid=' . esc_attr($matches[2]) . '&hl=en&fs=true" style="width:' . esc_attr($width) . 'px;height:' . esc_attr($height) . 'px" allowFullScreen="true" allowScriptAccess="always" />', $matches, $attr, $url, $rawattr );
+}
+
+/**
+ * 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 ) );
+
+ /**
+ * Filter the audio embed output.
+ *
+ * @since 3.6.0
+ *
+ * @param string $audio Audio embed output.
+ * @param array $attr An array of embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array $rawattr The original unmodified attributes.
+ */
+ return apply_filters( 'wp_embed_handler_audio', $audio, $attr, $url, $rawattr );