Creating a custom post type for sharing videos in WordPress

The idea

In a recent project that I worked on, my client wanted to be able to post videos on his website as a completely separate type of content (Video Sermons) with it’s own archive page. Further requirements included ability to post upload videos and link to them, as well as post videos from outside sources such as Vimeo, YouTube, etc.

There are several methods to accomplishing the above requirements. I chose to utilize the Custom Post Type method. If you aren’t familiar at all with Custom Post Types I would suggest reading the WordPress codex page on them.

Registering the Video Post Type

The first task is to register the new post type using the register_post_type function. Here is the function I created for this purpose, I have added comments in the code to help understand what is happening.

function hlc_videos_register() { 
    $args = array( 'label' => __('Videos','globe'), //plural label
        'singular_label' => __('Video','globe'),
        'public' => true, 'show_ui' => true,
        'capability_type' => 'post',
        'hierarchical' => false,
        'rewrite' => true,
        'supports' => array('title', 'editor'), //we want the editor field so that regular content can be posted 
        'taxonomies' => array('category','post_tag') //we are using regular post categories instead of creating our own for this type. Also allowing tags 
    );
    register_post_type('videos', $args); //the actual function call 
} 
add_action('init', 'hlc_videos_register'); //add our function to the WP init action so that it is registered at the right time

function hlc_videos_register()
{
	$args = array(
		'label' => __('Videos','globe'), //plural label 
		'singular_label' => __('Video','globe'),
		'public' => true,
		'show_ui' => true,
		'capability_type' => 'post',
		'hierarchical' => false,
		'rewrite' => true,
		'supports' => array('title', 'editor'), //we want the editor field so that regular content can be posted
		'taxonomies' => array('category','post_tag') //we are using regular post categories instead of creating our own for this type.  Also allowing tags
	);
	
	register_post_type('videos', $args); //the actual function call
}
add_action('init', 'hlc_videos_register');  //add our function to the WP init action so that it is registered at the right time

Adding the Video Upload meta box *

Next I needed to create the meta box that would hold the video information. I wanted to provide one field where the video information was placed, both for embed code (YouTube, etc.) and for local videos (uploaded to the site). I also wanted to use the built in media upload functionality of WordPress as much as possible in order to keep the interface consistent for the client. Since I borrowed heavily from this post for the next few items it seems silly to duplicate that information. I would encourage you to read Michael’s post to understand what is going on. I have posted my code and notes on things that I changed from Michael’s post. The main difference is that his post has to do with image upload and mine has to do with video upload.

$meta_box = array(
	'id' => 'hlc-meta-box',
	'title' => 'Video',
	'page' => 'videos',
	'context' => 'normal',
	'priority' => 'high',
	'fields' => array(
		array(
			'name' => 'Add Video',
			'desc' => 'Select a Video',
			'id' => 'upload_video',
			'type' => 'textarea',
			'std' => ''
		),
	array(
			'name' => '',
			'desc' => '',
			'id' => 'upload_video_button',
			'type' => 'button',
			'std' => 'Browse'
		),
	)
);
 
add_action('admin_menu', 'hlc_add_box');
 
// Add meta box
function hlc_add_box() {
	global $meta_box;
 
	add_meta_box($meta_box['id'], $meta_box['title'], 'hlc_show_box', $meta_box['page'], $meta_box['context'], $meta_box['priority']);
}
 
// Callback function to show fields in meta box
function hlc_show_box() {
	global $meta_box, $post;
 
	// Use nonce for verification
	echo '<input type="hidden" name="hlc_meta_box_nonce" value="', wp_create_nonce(basename(__FILE__)), '" />';
 
	echo '<table class="form-table">';
 
	foreach ($meta_box['fields'] as $field) {
		// get current post meta data
		$meta = get_post_meta($post->ID, $field['id'], true);
 
		echo '<tr>',
				'<th style="width:20%"><label for="', $field['id'], '">', $field['name'], '</label></th>',
				'<td>';
		switch ($field['type']) {
 
 
 
 
//If Text		
			case 'text':
				echo '<input type="text" name="', $field['id'], '" id="', $field['id'], '" value="', $meta ? $meta : $field['std'], '" size="30" style="width:97%" />',
					'<br />', $field['desc'];
				break;
 
 
//If Text Area			
			case 'textarea':
				echo '<textarea name="', $field['id'], '" id="', $field['id'], '" cols="60" rows="4" style="width:97%">', $meta ? $meta : $field['std'], '</textarea>',
					'<br />', $field['desc'];
				break;
 
 
//If Button	
 
				case 'button':
				echo '<input type="button" name="', $field['id'], '" id="', $field['id'], '"value="', $meta ? $meta : $field['std'], '" />';
				break;
		}
		echo 	'<td>',
			'</tr>';
	}
 
	echo '</table>';
}

Saving the data *

add_action('save_post', 'hlc_save_data');
 
// Save data from meta box
function hlc_save_data($post_id) {
	global $meta_box;
 
	// verify nonce
	if (!wp_verify_nonce($_POST['hlc_meta_box_nonce'], basename(__FILE__))) {
		return $post_id;
	}
 
	// check autosave
	if (defined('DOING_AUTOSAVE') &amp;&amp; DOING_AUTOSAVE) {
		return $post_id;
	}
 
	// check permissions
	if ('page' == $_POST['post_type']) {
		if (!current_user_can('edit_page', $post_id)) {
			return $post_id;
		}
	} elseif (!current_user_can('edit_post', $post_id)) {
		return $post_id;
	}
 
	foreach ($meta_box['fields'] as $field) {
		$old = get_post_meta($post_id, $field['id'], true);
		$new = $_POST[$field['id']];
 
		if ($new &amp;&amp; $new != $old) {
			update_post_meta($post_id, $field['id'], $new);
		} elseif ('' == $new &amp;&amp; $old) {
			delete_post_meta($post_id, $field['id'], $old);
		}
	}
}

