Categories
Responsive Design Tutorials WordPress

Automatic responsive videos in WordPress with oEmbed, FitVids and a little PHP magic

Automaitc responsive videos in WordPress with oEmbed, FitVids and PHP
UPDATE: I’ve added a 4th step to the list to remove automatic inline styles from being inserted when embedding videos.

If you’re using a responsive theme on your WordPress site (or you’ve built a responsive theme) and you’ve added YouTube, Vimeo or other videos using oEmbed you will undoubtedly have noticed those videos do not resize with the rest of the frame. And that’s a royal pain. Fortunately there are solutions out there that can fix this, but they are a little tricky to implement. In this tutorial I’ll share with you a method for making the process automatic so you don’t have to worry about it.

The Problem

Responsive themes use percentage values, media queries and other coding magic to make the content resize to fit the size of the window. But when you embed videos from YouTube etc using the built in oEmbed function in WordPress (i.e. just paste in the URL to the video and it appears automatically) that video is inserted with a fixed width and height. As a result when the rest of the page resizes to fit the window, the video stays the same size causing all sorts of problems. This is sub optimal.

FitVids to the rescue… almost

Realizing this is a frustrating problem Chris Coyier and Paravel created a clever little jQuery plugin called FitVids that when installed automatically resizes videos along with the rest of the content. FitVids attaches to specified containers and forces the video iframes within these containers to resize along with it. Very clever and it works exactly as expected. However, to make this work you have to wrap the video in a container with a specified class. So if you want to use the oEmbed method you have to go to HTML view, create a div with a class and then put the URL inside it. Which kind of takes away the whole point of using oEmbed which is simplicity.

The Solution

What is needed is a function that automatically wraps all oEmbed videos in a div with the correct class that applies FitVids so all the user has to do is paste in the link to the video and then WordPress does the rest. And that’s just what we’re going to do:

Step 1: Enqueue FitVids

Go download FitVids.js from GitHub and add the jquery.fitvids.js file to your theme. I place all my JavaScript files in a sub-folder called ‘js’ for simplicity. Then we need to enqueue the script and associate it with jQuery. This is done in functions.php:


<?php 
// Add FitVids to allow for responsive sizing of videos
function your_theme_fitvids() {
	if (!is_admin()) {

		wp_register_script( 'fitvids', get_template_directory_uri() . '/js/jquery.fitvids.js', array('jquery'), '1.0', true);    	
		wp_enqueue_script( 'fitvids');
	}
}

add_action('init', 'your_theme_fitvids');
?>

This function loads the jquery.fitvids.js file along with the packaged version of jQuery that comes with WordPress whenever a page is loaded.

Step 2: Create a function to target the videos

To make FitVids work you need to add a JavaScript function targeting a specific class. The function looks like this:


<?php
add_action('wp_footer', 'add_fitthem');
    	
function add_fitthem() { 
	    	jQuery(document).ready(function() {
    			jQuery('.video').fitVids();
    		});
}

All that happens here is the action is loaded in the footer (so it doesn’t slow down the population of the page itself and allows the videos in the iframes to load properly). It then appends the function to the .video class so that any video inside a div with the class video will be scaled to size.

This function is combined with the previous function so they get called at the same time. The resulting function looks like this:


<?php
// Add FitVids to allow for responsive sizing of videos
function your_theme_fitvids() {
	if (!is_admin()) {

		wp_register_script( 'fitvids', get_template_directory_uri() . '/js/jquery.fitvids.js', array('jquery'), '1.0', true);    	
    	wp_enqueue_script( 'fitvids');
    	add_action('wp_footer', 'add_fitthem');
    	
    	function add_fitthem() { 
		    	jQuery(document).ready(function() {
	    			jQuery('.video').fitVids();
	    		});

	    }
	}
}

add_action('init', 'your_theme_fitvids');

Step 3: Automatically wrap oEmbed videos in a div with a class

The last step is to change the oEmbed output so that it automatically wraps the video iframe in a div with the class .video. This is done using a filter:


<?php
// Automatically add FitVids to oembed YouTube videos
function your_theme_embed_filter( $output, $data, $url ) {

	$return = '<div class="video">'.$output.'</div>;
	return $return;

}
add_filter('oembed_dataparse', 'your_theme_embed_filter', 90, 3 );
?>

