Simple Podcasting Plugin

One of the most requested features we get is Podcasting.  People want a simple means for adding audio or video to their website and then have it display on iTunes.  There are lots of good solutions available in the plugin repository, but I’ve found most of them to be over bloated with features or riddled with ads for certain types of hosting solutions.  For our clients I need a simple solution that gets the job done, and leaves out all of the fluff.  Below is a version of what we use on a lot of our websites.  I’ll try to go through each step so you can edit the code to meet your needs.

Step One: Plugin Foundation

The first thing that needs to be done is to create our plugin file.  If you are connected to your website via FTP or code editor (I never recommend working on a live website, use a local copy or development version) create a folder title “pyd-simple_podcasting.”  Then create a php file titled “pyd-simple_podcasting.php”

The “pyd” designation (short for Poka Yoke Design) is something I use with every bit of code and file to make sure that it doesn’t conflict with a file or function of the same name.  You can use your own if you’d like.

In the php file you just created, drop in this bit of code at the top (just below the opening <?php tag).


/*
Plugin Name: Simple Podcasting
Plugin URI: http://gyura.com
Description: Creates a section for adding Podcasts to your website in a very simple and straight forward build.  There are many other podcasting plugins that do more, this pluign fills the need of getting content onto iTunes simply and quickly.  Makes use of the AMAZING CMB files from Jared Atchison.
Version: 1.0
Author: Michael Gyura
Author URI: http://gyura.com
License: GPL2
 */

Now if you go to your plugins page, you will see a new plugin listed as “Simple Podcasting.” Congrats, you’ve just made a plugin. Now, lets make it do something.

Step Two: Custom Post Types

Next we need to create a section to enter in the podcasting information.  We will first create  a custom post type to separate the data from other pages and posts, then we will use custom meta boxes to collect the data.

To create a custom post type, first create a new folder titled “includes” inside your plugin folder.  Inside this folder create a file titled “pyd-simple_posttypes.php” this is where we will drop in our custom post type code.  Paste the below code into your new file


function pyd_simple_podcast_post_types() {
register_post_type(
'pyd_simple_podcast', array(
'labels'              => array(
'name'               => __( 'Podcasting' ),
'singular_name'      => __( 'Podcast' ),
'add_new'            => __( 'New Podcast' ),
'add_new_item'       => __( 'New Podcasts' ),
'edit'               => __( 'Edit Podcasts' ),
'edit_item'          => __( 'Edit Podcast' ),
'new_item'           => __( 'New Podcast' ),
'view'               => __( 'View Podcasts' ),
'view_item'          => __( 'View Podcast' ),
'search_items'       => __( 'Search Podcasts' ),
'not_found'          => __( 'No Podcasts found' ),
'not_found_in_trash' => __( 'No Podcasts found in Trash' ),
'parent'             => __( 'Parent Podcast' ),
),
'public'              => true,
'show_ui'             => true,
'show_in_menu'        => true,
'publicly_queryable'  => true,
'exclude_from_search' => true,
'description'         => __( 'A place to edit and add podcasts to your website.' ),
'menu_position'       => 6,
'menu_icon'           => plugins_url( '/images/podcast_icon.png', __file__ ),
'hierarchical'        => false,
'query_var'           => true,
'supports'            => array( 'title' ),
'rewrite'             => array(
'slug'       => 'podcasts',
'with_front' => false
),
'has_archive'         => true,
'can_export'          => true
)
);
}

add_action( 'init', 'pyd_simple_podcast_post_types' );

I could spend pages explaining what’s going on above, but many people have done that already. For more information check out the WordPress Codex, or this amazing post from Justin Tadlock

Now, go back to your original php file “pyd-simple_podcasting.php” and place this line of code:


require_once( dirname( __FILE__ ) . '/includes/pyd-simple_posttypes.php' );

This will bring into the plugin the file you just created.

You should now see the Podcasting menu on the left side of your dashboard.

Clicking on “new podcast” will take you to the editing screen, but the only input box is for the title.  We’re going to need more than that, and that’s where custom meta boxes come in.

Step 3: Custom Meta Boxes

Custom meta boxes are extra input areas you can add to any page, post, or in our case custom post type.  There is an AMAZING bit of code from Jared Atchison that will blow your mind.  If you’ve ever tried to write out custom meta boxes by hand, you will kiss your computer after seeing this.  We are going to download the files and add them to our plugin.

First, create a page “pyd-simple_metaboxes.php” and place it in the “includes” folder.  Then paste this line of code in your main page, just below the last one you dropped in:


