Custom Post Types

Setting up Custom Post Types | Setting up Custom Fields | Templates

Setting up Custom Post Types

I was recently asked to create a custom post type for members of an association. Each member should be able to enter various kinds of information about themselves. Parts of this information would be pulled into other pages.

I will give a summary of what I did to accomplish this. If you need a more in depth tutorial read Justin Tadlock’s excellent article.

In order to create the custom post type I first created a folder in the ‘plugin’ section named ‘Partner Custom Posts’. Inside the folder I created a php file with the same name where I wrote all my code. The plugin needs to be activated in the plugins area of the dashboard.The code could also go into functions.php instead.

Here is the code I used to create the custom post type:

function my_partner_custom_post() {
	$labels = array(
		'name'               => _x( 'Partners', 'post type general name' ),
		'singular_name'      => _x( 'Partner', 'post type singular name' ),
		'add_new'            => _x( 'Add New', 'book' ),
		'add_new_item'       => __( 'Add New Partner' ),
		'edit_item'          => __( 'Edit Partner' ),
		'new_item'           => __( 'New Partner' ),
		'all_items'          => __( 'All Partners' ),
		'view_item'          => __( 'View Partner' ),
		'search_items'       => __( 'Search Partners' ),
		'not_found'          => __( 'No partner entries found' ),
		'not_found_in_trash' => __( 'No partner entries found in the Trash' ), 
		'parent_item_colon'  => '',
		'menu_name'          => 'Partners'
	$args = array(
		'labels'        => $labels,
		'rewrite' => array( 'slug' => 'partner' ),
		'description'   => 'Holds our partners and partners specific data',
		'public'        => true,
		'menu_position' => 5,
                'menu_icon' 	=> plugins_url('images/partner.png', __FILE__),
		'supports'      => array( 'title', 'editor', 'thumbnail', 'excerpt', 'custom-fields','comments', 'revisions'  ),
		'has_archive'   => true,
	register_post_type( 'partner', $args );	
add_action( 'init', 'my_partner_custom_post' );

In order to be able to filter partner displays I needed to add custom taxonomies. I created a number of them. Here is an example:

function partners_location() {
	$labels = array(
		'name'              => _x( 'Location', 'taxonomy general name' ),
		'singular_name'     => _x( 'Location', 'taxonomy singular name' ),
		'search_items'      => __( 'Search Locations' ),
		'all_items'         => __( 'All Locations' ),
		'parent_item'       => __( 'Parent Location' ),
		'parent_item_colon' => __( 'Parent Location:' ),
		'edit_item'         => __( 'Edit Location' ), 
		'update_item'       => __( 'Update Location' ),
		'add_new_item'      => __( 'Add New Location' ),
		'new_item_name'     => __( 'New Location' ),
		'menu_name'         => __( 'Locations' ),
	$args = array(
		'labels' => $labels,
		'hierarchical' => true,
	register_taxonomy( 'location', 'partner', $args );
add_action( 'init', 'partners_location', 0 );

The custom post type and taxonomies now appeared in the dashboard menu under ‘Partners’. The url for the custom post archive is website url/partner. In order to have ‘Partners in the menu I had to create a custom menu item by entering the url and label in the custom menu section of the ‘menus’ admin area.

Next I needed a new template that would display single partner posts. I duplicated single.php and renamed it single-partner.php. In order for partner posts to open with that template I added the following code to my partner-custom-posts.php file:

function include_template_function( $template_path ) {
    if ( get_post_type() == 'partner' ) {
        if ( is_single() ) {
            // checks if the file exists in the theme first,
            // otherwise serve the file from the plugin
            if ( $theme_file = locate_template( array ( 'single-partner.php' ) ) ) {
                $template_path = $theme_file;
            } else {
                $template_path = plugin_dir_path( __FILE__ ) . '/single-partner.php';
    return $template_path;
add_filter( 'template_include', 'include_template_function', 1 );

I also made sure messages sent to the user while editing a post would be updated to reflect the custom post type:

function my_updated_messages( $messages ) {
	global $post, $post_ID;
	$messages['partner'] = array(
		0 => '', 
		1 => sprintf( __('Partner post updated. <a href="%s">View partner post</a>'), esc_url( get_permalink($post_ID) ) ),
		2 => __('Custom field updated.'),
		3 => __('Custom field deleted.'),
		4 => __('Partner post updated.'),
		5 => isset($_GET['revision']) ? sprintf( __('Partner post restored to revision from %s'), wp_post_revision_title( (int) $_GET['partner'], false ) ) : false,
		6 => sprintf( __('Partner post published. <a href="%s">View partner post</a>'), esc_url( get_permalink($post_ID) ) ),
		7 => __('Partner post saved.'),
		8 => sprintf( __('Partner post submitted. <a target="_blank" href="%s">Preview partner post</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
		9 => sprintf( __('Partner post scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview partner post</a>'), date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
		10 => sprintf( __('Partner draft updated. <a target="_blank" href="%s">Preview partner post</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
	return $messages;
add_filter( 'post_updated_messages', 'my_updated_messages' );


Setting up Custom Fields

Since I needed various custom fields in each partner post, I used the Advanced Custom Fields plugin. It allowed me to set up a number of different custom fields in just a few minutes – from extra text entry areas with a WYSIWYG editor to video uploads and checkboxes.



By default the partner loop would use the same template as regular post (archive.php) to display partner posts. Since I added extra custom fileds this was not an option. So I duplicated archive.php, named it archive-partner.php. WordPress will always use the more specific php file before loading the more general one, so there was nothing else I needed to do to make sure partners would be displayed with this new file – other than edit it. I added the same kinds of edits in the single-partner.php created earlier.

If you are using the Advanced Custom Fieds plugin, all you need to display your custom fields is this:

<?php the_field('name of field'); ?>

If you are not using this plugin, you con use the following code to pull in custom fields:

<?php if ( get_post_meta($post->ID, 'biography', true) ) : ?>
<?php  echo get_post_meta($post->ID, 'biography', true); ?>
<?php endif; ?>

If your custom field allows you to upload an image, the data returned would be a url. So in order to display the image, you would write:

<img src="<?php the_field('name of the image upload field') ?> />

If you are displaying the image in a different context (for example, on an ‘About’ page) and you want it to link back to the original post,
you would write:

<a href="<?php get_permalink( $post->ID) ?>"><img src="<?php the_field('portrait') ?>" /></a>

or if you are not using the plugin:

<?php $portraitid = get_post_meta($post->ID, 'portrait', true); ?>
<?php echo '<a href=" '. get_permalink( $post->ID) . '">' . wp_get_attachment_image( $portraitid ) . '</a>'; ?>

If you want to display the custom taxonomies your custom post has been added to, you can use this code:
(note: in this example ‘profession’ is my custom taxonomy)

<?php $my_terms = wp_get_object_terms($post->ID, 'profession');?>
     <?php if(!empty($my_terms)){
	if(!is_wp_error( $my_terms )){
	   echo '<h2>Professions:</h2>';
	foreach($my_terms as $my_term) {
	   echo '<a href="' . get_term_link($my_term->slug, 'profession') . '">' . $my_term->name . ', </a>'; 
} ?>

There are many more exhaustive tutorials available on this subject, but hopefully this is useful as a general summary of the code needed.

Similar Posts

Leave a Reply

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