Give themers tangible, user-friendly template functions to take full advantage of structured post formats.

* the_audio()
* the_video()
* the_image()
* get_the_media()

Also introduces:

* get_the_extra_content()
* the_extra_content()

Those two functions are like their non-extra versions, except that they
will have any post-format bits extracted. e.g. It's an image post, for
which the_image() will extract an <img /> tag. the_extra_content() will
output the content *without* that image.

props wonderboymusic. Herculean effort. fixes #23572

git-svn-id: http://core.svn.wordpress.org/trunk@23819 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Mark Jaquith 2013-03-27 18:34:59 +00:00
parent acfeb6f20f
commit 1b83157127
4 changed files with 411 additions and 78 deletions

View File

@ -887,7 +887,7 @@ function wp_audio_shortcode( $attr ) {
}
$library = apply_filters( 'wp_audio_shortcode_library', 'mediaelement' );
if ( 'mediaelement' === $library ) {
if ( 'mediaelement' === $library && did_action( 'init' ) ) {
wp_enqueue_style( 'wp-mediaelement' );
wp_enqueue_script( 'wp-mediaelement' );
}
@ -994,7 +994,7 @@ function wp_video_shortcode( $attr ) {
}
$library = apply_filters( 'wp_video_shortcode_library', 'mediaelement' );
if ( 'mediaelement' === $library ) {
if ( 'mediaelement' === $library && did_action( 'init' ) ) {
wp_enqueue_style( 'wp-mediaelement' );
wp_enqueue_script( 'wp-mediaelement' );
}
@ -1828,40 +1828,50 @@ function get_attached_video( $post_id = 0 ) {
}
/**
* Extract the srcs from the post's [{media type}] <source>s
* Extract and parse {media type} shortcodes or srcs from the passed content
*
* @since 3.6.0
*
* @param string $type Type of media: audio or video
* @param string $content A string which might contain media data.
* @param boolean $html Whether to return HTML or URLs
* @param boolean $remove Whether to remove the found URL from the passed content.
* @return array A list of lists. Each item has a list of sources corresponding
* to a [{media type}]'s primary src and specified fallbacks
* @return array A list of parsed shortcodes or extracted srcs
*/
function get_content_media( $type, &$content, $remove = false ) {
$src = '';
function get_content_media( $type, &$content, $html = true, $remove = false ) {
$items = array();
$matches = array();
if ( preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER ) && ! empty( $matches ) ) {
foreach ( $matches as $shortcode ) {
if ( $type === $shortcode[2] ) {
$srcs = array();
$count = 1;
if ( $remove )
$content = str_replace( $shortcode[0], '', $content, $count );
$content =& str_replace( $shortcode[0], '', $content, $count );
$item = do_shortcode_tag( $shortcode );
preg_match_all( '#src=[\'"](.+?)[\'"]#is', $item, $src, PREG_SET_ORDER );
if ( ! empty( $src ) ) {
foreach ( $src as $s )
$srcs[] = $s[1];
$items[] = array_values( array_unique( $srcs ) );
}
$items[] = do_shortcode_tag( $shortcode );
}
}
}
return $items;
if ( $html )
return $items;
$src = '';
$data = array();
foreach ( $items as $item ) {
preg_match_all( '#src=[\'"](.+?)[\'"]#is', $item, $src, PREG_SET_ORDER );
if ( ! empty( $src ) ) {
$srcs = array();
foreach ( $src as $s )
$srcs[] = $s[1];
$data[] = array_values( array_unique( $srcs ) );
}
}
return $data;
}
/**
@ -1870,11 +1880,13 @@ function get_content_media( $type, &$content, $remove = false ) {
*
* @since 3.6.0
*
* @param string $type Type of media: audio or video
* @param string $content A string which might contain media data.
* @param boolean $remove Whether to remove the found URL from the passed content.
* @param int $limit Optional. The number of galleries to return
* @return array A list of found HTML media embeds and possibly a URL by itself
*/
function get_embedded_media( $type, &$content, $remove = false ) {
function get_embedded_media( $type, &$content, $remove = false, $limit = 0 ) {
$html = array();
$matches = '';
@ -1884,13 +1896,16 @@ function get_embedded_media( $type, &$content, $remove = false ) {
if ( $remove )
$content = str_replace( $matches[0], '', $content );
return $html;
if ( $limit > 0 && count( $html ) >= $limit )
break;
}
}
if ( ! empty( $html ) && count( $html ) >= $limit )
return $html;
$lines = explode( "\n", trim( $content ) );
$line = trim( array_shift( $lines ) );
if ( 0 === stripos( $line, 'http' ) ) {
if ( $remove )
$content = join( "\n", $lines );
@ -1901,17 +1916,18 @@ function get_embedded_media( $type, &$content, $remove = false ) {
}
/**
* Extract the srcs from the post's [audio] <source>s
* Extract the HTML or <source> srcs from the content's [audio]
*
* @since 3.6.0
*
* @param string $content A string which might contain audio data.
* @param boolean $html Whether to return HTML or URLs
* @param boolean $remove Whether to remove the found URL from the passed content.
* @return array A list of lists. Each item has a list of sources corresponding
* to a [audio]'s primary src and specified fallbacks
* @return array A list of lists. Each item has a list of HTML or srcs corresponding
* to an [audio]'s HTML or primary src and specified fallbacks
*/
function get_content_audio( &$content, $remove = false ) {
return get_content_media( 'audio', $content, $remove );
function get_content_audio( &$content, $html = true, $remove = false ) {
return get_content_media( 'audio', $content, $html, $remove );
}
/**
@ -1929,17 +1945,18 @@ function get_embedded_audio( &$content, $remove = false ) {
}
/**
* Extract the srcs from the post's [video] <source>s
* Extract the HTML or <source> srcs from the content's [video]
*
* @since 3.6.0
*
* @param string $content A string which might contain video data.
* @param boolean $html Whether to return HTML or URLs
* @param boolean $remove Whether to remove the found URL from the passed content.
* @return array A list of lists. Each item has a list of sources corresponding
* to a [video]'s primary src and specified fallbacks
* @return array A list of lists. Each item has a list of HTML or srcs corresponding
* to a [video]'s HTML or primary src and specified fallbacks
*/
function get_content_video( &$content, $remove = false ) {
return get_content_media( 'video', $content, $remove );
function get_content_video( &$content, $html = true, $remove = false ) {
return get_content_media( 'video', $content, $html, $remove );
}
/**
@ -2000,6 +2017,117 @@ function wp_video_embed( $matches, $attr, $url, $rawattr ) {
}
wp_embed_register_handler( 'wp_video_embed', '#https?://.+?\.(' . join( '|', wp_get_video_extensions() ) . ')#i', apply_filters( 'wp_video_embed_handler', 'wp_video_embed' ), 9999 );
/**
* Return suitable HTML code for output based on the content related to the global $post
* If found, remove the content from the @global $post's post_content field
*
* @since 3.6.0
*
* @param string $type Required. 'audio' or 'video'
* @param WP_Post $post Optional. Used instead of global $post when passed.
* @return string
*/
function get_the_media( $type, &$post = null ) {
global $wp_embed;
if ( empty( $post ) )
$post =& get_post();
if ( empty( $post ) )
return '';
if ( isset( $post->format_content ) )
return $post->format_content;
$count = 1;
if ( has_post_format( $type ) ) {
$meta = get_post_format_meta( $post->ID );
if ( ! empty( $meta['media'] ) ) {
if ( is_numeric( $meta['media'] ) ) {
$url = wp_get_attachment_url( $meta['media'] );
$shortcode = sprintf( '[%s src="%s"]', $type, $url );
} elseif ( preg_match( '/' . get_shortcode_regex() . '/s', $meta['media'] ) ) {
$shortcode = $meta['media'];
} elseif ( preg_match( '#<[^>]+>#', $meta['media'] ) ) {
$post->format_content = $meta['media'];
return $post->format_content;
} elseif ( 0 === strpos( $meta['media'], 'http' ) ) {
$post->split_content = str_replace( $meta['media'], '', $post->post_content, $count );
if ( strstr( $meta['media'], home_url() ) ) {
$shortcode = sprintf( '[%s src="%s"]', $type, $meta['media'] );
} else {
$post->format_content = $wp_embed->autoembed( $meta['media'] );
return $post->format_content;
}
}
if ( ! empty( $shortcode ) ) {
$post->format_content = do_shortcode( $shortcode );
return $post->format_content;
}
}
}
$medias = call_user_func( 'get_attached_' . $type );
if ( ! empty( $medias ) ) {
$media = reset( $medias );
$url = wp_get_attachment_url( $media->ID );
$shortcode = sprintf( '[%s src="%s"]', $type, $url );
$post->format_content = do_shortcode( $shortcode );
return $post->format_content;
}
// these functions expected a reference, not a value
$_content = $post->post_content;
$content =& $_content;
$htmls = get_content_media( $type, $content, true, true );
if ( ! empty( $htmls ) ) {
$html = reset( $htmls );
$post->split_content = $content;
$post->format_content = $html;
return $post->format_content;
}
$embeds = get_embedded_media( $type, $content, true, 1 );
if ( ! empty( $embeds ) ) {
$embed = reset( $embeds );
$post->split_content = $content;
if ( 0 === strpos( $embed, 'http' ) ) {
if ( strstr( $embed, home_url() ) ) {
$post->format_content = do_shortcode( sprintf( '[%s src="%s"]', $type, $embed ) );
} else {
$post->format_content = $wp_embed->autoembed( $embed );
}
} else {
$post->format_content = $embed;
}
return $post->format_content;
}
return '';
}
/**
* Output the first video in the current (@global) post's content
*
* @since 3.6.0
*
*/
function the_video() {
echo get_the_media( 'video' );
}
/**
* Output the first audio in the current (@global) post's content
*
* @since 3.6.0
*
*/
function the_audio() {
echo get_the_media( 'audio' );
}
/**
* Retrieve images attached to the passed post
*
@ -2033,22 +2161,22 @@ function get_attached_image_srcs( $post_id = 0 ) {
}
/**
* Check the content blob for image srcs
* Check the content blob for images or image srcs
*
* @since 3.6.0
*
* @param string $content A string which might contain image data.
* @param boolean $html Whether to return HTML or URLs
* @param boolean $remove Whether to remove the found data from the passed content.
* @param int $limit Optional. The number of image srcs to return
* @return array The found image srcs
* @return array The found images or srcs
*/
function get_content_images( &$content, $remove = false, $limit = 0 ) {
$src = '';
$srcs = array();
function get_content_images( &$content, $html = true, $remove = false, $limit = 0 ) {
$matches = array();
$tags = array();
$captions = array();
if ( $remove && preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER ) && ! empty( $matches ) ) {
$captions = array();
foreach ( $matches as $shortcode ) {
if ( 'caption' === $shortcode[2] )
$captions[] = $shortcode[0];
@ -2068,12 +2196,25 @@ function get_content_images( &$content, $remove = false, $limit = 0 ) {
$content = str_replace( $tag[0], '', $content, $count );
}
preg_match( '#src=[\'"](.+?)[\'"]#is', $tag[0], $src );
if ( ! empty( $src[1] ) ) {
$srcs[] = $src[1];
if ( $limit > 0 && count( $srcs ) >= $limit )
break;
}
$tags[] = $tag[0];
if ( $limit > 0 && count( $tags ) >= $limit )
break;
}
}
if ( $html )
return $tags;
$src = '';
$srcs = array();
foreach ( $tags as $tag ) {
preg_match( '#src=[\'"](.+?)[\'"]#is', $tag, $src );
if ( ! empty( $src[1] ) ) {
$srcs[] = $src[1];
if ( $limit > 0 && count( $srcs ) >= $limit )
break;
}
}
@ -2081,16 +2222,17 @@ function get_content_images( &$content, $remove = false, $limit = 0 ) {
}
/**
* Check the content blob for image srcs and return the first
* Check the content blob for images or srcs and return the first
*
* @since 3.6.0
*
* @param string $content A string which might contain image data.
* @param boolean $html Whether to return HTML or URLs
* @param boolean $remove Whether to remove the found data from the passed content.
* @return string The found data
*/
function get_content_image( &$content, $remove = false ) {
$srcs = get_content_images( $content, $remove, 1 );
function get_content_image( &$content, $html = true, $remove = false ) {
$srcs = get_content_images( $content, $html, $remove, 1 );
if ( empty( $srcs ) )
return '';
@ -2205,4 +2347,85 @@ function get_post_gallery_images( $post_id = 0 ) {
return array();
return $gallery['src'];
}
/**
* Return the first image in the current (@global) post's content
*
* @since 3.6.0
*
* @param string $attached_size If an attached image is found, the size to display it.
* @param WP_Post $post Optional. Used instead of global $post when passed.
*/
function get_the_image( $attached_size = 'full', &$post = null ) {
if ( empty( $post ) )
$post = get_post();
if ( empty( $post ) )
return '';
if ( isset( $post->format_content ) )
return $post->format_content;
$medias = get_attached_images();
if ( ! empty( $medias ) ) {
$media = reset( $medias );
$sizes = get_intermediate_image_sizes();
$urls = array();
foreach ( $sizes as $size ) {
$urls[] = reset( wp_get_attachment_image_src( $media->ID, $size ) );
$urls[] = get_attachment_link( $media->ID );
}
$count = 1;
$matches = array();
$content =& $post->post_content;
if ( preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER ) && ! empty( $matches ) ) {
foreach ( $matches as $shortcode ) {
if ( 'caption' === $shortcode[2] ) {
foreach ( $urls as $url ) {
if ( strstr( $shortcode[0], $url ) )
$content = str_replace( $shortcode[0], '', $content, $count );
}
}
}
}
foreach ( array( 'a', 'img' ) as $tag ) {
if ( preg_match_all( '#' . get_tag_regex( $tag ) . '#', $content, $matches, PREG_SET_ORDER ) && ! empty( $matches ) ) {
foreach ( $matches as $match ) {
foreach ( $urls as $url ) {
if ( strstr( $match[0], $url ) )
$content = str_replace( $match[0], '', $content, $count );
}
}
}
}
$post->split_content = $content;
$post->format_content = wp_get_attachment_image( $media->ID, $attached_size );
return $post->format_content;
}
$content =& $post->post_content;
$htmls = get_content_images( $content, true, true, 1 );
if ( ! empty( $htmls ) ) {
$html = reset( $htmls );
$post->split_content = $content;
$post->format_content = $html;
return $post->format_content;
}
}
/**
* Output the first image in the current (@global) post's content
*
* @since 3.6.0
*
* @param string $attached_size If an attached image is found, the size to display it.
*/
function the_image( $attached_size = 'full' ) {
echo get_the_image( $attached_size );
}

View File

@ -678,3 +678,89 @@ function get_the_url( $id = 0 ) {
function the_url() {
echo esc_url( get_the_url() );
}
/**
* Retrieve the post content, minus the extracted post format content
*
* @since 3.6.0
*
* @internal there is a lot of code that could be abstracted from get_the_content()
*
* @param string $more_link_text Optional. Content for when there is more text.
* @param bool $strip_teaser Optional. Strip teaser content before the more text. Default is false.
* @return string
*/
function get_the_extra_content( $more_link_text = null, $strip_teaser = false ) {
global $more, $page, $format_pages, $multipage, $preview;
$post = get_post();
if ( null === $more_link_text )
$more_link_text = __( '(more...)' );
$output = '';
$has_teaser = false;
$matches = array();
// If post password required and it doesn't match the cookie.
if ( post_password_required() )
return get_the_password_form();
if ( $page > count( $format_pages ) ) // if the requested page doesn't exist
$page = count( $format_pages ); // give them the highest numbered page that DOES exist
$content = $format_pages[$page-1];
if ( preg_match( '/<!--more(.*?)?-->/', $content, $matches ) ) {
$content = explode( $matches[0], $content, 2 );
if ( ! empty( $matches[1] ) && ! empty( $more_link_text ) )
$more_link_text = strip_tags( wp_kses_no_null( trim( $matches[1] ) ) );
$has_teaser = true;
} else {
$content = array( $content );
}
if ( false !== strpos( $post->post_content, '<!--noteaser-->' ) && ( ! $multipage || $page == 1 ) )
$strip_teaser = true;
$teaser = $content[0];
if ( $more && $strip_teaser && $has_teaser )
$teaser = '';
$output .= $teaser;
if ( count( $content ) > 1 ) {
if ( $more ) {
$output .= '<span id="more-' . $post->ID . '"></span>' . $content[1];
} else {
if ( ! empty( $more_link_text ) )
$output .= apply_filters( 'the_content_more_link', ' <a href="' . get_permalink() . "#more-{$post->ID}\" class=\"more-link\">$more_link_text</a>", $more_link_text );
$output = force_balance_tags( $output );
}
}
if ( $preview ) // preview fix for javascript bug with foreign languages
$output = preg_replace_callback( '/\%u([0-9A-F]{4})/', '_convert_urlencoded_to_entities', $output );
return $output;
}
/**
* Display the post content minus the parsed post format data.
*
* @since 3.6.0
*
* @param string $more_link_text Optional. Content for when there is more text.
* @param bool $strip_teaser Optional. Strip teaser content before the more text. Default is false.
*/
function the_extra_content( $more_link_text = null, $strip_teaser = false ) {
$extra = get_the_extra_content( $more_link_text, $strip_teaser );
remove_filter( 'the_content', 'post_formats_compat', 7 );
$content = apply_filters( 'the_content', $extra );
add_filter( 'the_content', 'post_formats_compat', 7 );
echo str_replace( ']]>', ']]&gt;', $content );
}

View File

@ -159,13 +159,11 @@ function get_the_guid( $id = 0 ) {
* @since 0.71
*
* @param string $more_link_text Optional. Content for when there is more text.
* @param bool $stripteaser Optional. Strip teaser content before the more text. Default is false.
* @param bool $strip_teaser Optional. Strip teaser content before the more text. Default is false.
*/
function the_content($more_link_text = null, $stripteaser = false) {
$content = get_the_content($more_link_text, $stripteaser);
$content = apply_filters('the_content', $content);
$content = str_replace(']]>', ']]&gt;', $content);
echo $content;
function the_content( $more_link_text = null, $strip_teaser = false ) {
$content = apply_filters( 'the_content', get_the_content( $more_link_text, $strip_teaser ) );
echo str_replace( ']]>', ']]&gt;', $content );
}
/**
@ -177,7 +175,7 @@ function the_content($more_link_text = null, $stripteaser = false) {
* @param bool $stripteaser Optional. Strip teaser content before the more text. Default is false.
* @return string
*/
function get_the_content( $more_link_text = null, $stripteaser = false ) {
function get_the_content( $more_link_text = null, $strip_teaser = false ) {
global $more, $page, $pages, $multipage, $preview;
$post = get_post();
@ -186,43 +184,49 @@ function get_the_content( $more_link_text = null, $stripteaser = false ) {
$more_link_text = __( '(more...)' );
$output = '';
$hasTeaser = false;
$has_teaser = false;
$matches = array();
// If post password required and it doesn't match the cookie.
if ( post_password_required() )
return get_the_password_form();
if ( $page > count($pages) ) // if the requested page doesn't exist
$page = count($pages); // give them the highest numbered page that DOES exist
if ( $page > count( $pages ) ) // if the requested page doesn't exist
$page = count( $pages ); // give them the highest numbered page that DOES exist
$content = $pages[$page-1];
if ( preg_match('/<!--more(.*?)?-->/', $content, $matches) ) {
$content = explode($matches[0], $content, 2);
if ( !empty($matches[1]) && !empty($more_link_text) )
$more_link_text = strip_tags(wp_kses_no_null(trim($matches[1])));
$content = $pages[$page - 1];
if ( preg_match( '/<!--more(.*?)?-->/', $content, $matches ) ) {
$content = explode( $matches[0], $content, 2 );
if ( ! empty( $matches[1] ) && ! empty( $more_link_text ) )
$more_link_text = strip_tags( wp_kses_no_null( trim( $matches[1] ) ) );
$hasTeaser = true;
$has_teaser = true;
} else {
$content = array($content);
$content = array( $content );
}
if ( (false !== strpos($post->post_content, '<!--noteaser-->') && ((!$multipage) || ($page==1))) )
$stripteaser = true;
if ( false !== strpos( $post->post_content, '<!--noteaser-->' ) && ( ! $multipage || $page == 1 ) )
$strip_teaser = true;
$teaser = $content[0];
if ( $more && $stripteaser && $hasTeaser )
if ( $more && $strip_teaser && $has_teaser )
$teaser = '';
$output .= $teaser;
if ( count($content) > 1 ) {
if ( count( $content ) > 1 ) {
if ( $more ) {
$output .= '<span id="more-' . $post->ID . '"></span>' . $content[1];
} else {
if ( ! empty($more_link_text) )
if ( ! empty( $more_link_text ) )
$output .= apply_filters( 'the_content_more_link', ' <a href="' . get_permalink() . "#more-{$post->ID}\" class=\"more-link\">$more_link_text</a>", $more_link_text );
$output = force_balance_tags($output);
$output = force_balance_tags( $output );
}
}
if ( $preview ) // preview fix for javascript bug with foreign languages
$output = preg_replace_callback('/\%u([0-9A-F]{4})/', '_convert_urlencoded_to_entities', $output);
$output = preg_replace_callback( '/\%u([0-9A-F]{4})/', '_convert_urlencoded_to_entities', $output );
return $output;
}

View File

@ -3677,7 +3677,7 @@ function get_paged_content( $content = null, $paged = null ) {
* @return bool True when finished.
*/
function setup_postdata($post) {
global $id, $authordata, $currentday, $currentmonth, $page, $pages, $multipage, $more, $numpages;
global $id, $authordata, $currentday, $currentmonth, $page, $pages, $format_pages, $multipage, $more, $numpages;
$id = (int) $post->ID;
@ -3691,18 +3691,38 @@ function setup_postdata($post) {
$page = 1;
if ( is_single() || is_page() || is_feed() )
$more = 1;
$content = $post->post_content;
$split_content = $content = $post->post_content;
$format = get_post_format( $post );
if ( $format && in_array( $format, array( 'image', 'audio', 'video' ) ) ) {
switch ( $format ) {
case 'image':
get_the_image( 'full', $post );
if ( isset( $post->split_content ) )
$split_content = $post->split_content;
break;
case 'audio':
get_the_media( 'audio', $post );
if ( isset( $post->split_content ) )
$split_content = $post->split_content;
break;
case 'video':
get_the_media( 'video', $post );
if ( isset( $post->split_content ) )
$split_content = $post->split_content;
break;
}
}
if ( strpos( $content, '<!--nextpage-->' ) ) {
if ( $page > 1 )
$more = 1;
$multipage = 1;
$content = str_replace("\n<!--nextpage-->\n", '<!--nextpage-->', $content);
$content = str_replace("\n<!--nextpage-->", '<!--nextpage-->', $content);
$content = str_replace("<!--nextpage-->\n", '<!--nextpage-->', $content);
$pages = explode('<!--nextpage-->', $content);
$numpages = count($pages);
$pages = paginate_content( $content );
$format_pages = paginate_content( $split_content );
$numpages = count( $pages );
} else {
$pages = array( $post->post_content );
$format_pages = array( $split_content );
$multipage = 0;
}