require_once( dirname( __FILE__ ) . '/includes/pyd-simple_metaboxes.php' );

Next head over to Github and grab the files and download them to your computer.
Create a new folder titled “metabox” inside the “includes” folder and place the unzipped files into it. Upload to your server, if needed.

Now it’s time to have some fun and create custom meta boxes for our custom post type.

Paste this code into your “pyd-simple_metaboxes.php” metabox file:


$prefix = '_pydsimple_';
add_filter( 'cmb_meta_boxes', 'pyd_simple_podcast_metaboxes' );

function pyd_simple_podcast_metaboxes( $meta_boxes ) {
global $prefix;

$meta_boxes[ ] = array(
'id'         => 'simple_podcast_metabox',
'title'      => 'Podcasting Information',
'pages'      => array( 'pyd_simple_podcast' ),
'context'    => 'normal',
'priority'   => 'low',
'show_names' => true,
'fields'     => array(
array(
'name' => 'Instructions',
'desc' => 'If you would like this publication added to your Podcast, please fill out the below information.<p>You must first fill out the default settings and link to iTunes for the Podcast to work<br />The title of your Podcast is the title of this post</p>',
'id'   => $prefix . 'pod_intro',
'type' => 'title'
),
array(
'name' => 'Date',
'desc' => 'Date of Publication',
'id'   => $prefix . 'pubs_date',
'type' => 'text_date_timestamp'
),
array(
'name' => 'Information',
'desc' => 'If you have details, add them here.',
'id'   => $prefix . 'pubs_info',
'type' => 'textarea',
),
array(
'name' => 'MP3 Audio Publication',
'desc' => 'Upload or link to an MP3 file',
'id'   => $prefix . 'pubs_mp3',
'type' => 'file'
),
array(
'name' => 'Video Publication Link',
'desc' => 'Link to a full URL of a video file from YouTube or Vimeo.',
'id'   => $prefix . 'pubs_video',
'type' => 'text'
),
array(
'name'    => 'Type of Media',
'desc'    => 'Let iTunes know what kind of media is being used',
'id'      => $prefix . 'pubs_filetype',
'type'    => 'select',
'options' => array(
array(
'name'  => '.mp3',
'value' => 'audio/mpeg',
),
array(
'name'  => '.m4a',
'value' => 'audio/x-m4a',
),
array(
'name'  => '.mp4',
'value' => 'video/mp4',
),
array(
'name'  => '.m4v',
'value' => 'video/x-m4v',
),
array(
'name'  => '.mov',
'value' => 'video/quicktime',
),
),
),
array(
'name' => 'MP3 Size in Bytes',
'desc' => 'Example: 8727310.  The size attribute is the file size in bytes. Find this information in the files properties (on a Mac, "Get Info" and refer to the size row). This is important for the iTunes Podcast',
'id'   => $prefix . 'pod_size',
'type' => 'text_small'
),
array(
'name' => 'MP3 Duration',
'desc' => 'Example: 13:34  How long is this Podcast',
'id'   => $prefix . 'pod_duration',
'type' => 'text_small'
),
array(
'name' => 'iTunes Keywords',
'desc' => 'Example: sermon, worship, presbyterian.  Comma separated keywords for this Podcast',
'id'   => $prefix . 'pod_keyword',
'type' => 'text'
),

)
);

//return all the good stuff
return $meta_boxes;
}

// Initialize the metabox class
add_action( 'init', 'pyd_initialize_cmb_meta_boxes', 9999 );

function pyd_initialize_cmb_meta_boxes() {
if ( !class_exists( 'cmb_Meta_Box' ) ) {
require_once( 'metabox/init.php' );
}
}

The above code drops in a different metabox with each array. There are all sorts of fields you can add, just check the example file that came with the files on Github for samples.   The top section is where we define the unique aspects of these metaboxes.  The ID is an identifier for these boxes, “pages” is what tells the system where to place these boxes.  If we were to say “page” or “post” or another custom post type, the boxes would have shown up there.  We could also use an array to place these in multiple areas.

Once you have the core files installed on your WordPress website, you can call them multiple times in different areas. Typically, we call in the core files once, and then build a whole slew of different plugins off of it.  These files have almost become as standard for us as WordPress itself.  It would be great to see something like this woven into the core at some point…

If everything is going smoothly you should see your podcasting section taking shape.

