Developer's Roundtable Notes

Session: Creating and Using Custom Post Types

Why CPTs?

An easy way to sort special purpose posts.

An easy way to add custom meta fields and re-arrange the edit screen – without affecting post and page edit screens.

Generally, just a cleaner way to add special posts without complicated queries.
(No need to exclude them from your normal blog page.)

Much simpler for clients to understand and manage.

Easy to create custom layout templates.

Category vs. CPT

When do you need a CPT?

Never need to integrate with posts

A completely different display

Need for custom fields

To make it simpler for client

Some Common Uses for CPTs

FAQs

Testimonials

Staff Bios

Restaurant Menu Items

Events / Calendar Items

Recommended Links

 

 

CPT for FAQs

Create a custom post type for FAQs:

<?php

add_action( 'init', 'register_lt_faq' );
 
function register_lt_faq() {
 
    $labels = array(
        'name' => 'FAQs',
        'singular_name' => 'FAQ',
        'add_new' =>  'Add New',
        'add_new_item' => 'Add New FAQ',
        'edit_item' => 'Edit FAQs',
        'new_item' => 'New FAQ',
        'view_item' => 'View FAQs',
        'search_items' => 'Search FAQs',
        'not_found' => 'No FAQ found',
        'not_found_in_trash' => 'No FAQ found in Trash',
        'parent_item_colon' => 'Parent FAQ:',
        'menu_name' => 'FAQs',
    );
 
    $args = array(
        'labels' => $labels,
        'hierarchical' => false,        
        'supports' => array( 'title', 'editor' ),
        'public' => true,
        'show_ui' => true,
        'show_in_menu' => true,  
        'show_in_nav_menus' => true,
        'publicly_queryable' => true,
        'exclude_from_search' => false,
        'has_archive' => true,
        'query_var' => true,
        'can_export' => true,
        'rewrite' =>array( 'slug' => 'frequently-asked-questions' ),
        'capability_type' => 'post',
    );
 
    register_post_type( 'lt-faq', $args );
}

 

CPT for Staff Members

This is the code to create a custom post type for Staff.

<?php

add_action( 'init', 'register_lt_staff' );
 
function register_lt_staff() {
 
    $labels = array(
        'name' => 'Staff',
        'singular_name' => 'Staff',
        'add_new' =>  'Add New',
        'add_new_item' => 'Add New Staff',
        'edit_item' => 'Edit Staff',
        'new_item' => 'New Staff',
        'view_item' => 'View Staff',
        'search_items' => 'Search Staff',
        'not_found' => 'No Staff found',
        'not_found_in_trash' => 'No Staff found in Trash',
        'parent_item_colon' => 'Parent Staff:',
        'menu_name' => 'Staff',
    );
 
    $args = array(
        'labels' => $labels,
        'hierarchical' => false,        
        'supports' => array( 'title', 'editor' , 'page-attributes', 'thumbnail' ),
        'public' => true,
        'show_ui' => true,
        'show_in_menu' => true,  
        'show_in_nav_menus' => true,
        'publicly_queryable' => true,
        'exclude_from_search' => false,
        'has_archive' => true,
        'query_var' => true,
        'can_export' => true,
		'menu_position' => 5,
        'rewrite' =>array( 'slug' => 'staff' ),
        'capability_type' => 'post',
    );
 
    register_post_type( 'lt-staff', $args );
}

 

Adding a Custom Taxonomy

This code creates a custom taxonomy for your CPT.

<?php
function register_taxonomy_lt_staff_department() {

    $labels = array( 
        'name' => 'Departments',
        'singular_name' => 'Department',
        'search_items' => 'Search Departments',
        'popular_items' => 'Popular Departments',
        'all_items' => 'All Departments',
        'parent_item' => 'Parent Department',
        'parent_item_colon' => 'Parent Department:',
        'edit_item' => 'Edit Department',
        'update_item' => 'Update Department',
        'add_new_item' => 'Add New Department',
        'new_item_name' => 'New Department',
        'separate_items_with_commas' => 'Separate Departments with commas',
        'add_or_remove_items' => 'Add or remove Departments',
        'choose_from_most_used' => 'Choose from the most used Departments',
        'menu_name' => 'Departments',
    );

    $args = array( 
        'labels' => $labels,
        'public' => true,
        'show_in_nav_menus' => true,
        'show_ui' => true,
        'show_tagcloud' => true,
        'show_admin_column' => true,
        'hierarchical' => true,
        'rewrite' => false,
        'query_var' => true
    );

    register_taxonomy( 'lt_staff_department', array('lt_staff'), $args );
}

 

