Get first video from the post (both embed and video shortcodes)

The goal is to grab the first video (embed or shortcode) from the post.
So we need to check post content if it has embedded videos ( supported by WP ) or shortcodes. Multiple videos and embeds could exist in the single post.
If found any – return the very first of them, not depending on order of given patterns to match, but on order they have been inserted into the post.

Here is my progress so far…

This one returns first shortcode.
Is there a way to make it look for not only video shortcodes, but for embeds also?

function theme_self_hosted_videos() {
global $post;
$pattern = get_shortcode_regex();
  if ( preg_match_all( "https://wordpress.stackexchange.com/". $pattern .'/s', $post->post_content, $matches ) && array_key_exists( 2, $matches ) && in_array( 'video', $matches[2] ) ) {
    $videos = $matches[0];
    $i = 0;
    foreach ($videos as $video ) {
        if($i == 0) {
            echo do_shortcode($video);
        }
        $i++;
    }
  }
  return false;
}
add_action( 'wp', 'theme_self_hosted_videos' );

Here’s my current progress of a function to return first video embed from the post. Not working as expected, though. Obviously depends on $pattern_array order and maybe on the patterns themselves…

function theme_oembed_videos() {

global $post;

// Here is a sample array of patterns for supported video embeds from wp-includes/class-wp-embed.php
$pattern_array = array(
    '#https://youtu\.be/.*#i',
    '#https://(www\.)?youtube\.com/playlist.*#i',
    '#https://(www\.)?youtube\.com/watch.*#i',
    '#http://(www\.)?youtube\.com/watch.*#i',
    '#http://(www\.)?youtube\.com/playlist.*#i',
    '#http://youtu\.be/.*#i',
    '#https?://wordpress.tv/.*#i',
    '#https?://(.+\.)?vimeo\.com/.*#i'
);

foreach ($pattern_array as $pattern) {

    if (preg_match_all($pattern, $post->post_content, $matches)) {
        return wp_oembed_get( $matches[0] );
    }
    return false;

}

}

3 s
3

You could try mashing all the patterns together in one big regexp or and then doing a simple line by line parse of the content:

function theme_oembed_videos() {

    global $post;

    if ( $post && $post->post_content ) {

        global $shortcode_tags;
        // Make a copy of global shortcode tags - we'll temporarily overwrite it.
        $theme_shortcode_tags = $shortcode_tags;

        // The shortcodes we're interested in.
        $shortcode_tags = array(
            'video' => $theme_shortcode_tags['video'],
            'embed' => $theme_shortcode_tags['embed']
        );
        // Get the absurd shortcode regexp.
        $video_regex = '#' . get_shortcode_regex() . '#i';

        // Restore global shortcode tags.
        $shortcode_tags = $theme_shortcode_tags;

        $pattern_array = array( $video_regex );

        // Get the patterns from the embed object.
        if ( ! function_exists( '_wp_oembed_get_object' ) ) {
            include ABSPATH . WPINC . '/class-oembed.php';
        }
        $oembed = _wp_oembed_get_object();
        $pattern_array = array_merge( $pattern_array, array_keys( $oembed->providers ) );

        // Or all the patterns together.
        $pattern = '#(' . array_reduce( $pattern_array, function ( $carry, $item ) {
            if ( strpos( $item, '#' ) === 0 ) {
                // Assuming '#...#i' regexps.
                $item = substr( $item, 1, -2 );
            } else {
                // Assuming glob patterns.
                $item = str_replace( '*', '(.+)', $item );
            }
            return $carry ? $carry . ')|('  . $item : $item;
        } ) . ')#is';

        // Simplistic parse of content line by line.
        $lines = explode( "\n", $post->post_content );
        foreach ( $lines as $line ) {
            $line = trim( $line );
            if ( preg_match( $pattern, $line, $matches ) ) {
                if ( strpos( $matches[0], '[' ) === 0 ) {
                    $ret = do_shortcode( $matches[0] );
                } else {
                    $ret = wp_oembed_get( $matches[0] );
                }
                return $ret;
            }
        }
    }
}

Also you might want to use transients for the embeds – see this answer I gave.

Leave a Comment