Before you move any further, test to see if you can create a Podcast.  Fill in all of the forms and upload an mp3 (or paste the link) and see if the info sticks on publish.  If your content saves, you are doing great so far.  Great work!

Step 4: User information

The above system will create data for each episode, but we need to add a section where our users can enter in data about their organization.  To do this, we are going to create an options area for our plugin and place the link on our dashboard menu.

First, we need to create options to fill in once.  Go back to your main page “pyd-simple_podcasting.php” and paste in these lines:


function pyd_simple_podcasts_settings() {

register_setting( 'pyd-podcast-settings-group', 'pyd_podcast_title' );
register_setting( 'pyd-podcast-settings-group', 'pyd_podcast_copyright' );
register_setting( 'pyd-podcast-settings-group', 'pyd_podcast_subtitle' );
register_setting( 'pyd-podcast-settings-group', 'pyd_podcast_summary' );
register_setting( 'pyd-podcast-settings-group', 'pyd_podcast_owner_name' );
register_setting( 'pyd-podcast-settings-group', 'pyd_podcast_owner_email' );
register_setting( 'pyd-podcast-settings-group', 'pyd_podcast_image' );
register_setting( 'pyd-podcast-settings-group', 'pyd_podcast_category' );
register_setting( 'pyd-podcast-settings-group', 'pyd_podcast_subcategory' );
register_setting( 'pyd-podcast-settings-group', 'pyd_podcast_clean' );
}

add_action( 'admin_init', 'pyd_simple_podcasts_settings' );

This creates a settings fields in the database for us to fill in. These type of fields are great when you have data that needs to be entered in once, and doesn’t need to change much (like organizational information).

Now, we need to create a page to put our setting fields in.  In the “includes” folder create “pyd-simple_settings.php.”  Then paste the below code in:


function pyd_simple_podcast_settings() {
echo '<div>';
if ( isset( $_GET[ 'settings-updated' ] ) ) {
?>
<div id="message">
<p><strong><?php _e( 'Settings saved.' ) ?></strong></p>
</div>
<?php
}

echo '<h2>Settings for iTunes Podcast Feed</h2>';
echo '<p>Fill out this section for iTunes.  Every filed needs to be filled out for your iTunes Podcast to work</p>';
echo '<p>For information on what to place here, <a href="http://www.apple.com/itunes/podcasts/specs.html">see this link</a></p>';
?>
<form method="post" action="options.php">
<?php settings_fields( 'pyd-podcast-settings-group' ); ?>
<table>
<tr valign="top">
<th scope="row">Podcast Main Title</th>
<td><input type="text" name="pyd_podcast_title"
value="<?php echo get_option( 'pyd_podcast_title' ); ?>" />
</td>
</tr>
<tr valign="top">
<th scope="row">Podcast Copyright Message</th>
<td><input type="text" name="pyd_podcast_copyright"
value="<?php echo get_option( 'pyd_podcast_copyright' ); ?>" /></td>
</tr>
<tr valign="top">
<th scope="row">Podcast Subtitle</th>
<td><input size="70" type="text" name="pyd_podcast_subtitle"
value="<?php echo get_option( 'pyd_podcast_subtitle' ); ?>" /></td>
</tr>
<tr valign="top">
<th scope="row">Podcast Summary</th>
<td><textarea rows="4" cols="30"
name="pyd_podcast_summary"><?php echo get_option( 'pyd_podcast_summary' ); ?></textarea>
</td>
</tr>
<tr valign="top">
<th scope="row">Podcast Category</th>
<td><textarea rows="4" cols="30"
name="pyd_podcast_category"><?php echo get_option( 'pyd_podcast_category' ); ?></textarea>
</td>
</tr>
<tr valign="top">
<th scope="row">Podcast Sub-Category</th>
<td><textarea rows="4" cols="30"
name="pyd_podcast_subcategory"><?php echo get_option( 'pyd_podcast_subcategory' ); ?></textarea>
</td>
</tr>
<tr valign="top">
<th scope="row">Podcast Owner Name</th>
<td><input type="text" name="pyd_podcast_owner_name"
value="<?php echo get_option( 'pyd_podcast_owner_name' ); ?>" /></td>
</tr>
<tr valign="top">
<th scope="row">Podcast Owner Email</th>
<td><input type="text" name="pyd_podcast_owner_email"
value="<?php echo get_option( 'pyd_podcast_owner_email' ); ?>" /></td>
</tr>
<tr valign="top">
<th scope="row">Podcast Image URL (600px x 600px)</th>
<td><input type="text" name="pyd_podcast_image"
value="<?php echo get_option( 'pyd_podcast_image' ); ?>" />
</td>
</tr>
<tr valign="top">
<th scope="row">Is this Explicit? Yes, No or Clean</th>
<td><input type="text" name="pyd_podcast_clean"
value="<?php echo get_option( 'pyd_podcast_clean' ); ?>" />
</td>
</tr>
</table>
<p>
<input type="submit" value="Save" />
</p>
</form>
<?php if ( get_option( 'pyd_podcast_image' ) == "" && get_option( 'pyd_podcast_owner_email' ) == "" && get_option( 'pyd_podcast_owner_name' ) == "" && get_option( 'pyd_podcast_summary' ) == "" && get_option( 'pyd_podcast_subtitle' ) == "" && get_option( 'pyd_podcast_copyright' ) == "" && get_option( 'pyd_podcast_title' ) == "" ) {
echo '<div id="message">';
echo '<p><b>Before you can link to iTunes, all fields needs to be updated</b></p>';
echo '</div>';
}
else {
echo '<div id="message">';
echo '<p><b>Use the below link as the Feed URL for iTunes</b><br/>' . get_bloginfo( 'url' ) . '/?feed=simple-podcast-feed&post_type=pyd_simple_podcast</p>';
echo '</div>';
}
?>
<?php
echo '</div>';
}

