Skip to Content

video_meta()

Get video metadata from Youtube or Vimeo.

PHP November 24, 2017

Usage

PHP
nebula()->video_meta($provider, $id)

Parameters

$provider
(Required) (String) Which video service to check
Default: None

$id
(Required) (String) The ID of the video to get metadata for
Default: None

Request or provide clarification »

Examples

Trackable Youtube video iframe

PHP
<?php $youtube_data = nebula()->video_meta('youtube', 'fjh61K3hyY0'); ?>
<div class="embed-responsive embed-responsive-16by9">
    <iframe id="<?php echo $youtube_data['id']; ?>" class="youtube embed-responsive-item" width="560" height="315" title="<?php echo $youtube_data['title']; ?>" src="//www.youtube.com/embed/<?php echo $youtube_data['id']; ?>?wmode=transparent&enablejsapi=1&rel=0"></iframe>
</div>

Trackable Vimeo video iframe

PHP
<?php $vimeo_data = nebula()->video_meta('vimeo', '208432684'); ?>
<div class="embed-responsive embed-responsive-16by9">
    <iframe id="<?php echo $vimeo_data['id']; ?>" class="vimeo embed-responsive-item" src="https://player.vimeo.com/video/<?php echo $vimeo_data['id']; ?>" width="560" height="315"></iframe>
</div>

Demo




Youtube

See nebulaYoutubeTracking() for available Nebula data for Youtube videos.

Note: the enablejsapi=1 query parameter is needed for tracking to work. Nebula adds it automatically, but it is significantly faster to include it manually.

Note: it is recommended to use a title attribute on the iframe to enhance analytics reports with a video title (rather than a video ID).

Note: iframes can be lazy loaded with either hard-coded HTML (nebula-lazy class on noscript tag) or using the lazy_load() function (or one of its aliases).


() by


This video was lazy-loaded.


PHG Overview Video (2:04) by Pinckney Hugo Group
Pinckney Hugo Group is a fully integrated ad agency. We take our work seriously, but not ourselves. We work ridiculous hours. We play well with others. We're good listeners. We pride ourselves on accomplishing what others can't. And we love what we do.

Available Youtube Data

JavaScript
{
    "kind": "youtube#video",
    "etag": "_lil0468bQlfRrz2QRjjFVCly6M",
    "id": "WCtWWgtzC-c",
    "snippet": {
        "publishedAt": "2018-09-25T20:47:29Z",
        "channelId": "UCrO9BZ4TaJ4taT91y9l1oCg",
        "title": "PHG Overview Video",
        "description": "Pinckney Hugo Group is a fully integrated ad agency. We take our work seriously, but not ourselves. We work ridiculous hours. We play well with others. We're good listeners. We pride ourselves on accomplishing what others can't. And we love what we do.",
        "thumbnails": {
            "default": {
                "url": "https:\/\/i.ytimg.com\/vi\/WCtWWgtzC-c\/default.jpg",
                "width": 120,
                "height": 90
            },
            "medium": {
                "url": "https:\/\/i.ytimg.com\/vi\/WCtWWgtzC-c\/mqdefault.jpg",
                "width": 320,
                "height": 180
            },
            "high": {
                "url": "https:\/\/i.ytimg.com\/vi\/WCtWWgtzC-c\/hqdefault.jpg",
                "width": 480,
                "height": 360
            },
            "standard": {
                "url": "https:\/\/i.ytimg.com\/vi\/WCtWWgtzC-c\/sddefault.jpg",
                "width": 640,
                "height": 480
            },
            "maxres": {
                "url": "https:\/\/i.ytimg.com\/vi\/WCtWWgtzC-c\/maxresdefault.jpg",
                "width": 1280,
                "height": 720
            }
        },
        "channelTitle": "Pinckney Hugo Group",
        "categoryId": "1",
        "liveBroadcastContent": "none",
        "localized": {
            "title": "PHG Overview Video",
            "description": "Pinckney Hugo Group is a fully integrated ad agency. We take our work seriously, but not ourselves. We work ridiculous hours. We play well with others. We're good listeners. We pride ourselves on accomplishing what others can't. And we love what we do."
        }
    },
    "contentDetails": {
        "duration": "PT2M4S",
        "dimension": "2d",
        "definition": "hd",
        "caption": "false",
        "licensedContent": false,
        "contentRating": {},
        "projection": "rectangular"
    },
    "statistics": {
        "viewCount": "1034",
        "favoriteCount": "0",
        "commentCount": "0"
    }
}