Adding Custom Fields

This code creates a custom meta box for the custom fields.

<?php

$prefix = 'lt_staff_';

$testimonials_meta_box = array(
	'id' => 'lt_staff-meta-box',
	'title' => 'Staff Info',
	'page' => '_lt_staff',
	'context' => 'side',
	'priority' => 'high',
	'fields' => array(
		array(
		'name' => 'Name',
		'id' => $prefix . 'name',
		'type' => 'text',
		'std' => ''
		),
		array(
		'name' => 'Title',
		'id' => $prefix . 'title',
		'type' => 'text',
		'std' => ''
		),
		array(
		'name' => 'Email',
		'id' => $prefix . 'email',
		'type' => 'text',
		'std' => ''
		),
	)
);

add_action('admin_menu', 'lt_staff_add_box');

/* Add the meta box */
function lt_staff_add_box() {
	global $staff_meta_box;

	add_meta_box($staff_meta_box['id'], $staff_meta_box['title'], 'lt_staff_show_box', $staff_meta_box['page'], $staff_meta_box['context'], $staff_meta_box['priority']);
}

/* DISPLAY the new meta box */
function lt_staff_show_box() {
global $staff_meta_box, $post;

echo ' 
	<style>
	.ltt_panel label {  
	display: block;  
	font-weight: bold;  
	margin: 6px;  
	margin-bottom: 0;  
	margin-top: 12px;  
	}  
	.ltt_panel input[type="text"] {  
	margin-bottom: 3px;  
	width: 98%;  
	}  
	.ltt_panel h4 {  
	color: #999;  
	font-size: 1em;  
	margin: 15px 6px;  
	text-transform:uppercase;  
	}  
	</style>';

// Use nonce for verification
echo '<input type="hidden" name="lt_staff_meta_box_nonce" value="', wp_create_nonce(basename(__FILE__)), '" />'; 

echo '<div class="ltt_panel">';
	foreach ($staff_meta_box['fields'] as $field) {	
		// get current post meta data
		$meta = get_post_meta($post->ID, $field['id'], true);       
		echo '<label for="'. $field['id']. '">'. $field['name']. '</label>';
		echo '<input type="text" name="'. $field['id']. '" id="'. $field['id']. '" value="'. $meta. '" />' ;
	}
echo '</div>  ';
}

/* NOW, to save the data */
add_action('save_post', 'lt_staff_save_data');

// Save data from meta box
function lt_staff_save_data($post_id) {
	global $staff_meta_box;

	// verify nonce
	if (!wp_verify_nonce($_POST['lt_staff_meta_box_nonce'], basename(__FILE__))) {
		return $post_id;
	}

	// check autosave
	if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
		return $post_id;
	}

	//check QuickEdit
	if (defined('DOING_AJAX') ) {
		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 ($staff_meta_box['fields'] as $field) {
		$old = get_post_meta($post_id, $field['id'], true);
		$new = $_POST[$field['id']];

		if ($new && $new != $old) {
			update_post_meta($post_id, $field['id'], $new);
		} elseif ('' == $new && $old) {
			delete_post_meta($post_id, $field['id'], $old);
		}
	}
}

 

Template Magic

The magic of WordPress templates:

template-hierarchyJust name your template file correctly, and WP does the rest!

Single Page for Staff

Here is the code for displaying a single staff member. Name this page single-lt_staff.php.

<?php get_header();?>

<div class="content">
 
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
<div class="post" id="post-<?php the_ID(); ?>" style="border-bottom:0">

    <h1><?php echo $name ?></h1>
    <div class="staff">
	<?php
	$name=get_post_meta($post->ID, 'lt_staff_name', true);
	$title=get_post_meta($post->ID, 'lt_staff_title', true);
	$email=get_post_meta($post->ID, 'lt_staff_email', true);
	?>
    <div class="staff-pic">
	<?php the_post_thumbnail( 'full' ); ?>
    </div>
    <h2><?php echo $name ?></h2>
    <p><?php echo $title ?><br>
    <a href="mailto:<?php echo $email ?>"><?php echo $email ?></a></p>
    <?php the_content(); ?>
    </div>
