How to Link to Specific Parts of an Embedded Vimeo Video Using Froogaloop API

By February 19, 2015 Web Development 6 Comments
how-to-link-to-specific-part-of-embeded-vimeo-video

I recently needed to create links to specific parts of embedded Vimeo videos and despite the long hours of searching Google, it was definitely not an easy task. In the end though, I was finally able to achieve the results I was looking for. I would have sure loved to come across a page like this when I was trying to do it so I decided to share what I learned in the process.

Since I can’t show you a working example on my membership site because only paying members are able to use the functionality, I have created a much more simplified version using JSFiddle. This is the complete code needed to make the links. Just click on the results tab and you will see the links in action.

In my case, I needed these links to work across multiple embedded Vimeo videos because some of the tutorials we have at Yeners Way are multiple parts. Since this made things far more complicated (seriously, took me about a week to get everything working right) and you may not even need to do this, I will spare you the details and will explain it only for a single Vimeo video.

I will go through each bit of code in the fiddle above and explain what it does. The side notes that you see in this article are just extra information on how I did it differently on my own site. If you just want clickable links, you can ignore the side notes.

So let’s get started.

The HTML

Vimeo provides a script called Froogaloop that handles API calls so the first thing to do is include the following line (I included it in header.php).

<script type="text/javascript" src="https://f.vimeocdn.com/js/froogaloop2.min.js"></script>

The next simple, but important thing to do is to make sure you are adding id=”player_1″ to the iframe of the embedded vimeo code as well as adding ?api=1&player_id=player_1 to the end of the src. Like this…

<iframe id="player_1" src="//player.vimeo.com/video/59785024?title=0&byline=0&portrait=0?api=1&player_id=player_1" width="400" height="170" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>

Here is the HTML to create the links that are clicked on. Each link has a class relative to its nature and the href’s are all javascript:void(0). Finally a span after each link will be where we will display status messages relative to the link.

<div class="links">
    02:30 - <a class="link_1" href="javascript:void(0);" target="_self">Link 1</a><span class="link_1_status"></span><br/>
    07:36 - <a class="link_2" href="javascript:void(0);" target="_self">Link 2</a><span class="link_2_status"></span><br/>
    11:05 - <a class="link_3" href="javascript:void(0);" target="_self">Link 3</a><span class="link_3_status"></span>
</div>
The Javascript

In order to be able to make the video jump to different tracking locations, we will obviously first need to know where these locations are. So lets assume that we have 3 different points to jump to. Take note that these values have to be in seconds.

var link_1_track = 150; //2:30 
var link_2_track = 456; //7:36
var link_3_track = 665; //11:05
SIDE NOTE – Retrieving track locations from custom fields in WordPress and converting #:##:## format into seconds format.

When I am editing a video (using Sony Vegas), I place markers to split up the sections, so I can later use these markers to determine the tracking locations. Since I work with tutorials, I use markers to split the video up into the different “lessons”. Then I input this data into custom fields that I have created in WordPress. I use the Advanced Custom Fields plugin where I have custom fields set up to be able to store data for 30 lessons. For each lesson, I have a name, starting point, duration and a few other things.