Vimeo

See nebulaVimeoTracking() for available Nebula data for Vimeo videos.

Note: Nebula tracking prefers the Vimeo ID to be entered as a data attribute data-vimeo-id to match the Vimeo video ID (which will be a number). It also accepts this as the iframe ID and ultimately modifies the ID itself. If needing to select the iframe with CSS, you'll need to escape the ID selector.

Note: the query parameters api and player_id are no longer needed. In fact, they will prevent video tracking from working, so they must be removed!

Note: iframes can be lazy loaded with either hard-coded HTML (nebula-lazy class on noscript tag) or using the lazy_load() function (or one of its aliases).


NORTHBOUND | Skateboarding on Frozen Sand 4K (8:38) by Graham Film
Please click the CC button in the lower right hand corner for English subtitles.

See the full length documentary about the project here: https://vimeo.com/ondemand/onthinice

Ice, driftwood, foamy waves and … skateboards? Four skaters head north to the cold Norwegian coast, applying their urban skills to a wild canvas of beach flotsam, frozen sand and pastel skies. The result is a beautiful mashup — biting winds and short days, ollies and a frozen miniramp.

Skaters:
Hermann Stene
Didrik Galasso
Henrik Lund
Karsten Kleppan

Director: Jørn Nyseth Ranum
Producer: Anders Graham
Cinematography: Lukasz Zamaro
Editors: Marta Sæverud and Jørn Nyseth Ranum
Sound Engineer: Ole Richard Korsan Stuwe
Music: Erlend Elvesveen

Make sure to follow us on Facebook: https://www.facebook.com/NorthboundSkate/

See more information about the film on www.northboundfilm.com

This film was shot using RED Dragon with Zeiss Ultra Primes.

Northbound is produced by Turbin Film www.turbinfilm.no

See the directors previous film "North of The Sun" here: https://vimeo.com/ondemand/northofthesun


This video was lazy-loaded.


California Inspires Me: Reggie Watts (3:45) by Drew Tyndell
Animation by Drew Tyndell
Music by Shannon Ferguson
Sound Production by Mooj Zadie
Special Thanks to Kevin Ferguson

California Inspires Me is a collaboration between Google Play and California Sunday Magazine.

Available Vimeo Data

JavaScript
{
    "id": 132454664,
    "title": "California Inspires Me: Reggie Watts",
    "description": "Animation by Drew Tyndell<br \/>\r\nMusic by Shannon Ferguson<br \/>\r\nSound Production by Mooj Zadie<br \/>\r\nSpecial Thanks to Kevin Ferguson<br \/>\r\n<br \/>\r\nCalifornia Inspires Me is a collaboration between Google Play and California Sunday Magazine.",
    "url": "https:\/\/vimeo.com\/132454664",
    "upload_date": "2015-07-02 12:46:22",
    "mobile_url": "https:\/\/vimeo.com\/132454664",
    "thumbnail_small": "http:\/\/i.vimeocdn.com\/video\/525124557_100x75.jpg",
    "thumbnail_medium": "http:\/\/i.vimeocdn.com\/video\/525124557_200x150.jpg",
    "thumbnail_large": "http:\/\/i.vimeocdn.com\/video\/525124557_640.jpg",
    "user_id": 2624480,
    "user_name": "Drew Tyndell",
    "user_url": "https:\/\/vimeo.com\/drewtyndell",
    "user_portrait_small": "http:\/\/i.vimeocdn.com\/portrait\/20098251_30x30",
    "user_portrait_medium": "http:\/\/i.vimeocdn.com\/portrait\/20098251_75x75",
    "user_portrait_large": "http:\/\/i.vimeocdn.com\/portrait\/20098251_100x100",
    "user_portrait_huge": "http:\/\/i.vimeocdn.com\/portrait\/20098251_300x300",
    "stats_number_of_likes": 3627,
    "stats_number_of_plays": 101471,
    "stats_number_of_comments": 42,
    "duration": 225,
    "width": 1920,
    "height": 1080,
    "tags": "California Sunday Magazine, Reggie Watts, Google Play, Shannon Ferguson, Mooj Zadie, Kevin Ferguson, Drew Tyndell, Computer Team",
    "embed_privacy": "anywhere"
}


