Tutorial – Custom Post Types for WordPress

With WordPress 3, came a slew of new features, the best one by far being Custom Post Types. I had fun using this to generate a “Dogs” page for the charity “Stiggy’s Dogs” that I manage. Stiggy’s Dogs rehabilitates dogs to pair them with returning veterans. I realize there is an abundance of tutorials out there, but they are all slightly different. Hopefully this will help someone else or give them some ideas: Here is an image of the final product as it is today:

WordPress Custom Post Type

There is a plan to develop it further with links that direct you to a chronological archive of posts related to the individual dog (almost like a diary), however this custom post type has already been very beneficial so far, as this static page gets quite a bit of traffic. For the charity, it’s a great way of showing their “portfolio”. Depending on the choices made when posting, the following various images will be displayed:

WordPress Custom Port Type Images

Now that you’ve seen where we’re going, let me show you how we get there. Custom Post Types only really consist of two files, the back-end which I’ve contained in the functions.php, and the front-end which we’ll use a loop for. As for functions.php, this is what it looks like (please take note that I’ve had to add additional php openers in order for the code to display below, if you want the final code, please download below).

Backend: Functions.php

In first line, we’ll fire up the custom post type fundamentals, defining the basics of our new tool. There are quite a number of parameters, so definitely reference the WordPress Codex if working with this for the first time:

// ************ DOGS START **************
// 1. Initialize
add_action( 'init', 'noeltockdotcom_dogs_register' );
// 2. Register Custom Post Type
function noeltockdotcom_dogs_register() {
	
		$labels = array(
			'name' => __( 'Dogs' ),
			'singular_name' => __( 'Dog' ),
			'add_new' => __( 'Add New' ),
			'add_new_item' => __( 'Add New Dog' ),
			'edit' => __( 'Edit' ),
			'edit_item' => __( 'Edit Dog' ),
			'new_item' => __( 'New Dog' ),
			'view' => __( 'View Dog' ),
			'view_item' => __( 'View Dog' ),
			'search_items' => __( 'Search Dogs' ),
			'not_found' => __( 'No dogs found' ),
			'not_found_in_trash' => __( 'No dogs found in deleted items' ),
			'parent' => __( 'Parent Dog' ),
		);
		
		$args = array( 
		'labels' => $labels,
		'description' => __( 'Your Dogs' ), 
		'public' => true,
		'supports' => array('title','editor','author','thumbnail','excerpt','comments'),
                'rewrite' => true,
                'capability_type' => 'post',
		);
		
	register_post_type( 'noeltockdotcom_dogs', $args);
}

Next up we’ll need to register our custom fields. This is what will make our custom post type so special. In the first instance we’ll tell WordPress which fields we want:

<!--?php
// **** 3. Register Custom Fields **** 
// Initialize
	add_action( 'admin_init', 'noeltockdotcom_dogs_admin' );
	
	// Add Meta Boxes
	
	function noeltockdotcom_dogs_admin(){
		add_meta_box("noeltockdotcom_dog_meta", "Dog Details", "noeltockdotcom_dog_meta", "noeltockdotcom_dogs", "normal", "low");
	}
	
	// Display Dog
	
	function noeltockdotcom_dog_meta (){
		global $post;
		$custom = get_post_custom($post->ID);
		$name = $custom["dog_name"][0];
		$status = $custom["dog_status"][0];	
		$gender = $custom["dog_gender"][0];
		$owner = $custom["dog_owner"][0];
		$branch = $custom["dog_branch"][0];
		$placed = $custom["dog_placed"][0];
	?>
	
	<label>Name of Dog:</label>
	<input name="dog_name" value="<?php echo $name; ?>" />
	<label>Status:</label>
	<select name="dog_status">
		<option value="deployed" <?php if (($status == '') || ($status == 'deployed')) { ?>selected="selected"<?php } ?>>Deployed</option>
		<option value="intraining" <?php if ($status == 'intraining') { ?>selected="selected"<?php } ?>>In Training</option>
		<option value="prospective" <?php if ($status == 'prospective') { ?>selected="selected"<?php } ?>>Prospective</option>	
	</select>	
	<label>Gender:</label>
	<select name="dog_gender">
		<option value="male" <?php if (($gender == '') || ($gender == 'male')) { ?>selected="selected"<?php } ?>>Male</option>
		<option value="female" <?php if ($gender == 'female') { ?>selected="selected"<?php } ?>>Female</option>
	</select>	
	<label>New Owner:</label>
	<input name="dog_owner" value="<?php echo $dog_owner; ?>" />
	<label>From Military Branch:</label>
	<select name="dog_branch">
		<option value="army" <?php if (($branch == '') || ($branch == 'army')) { ?>selected="selected"<?php } ?>>Army</option>
		<option value="marines" <?php if ($branch == 'marines') { ?>selected="selected"<?php } ?>>Marine Corps</option>
		<option value="navy" <?php if ($branch == 'navy') { ?>selected="selected"<?php } ?>>Navy</option>
		<option value="airforce" <?php if ($branch == 'airforce') { ?>selected="selected"<?php } ?>>Air Force</option>
		<option value="coastguard" <?php if ($branch == 'coastguard') { ?>selected="selected"<?php } ?>>Coast Guard</option>
		<option value="none" <?php if ($branch == 'none') { ?>selected="selected"<?php } ?>>None</option>
	</select>
	<label>Date Placed:</label>
	<input name="dog_placed" value="<?php echo $dog_placed; ?>" />
	<?php
	}
	
	// Save Fields
	
	add_action ('save_post', 'save_dogs');
	
	function save_dogs(){
		global $post;
		update_post_meta($post->ID, "dog_name", $_POST["dog_name"]);
		update_post_meta($post->ID, "dog_status", $_POST["dog_status"]);
		update_post_meta($post->ID, "dog_gender", $_POST["dog_gender"]);
		update_post_meta($post->ID, "dog_owner", $_POST["dog_owner"]);
		update_post_meta($post->ID, "dog_branch", $_POST["dog_branch"]);
		update_post_meta($post->ID, "dog_placed", $_POST["dog_placed"]);
	}

