FAQs and Custom Post Types

One of the new features of Mad Scientist Technologies v1.3 is a completely redesigned FAQ Section. In the new FAQ section I decided to use WordPress’s Custom Post Type for ease of management of the FAQs. So I thought I would share how I created a custom post type for the FAQs.

Before I dive-in, if you are uncomfortable working with code – HTML and PHP – you may want to consider hiring someone to create your custom post type. Also, if you follow this tutorial and it breaks your site – Do Not Blame Me. Now on with the show!

What are Custom Post Types

Custom Post Types are a way for you to create new content that is outside of your main blog posts. A great example – which will be using during this tutorial – is screencasts. Over at Mad Scientist Technologies we will be posting screencast on different topics. However, we don’t want them to go out in the normal RSS feed of the site – so we are going to create a custom post type for our screencasts post.

Planning

The first thing we need to do is plan for this new post type, we need to know names – slugs – options – etc. So we’re going to work that out right now.

The first thing is a name, which we decided to go with Podcasts. Why Podcasts, it generic enough but yet still makes sense – you can name them anything you want but this is what I’m going with. So once we have a name we can create a unique internal function name for WordPress. According to the WordPress Codex these name must be unique or it will cause issues, they suggest to prefix your custom post type function name with a unique namespace. But you only need to worry about this if you plan to share/sell your theme to others. So we are going to use my custom namespace for the function name – mst_ thus my internal name of this post type will be mst_podcast_post.

Now we need to decide about some of the functionality of the particular post type. Let see, it will act much like a regular post, we want comments, we need a place to throw the embed code for the video and show notes. So the following options will be used:

'capability_type' =>    'post',
'supports'        =>    array('title', 'editor', 'comments')

However that doesn’t take care of the place for the video embed code – so we’re going to create a streamlined custom field just for that – but we will tackle that in the coding section.

So this is what we have so far – podcast title, a place for the show notes, comments are enabled, a custom field just for the video embed.

The last thing we need to look into before we start coding this up is the URL that this podcast posts will live at. We have decided to go with http://madscitech.com/screencasts/, an easy to remember and SEO friendly name. So the following code with take care of that for us:

'rewrite'         =>    array('slug' => 'screencasts'),

Now that we have the planning done we can move on to coding this post type up.

Coding Time

Important: You may want to backup your WordPress Installation and Database before starting this section!
Note: You may even want to play around locally first (via XAMPP or MAMP) then upload to your site.

To start coding the post type we need to open our current theme’s functions.php – for example assuming that your using the default Twenty Ten Theme with WordPress, your theme function file will be located at ~/wp-content/themes/twentyten/functions.php. So go ahead and open the file in your favorite text editor, the following is what we are dump into the file to create our post type:

// Custom Post Types - Screencasts
add_action('init', 'screencast_register');

function screencast_register(){
  $args = array(
      'label'             =>    __('Podcasts'),
      'singular_label'    =>    __('Podcast'),
      'public'            =>    true,
      'show_ui'           =>    true,
      'capability_type'   =>    'post',
      'hierarchical'      =>    false,
      'rewrite'           =>    array('slug' => 'screencasts'),
      'has_archive'       =>    true,
      'supports'          =>    array('title', 'editor', 'comments')
  );

  register_post_type( 'mst_podcast_post' , $args );
}

This code is the bare minimum code to create an custom post type, these arguments are mostly understandable. But the few that would catch some people off guard are: 'capability_type' 'rewrite' 'has_archive' 'supports'.

label – The label argument is the regular name of the Post Type in the plural form . The __('') is part of the WordPress Language Translation.

singular_label – This label has several sub-arguments, this argument will allow you to control the text used in the headers when working with a single item from the custom post type.

capability_type – is what the custom post type will act most like that is built into WordPress e.g. Post, Pages, etc.

rewrite – This allows you to override the default URL structure, e.g. default would been example.com/podcasts/%post-name%/ now it would be example.com/screencasts/%post-name%/.

has_archive – Just a simple question, do you want to have an archive for this post type?

support – These are the available features that will appear for the custom post type in the WordPress Admin, see the full list at the WordPress Codex.

Now, in order to create our field for the video embed code, paste in the below code to create it.

// Podcasts Video Embed Field
add_action("admin_init", "admin_init");
add_action('save_post', 'save_video');

function admin_init(){
	add_meta_box("podcast-meta", "Video Embed", "meta_options", "mst_podcast_post", "side", "low");
}

function meta_options(){
	global $post;
	$custom = get_post_custom($post->ID);
	$video_link = $custom['mst_video_embed'][0];

  echo '<label id="video_code">Video Embed Code</label><textarea id="video_code" name="video_embed" style="height:100px; width:100%;">';
  echo $video_link;
  echo '</textarea>';
}

function save_video(){
	global $post;
	update_post_meta($post->ID, "mst_video_embed", $_POST["video_embed"]);
}

In the above code we are adding hooks into the WordPress Admin and creating a save function. We are going to start from the top.

The first two items add_action("admin_init", "admin_init"); and add_action('save_post', 'save_video'); are the actual hooks into WordPress. The first one says when starting WordPress Admin run the function admin_init and the same goes for the second one – when saving a post run the save_video function.