</div>
<?php endwhile; endif; ?>
</div>
<?php get_sidebar(); ?>
 
<?php get_footer(); ?>

 

Archive Page for Staff

Here’s the code for archive-lt_staff.php:

<?php get_header();?>
 
<div class="content">
<h2>Our Staff</h2>	
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
        <div class="post" id="post-<?php the_ID(); ?>" style="border-bottom:0">
            <div class="staff">
		  <?php
			$name=get_post_meta($post->ID, 'lt_staff_name', true);
			$title=get_post_meta($post->ID, 'lt_staff_title', true);
			$email=get_post_meta($post->ID, 'lt_staff_email', true);
			?>
			<div class="staff-pic">
				<?php the_post_thumbnail( array(150,150) ); ?>
			</div>
			<h2><?php echo $name ?></h2>
			<p><?php echo $title ?><br>
			<a href="mailto:<?php echo $email ?>"><?php echo $email ?></a></p>
           <?php the_content(); ?>
            </div>
        </div>
      <?php endwhile; endif; ?>
<p align="center"><?php posts_nav_link(' - ','&#171; Previous','Next &#187;') ?></p>
<p>&nbsp;</p>
</div>
 
<?php get_sidebar(); ?>
 
<?php get_footer(); ?>

 

Archive Page by Taxonomy

To list staff members by their department, use this code for archive-lt_staff.php instead.

<?php get_header();?>

<div class="content">	

<h1>Our Staff by Department</h1>	

<?php
	$categories = get_terms('lt_staff_department');
	foreach ( $categories as $category ) {
?>
	<h2><?php echo $category->name; ?></h2>
	<?php
		$posts = new WP_Query(array(
		'post_type' => 'lt_staff',
		'orderby' => 'menu_order',
		'order' =>  'ASC',
		'taxonomy' => $category->taxonomy,
		'term'  => $category->slug,
		'nopaging' => true,
		));
	?>
	<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
		<div class="post" id="post-<?php the_ID(); ?>">
			<div class="staff">
				<?php
					$name=get_post_meta($post->ID, 'lt_staff_name', true);
					$title=get_post_meta($post->ID, 'lt_staff_title', true);
					$email=get_post_meta($post->ID, 'lt_staff_email', true);
				?>
				<div class="staff-pic">
					<?php the_post_thumbnail( array(150,150) ); ?>
				</div>
				<h3><?php echo $name ?></h3>
				<p><?php echo $title ?><br>
				<a href="mailto:<?php echo $email ?>"><?php echo $email ?></a></p>
				<?php the_content(); ?>
			</div>
		</div>
	<?php endwhile; endif; ?>
	<?php } ?>
	</div>

<?php get_sidebar(); ?>

<?php get_footer(); ?>

 

Put it into a Plugin

Because your client will be unhappy if they lose all their staff bios when they change to a new theme!

<?
/*
Plugin Name: CPT for Staff Members
Description: Custom Post Type for Staff
Author: Diana Nichols
Version: 1.0
Author URI: http://www.lavenderthreads.com
*/

<?php

/** 1. the custom post type *******************************/

add_action( 'init', 'register_lt_staff' );
function register_lt_staff() {
    $labels = array(
        'name' => 'Staff',
        'singular_name' => 'Staff',
        'add_new' =>  'Add New',
        'add_new_item' => 'Add New Staff',
        'edit_item' => 'Edit Staff',
        'new_item' => 'New Staff',
        'view_item' => 'View Staff',
        'search_items' => 'Search Staff',
        'not_found' => 'No Staff found',
        'not_found_in_trash' => 'No Staff found in Trash',
        'parent_item_colon' => 'Parent Staff:',
        'menu_name' => 'Staff',
    );
    $args = array(
        'labels' => $labels,
        'hierarchical' => false,        
        'supports' => array( 'title', 'editor' , 'page-attributes', 'thumbnail' ),
        'public' => true,
        'show_ui' => true,
        'show_in_menu' => true,  
        'show_in_nav_menus' => true,
        'publicly_queryable' => true,
        'exclude_from_search' => false,
        'has_archive' => true,
        'query_var' => true,
        'can_export' => true,
        'menu_position' => 5,
        'rewrite' =>array( 'slug' => 'staff' ),
        'capability_type' => 'post',
    );
    register_post_type( 'lt-staff', $args );
}