/*-----------------------------------------------------------------------------------*/
/* Set up the custom iTunes feed */
/* then use the url of "site url"/?feed=simple-podcast-feed&post_type=pyd_simple_podcast */
/*-----------------------------------------------------------------------------------*/

function pyd_simple_itunes_customfeed() {
load_template( dirname( __FILE__ ) . '/pyd-iTunesXML.php' );
}

add_action( 'do_feed_simple-podcast-feed', 'pyd_simple_itunes_customfeed', 10, 1 );

/*-----------------------------------------------------------------------------------*/
/* Create settings menu for our functions */
/*-----------------------------------------------------------------------------------*/

function pyd_simple_podcast_settings_menu() {
add_submenu_page( 'edit.php?post_type=pyd_simple_podcast', 'Podcast Settings', 'Podcast Settings', 'edit_posts', 'audio-settings', 'pyd_simple_podcast_settings' );
}

add_action( 'admin_menu', 'pyd_simple_podcast_settings_menu' );

The first function “pyd_simple_podcast_settings() ” creates the HTML tables to collect the data.

The second function “pyd_simple_itunes_customfeed” is a method of creating custom RSS feeds.  It filters out particular content and only displays that using custom php that we will generate in the next step.  This function is useful in many situations.

The third function “pyd_simple_podcast_settings_menu” creates the menu link in our podcast menu for the settings page.

Finally we need to link our newly created page to our main function.  Head back to the main php file “pyd-simple_podcasting.php” and drop in this code:


require_once( dirname( __FILE__ ) . '/includes/pyd-simple_settings.php' );

If all is working correctly, you should now see an extra link in the Podcasting menu titled “Podcast Settings.”

Step 5: Custom iTunes XML

We now have a system for adding mp3 files to our website, so we can start adding data.  But, we need to have a way for iTunes to read this information so it can create the podcast.  This is where a custom xml sheet will come in handy.

Create a page in the “includes” folder and title it “pyd-iTunesXML.php.”  This one will not need to be called in by our main page, because it is called in by our settings page.  In that page, paste in the following code


header( 'Content-Type: ' . feed_content_type( 'rss-http' ) . '; charset=' . get_option( 'blog_charset' ), true );
$more = 1;

echo '<?xml version="1.0" encoding="UTF-8"?>'; ?>

<rss
version="2.0"
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
<?php do_action( 'rss2_ns' ); ?>
>

<channel>
<title><?php echo get_option( 'pyd_podcast_title' ); ?></title>
<atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
<link><?php echo bloginfo( 'url' ); ?></link>
<language>en-us</language>
<copyright>&#x2117; &amp; &#xA9; <?php echo get_option( 'pyd_podcast_copyright' ); ?></copyright>
<itunes:subtitle><?php echo get_option( 'pyd_podcast_subtitle' ); ?></itunes:subtitle>
<itunes:author><?php echo get_option( 'pyd_podcast_owner_name' ); ?></itunes:author>
<itunes:summary><?php echo get_option( 'pyd_podcast_summary' ); ?></itunes:summary>
<description><?php echo get_option( 'pyd_podcast_summary' ); ?></description>
<itunes:owner>
<itunes:name><?php echo get_option( 'pyd_podcast_owner_name' ); ?></itunes:name>
<itunes:email><?php echo get_option( 'pyd_podcast_owner_email' ); ?></itunes:email>
</itunes:owner>
<itunes:image href="<?php echo get_option( 'pyd_podcast_image' ); ?>" />
<itunes:category text="<?php echo get_option( 'pyd_podcast_category' ); ?>">
<itunes:category text="<?php echo get_option( 'pyd_podcast_subcategory' ); ?>" />
</itunes:category>
<itunes:explicit><?php echo get_option( 'pyd_podcast_clean' ); ?></itunes:explicit>