HTML5

video_meta() is not used with HTML5 videos, but for demo purposes, Google Analytics tracking, and MediaSession API it is shown here for reference. See nebulaHTML5VideoTracking() for available Nebula data for HTML5 videos.


iOS requires videos to be muted for autoplay to work. Nebula will not send events to Google Analytics for videos that have both autoplay and loop attributes.


This video was lazy-loaded.

Additional Notes

This function returns an array that includes data such as “raw”, “title”, “safetitle”, “description”, “thumbnail”, “author”, “date”, “url”, “duration” (which is an array of “time” and “seconds”).

This function includes two aliases: vimeo_meta() and youtube_meta().

Source File

Located in /libs/Functions.php on line 1201.

1 Hook

Find these filters and actions in the source code below to hook into them. Use do_action() and add_filter() in your functions file or plugin.

Filters
"pre_video_meta"
Need a new filter hook? Request one here.

Actions
This function has no action hooks available. Request one?

PHP
    public function video_meta($provider, $id){
        $override = apply_filters('pre_video_meta', null, $provider, $id);
        if ( isset($override) ){return $override;}

        $timer_name = $this->timer('Video Meta (' . $id . ')', 'start', 'Video Meta');

        $video_metadata = array(
            'origin' => $this->url_components('basedomain'),
            'id' => $id,
            'error' => false
        );

        if ( !empty($provider) ){
            $provider = strtolower($provider);
        } else {
            $video_metadata['error'] = 'Video provider is required.';
            return $video_metadata;
        }

        //Get Transients
        $video_json = get_transient('nebula_' . $provider . '_' . $id);
        if ( empty($video_json) ){ //No ?debug option here (because multiple calls are made to this function). Clear with a force true when needed.
            if ( $provider === 'youtube' ){
                if ( !$this->get_option('google_server_api_key') && $this->is_staff() ){
                    trigger_error('No Google Youtube Iframe API key. Youtube videos may not be tracked!', E_USER_WARNING);
                    echo '<script>console.warn("No Google Youtube Iframe API key. Youtube videos may not be tracked!");</script>';
                    $video_metadata['error'] = 'No Google Youtube Iframe API key.';
                }

                $response = $this->remote_get('https://www.googleapis.com/youtube/v3/videos?id=' . $id . '&part=snippet,contentDetails,statistics&key=' . $this->get_option('google_server_api_key'));
                if ( is_wp_error($response) ){
                    trigger_error('Youtube video is unavailable.', E_USER_WARNING);
                    $video_metadata['error'] = 'Youtube video is unavailable.';
                    return $video_metadata;
                }

                $video_json = $response['body'];
            } elseif ( $provider === 'vimeo' ){
                $response = $this->remote_get('http://vimeo.com/api/v2/video/' . $id . '.json');
                if ( is_wp_error($response) ){
                    trigger_error('Vimeo video is unavailable.', E_USER_WARNING);
                    $video_metadata['error'] = 'Vimeo video is unavailable.';
                    return $video_metadata;
                }

                $video_json = $response['body'];
            }

            set_transient('nebula_' . $provider . '_' . $id, $video_json, HOUR_IN_SECONDS*12); //12 hour expiration
        }
        $video_json = json_decode($video_json);

        //Check for errors
        if ( empty($video_json) ){
            if ( current_user_can('manage_options') || $this->is_dev() ){
                if ( $provider === 'youtube' ){
                    $video_metadata['error'] = 'A Youtube Data API error occurred. Make sure the Youtube Data API is enabled in the Google Developer Console and the server key is saved in Nebula Options.';
                } else {
                    $video_metadata['error'] = 'A Vimeo API error occurred (A video with ID ' . $id . ' may not exist). Tracking will not be possible.';
                }
            }
            return $video_metadata;
        } elseif ( $provider === 'youtube' && !empty($video_json->error) ){
            if ( current_user_can('manage_options') || $this->is_dev() ){
                $video_metadata['error'] = 'Youtube API Error: ' . $video_json->error->message;
            }
            return $video_metadata;
        } elseif ( $provider === 'youtube' && empty($video_json->items) ){
            if ( current_user_can('manage_options') || $this->is_dev() ){
                $video_metadata['error'] = 'A Youtube video with ID ' . $id . ' does not exist.';
            }
            return $video_metadata;
        } elseif ( $provider === 'vimeo' && is_array($video_json) && empty($video_json[0]) ){
            $video_metadata['error'] = 'A Vimeo video with ID ' . $id . ' does not exist.';
        }

        //Build Data
        if ( $provider === 'youtube' ){
            $video_metadata['raw'] = $video_json->items[0];
            $video_metadata['title'] = $video_json->items[0]->snippet->title;
            $video_metadata['safetitle'] = preg_replace('/(\W)/i', '', $video_json->items[0]->snippet->title);
            $video_metadata['description'] = $video_json->items[0]->snippet->description;
            $video_metadata['thumbnail'] = $video_json->items[0]->snippet->thumbnails->high->url;
            $video_metadata['author'] = $video_json->items[0]->snippet->channelTitle;
            $video_metadata['date'] = $video_json->items[0]->snippet->publishedAt;
            $video_metadata['url'] = 'https://www.youtube.com/watch?v=' . $id;
            $start = new DateTime('@0'); //Unix epoch
            $start->add(new DateInterval($video_json->items[0]->contentDetails->duration));
            $duration_seconds = intval($start->format('H'))*60*60 + intval($start->format('i'))*60 + intval($start->format('s'));
        } elseif ( $provider === 'vimeo' ){
            $video_metadata['raw'] = $video_json[0];
            $video_metadata['title'] = $video_json[0]->title;
            $video_metadata['safetitle'] = preg_replace('/(\W)/i', '', $video_json[0]->title);
            $video_metadata['description'] = $video_json[0]->description;
            $video_metadata['thumbnail'] = $video_json[0]->thumbnail_large;
            $video_metadata['author'] = $video_json[0]->user_name;
            $video_metadata['date'] = $video_json[0]->upload_date;
            $video_metadata['url'] = $video_json[0]->url;
            $duration_seconds = strval($video_json[0]->duration);
        }
        $video_metadata['duration'] = array(
            'time' => intval(gmdate("i", $duration_seconds)) . gmdate(":s", $duration_seconds),
            'seconds' => $duration_seconds
        );

        $this->timer($timer_name, 'end');
        return $video_metadata;
    }

Override

To override this PHP function, use this hook in your child theme or plugin ("my_custom" can be changed):

PHP
add_filter('pre_video_meta', 'my_custom_video_meta', 10, 3); //The last integer must be 1 more than the actual parameters
function my_custom_video_meta($null, $provider, $id){ //$null is required, but can be ignored
    //Write your own code here

    return true; //Return true to prevent the original function from running afterwords
}

You can completely disable this PHP function with a single line actions:

PHP
 add_filter('pre_video_meta', '__return_false');