Last but not least; The great thing about Custom Post Types is that they also have their own dashboard for viewing all posts at once (which you can customize to show any or all of your custom fields). To display these various columns showing your custom content, whip up the following code:

<!--?php
// **** 4. Show Columns in Admin ****
// Initialize
add_action ("manage_posts_custom_column", "dogs_custom_columns");
add_filter ("manage_edit-noeltockdotcom_dogs_columns", "dogs_edit_columns");
// Display Columns
function dogs_edit_columns($columns){
	$columns = array (
		"cb" => "<input type=\"checkbox\" />",
		"title" => "Dog Name",
		"status" => "Status",
		"gender" => "Gender",
		"owner" => "Owner",
		"branch" => "Military Branch",
		"placed" => "Date Placed",
		"description" => "Description",
	);
	
	return $columns;
}
	
// Define Column Content
	
function dogs_custom_columns($column){
	global $post;
	switch ($column){
		case "status":
			$custom = get_post_custom();
			echo $custom["dog_status"][0];
			break;					
		case "gender":
			$custom = get_post_custom();
			echo $custom["dog_gender"][0];
			break;
		case "owner":
			$custom = get_post_custom();
			echo $custom["dog_owner"][0];
			break;	
		case "branch":
			$custom = get_post_custom();
			echo $custom["dog_branch"][0];
			break;	
		case "placed":
			$custom = get_post_custom();
			echo $custom["dog_placed"][0];
			break;	
		case "description":
			the_excerpt();
			break;		
	}
}

At this point, you’ll have successfully created everything needed in the back-end to make this functional. Good job!

Frontend: The Loop

This is actually the easy part, and I’ve tried to throw in some inline CSS (although not best practice) to show you how it all works.

<?php
//The Query
query_posts('post_type=noeltockdotcom_dogs&meta_key=dog_status&orderby=meta_value&order=ASC');
//The Loop
if (have_posts()) : ?>
<?php while (have_posts()) : the_post(); ?>
<?php
	$custom = get_post_custom($post->ID);
	$name = $custom["dog_name"][0];
	$status = $custom["dog_status"][0];
	$gender = $custom["dog_gender"][0];
	$owner = $custom["dog_owner"][0];
	$branch = $custom["dog_branch"][0];
	$placed = $custom["dog_placed"][0];
	$post_image_id = get_post_thumbnail_id($post_to_use->ID);
		if ($post_image_id) {
			$thumbnail = wp_get_attachment_image_src( $post_image_id, 'post-thumbnail', false);
			if ($thumbnail) (string)$thumbnail = $thumbnail[0];
		}
?>
<div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<div class="dogblock">
			<div style="float:left;background: url('<?php echo $thumbnail; ?>') no-repeat; width:300px; height:250px;">
				<?php if ($status == "deployed") {
					echo "<img src='http://www.stiggysdogs.org/images/deployed.png' />";
					} elseif ($status == "intraining") {
					echo "<img src='http://www.stiggysdogs.org/images/intraining.png' />";
					} else {
					echo "";
				} ?>
			</div>
			<div class="customdogcontent">
				<h3><?=$name?></h3>
				<?php if ($status == "deployed") {
					echo "<div style=\"background: url('http://www.stiggysdogs.org/images/$branch.png') no-repeat; min-height:60px;;width:320px;padding:20px 0 0 70px;font-size:20px;\">$owner</div>"; } ?>
				<p><?php the_content(); ?></p>
			</div>
</div>
</div>
<div style="padding:20px 0 0 0;width:660px;border-bottom:1px dotted #b49579;clear:both;"></div>
<?php endwhile; ?>
<!-- Stop the post loop and process any code included here only once. This text is generated only if there are posts. Any code included in this part of the document is processed only once. -->
<?php else : ?>
<p>No Dogs :( </p>
<!-- If you are seeing this message, there are no posts to process/display. Any code included in this part of the document is processed only once. -->
<?php endif; ?>

Summary

Custom Post Types for WordPress are incredibly useful as they allow you to create and display content exactly how you want it, making your life as a web designer that much easier. More importantly, they are an excellent way to manage your client’s needs within WordPress (as opposed to custom PHP/MySQL development which may not always be future-proof when considering future versions of WordPress). If you have any questions, please let me know, I’d be glad to help!

Download

Download the two PHP files here (functions.php & loop.php)

Related Links