This function grabs the output of the oembed_dataparse function (the one that creates the final code when you paste in a video URL) and wraps it in the correct div.

Step 4: Set Maximum Embed Size to 0

To get everything to work properly you have to go to Settings -> Media and set both width and height under Maximum Embed Size to 0. If you have a value in either of these fields, WordPress will include inline style code to constrain the size of the video and as a result the automatic resizing will not work.

That is all! When you add new videos to posts and pages using the oEmbed function, they are not automatically wrapped in the correct div and class and FitVids is applied. And voila: Your videos are responsive.

Caveat: These functions are not recursive!

The only catch with this process is that it is not recursive. By that I mean it doesn’t automatically work on videos that have already been embedded on your site. That is because the oembed_dataparse() function is called the when the post is published or updated. As a result, the function has already been run on old content and to apply the new div and class you have to re-run it. Fortunately that just means going in and clicking the Update button for each of the posts that have oEmbed videos in them, but if you have hundreds of videos you may want to consider doing some sort of database search/replace action.

To avoid the recursive problem I suggest you add this function to your theme at the very beginning and be done with it. That way as you populate your site the all your videos will be responsive.

Comments? Questions? Problems?

Got something to say? Leave a comment below.

By Morten Rand-Hendriksen

Morten Rand-Hendriksen is a staff author at LinkedIn Learning and lynda.com specializing in WordPress and web design and development and an instructor at Emily Carr University of Art and Design. He is a popular speaker and educator on all things design, web standards and open source. As the owner and Web Head at Pink & Yellow Media, a boutique style digital media company in Burnaby, BC, Canada, he has created WordPress-based web solutions for multi-national companies, political parties, banks, and small businesses and bloggers alike. He also contributes to the local WordPress community by organizing Meetups and WordCamps.

27 replies on “Automatic responsive videos in WordPress with oEmbed, FitVids and a little PHP magic”

Thanks for this detailed work around Morten.

Is there a way that we can use the other functions when embedding youtube videos like – autoplay, no related videos and stripping the controls?

After the 3.4 wordpress update and oembed tweets I face a similar problem when embedding tweets in my responsive theme (Twenty Twelve preview) They don’t resize with the responsive theme but rather just stay the size you can specify in wordpress settings. Is there any workaround for that?

For those of us who don’t really do a lot of coding, would there be a simple way to create a short code with the post snippets plug-in in order to use post-vid div wrap each time you put an URL in the H TML?

I came across this while trying to find an error within FitVids, so I just wanted to post the solution in case anyone else finds this post the same way I did… Internet Explorer 9 can sometimes cause problems when using FitVids and YouTube. This is because IE 9 does not support wrapping iframes using Javascript. The solution is to replace this code:

$this.wrap(”).parent(‘.fluid-width-video-wrapper’).css(‘padding-top’, (aspectRatio * 100)+”%”);
$this.removeAttr(‘height’).removeAttr(‘width’);

With this code:

$this.before(”);
$this.removeAttr(‘height’).removeAttr(‘width’);
$this.prev(‘.fluid-width-video-wrapper’).css({ ‘padding-top’: (aspectRatio * 100)+”%” });
$this.clone().appendTo($this.prev(‘.fluid-width-video-wrapper’));
$this.hide();

Hi,

I just finished the responsive theme tut. Love your work! I know Xmas is a few months away, but there are some areas that your wizardry could really help get my site running with the Anaximander theme before Santa arrives:

1. What would the easiest steps be to have responsive self-hosted videos, rather than the Vimeo and YouTube options?

2. Is the “fitvidsjs” plugin below an option or would some magic code make everything work?

http://wordpress.org/extend/plugins/fitvids-for-wordpress/screenshots/

3. If the fitvids plugin is the answer what should I enter for the Add jQuery 1.7.2 from Google CDN (ticked or unticked) CSS selector?

Btw, congrats on the “Staff Author” title. I have been through three of your tut’s and Lynda’s concept itself is amazing.

Looking forward to hearing from you. As they say in Deutschland, “Bleib Kool” (stay cool),

Big B

Hi Big B. If you want to host your videos on your own server (not something I would recommend) then you can use the VideoJS plugin to embed HTML5 videos. This requires that you have a minimum of 3 different video files (OGG, WebM and MP4) and you should probably have a Flash fallback as well. With this option you just have to wrap it all in a standard