When I enter the values for these custom fields in WordPress, I enter them as I see them in my video editing application. So for example, Hours:Minutes:Seconds (#:##:##) and in some cases, it may only be Minutes:Seconds (##:##). So in order to track to a certain location in the embedded Vimeo video, we first need to translate these field values into seconds. Since it is unknown whether each field will contain an Hour value, Minute value or Second value, I wrote the following code to first count how many semicolons there are in each field.

$no_of_semis_in_1 = substr_count(get_field('lesson_1_tracking'), ':'); //lesson_1_tracking is the custom field in WP.

Then I use the following code to give me the tracking location in seconds format.

 
if ($no_of_semis_in_1 == 1) {
	$parts = explode(":", $lesson_1_tracking);
	$lesson_1_tracking_secs = ($parts[0] * 60 + $parts[1]);
} else if ($no_of_semis_in_2 == 2) {
	$parts = explode(":", $lesson_1_tracking); 
	$lesson_1_tracking_secs = ($parts[0] * 60 * 60 + $parts[1] * 60 + $parts[2]);
}
//Repeat for subsequent lessons/links

So then I would take the data in $lesson_#_tracking_secs over to the javascript.

When a link is clicked, we want to add a status message next to it indicating that it is being playing. So we need to declare variables for each link, that connect to a relative HTML element via it’s class.

// Variables for status messages
var link_1_status = jQuery('.link_1_status');
var link_2_status = jQuery('.link_2_status');
var link_3_status = jQuery('.link_3_status');
var main_status = jQuery('.main_status');

This will be the actual HTML that is displayed next to the link when it is clicked.

// Message displayed when link is playing
var playNotice = ' - <strong><i>Now playing...</i></strong>';

This function clears all ‘Now Playing…’ messages. We need to do run this function right before we want to display the ‘Now Playing…’ message so that there is always only one instance of it. If we don’t do this, there will be multiple ‘Now Playing’ messages after clicking on a few links.

// Function to hide all status messages
hidePlayNoticeAll = function() {
    jQuery(".link_1_status").html("");
    jQuery(".link_2_status").html("");
    jQuery(".link_3_status").html("");
}

This basically tells the Froogaloop API that your embedded video has an id of ‘player_1’.

// Load Vimeo API for the embedded video
var iframe_player = jQuery('#player_1')[0];
var player_1 = $f(iframe_player);

These listeners allow you to trigger events when the video is paused, finished or playing.

// Optional listeners for pause, finish, and playProgress
player_1.addEvent('ready', function() {
    player_1.addEvent('pause', onPause);
    player_1.addEvent('finish', onFinish);
    player_1.addEvent('playProgress', onPlayProgress);
}); 

The onPlayProgress is an important one as it is used to make sure the ‘Now Playing’ message is always next to the link section that is being played. If we don’t use the playProgress event, than here’s what would happen…The user would click on a link and start watching. After the video plays past the point of another link, the status message will not move down to the next link. Not good. This is why it’s a good idea to use the playProgress event if you want to display ‘Now Playing’ status messages. Please refer to the comments within the code to see what each line does.

// Functions for each listener event
function onPause(id) { // When the video is paused, do this.
    jQuery(".main_status").html('Paused');
}
function onFinish(id) { // When the video is finished, do this.
    jQuery(".main_status").html('Finished');
}
function onPlayProgress(data, id) { // While the video is playing, do this.
    jQuery(".main_status").html('Playing - ' + data.seconds + 's played'); // data.percent can also be used.

   if (data.seconds < link_1_track) {hidePlayNoticeAll();}
    
    //this will ensure that the 'Now playing' message automatically moves to the next link when the video plays through. 
    //Otherwise, it will always stay next to the link that was last clicked.
    if (data.seconds > link_1_track && data.seconds < link_2_track){
        hidePlayNoticeAll();
        jQuery(".link_1_status").html(playNotice);
    }
    if (data.seconds > link_2_track && data.seconds < link_3_track){
        hidePlayNoticeAll();
        jQuery(".link_2_status").html(playNotice);
    }
    if (data.seconds > link_3_track){
        hidePlayNoticeAll();
        jQuery(".link_3_status").html(playNotice);
    }
}
SIDE NOTE
For my own situation, I heavily used the onPlayProgress function to do a lot of different things that are outside the scope of this tutorial. Basically I created some rewind and fast forward skip buttons as well as some repeat functions so that the video would loop for 30 or 60 seconds as long as the relevant repeat button was activated. Here’s a screenshot of what I mean.

action-buttons-shot
If you want to know how I did this, please contact me and I will try to help.

Finally, here is the function that makes the links clickable. As can see from the comments in the link_1 function…when the user clicks on a link, first the video plays, then it seeks to the designated location, then it clears all status messages and finally displays the Now Playing message next to the clicked link.

// Function to control what happens when each lesson link is clicked
function setupLinks() {
        
    jQuery(".link_1").click(function () {
        player_1.api('play'); //Play the video
        player_1.api('seekTo', link_1_track); //Seek to the number of seconds in the variable link_1_track
        hidePlayNoticeAll(); // Hide all status messages before displaying (to prevent them from sticking) 
        jQuery(".link_1_status").html(playNotice); //Display status message (playNotice) within span with class link_1_status
    });
    
    jQuery(".link_2").click(function () {
        player_1.api('play');
        player_1.api('seekTo', link_2_track);
        hidePlayNoticeAll();
        jQuery(".link_2_status").html(playNotice);
    });
    
    jQuery(".link_3").click(function () {
        player_1.api('play');
        player_1.api('seekTo', link_3_track);
        hidePlayNoticeAll();
        jQuery(".link_3_status").html(playNotice);
    });
}
setupLinks();
SIDE NOTE

If you need to convert a PHP variable to a javascript variable, heres how to do it…

var JSvariable = <?php echo $PHPvariable; ?>;

Another thing to take note of is that since I have all these custom fields set up in WP (30 of them), sometimes my video might only have 10 links, and if i leave any of the 30 custom fields blank, then these variables ($lesson_#_tracking_secs) may store nothing. This is a problem and it usually shows errors in the console and prevents the whole thing from working. So to overcome this I did the following for every field. Basically it just checks if the custom field is empty, and if it is, then it sets it to 0.

$link_1_track = get_field('link_1_track');
if ($link_1_track == '') {$link_1_track = 0;}

So that’s it! As mentioned, if you want to see it in action, just scroll back to the top and click on the ‘Result’ tab of the embedded JSFiddle. This is a highly stripped down version of what I actually use at Yeners Way – Cake Art Tutorials (I have 30 links and am able to to handle up to 4 embedded videos on the same page). It gets quite complicated when you have multiple videos because you need to handle stopping another video before another one plays, as well as figuring out which embedded video each lesson refers to. If you need more information on how I got it to work with multiple videos as well as how I created the action buttons, just ask me and I will do my best to assist.

About Serkan Yener

Serkan Yener is an artist who has delved into many different forms of art. Among music production, drawing, graphic design, digital painting and sculpting, he has spent most of the last 15 years as a cake decorator. Serkan also enjoys web development and design. Recently he has put the cake decorating aside to build an online business called Yeners Way as well as pursue other artistic ventures, mainly in the realm of 3D sculpting and printing. Learn more...

  • silversands

    great tutorial serkan, just what I was looking for since my coding skils are limited. would it be possible to add an auto stop function at (multiple) specific locations? is this something you have tried in combination with this code? thx peter

  • http://www.serkanyener.com/ Serkan Yener

    Hi Peter, thanks for your comment.
    I guess you could do something like…

    function onPlayProgress(data, id) {
    if (data.seconds > 150) {
    player_1.api(‘pause’);
    //Do something else
    }
    }

    I am not sure about your particular use case but if you want multiple locations, you would need to trigger the play event again after whatever it is you want to do after stopping it.

    Thanks

  • silversands

    i´ll check this out. again, awesome tut you´ve shared here. thanks

  • Jonathan Thomas

    Hi Serkan Yener, Its great that you have shared this awesome tutorial. Currently I’m helping a Non-profit organisation in making an online course for Hearing deficiency children using wordpress. Could you please tell me where should I add the javascript code in the theme? thanks in advance

    • http://www.serkanyener.com/ Serkan Yener

      Hi Jonathan, thanks for your message.
      I use a plugin called Custom Post Templates (https://wordpress.org/plugins/custom-post-template/) which allows you to select a custom template for any post. In other words you are able to select a php file from your themes folder to load when that particular post is viewed. Of course you would need to look at whatever file is currently being loaded for a post, and duplicate that one for a start, so that you still have your header and footer etc. Then the new custom template would be where you play with or add the code. Hope this helps. Thanks!

  • Jonathan Joosten

    you could still add some extra functionality will playing, so the now playing will update.
    But looks like something I could definitely use.

    Thanks!!