This tutorial started with a question I got from a friend of mine about displaying the video in place of the featured image.
He was using Breakdance, so I thought it would be great to make it into a full-fledged tutorial.
Some practical uses would be for websites where there’s a good mix of text and video content where the video is the main point of the posts. Normally, when a single post template is set up, the featured image is displayed dynamically in the template, but that means if the video takes a prime spot, it will most likely just be a double of the video thumbnail, and I think we can make it look better.
Note: This post is a prime example of doubling the featured image, once on the post, and once in the video thumbnail. I actually debated whether I should do this or not, and I’m still making some decisions on the layouts, and planning some more content which might shift some layouts, so if you see double featured image on this post, I’m in the process of making up my mind! If you don’t, then I’ve obviously made a decision haha
The Video
Timestamps
- 0:05 Introduction
- 0:40 Preparation for the code: custom blank plugin
- 1:32 extra note: Hiding the license key
- 1:56 Chapter 1. Displaying the video via conditions
- 2:05 ACF field group for the video
- 4:01 Breakdance template for single post
- 11:42 Chapter 2. Taking it a step further, adding the featured image automatically
- 13:30 Adding the code
Text explanation and code below:
Setting up the post with ACF
You can of course, use other meta field tools, but I’ve always used ACF, so that’s what we’re using here as well.
Create a field group that will add a YouTube video URL to a post.
Displaying it on the post with Breakdance
Displaying it itself is simple enough with the dynamic data feature of the Breakdance builder, but we need a little bit of logic to make it show instead of the featured image.
We’ll start with the featured image itself and expand from there.
1. Add the featured image with a dynamic image block.
In the post template, add an image element and make it dynamically take the featured image from the post.
Adjust the sizes or whatever you’ll need to make it show the way you’d like. I suggest making it 16:9 just so it will take up the same space as a FHD video (1920 x 1080).
Now go to conditions and set it so it will check for the ACF field (of the video) and show only when the field is empty.
Extra step that will be relevant later
Duplicate the image element.
Change the conditions so it will display when the video field is NOT empty.
Make it position absolute, z-index -1. (This will hide the image from the regular document flow and won’t show for regular users, but will still load)
2. Add a video element
Add a video element under the images and make it dynamically populate from the ACF video field.
Style it accordingly.
Give it a condition of showing only when the ACF field is NOT empty.
Done.
That was simple, right?
Adding the featured image automatically
Now let’s make it even cooler.
This is the code you can add to your plugin (or theme functions file) so the post will fill in the featured image automatically from the video thumbnail only when there is no other featured image present (and if there is no duplicate file).
Copy paste this code into your plugin.
The code
The only thing you need to remember is to make sure the field name )‘featured_video’ in this case) matches the field name you set up for your website.
////// Add to a plugin or a theme functions file
add_action('save_post', 'ai_set_youtube_thumbnail_as_featured_image');
function ai_set_youtube_thumbnail_as_featured_image($post_id) {
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (wp_is_post_revision($post_id)) return;
if (has_post_thumbnail($post_id)) return;
// Get the YouTube URL. Change 'featured_video' to your field name
$youtube_url = get_post_meta($post_id, 'featured_video', true);
if (!$youtube_url) return;
preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $youtube_url, $match);
$youtube_id = isset($match[1]) ? $match[1] : '';
if (!$youtube_id) return;
$hq_url = 'https://img.youtube.com/vi/' . $youtube_id . '/hqdefault.jpg';
$upload_dir = wp_upload_dir();
$image_name = 'youtube_thumbnail_' . $youtube_id . '.jpg';
$image_path = $upload_dir['path'] . '/' . $image_name;
// Check if the image already exists in the media library
$attachment_id = ai_get_attachment_id_by_filename($image_name);
if ($attachment_id) {
set_post_thumbnail($post_id, $attachment_id);
return;
}
$image_data = file_get_contents($hq_url);
if (!$image_data) return;
file_put_contents($image_path, $image_data);
$attachment = array(
'post_mime_type' => 'image/jpeg',
'post_title' => sanitize_file_name($image_name),
'post_content' => '',
'post_status' => 'inherit'
);
$attachment_id = wp_insert_attachment($attachment, $image_path, $post_id);
require_once(ABSPATH . 'wp-admin/includes/image.php');
$attachment_data = wp_generate_attachment_metadata($attachment_id, $image_path);
wp_update_attachment_metadata($attachment_id, $attachment_data);
set_post_thumbnail($post_id, $attachment_id);
}
function ai_get_attachment_id_by_filename($filename) {
$args = array(
'post_type' => 'attachment',
'post_status' => 'inherit',
'meta_query' => array(
array(
'key' => '_wp_attached_file',
'value' => $filename,
'compare' => 'LIKE',
),
),
'posts_per_page' => 1,
);
$query = new WP_Query($args);
if ($query->have_posts()) {
return $query->posts[0]->ID;
}
return false;
}
And that’s all there is to it! Super simple way to make your client websites so much cooler.
Extra notes for alternate methods
If you want to simply display the video thumbnail somewhere else for some reason, you can use this code to display it directly without adding it to the featured image.
<?php
// $featured_video = "http://www.youtube.com/watch?v=dQw4w9WgXcQ"; //just a random YouTube video
$featured_video = get_field('featured_video');
preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $featured_video, $match);
$youtube_id = isset($match[1]) ? $match[1] : '';
if ($youtube_id) {
$hq_url = 'https://img.youtube.com/vi/' . $youtube_id . '/hqdefault.jpg';
$mq_url = 'https://img.youtube.com/vi/' . $youtube_id . '/mqdefault.jpg';
// breakdance image module stylez
echo '
<div class="bde-image ai-post_custom-thumbnail">
<figure class="breakdance-image">
<div class="breakdance-image-container">
<div class="breakdance-image-clip">
<a class="breakdance-image-link breakdance-image-link--url" href="'. the_permalink() .'" target="_self" rel="noopener">
<img class="breakdance-image-object" src="'. esc_url($hq_url) .'" width="684" height="385" srcset="'. esc_url($mq_url) .' 300w, '. esc_url($hq_url) .' 684w" sizes="(max-width: 684px) 100vw, 684px">
</a>
</div>
</div>
</figure>
</div>
';
} else {
echo 'Invalid YouTube URL';
}
?>
or if you see yourself doing this in a template (or if you’re coding your own theme, or similar) and would prefer to just make it into a function, use the code below. (note: make sure you don’t paste the <?php and the ?> parts since it will already be inside a plugin)
<?php
// Add this code to your custom plugin file
function ai_get_youtube_thumbnail_html($url, $post_permalink) {
preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $url, $match);
$youtube_id = isset($match[1]) ? $match[1] : '';
if ($youtube_id) {
$hq_url = 'https://img.youtube.com/vi/' . $youtube_id . '/hqdefault.jpg';
$mq_url = 'https://img.youtube.com/vi/' . $youtube_id . '/mqdefault.jpg';
// breakdance image module stylez
return '
<div class="bde-image ai-post_custom-thumbnail">
<figure class="breakdance-image">
<div class="breakdance-image-container">
<div class="breakdance-image-clip">
<a class="breakdance-image-link breakdance-image-link--url" href="' . esc_url($post_permalink) . '" target="_self" rel="noopener" data-sub-html="" data-lg-size="-">
<img class="breakdance-image-object" src="' . esc_url($hq_url) . '" width="684" height="385" srcset="' . esc_url($mq_url) . ' 300w, ' . esc_url($hq_url) . ' 684w" sizes="(max-width: 684px) 100vw, 684px">
</a>
</div>
</div>
</figure>
</div>';
} else {
return 'Invalid YouTube URL';
}
}
?>
To use it anywhere on the site, you can now use the function.
<?php
/// change the 'featured_video' to match your field name
$featured_video = get_field('featured_video');
$post_permalink = get_permalink();
echo ai_get_youtube_thumbnail_html($featured_video, $post_permalink);
?>
The CSS you’ll need to make sure it displays in proper 16:9.
.bde-image.ai-post_custom-thumbnail .breakdance-image-object {
aspect-ratio: 16/9;
object-fit: cover;
}
Please note: The html output is based on how Breakdance displays its image elements, and is made to be used in the post archive grid (which is why it has post_permalink as the wrapping link), so if you use something else (like a custom theme or Bricks, or some other builder that allows php directly in builder) then you’ll need to modify the html output to match the rest of the site.
Hope that helps!
Resources
How to get YouTube video ID with PHP Regex ?
https://www.geeksforgeeks.org/how-to-get-youtube-video-id-with-php-regex/
How do I get a youtube video ID (PHP)
https://stackoverflow.com/questions/9522868/how-do-i-get-a-youtube-video-id-php
How do I get a YouTube video thumbnail from the YouTube API?
https://stackoverflow.com/questions/2068344/how-do-i-get-a-youtube-video-thumbnail-from-the-youtube-api
A blank plugin you can customize to use on your website.