Wow, that was fast! A reply in 10 mins!!

I know that the self-hosted option has its drawbacks…my content is mostly pix and vids of my kids for family and friends. More “control” over the media I have, and am willing to share, is the caveat to hungry-space-eating videos and pix. I guess I will have to delve into Vimeo or YouTube and look at their options again. This new theme that you made is really great: a fresh start.

I have spent many, many hours with your courses over the last weeks. There were a couple of things that threw me when my brain wasn’t functioning at 100%. Probably have been covered already, but just as a heads up:

in “WordPress Essential Training”:

Ch3 placing WordPress in a Directory:

I couldn’t see the .htaccess file even after making files visible and invisible in Filezilla and in Forklift. I ended up installing a security plugin that created it.

Ch8 Extending…with plugins

I have only used one hosting company since I have been here in Germany. There is a “rights” section buried deep in the admin panel about permissions for using the FTP uploader and permission for using the WP to upload plugins etc. Caused me a lot of frustration before I understood what was happening when it asked for “ftp credentials”. How the “recursive” function works and what it means. Could be worth mentioning for other newbies like me if plugins aren’t installing via the FTP client or the WP installation.

Responsive Theme Tut

Ch10
I am still trying to problem solve around the Flexislider. I copied the exercise files over directly into my FTP client, but the picture slider doesn’t appear. Any tips? I haven’t installed any feature images, does that make a difference?

Wow, this has turned into a monster “comment”. Thanks so much for responding to my query earlier. Sounds like you have a lot on your plate with new courses, your biz and enjoying life in BC.

Laters,

Big B

@Big B: Let me try to answer your questions one by one:

– Different web hosts have different settings when it comes to the .htaccess file. Some provide it by default, some ask you to create it. If it’s not there and your site works, then don’t worry about it. WordPress will likely write a .htaccess file for you automatically once it’s needed.
– FTP access also differs from host to host. Sounds like you sorted that out on your own.
– Flexslider is in nearly constant development and will change from time to time. For absolute up-to-date documentation on how to use it you should check out the website at http://www.woothemes.com/flexslider/

Very useful tut Morten, it helped me map out a plan for my own work – big THANKS!

One little nugget I picked up along the way is that you can actually conditionally load resources like fitvid, not just by is_page() filters and the like, but even more precisely on posts and pages that actually have videos on them – no matter where the fall.

To do this, we can use a short code to signal the dynamic loading (as of WordPress 3.3)

Note: I’ve not extensively tested the code below in all situations, but it does seem to be pretty solid in my environment. Also this shortcode doesn’t help you embed the video like some short codes can, meerly acts as a flag, telling wordpress to only include the js on pages that need it – thus making your site a wee bit faster.

First the short code: (lightly modified version of the above)
function your_fitvids_shortcode($atts) {
// add FitVids to site
wp_register_script( 'fitvids', plugins_url('fitvid/jquery.fitvids.js', __FILE__), array('jquery'), '1.0', true);
wp_enqueue_script( 'fitvids');
// slecetor script
if (!function_exists('add_fitthem')){ // we only need it to fire once!
function add_fitthem() {
ob_start(); ?>

jQuery(document).ready(function() {
jQuery(".oembed").fitVids({customSelector: "iframe[src^='http://youtu.be']"});
});

<? echo ob_get_clean();
}
}
add_action('wp_footer', 'add_fitthem');
}
add_shortcode('fitvid', 'your_fitvids_shortcode');

the only thing left now is do, add the shortcode into the example in step 3.

$return = '[fitvid]'.$output.'';

Its helped me a lot, so did

Hi Morten,

Thanks for the great tutorial on responsive designs. I was just wondering about media queries – what do we do for ie7 and ie8 because they don’t seem to accept media queries?

Cheers,

Andy

If you look in the files for Anaximander you’ll see a JavaScript file called html5.js. This file adds a shim to the site so that if older browsers are used, the media queries still work. The shim is included with conditional statements at the top of header.php.

Thanks very for this. Brilliant tutorial

I’m not much of a developer and have a few other functions in my functions.php

I’ve created a twenty twelve child theme and can’t get this function to work even though I’ve put it at the top of my file

jQuery(document).ready(function() {
jQuery('.video').fitVids();
});
<?php
}
}
}

add_action('init', 'your_theme_fitvids');