Note: All of the above code is in a file called video.php and located in the theme’s lib folder.

Adding the JavaScript *

First we need to create some javascript to handle tying in our field with the media uploader. This is placed in a file named video-upload.js in the theme’s js folder.

jQuery(document).ready(function() {
	
	jQuery('#upload_video_button').click(function() {	
		tb_show('', 'media-upload.php?type=video&amp;TB_iframe=true');  //when our browse button is clicked popup the media page with type set to video instead of image
		return false;
	});

	window.send_to_editor = function(html) {
		var vidurl = jQuery(html).attr('href'); //get the video's url so we can place it in our textarea
		jQuery('#upload_video').val(vidurl); //place it in the textarea
		tb_remove(); //close the media window	
	}
});

Then we need to make sure we include the media upload js and styles

function my_admin_scripts() {
    wp_enqueue_script('media-upload');
    wp_enqueue_script('thickbox');
    wp_register_script('video-upload', get_bloginfo('stylesheet_directory') . '/js/video-upload.js', array('jquery','media-upload','thickbox'));
    wp_enqueue_script('video-upload');
}
function my_admin_styles() {
    wp_enqueue_style('thickbox');
}
add_action('admin_print_scripts', 'my_admin_scripts');
add_action('admin_print_styles', 'my_admin_styles');

* Thanks to this post by Michael for giving me a great base from which to build.

Creating the Video Sermon archive page

To create the Video Sermon archive page, I copied the theme’s page.php code and modified the query_posts function to pull in the video post type exclusively. Here is the top of the page with all of the parts that I modified (see the comments in the code for more details)

/**
* Template Name: Videos Page //added template name so I can tie a page to it.
**/

		$paged = get_query_var('paged') ? get_query_var('paged') : 1; //make sure we get the paged variable so pagination works correctly
		$a = array(
			'post_type' =&gt; 'videos', //only get the video post type
			'posts_per_page' =&gt; 10,  //limit the results to 10
			'paged' =&gt; $paged //pass in the paged variable
		);
		query_posts($a); //modify the query

Everything else on the page (including the loop) remained identical to the page.php file. Next I created a new page in the WordPress Admin and selected this template.

Creating the single video page

To create the single video page I copied the theme’s single.php file and made these modifications:

  • For local (uploaded) videos I needed a video player. I chose to use Flowplayer. I included an add_action call at the very top of the page for the video player so that it only is called on that page. add_action('wp_enqueue_scripts', 'hlc_flowplayer_setup');
  • Inside the loop, I needed to get the code from the video meta box and determine whether it was a local video or not and display it appropriately based on that.
$video = get_post_meta($post->ID,'upload_video',true);[/php] //get the video code (either a url for local or iframe for embed) 
//need to see if it is local or other (youtube)
$test = str_replace('iframe','[YT]',$video); //replace iframe with [YT] so we can count whether it exists or not
//now split on [YT]
$test = explode('[YT]', $test); 

if(count($test) < 2): //if [YT] doesn't exist the $test var will have only 1 item so we know it is a local video
<a href="[php] echo $video;[/php]" id="player"></a> //echo the url in this link for flowplayer to use
                       //now we add the flowplayer js to get it working
<script language="JavaScript">
			flowplayer("player","[php] bloginfo('url');[/php]/wp-content/themes/glass-globe-11/third-party/flowplayer-3.2.6/flowplayer-3.2.7.swf", {
				clip: {
					autoPlay: false,
					autoBuffering: true
				}
			});
			</script>
else: //otherwise if $test's count is 2 or more we have an embed video and all we need to do is print the embed code
print $video;[/php]
endif; //count($test)

Adding Flowplayer to the theme

In order to add Flowplayer for use in the theme, I placed the downloaded Flowplayer files in a new folder (called third-party to keep it separate from other theme files) inside the theme. You can see the reference to the swf file on line 13 of the code above.

Bringing it all together in the functions.php file

First I pull in the video.php file that creates the video post type:

//include videos post type
require_once('lib/videos.php');

Then we create the function that pulls in the flowplayer javascript. (the one we called from the single video page.

//include flowplayer on video posttype pages
function hlc_flowplayer_setup() {
	wp_register_script('flowplayer',get_bloginfo('stylesheet_directory').'/third-party/flowplayer-3.2.6/flowplayer-3.2.6.min.js');
	wp_enqueue_script('flowplayer');
}

2 thoughts on “Creating a custom post type for sharing videos in WordPress

  1. I am REALLY hoping this works! I’ve been trying to find a Video Post type tutorial for THE LONGEST TIME! Glad I came across this. I am confused on a couple things though…

    1.Instead of creating a plugin file can I just add the code to my functions.php to make the post type ect?
    2. Lost on where the code under “Creating the single video page” should be placed//
    add_action(wp_enqueue_scripts, hlc_flowplayer_setup)
    and the large chunk of code beneath that…
    Do they go in a single-videos.php file, functions.php, or the separate plugin file if that is needed…?

    Looking forward to getting this post type working!
    Thanks in advance!

    -Keisa

  2. Keisa,
    Thanks for stopping by the site and asking your questions! I hope this helps to clarify things:

    1) Yes you can put that code directly in your functions.php file.

    2) Those go in the single-videos.php file. I put the add_action code at the very top of the page (before the get_header(); line). The rest of the code goes inside the loop, so after the while( have_posts() ) : the_post(); part of the single-videos.php file.

    Randy

Leave a Reply

Your email address will not be published. Required fields are marked *