Wordpress - Custom Video Post Type with PHP

In my work at KVCR/FNX, I was asked to create a "Video Portal" where users could watch our licensed and original content. The equipment we had to do this was a WordPress host and a Vimeo pro account.

To get started, I created a WordPress installation from scratch, and built around a custom post type I created programatically via PHP. This custom post type was "Video", and allowed for several pick and choose options. These options included Geoblocking, series selection, automatic thumbnail selection via the vimeo/youtube thumbnail, and more.

In this post, we'll go over the YouTube/Vimeo thumbnail selection and generation.

Declare Support your Theme Needs

/* functions.php */
add_theme_support('post-thumbnails'); 
add_theme_support('title-tag');
new Videos;

Create the Custom Post Type

/*
    class.videos.php
*/

class Videos {
    /*
        Videos Class
        `   Provides the wordpress functionality to add videos.
            VITAL to theme.
    */
    public function __construct() {
            register_post_type('video', $this->create_video());
            add_action( 'post_updated', array($this, 'save_video')); 
    }
    public function create_video() {
        /*
            Defines the "Video" Content Type in wordpress. 
        */
        $args = array (
            'labels' => array(
                'name' => __( 'Videos' ),
                'singular_name' => __( 'Videos' ),
                'add_new' => __( 'Add Video' ),
                'add_new_item' => __( 'Add New Video' ),
                'edit_item' => __( 'Edit Video' ),
                'new_item' => __( 'Add New Video' ),
                'view_item' => __( 'View Video' ),
                'search_items' => __( 'Search Videos' ),
                'not_found' => __( 'No Videos Found' ),
                'not_found_in_trash' => __( 'No Videos found in trash. ' )
            ),
            'has_archive' => true,
            'menu_icon' => 'dashicons-format-video',   
            'public' => true,
            'show_ui' => true,
            'capability_type' => 'post',
            'hierarchical' => false,
            'rewrite' => true,
            'menu_position' => 20,
            'supports' => array('title', 'thumbnail', 'editor'),
        );
        return $args;
    }
}

This is very simple code, and should add a "Video" custom post type. No support for the above mentioned features has been added yet.

In order to allow for a custom featured image, the user needs to input a youtube or a vimeo ID. This is the frontend code that allows you to input that Vimeo/YouTube ID so that the system can automatically pick that thumbnail.

The user selects whether it is a Vimeo or YouTube video through a radio selection box.

/*
    class.videos.php
*/

add_action( 'add_meta_boxes', array($this, 'video_meta_boxes'));