The first function we come to will add the field to the WordPress Admin, the function admin_init will run the built-in WordPress function add_meta_box. The arguments to add_meta_box are as follows:

add_meta_box(
  "podcast-meta"  - The CSS ID of the New field container,
  "Video Embed"  - The Human Readable Name in the WordPress Admin,
  "meta_options  - Callback function,
  "mst_podcast_post  - The custom post type name,
  "side"  - Position of the Container,
  "low"  - Important of the position of the container
)

If you still need help, please see the add_meta_box page on the Codex

Now we can get started on the work horse of the function – meta_options(). This callback function will get the value of mst_video_embed from the database and place it into the variable $video_link. Then it will create the textarea and place the value of the variable $video_link inside of it. If you change the variable name and/or the name of the textarea please remember to update the variable on the above line and the name in the $_POST line below.

Then we come to the save_video function which will save the contents of the video embed textarea. The three arguments of the update_post_meta are as follows:

save_video(){
  $post->ID  - Gets the current Post ID
  "mst_video_embed"  - The Key value in the database
  $_POST["video_embed"]  - This is the value that will be placed in the database, from the textarea's name value.
}

For a full description of the arguments available for the custom post type function, please see the WordPress Codex page

Testing Time

After you dump that code into the functions.php file, reload your site to see if there is any PHP errors in your code. If your site loads without a problem your good to go on! If you get some errors either try fixing them or copy and paste the code directly from the code blocks above.

Now you can log into your WordPress Admin and you should see a new Navigation item – mostly likely below the comments navigation item. If you click on your new post type you should see what seems like a regular post editor page but without some the extras. Also you should see a Video Embed Code box below the “Publish” box.

If things look right, you should try to create a dummy post placing info in all the fields – title, body and video embed code – and publish it. The default page template used will be the single page view, we discuss how to customize the page template in the next section.

Troubleshooting

When I try to go to my new custom post type I get a 404 – In the WordPress Admin go to Settings > Permalinks, then reload the custom post type page. By doing so WordPress will reset your permalinks settings, you don’t even need to save or edit the settings for this to work. I found this out from Justin Tadlock’s Blog which also discuss this topic.

The custom field isn’t showing up in the WordPress Admin – In the above code examples their are spaces in the tags Label and Textarea, try removing them first. If it still doesn’t show up, check to make sure that the textarea is included in the meta_options functions.

The custom field isn’t working – If you have changed any of the variables or the name associated with the textarea please remember to update the name in the other locations.

Finished Up & the Beginning

You should now have a working custom post type for a podcast directory on your WordPress powered site. There is only two more steps to complete your custom post type – configure a custom page template and adding the CONTENT.

Custom Page Template for your Custom Post Type

In order to create a custom page template you just create a custom page template. Let me explain, I must assume that you either understand how to create WordPress themes – but if you don’t I will do a quick run through of it.

Lets assume you create your custom post type with the name mst_podcast_post – I got this from the last line of the screencast_register() function where it says register_post_type( 'mst_podcast_post' , $args );. Now that you have the proper name of your custom post type, you create a file named single-mst_podcast_post.php and drop that into your theme folder.

To illustrate this point this is my page template for the above post type:

single-mst_podcast_post.php

<?php
the_post();
$custom = get_post_custom($post->ID);
$video_embed = $custom["mst_video_embed"][0];

get_header();
?>
	<div id="articles">
 		<div <?php post_class('article'); ?> id="post-<?php the_ID(); ?>">
      <div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
        <h1 class="entry-title"><?php the_title(); ?></h1>

      	<div class="post-entry">
      	  <?php 
          // If $video_embed does not include <iframe assume YouTube Video ID
          if(!preg_match("/<iframe/", $video_embed)){ ?>
            <iframe width="100%" height="400" src="http://www.youtube.com/embed/<?=$video_embed; ?>" frameborder="0" allowfullscreen></iframe>
          <?php } else { 
            // Else post as normal video embed code
            echo $video_embed;
          } ?>

          <hr />      	
 
      		<?php the_content(); ?>
      	</div>
      </div>
    <?php comments_template(); ?>
    </div>
  </div>
<?php get_sidebar(); get_footer(); ?>  

The most important bits are the file name and first three lines above get_header();. The third line is setting the video embed code from the backend to a variable we can use on this page to print out to the browser. The rest of the code setup the theme’s layout DIVs and the if statement in the middle of the page allows me to just paste a YouTube Video ID into the Video Embed Code field in the WordPress Admin and the page will take care of the rest.

To create an archive page for a custom post type, you would do the same thing just instead of single-mst_podcast_post.php it would be archive-mst_podcast_post.php.

Conclusion

A custom post type may take some time to get setup and running – but in the long run it will allow you to have more control over your content and how it is presented to your visitors. Also, some may argue that this type of feature would be better served by a plugin instead of the theme’s functions file, but at the speed of implementing such a feature this way – it is a great way to test before you commit to another plugin.

What is your opinion of the new custom post types available in WordPress? Share your thoughts below in the comments.

More Reading

WordPress Codex – Post Types
WordPress Codex – Register Post Types
WordPress Codex – Add Meta Box
WordPress Codex – Update Post Meta
Rock-Solid WordPress 3.0 Themes using Custom Post Types
Justin Tadlock – Custom post types in WordPress