<?php do_action( 'rss2_head' );
global $prefix, $post;

$args     = array(
'post_type'      => 'pyd_simple_podcast',
'posts_per_page' => 500,
'meta_key'       => $prefix . 'pubs_date',
'orderby'        => 'meta_value_num',
'order'          => 'DESC'
);
$wp_query = new WP_Query( $args );

if ( $wp_query->have_posts() ) : while ( $wp_query->have_posts() ) : $wp_query->the_post();
?>
<item>
<title><?php the_title_rss() ?></title>
<itunes:author><?php the_author() ?></itunes:author>
<itunes:subtitle><?php echo get_post_meta( $post->ID, $prefix . 'pubs_info', $single = true ); ?></itunes:subtitle>
<itunes:summary><?php echo get_post_meta( $post->ID, $prefix . 'pubs_info', $single = true ); ?></itunes:summary>
<itunes:image href="<?php echo get_option( 'pyd_podcast_image' ); ?>" />
<enclosure url="<?php echo get_post_meta( $post->ID, $prefix . 'pubs_mp3', $single = true ); ?>"
length="<?php echo get_post_meta( $post->ID, $prefix . 'pod_size', $single = true ); ?>"
type="<?php echo get_post_meta( $post->ID, $prefix . 'pubs_filetype', $single = true ); ?>" />
<guid><?php echo get_post_meta( $post->ID, $prefix . 'pubs_mp3', $single = true ); ?></guid>
<pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate>
<itunes:duration><?php echo get_post_meta( $post->ID, $prefix . 'pod_duration', $single = true ); ?></itunes:duration>
<itunes:keywords>
<![CDATA[<?php echo get_post_meta( $post->ID, $prefix . 'pod_keyword', $single = true ); ?>
]]>
</itunes:keywords>
<?php rss_enclosure(); ?>
<?php do_action( 'rss2_item' ); ?>
</item>
<?php
endwhile;
endif;
?>
</channel>
</rss>

This code runs a loop through our custom post type and uses the data to fill in an RSS channel. This is what iTunes will use to populate your new podcast.

Step 6: Testing and Using

There it is!  You’ve done it, created a plugin that can feed your iTunes Podcast.  Great work.  All that’s left is to populate some episodes, test, and then link to iTunes.

To test, first put in some data.  Make sure to fill out all of the settings and add at least one episode.  Then head back to the “Podcast Settings” page and copy the link that is in the bottom yellow box.  This is the URL you will test and give to iTunes.  Navigate to Feed Validator and paste in your URL to the box and click the validate button.  If all of your data is entered in correctly, you have a valid feed.  If not, go and fix the errors that come up.  Use the Apple guidelines for entering in correct data.

When your feed has validated, it’s time to submit your feed to Apple.  To do that, click here.  This will open up your iTunes program and walk you through the steps to add your Podcast to the iTunes store.

You can also use an RSS reader (like the default one with WordPress) to display your Podcasting feed in the widget section.  There are all sorts of ways to pull in the data and share your episodes.

Check Your Work or Skip to the Finish

Here are the files that are used in this turtorial.  You can either just install this as a standalone plugin, or use it to check your work.

pyd-simple_podcasting

Happy Podcasting.

Trackbacks

  1. [...] are curious about how we did this, or if you want the plugin for your own website, take a look at this post.  It’s just one of the many things we offer our Worship Times [...]

  2. [...] are curious about how we did this, or if you want the plugin for your own website, take a look at this post.  It’s just one of the many things we offer our Worship Times members. Filed Under: Home [...]

  3. [...] are curious about how we did this, or if you want the plugin for your own website, take a look at this post.  It’s just one of the many things we offer our Worship Times members. Filed Under: Home Posts [...]

Speak Your Mind

Connect with Facebook

*