/** 2. the custom taxonomy ******************************/

function register_taxonomy_lt_staff_department() {

    $labels = array( 
        'name' => 'Departments',
        'singular_name' => 'Department',
        'search_items' => 'Search Departments',
        'popular_items' => 'Popular Departments',
        'all_items' => 'All Departments',
        'parent_item' => 'Parent Department',
        'parent_item_colon' => 'Parent Department:',
        'edit_item' => 'Edit Department',
        'update_item' => 'Update Department',
        'add_new_item' => 'Add New Department',
        'new_item_name' => 'New Department',
        'separate_items_with_commas' => 'Separate Departments with commas',
        'add_or_remove_items' => 'Add or remove Departments',
        'choose_from_most_used' => 'Choose from the most used Departments',
        'menu_name' => 'Departments',
    );

    $args = array( 
        'labels' => $labels,
        'public' => true,
        'show_in_nav_menus' => true,
        'show_ui' => true,
        'show_tagcloud' => true,
        'show_admin_column' => true,
        'hierarchical' => true,
        'rewrite' => false,

/** 3. the custom fields meta box ************************/

$prefix = 'lt_staff_';

$testimonials_meta_box = array(
    'id' => 'lt_staff-meta-box',
    'title' => 'Staff Info',
    'page' => '_lt_staff',
    'context' => 'side',
    'priority' => 'high',
    'fields' => array(
        array(
        'name' => 'Name',
        'id' => $prefix . 'name',
        'type' => 'text',
        'std' => ''
        ),
        array(
        'name' => 'Title',
        'id' => $prefix . 'title',
        'type' => 'text',
        'std' => ''
        ),
        array(
        'name' => 'Email',
        'id' => $prefix . 'email',
        'type' => 'text',
        'std' => ''
        ),
    )
);

add_action('admin_menu', 'lt_staff_add_box');

/* Add the meta box */
function lt_staff_add_box() {
    global $staff_meta_box;

    add_meta_box($staff_meta_box['id'], $staff_meta_box['title'], 'lt_staff_show_box', $staff_meta_box['page'], $staff_meta_box['context'], $staff_meta_box['priority']);
}

/* DISPLAY the new meta box */
function lt_staff_show_box() {
global $staff_meta_box, $post;

echo ' 
    <style>
    .ltt_panel label {  
    display: block;  
    font-weight: bold;  
    margin: 6px;  
    margin-bottom: 0;  
    margin-top: 12px;  
    }  
    .ltt_panel input[type="text"] {  
    margin-bottom: 3px;  
    width: 98%;  
    }  
    .ltt_panel h4 {  
    color: #999;  
    font-size: 1em;  
    margin: 15px 6px;  
    text-transform:uppercase;  
    }  
    </style>';

// Use nonce for verification
echo '<input type="hidden" name="lt_staff_meta_box_nonce" value="', wp_create_nonce(basename(__FILE__)), '" />'; 

echo '<div class="ltt_panel">';
    foreach ($staff_meta_box['fields'] as $field) {    
        // get current post meta data
        $meta = get_post_meta($post->ID, $field['id'], true);       
        echo '<label for="'. $field['id']. '">'. $field['name']. '</label>';
        echo '<input type="text" name="'. $field['id']. '" id="'. $field['id']. '" value="'. $meta. '" />' ;
    }
echo '</div>  ';
}

/* NOW, to save the data */
add_action('save_post', 'lt_staff_save_data');

// Save data from meta box
function lt_staff_save_data($post_id) {
    global $staff_meta_box;

    // verify nonce
    if (!wp_verify_nonce($_POST['lt_staff_meta_box_nonce'], basename(__FILE__))) {
        return $post_id;
    }

    // check autosave
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return $post_id;
    }

    //check QuickEdit
    if (defined('DOING_AJAX') ) {
        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 ($staff_meta_box['fields'] as $field) {
        $old = get_post_meta($post_id, $field['id'], true);
        $new = $_POST[$field['id']];

        if ($new && $new != $old) {
            update_post_meta($post_id, $field['id'], $new);
        } elseif ('' == $new && $old) {
            delete_post_meta($post_id, $field['id'], $old);
        }
    }
}

 One caveat here… the custom display pages (single-lt_staff.php and archive-lt_staff.php) need to be included in the theme files.

Skip to toolbar