// Automatically add FitVids to oembed YouTube videos
function your_theme_embed_filter( $output, $data, $url ) {

$return = ''.$output.'';
return $return;

}
add_filter('oembed_dataparse', 'your_theme_embed_filter', 90, 3 );

// Load up theme options page and related code.
require( get_stylesheet_directory() . '/inc/theme-options.php' );

// Change header width
function tto_custom_header_setup() {
$header_args = array(
'width' => 1000,
'height' => 250
);
add_theme_support( 'custom-header', $header_args );
}
add_action( 'after_setup_theme', 'tto_custom_header_setup' );

// ADD A SECOND NAVIGATION MENU
// de-queue navigation js
add_action('wp_print_scripts','tto_dequeue_navigation');
function tto_dequeue_navigation() {
wp_dequeue_script( 'twentytwelve-navigation' );
}
// load the new navigation js
function tto_custom_scripts()
{

// Register the new navigation script
wp_register_script( 'lowernav-script', get_stylesheet_directory_uri() . '/js/navigation.js', array(), '1.0', true );

// Enqueue the new navigation script
wp_enqueue_script( 'lowernav-script' );
}
add_action( 'wp_enqueue_scripts', 'tto_custom_scripts' );

// Add the new menu
register_nav_menus( array(
'primary' => __( 'Top Menu (Above Header)', 'tto' ),
'secondary' => __( 'Lower Menu (Below Header))', 'tto'),
) );
// END OF SECOND NAV CODE ABOVE

// Add a Theme Options link to Admin Bar
function theme_options_link()
{
global $wp_admin_bar, $wpdb;
if (!is_super_admin() || !is_admin_bar_showing())
return;
$wp_admin_bar->add_menu(array('parent' => 'appearance', 'title' => __('Theme Options', 'Theme Options'), 'href' => home_url() . '/wp-admin/themes.php?page=theme_options'));
}
add_action('admin_bar_menu', 'theme_options_link', 1000);

// Change default thumbnail size
function tto_twentytwelve_setup() {
set_post_thumbnail_size( 651, 9999 ); // (default featured images)Unlimited height, soft crop
add_image_size( 'post-excerpt-thumbnail', 120, 120, true ); // Post excerpt Thumbnails
}
add_action( 'after_setup_theme', 'tto_twentytwelve_setup', 11 );

// Override content width (for photo and video embeds)
$content_width = 651;

function tto_content_width() {
if ( is_page_template( 'page-templates/full-width.php' ) || is_attachment() || ! is_active_sidebar( 'sidebar-1' ) ) {
global $content_width;
$content_width = 1000;
}
}
add_action( 'template_redirect', 'tto_content_width', 11 );

// Body class for custom page template and 3 column layouts
add_filter( 'body_class', 'tto_custom_body_class');
function tto_custom_body_class( $classes ) {
if( !is_page_template() )
$classes[] = 'custom-layout';
return $classes;
}

// Set default background color for color schemes
add_action('after_setup_theme','child_default_background_color');
function child_default_background_color() {
$theme_options = get_option( 'tto_theme_options');

if ( 'dark' == $theme_options['color_scheme'] )
$default_background_color = '181818';
else
$default_background_color = 'E6E6E6';

add_theme_support( 'custom-background', array(
// set default background color in child theme
'default-color' => $default_background_color
) );
}

// Blog posts excerpt
function get_the_post_excerpt(){
$excerpt = get_the_content();
$excerpt = preg_replace(" (\[.*?\])",'',$excerpt);
$excerpt = strip_shortcodes($excerpt);
$excerpt = strip_tags($excerpt);
$excerpt = substr($excerpt, 0, 220); // change this to whatever you like
$excerpt = substr($excerpt, 0, strripos($excerpt, " "));
$excerpt = trim(preg_replace( '/\s+/', ' ', $excerpt));
$excerpt = ''.$excerpt.' ID) . '">Continue Reading »';
return $excerpt;
}

//add a widget area in the header
if ( function_exists ('register_sidebar') )
register_sidebar( array(
'name' => __( 'Header Widgets Area', 'twentytwelve' ),
'id' => 'sidebar-header',
'description' => __( 'A new header widgets area for my child them' , 'twentytwelve' ),
'before_widget' => '',
'after_widget' => '',
'before_title' => '',
'after_title' => '',
) );
add_action( 'widgets_init', 'twentytwelve_widgets_init' );

