Beautiful, Functional Websites for Creative Professionals and Small Businesses
 

Modify WordPress Video Shortcode to support responsive wrappers

Both Bootstrap and Foundation are packaged with responsive video wrappers.

Both work in a similar way. An iframe or video are positioned absolutely inside a relative <div> tag.

The div takes it’s aspect ratio from its bottom padding.

The technique is well established, works well across devices and is dead easy to implement.

How WordPress shortcode works

By default if you insert media inside the WordPress WYSIWG editor it will create a shortcode like this

[video width="1920" height="1080" mp4="https://domain.tld/mediapath/file.mp4"][/video]

This creates the following HTML output within the post.

<div style="width: 1920px;" class="wp-video">
	<!--[if lt IE 9]><script>document.createElement('video');</script><![endif]-->
	<video class="wp-video-shortcode" id="video-XXXX-Y" width="1920" height="1080" preload="metadata" controls="controls">
		<source type="video/mp4" src="https://domain.tld/mediapath/file.mp4" />
		<a href="https://domain.tld/mediapath/file.mp4">https://domain.tld/mediapath/file.mp4</a>
	</video>
</div>

This is a bit of a mess.

Not only is the output unresponsive; but because the width is defined on the containing div it will often exceed the width of the page

The Solution

What is preferable is that we create a responsive container that will fit any aspect ratio video on the fly.

To do this we simply need to override the wp_video_shortcode filter; remove the existing div; and wrap the video in a responsive div with the padding defined from the aspect ratio of the video.

I use the following code. This can be inserted directly into a themes function.php file.

/* ========================================================================================================================

Wrap WordPress Video Shortcode in Responsive Wrapper

======================================================================================================================== */

function lookupIDfromURL($image_url) {

	// basic lookup from DB to match media URL with media URL
	global $wpdb;
	$attachment = $wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid='%s';", $image_url )); 
        return $attachment[0]; 

}

add_filter( 'wp_video_shortcode', function( $output ) {

	// get SRC 
	// this is a bit hacky

	preg_match( '@src="([^"]+)"@' , $output, $match );
	$src = array_pop($match);
	$src = preg_replace('/\?.*/', '', $src);

	// get ID

	$postid = lookupIDfromURL( $src );
	$meta = wp_get_attachment_metadata($postid);

	// let it autoplay 
	// and include playsinline to fix issues on iOS

	$output = str_replace( "<video", "<video muted playsinline autoplay loop ", $output );
	$output = str_replace( "controls=", "data-controls=", $output );
	
	// wrap it all up

	$str = preg_replace('/\<[\/]{0,1}div[^\>]*\>/i', '', $output);
	$padding = ($meta['height']/$meta['width'])*100;
	$wrap = "<div class='flex-video' style='padding-bottom:".$padding."%'>".$str."</div>";
    
	$output = $wrap;
	return $output;

} );

This will now have WordPress return a responsive element.

<div class='flex-video' style='padding-bottom:56.25%'>
	<!--[if lt IE 9]><script>document.createElement('video');</script><![endif]-->
	<video muted playsinline autoplay class="wp-video-shortcode" id="video-XXXX-Y" width="1920" height="1080" preload="metadata" data-controls="controls">
		<source type="video/mp4" src="https://domain.tld/mediapath/file.mp4" />
		<a href="https://domain.tld/mediapath/file.mp4">https://domain.tld/mediapath/file.mp4</a>
	</video>
</div>

This will autoplay and loop. It has hidden controls and is muted which allows it to autoplay on mobile devices and Chrome.

This assumes you will treat your video’s like a GIFs. If you do not and want to keep controls comment out the str_replace replace lines.

Responsive Video Class

I am using the flex-video class (which Foundation uses for responsive media elements).

If you using bootstrap replace it with embed-responsive.

If you do not wish to use either framework simply add the following CSS to your design.

.flex-video {
	width:100%;
	height:0px;
	overflow:hidden;
	padding-bottom:56.25%
}
.flex-video iframe,
.flex-video video {
	position:absolute;
	top:0;
	left:0;
	width:100%;
	height:100%;
}