public function video_meta_boxes() {
/*
    Defines three meta boxes for the left side.
    youtube Information
    And a notice about the thumbnail (UI)
*/
add_meta_box(
    'metainfo',
    'Meta Information',
    array($this, 'video_meta_information'),
    'video',
    'normal',
    'high'
);
add_meta_box(
    'featured_image_help',
    'Note',
    array($this, 'video_featured_image_help'),
    'video',
    'side',
    'low'
);
public function video_meta_information( $post ) {
    /*
        Call back for the video ID metabox
    */
    wp_nonce_field( 'video_meta_save', 'video_meta_box' );

    $provider = get_post_meta($post->ID, 'provider', true);
    $videoid = get_post_meta($post->ID, 'videoid', true);
    $season = get_post_meta($post->ID, 'season', true);
    $episode = get_post_meta($post->ID, 'episode', true);

    require_once(THEME_ROOT. 'includes/tpl/video-meta.tpl.php');
    /*
        <table class="admin">
            <tr>
                <td colspan=2><p><i>Please enter JUST the youtube OR Vimeo ID. E.G TimW1s36NCI/112212232</i></p></td>
            </tr>
            <tr>
                <th>Video ID</th>
                <td><input type="text" name="videoid" value="<?php print $videoid; ?>"/></td>
            </tr>
            <tr>
                <th>Provider</th>
                <td>
                    <table>
                        <tr>
                            <td>
                                <input type="radio" name="provider" value="youtube" <?php if($provider == 'youtube') {print 'checked'; } ?>>Youtube
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <input type="radio" name="provider" value="vimeo" <?php if($provider == 'vimeo') {print 'checked'; } ?>>Vimeo
                            </td>
                        </tr>
                    </table>
                </td>
            </tr>
        </table>
    */
}
public function video_featured_image_help( $post ) {
    /*
        Call back for the featured image metabox
    */
    require_once(THEME_ROOT.'includes/tpl/video-featured-image-help.tpl.php');
    /*
        <p>Upon uploading of this video, the server will make the featured image a thumbnail from the Vimeo ID provided.<br /><br />To override this feature, simply replace the image once it has added in.</p>
    */
}

We needed support for a "Featured Image". This image was what shows in the frontend when a user clicks on an episode. This should be pulled from Youtube/Vimeo to make everyones lives easier.

Here is some code to accomplish that. Note that you need a Youtube API key in order to grab a thumbnail from Youtube.

public function save_video( $post_id ) {
    if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        /*
            If autosaving, do nothing
        */
        return;
    }
    /*
        Update video ID
    */
    $videoid = wp_kses( $_POST['videoid'], '');
    update_post_meta( $post_id, 'videoid', $videoid, '' );

    /*
        Update video provider
    */
    $provider = wp_kses ($_POST['provider'], '');
    update_post_meta( $post_id, 'provider', $provider, '');

    if( !isset( $_POST['videoid'] ) || !isset ( $_POST['provider']) || !wp_verify_nonce( $_REQUEST['video_meta_box'], 'video_meta_save' ) ) {
        /*
            If the video ID and provider isn't selected, or the wp_kses is faked, get out
        */
        return;
    }

    if( !has_post_thumbnail($post_id)) {
        if($provider == 'youtube') {
            $this->Generate_Featured_Image( $this->fetch_youtube_thumbnail($videoid), $post_id );
        }
        if($provider == 'vimeo') {
            $this->Generate_Featured_Image( $this->fetch_vimeo_thumbnail($videoid), $post_id );
        }
    }
}
public function fetch_vimeo_thumbnail($vimeoid) {
    /*
        Used to get the thumbnail URL from a vimeo ID.
    */
    $jsonurl = 'https://vimeo.com/api/oembed.json?url=http://vimeo.com/'.$vimeoid;
    $jsondownload = file_get_contents($jsonurl);
    $jsondecoded = json_decode($jsondownload, true);
    $thumbnailurl = $jsondecoded['thumbnail_url'];
    return $thumbnailurl;
}
public function fetch_youtube_thumbnail($youtubeid) {
    /*
        Used to get the thumbnail URL from a video ID.
    */
    $jsonurl = 'https://www.googleapis.com/youtube/v3/videos?part=id,snippet&id='.$youtubeid.'&key=YOUTUBEAPIKEY';
    $jsondownload = file_get_contents($jsonurl);
    $jsondecoded = json_decode($jsondownload);
    $thumbnailurl =  $jsondecoded->items[0]->snippet->thumbnails->high->url;
    return $thumbnailurl;
}
private function Generate_Featured_Image( $image_url, $post_id  ){
    /*
        Given an Image URL, downloads the image to the WP media gallery
        And sets it to the featured image.
    */
    $upload_dir = wp_upload_dir();
    $image_data = file_get_contents($image_url);
    $filename = date('mdyHisu').basename($image_url);
    if(wp_mkdir_p($upload_dir['path']))
        $file = $upload_dir['path'] . '/' . $filename;
    else
        $file = $upload_dir['basedir'] . '/' . $filename;
    file_put_contents($file, $image_data);
    $wp_filetype = wp_check_filetype($filename, null );
    $attachment = array(
        'post_mime_type' => $wp_filetype['type'],
        'post_title' => sanitize_file_name($filename),
        'post_content' => '',
        'post_status' => 'inherit'
    );
    $attach_id = wp_insert_attachment( $attachment, $file, $post_id );
    require_once(ABSPATH . 'wp-admin/includes/image.php');
    $attach_data = wp_generate_attachment_metadata( $attach_id, $file );
    $res1 = wp_update_attachment_metadata( $attach_id, $attach_data );
    $res2 = set_post_thumbnail( $post_id, $attach_id );
}

At this point, the user should have a custom post type called "Video" and be able to assign a featured image. This featured image is automatically pulled from Youtube or Vimeo (depending on what the user selected) once the user clicks "Publish".