// Register footer widgets
register_sidebar( array(
'name' => __( 'Footer Widget One', 'tto' ),
'id' => 'sidebar-4',
'description' => __( 'Found at the bottom of every page (except 404s, optional homepage and full width) as the footer. Left Side.', 'tto' ),
'before_widget' => '',
'after_widget' => '',
'before_title' => '',
'after_title' => '',
) );

register_sidebar( array(
'name' => __( 'Footer Widget Two', 'tto' ),
'id' => 'sidebar-5',
'description' => __( 'Found at the bottom of every page (except 404s, optional homepage and full width) as the footer. Center.', 'tto' ),
'before_widget' => '',
'after_widget' => "",
'before_title' => '',
'after_title' => '',
) );

register_sidebar( array(
'name' => __( 'Footer Widget Three', 'tto' ),
'id' => 'sidebar-6',
'description' => __( 'Found at the bottom of every page (except 404s, optional homepage and full width) as the footer. Right Side.', 'tto' ),
'before_widget' => '',
'after_widget' => "",
'before_title' => '',
'after_title' => '',
) );

// Use WP-PageNavi when it's active
function twentytwelve_content_nav( $nav_id ) {
global $wp_query;
if ( $wp_query->max_num_pages > 1 ) : ?>

<nav id="">

<?php next_posts_link( __( '← Older posts', 'tto' ) ); ?>
<?php previous_posts_link( __( 'Newer posts ←', 'tto' ) ); ?>

<?php endif;

}

I just want to thank you for everything that I learned from you, I’m a premium member on lynda.com and I looked at all your MASTERCLAS play list. You’re the man 🙂
I please tell me how to remove

You may use these HTML tags and attributes:

under comment

I’m amazed, I must say. Seldom do I encounter a blog that’s equally educative and amusing, and without a doubt, you’ve hit the nail on the head. The issue is an issue that too few folks are speaking intelligently about. I’m very happy I found this during my hunt for something concerning this.

I was so glad to find this solution, but even following the directions meticulously and trying several separate times, it’s not working for me.

I did note that the videos need to be added *after* adding the JS and PHP.

Vimeo videos don’t “respond” at all.

Any ideas what I might be doing wrong? Anything I can check?

Thanks in advance –
Patty

Hello,
I’d know I’m late to the party, and this is an old post now, but wanted to add my thanks to you, Morten – I’ve learnt so much from your videos and posts; you always seem to nail the solution I’m looking for where others confuse.

This may help Patty (above), but I noticed in the code posted, the final function is missing a closing single quote:

$return = ”.$output.’;

This was not allowing the php to close off for me, and so breaking the site.
Thanks again for all the great information,
Tim

I took your Lynda.com WordPress Essential Training course as I am new to WP and quite frankly web design in general.
There are quite a few things that don’t work in the 4.1 WP version compared to what you show on the video, most are probably theme related as I am using 2015.
However, I cant for the heck of it oEmbed a youtube video. Just a link, or a blank box appears.
Any thoughts on how to do so?
Thanks for your time,
Jerry

Hello,
Thank you for your tuts.
I’m using wp 4.2.1, but the last part of the code for adding class=video automatically is not working for me.
When I add class=video manually it works good.

// Automatically append .video class to oembed content (not a perfect solution, but close)
function anaximander_embed_filter( $html, $data, $url ) {

$return = ”.$html.”;
return $return;
}
add_filter(‘oembed_dataparse’, ‘anaximander_embed_filter’, 90, 3 );

I would be grateful if you could help me.

Sanam

Hi,

A very useful guide this cheers, I’ve used this approach a few times now. One point: there’s a typo in section 3:

$return = ”.$output.’;

…that last sting isn’t closed of course, so should be:

$return = ”.$output.”;

(it’ll cause a fatal error with ‘Parse error: syntax error, unexpected ‘oembed_dataparse’ (T_STRING)’ otherwise )

Hi,
well with your solution, it’s all the post which will be at 60%, that’s not the point.
I think I found a solution. I added this in my ccs child theme and it’s working :

.fluid-width-video-wrapper iframe,
.fluid-width-video-wrapper object,
.fluid-width-video-wrapper embed {
height: 80% !important;
left: 9% !important;
position: absolute;
top: 0;
width: 80% !important;
}

Comments are closed.