post

Developing a Custom Post Type and a Custom Taxonomy in Genesis with Custom Pages, Part 1

Custom Post Type Metaboxes

Recently, someone contacted me to develop a custom post type setup for their website, and they were lamenting how there is nothing on the web that succinctly walks them through the process: soup to nuts. So here’s my attempt! However, I am going to assume basic knowledge of custom post types. If you haven’t read through my Understanding Custom Post Types series yet, you may want to do that.

First, I created a new php file called wps-admin-functions.php. This is where we will house our Custom Post Types, Taxonomies, and Metaboxes. We could have added this to our theme’s function.php file but this will allow us to have a separate file dedicated to our newly added features. To do this, simply create a new text document in your favorite text editor and save as wps-admin-functions.php.

1. Register your Custom Post Type

<?php
// registration code for discbrakes post type
function wps_register_discbrakes_posttype() {
	$labels = array(
		'name' => _x( 'Disc Brakes', 'post type general name' ),
		'singular_name' => _x( 'Disc Brake', 'post type singular name' ),
		'add_new' => _x( 'Add New', 'Disc Brake'),
		'add_new_item' => __( 'Add New Disc Brake '),
		'edit_item' => __( 'Edit Disc Brake '),
		'new_item' => __( 'New Disc Brake '),
		'view_item' => __( 'View Disc Brake '),
		'search_items' => __( 'Search Disc Brakes '),
		'not_found' =>  __( 'No Disc Brake found' ),
		'not_found_in_trash' => __( 'No Disc Brakes found in Trash' ),
		'parent_item_colon' => ''
	);

	$supports = array( 'title' , 'editor' , 'thumbnail' , 'excerpt' , 'revisions' );

	$post_type_args = array(
		'labels' => $labels,
		'singular_label' => __( 'Disc Brake' ),
		'public' => true,
		'show_ui' => true,
		'publicly_queryable' => true,
		'query_var' => true,
		'capability_type' => 'post',
		'has_archive' => true,
		'hierarchical' => false,
		'rewrite' => array( 'slug' => 'discbrakes' ),
		'supports' => $supports,
		'menu_position' => 5,
		'taxonomies' => array( 'wps_axlesizes' ),
		'menu_icon' => 'http://mydomain.com/wp-content/themes/lib/images/discbrakes-icon.png'
	 );
	 register_post_type( 'wps_discbrakes' , $post_type_args );
}
add_action( 'init', 'wps_register_discbrakes_posttype' );

Notice in this code that I associate my custom post type with my coming custom taxonomy: 'taxonomies' => array( 'wps_axlesizes' ),. Also, note that I am using a prefix on both my custom post type and taxonomy. The reason this is done is that there may be a naming conflict with a plugin or other code in your theme. The prefix uniquely identifies it to prevent this. It is a best practice, and make sure you do not use the wp_ or genesis_ prefixes.

2. Register your Custom Taxonomy

<?php
// registration code for AxleSizes taxonomy
function wps_register_axlesizes_tax() {
	$labels = array(
		'name' => _x( 'Axle Sizes', 'taxonomy general name' ),
		'singular_name' => _x( 'Axle Size', 'taxonomy singular name' ),
		'add_new' => _x( 'Add New Axle Size', 'Axle Size'),
		'add_new_item' => __( 'Add New Axle Size' ),
		'edit_item' => __( 'Edit Axle Size' ),
		'new_item' => __( 'New Axle Size' ),
		'view_item' => __( 'View Axle Size' ),
		'search_items' => __( 'Search Axle Sizes' ),
		'not_found' => __( 'No Axle Size found' ),
		'not_found_in_trash' => __( 'No Axle Size found in Trash' ),
	);

	$pages = array( 'wps_discbrakes' );

	$args = array(
		'labels' => $labels,
		'singular_label' => __( 'Axle Size' ),
		'public' => true,
		'show_ui' => true,
		'hierarchical' => false,
		'show_tagcloud' => false,
		'show_in_nav_menus' => true,
		'rewrite' => array('slug' => 'axle-sizes'),
	 );
	register_taxonomy( 'wps_axlesizes' , $pages , $args );
}
add_action( 'init' , 'wps_register_axlesizes_tax' );

Custom Post TypeNotice in the registration, the taxonomy is associated with my custom post type: $pages = array( 'wps_discbrakes' );.

Once these are registered, you should see your custom post type to the left under POST.

3. Create my Metaboxes
With metaboxes, you can go the long way; however, I prefer to use a class. Soon WordPress will have a metabox class, hopefully in WordPress 3.3, so this section will be rendered “obsolete” yet still usable. First, download the custom metabox code from GitHub. For a great explanation of the code, see Bill Erickson’s tutorial. Because of the tutorial, I won’t break down this section.

Once downloaded, place the metabox folder in your lib folder in the child theme folder so that: CHILD_URL . '/lib/metabox/init.php'

So the file structure is
CHILD-THEME-FOLDER

  • IMAGES FOLDER
  • LIB FOLDER
    • METABOX FOLDER
    • IMAGES FOLDER
    • wps-admin-functions.php
  • functions.php
  • style.css
  • readme.txt
<?php
// Create Metaboxes
$prefix = '_wps_';
add_filter( 'cmb_meta_boxes', 'wps_create_metaboxes' );
function wps_create_metaboxes() {
	global $prefix;

	$meta_boxes[] = array(
		'id' => 'disk-brakes-info',
		'title' => 'Disk Brakes Information',
		'pages' => array( 'wps_discbrakes' ), // post type
		'context' => 'normal',
		'priority' => 'low',
		'show_names' => true, // Show field names left of input
		'fields' => array(
			array(
				'name' => 'Instructions',
				'desc' => 'In the right column upload a featured image. Make sure this image is at least 900x360px wide. Then fill out the information below.',
				'id' => $prefix . 'title',
				'type' => 'title',
			),
			array(
				'name' => 'Part Number',
				'desc' => 'Enter the part number (e.g., XXXXXXX)',
				'id' => $prefix . 'part_number',
				'type' => 'text'
			),
			array(
				'name' => 'Rotor',
				'desc' => '',
				'id' => $prefix . 'rotor',
				'type' => 'select',
				'options' => array(
					array('name' => 'Stainless Steel', 'value' => 'stainless-steel'),
					array('name' => 'E-Coat (Black)', 'value' => 'e-coat-black'),
					array('name' => 'Option Three', 'value' => 'none')
				)
			),
			array(
				'name' => 'Caliper',
				'desc' => '',
				'id' => $prefix . 'caliper',
				'type' => 'select',
				'options' => array(
					array('name' => 'Stainless Steel', 'value' => 'stainless-steel'),
					array('name' => 'E-Coat (Black)', 'value' => 'e-coat-black'),
					array('name' => 'Option Three', 'value' => 'none')
				)
			),
			array(
				'name' => 'Mounting Bracket',
				'desc' => '',
				'id' => $prefix . 'mounting_bracket',
				'type' => 'select',
				'options' => array(
					array('name' => 'Stainless Steel', 'value' => 'stainless-steel'),
					array('name' => 'E-Coat (Black)', 'value' => 'e-coat-black'),
					array('name' => 'Option Three', 'value' => 'none')
				)
			),
			array(
				'name' => 'Weight per Axle Set',
				'desc' => 'e.g., 45 LBS.',
				'id' => $prefix . 'weight_per_axle_set',
				'type' => 'text'
			),
		),
	);

	return $meta_boxes;
}

// Initialize the metabox class
add_action( 'init', 'be_initialize_cmb_meta_boxes', 9999 );
function be_initialize_cmb_meta_boxes() {
	if ( !class_exists( 'cmb_Meta_Box' ) ) {
		require_once(CHILD_DIR . '/lib/metabox/init.php');
	}
}

This will create the metaboxes for the custom post type.
Custom Post Type Metaboxes

4. Clear Permalinks
Now in your admin area, navigate to Settings > Permalinks and click Save Changes. This will flush and clear your permalinks. This is important if you are getting strange 404 Page Not Found errors.

So our finished product is this: wps-admin-functions.php

<?php

/**
 * Admin Functions
 *
 * This file is responsible for registering the
 * custom post types, taxonomies, and metaboxes.
 *
 * @author       Travis Smith <travis@wpsmith.net>
 * @copyright    Copyright (c) 2011, Travis Smith
 * @license      http://opensource.org/licenses/gpl-2.0.php GNU Public License
 *
 */

// registration code for discbrakes post type
// registration code for discbrakes post type
function wps_register_discbrakes_posttype() {
	$labels = array(
		'name' => _x( 'Disc Brakes', 'post type general name' ),
		'singular_name' => _x( 'Disc Brake', 'post type singular name' ),
		'add_new' => _x( 'Add New', 'Disc Brake'),
		'add_new_item' => __( 'Add New Disc Brake '),
		'edit_item' => __( 'Edit Disc Brake '),
		'new_item' => __( 'New Disc Brake '),
		'view_item' => __( 'View Disc Brake '),
		'search_items' => __( 'Search Disc Brakes '),
		'not_found' =>  __( 'No Disc Brake found' ),
		'not_found_in_trash' => __( 'No Disc Brakes found in Trash' ),
		'parent_item_colon' => ''
	);

	$supports = array( 'title' , 'editor' , 'thumbnail' , 'excerpt' , 'revisions' );

	$post_type_args = array(
		'labels' => $labels,
		'singular_label' => __( 'Disc Brake' ),
		'public' => true,
		'show_ui' => true,
		'publicly_queryable' => true,
		'query_var' => true,
		'capability_type' => 'post',
		'has_archive' => true,
		'hierarchical' => false,
		'rewrite' => array( 'slug' => 'discbrakes' ),
		'supports' => $supports,
		'menu_position' => 5,
		'taxonomies' => array( 'wps_axlesizes' ),
		'menu_icon' => 'http://mydomain.com/wp-content/themes/lib/images/discbrakes-icon.png'
	 );
	 register_post_type( 'wps_discbrakes' , $post_type_args );
}
add_action( 'init', 'wps_register_discbrakes_posttype' );

// registration code for AxleSizes taxonomy
function wps_register_axlesizes_tax() {
	$labels = array(
		'name' => _x( 'Axle Sizes', 'taxonomy general name' ),
		'singular_name' => _x( 'Axle Size', 'taxonomy singular name' ),
		'add_new' => _x( 'Add New Axle Size', 'Axle Size'),
		'add_new_item' => __( 'Add New Axle Size' ),
		'edit_item' => __( 'Edit Axle Size' ),
		'new_item' => __( 'New Axle Size' ),
		'view_item' => __( 'View Axle Size' ),
		'search_items' => __( 'Search Axle Sizes' ),
		'not_found' => __( 'No Axle Size found' ),
		'not_found_in_trash' => __( 'No Axle Size found in Trash' ),
	);

	$pages = array( 'wps_discbrakes' );

	$args = array(
		'labels' => $labels,
		'singular_label' => __( 'Axle Size' ),
		'public' => true,
		'show_ui' => true,
		'hierarchical' => false,
		'show_tagcloud' => false,
		'show_in_nav_menus' => true,
		'rewrite' => array('slug' => 'axle-sizes'),
	 );
	register_taxonomy( 'wps_axlesizes' , $pages , $args );
}
add_action( 'init' , 'wps_register_axlesizes_tax' );

// Create Metaboxes
$prefix = '_wps_';
add_filter( 'cmb_meta_boxes', 'wps_create_metaboxes' );
function wps_create_metaboxes() {
	global $prefix;

	$meta_boxes[] = array(
		'id' => 'disk-brakes-info',
		'title' => 'Disk Brakes Information',
		'pages' => array( 'wps_discbrakes' ), // post type
		'context' => 'normal',
		'priority' => 'low',
		'show_names' => true, // Show field names left of input
		'fields' => array(
			array(
				'name' => 'Instructions',
				'desc' => 'In the right column upload a featured image. Make sure this image is at least 900x360px wide. Then fill out the information below.',
				'id' => $prefix . 'title',
				'type' => 'title',
			),
			array(
				'name' => 'Part Number',
				'desc' => 'Enter the part number (e.g., XXXXXXX)',
				'id' => $prefix . 'part_number',
				'type' => 'text'
			),
			array(
				'name' => 'Rotor',
				'desc' => '',
				'id' => $prefix . 'rotor',
				'type' => 'select',
				'options' => array(
					array('name' => 'Stainless Steel', 'value' => 'stainless-steel'),
					array('name' => 'E-Coat (Black)', 'value' => 'e-coat-black'),
					array('name' => 'Option Three', 'value' => 'none')
				)
			),
			array(
				'name' => 'Caliper',
				'desc' => '',
				'id' => $prefix . 'caliper',
				'type' => 'select',
				'options' => array(
					array('name' => 'Stainless Steel', 'value' => 'stainless-steel'),
					array('name' => 'E-Coat (Black)', 'value' => 'e-coat-black'),
					array('name' => 'Option Three', 'value' => 'none')
				)
			),
			array(
				'name' => 'Mounting Bracket',
				'desc' => '',
				'id' => $prefix . 'mounting_bracket',
				'type' => 'select',
				'options' => array(
					array('name' => 'Stainless Steel', 'value' => 'stainless-steel'),
					array('name' => 'E-Coat (Black)', 'value' => 'e-coat-black'),
					array('name' => 'Option Three', 'value' => 'none')
				)
			),
			array(
				'name' => 'Weight per Axle Set',
				'desc' => 'e.g., 45 LBS.',
				'id' => $prefix . 'weight_per_axle_set',
				'type' => 'text'
			),
		),
	);

	return $meta_boxes;
}

// Initialize the metabox class
add_action( 'init', 'wps_initialize_cmb_meta_boxes', 9999 );
function wps_initialize_cmb_meta_boxes() {
	if ( !class_exists( 'cmb_Meta_Box' ) ) {
		require_once(CHILD_DIR . '/lib/metabox/init.php');
	}
}
post

Custom Post Types Plugin Spotlight: Easy Content Types (Premium)

ecpt-preview

One of the best custom post type plugins has to be Easy Content Types by Pippin Williamson (@pippinspages). This previously mentioned plugin, Easy Content Types provides an extremely easy-to-use, familiar (very WordPress-like) and intuitive interface for creating custom post types, taxonomies, and meta boxes. It makes creating custom categories, custom tags, and custom input fields so easy and simple. The stepwise process of creating the custom post type is extremely logical.

  1. Create the Custom Post Type (register custom post type)
  2. Create the Custom Taxonomies (register taxonomy)
  3. Create the Metabox
  4. Create the Metabox fields

Just like Custom Post Types UI exported CPT registration information, just recently announced, Pippin’s newest edition now exports metabox php! Thus, this becomes the best custom post type plugin available! Now child theme designers can easily create custom post types in their sandbox, copy and paste the code in their functions.php file or an associate cpt.php file (or whatever) and have an excellently created custom post type to continue working to design!

So to demonstrate the exported php code, I went into the plugin, created a post type called wps_books, a custom taxonomy called wps_genre, and added a meta box with a few fields. Then I copied and pasted the code in my functions.php file, deactivated the plugin and the code works!

The Easy Content Types plugin is a premium plugin, available on CodeCanyon for $20. I know that most of us WordPress junkies are not keen on paying for premium plugins, but using this plugin can make coding easy and make it easy to learn how to do custom post types on your own.

However, for those who are just cheap and want a free plugin (like I do most of the time!): check out the giveaway of the plugin we’re running at the bottom of the post!

Here’s the exported registration code:

// registration code for wps_books post type
	function register_wps_books_posttype() {
		$labels = array(
			'name' 				=> _x( 'Books', 'post type general name' ),
			'singular_name'		=> _x( 'Book', 'post type singular name' ),
			'add_new' 			=> _x( 'Add New', 'Book'),
			'add_new_item' 		=> __( 'Add New Book '),
			'edit_item' 		=> __( 'Edit Book '),
			'new_item' 			=> __( 'New Book '),
			'view_item' 		=> __( 'View Book '),
			'search_items' 		=> __( 'Search Books '),
			'not_found' 		=>  __( 'No Book found' ),
			'not_found_in_trash'=> __( 'No Books found in Trash' ),
			'parent_item_colon' => ''
		);
		
		$supports = array('title','editor','author','thumbnail','excerpt','custom-fields','comments');
		
		$post_type_args = array(
			'labels' 			=> $labels,
			'singular_label' 	=> __('Book'),
			'public' 			=> true,
			'show_ui' 			=> true,
			'publicly_queryable'=> true,
			'query_var'			=> true,
			'capability_type' 	=> 'post',
			'has_archive' 		=> true,
			'hierarchical' 		=> false,
			'rewrite' 			=> array('slug' => 'books'),
			'supports' 			=> $supports,
			'menu_position' 	=> 5,
			'menu_icon' 		=> 'http://localhost:8888/www/sandbox/wp-content/uploads/2011/09/Book-icon16.png'
		 );
		 register_post_type('wps_books',$post_type_args);
	}
	add_action('init', 'register_wps_books_posttype');									

Then I created a custom taxonomy called wps_genre, and here is the exported registration code:

// registration code for wps_genre taxonomy
function register_wps_genre_tax() {
	$labels = array(
		'name' 					=> _x( 'Genre', 'taxonomy general name' ),
		'singular_name' 		=> _x( 'Genre', 'taxonomy singular name' ),
		'add_new' 				=> _x( 'Add New Genre', 'Genre'),
		'add_new_item' 			=> __( 'Add New Genre' ),
		'edit_item' 			=> __( 'Edit Genre' ),
		'new_item' 				=> __( 'New Genre' ),
		'view_item' 			=> __( 'View Genre' ),
		'search_items' 			=> __( 'Search Genre' ),
		'not_found' 			=> __( 'No Genre found' ),
		'not_found_in_trash' 	=> __( 'No Genre found in Trash' ),
	);
	
	$pages = array('wps_books');
				
	$args = array(
		'labels' 			=> $labels,
		'singular_label' 	=> __('Genre'),
		'public' 			=> true,
		'show_ui' 			=> true,
		'hierarchical' 		=> false,
		'show_tagcloud' 	=> false,
		'show_in_nav_menus' => true,
		'rewrite' 			=> array('slug' => 'genre'),
	 );
	register_taxonomy('wps_genre', $pages, $args);
}
add_action('init', 'register_wps_genre_tax');								

Then I created a meta box area called “Book Information” with 3 fields: Pages, ISBN, and Publish Date, and here is the exported metabox code:

$bookinformation_metabox = array( 
	'id' => 'bookinformation',
	'title' => 'Book Information',
	'page' => 'wps_books',
	'context' => 'normal',
	'priority' => 'high',
	'fields' => $bookinformation_fields = array(

				
				array(
					'name' 			=> 'Pages',
					'desc' 			=> 'Enter the number of pages',
					'id' 			=> 'ecpt_pages',
					'class' 		=> 'ecpt_pages',
					'type' 			=> 'text',
					'rich_editor' 	=> 0,			
					'max' 			=> 0													
				),
															
				array(
					'name' 			=> 'ISBN',
					'desc' 			=> 'ISBN',
					'id' 			=> 'ecpt_isbn',
					'class' 		=> 'ecpt_isbn',
					'type' 			=> 'text',
					'rich_editor' 	=> 0,			
					'max' 			=> 0													
				),
															
				array(
					'name' 			=> 'Publish Date',
					'desc' 			=> '',
					'id' 			=> 'ecpt_publishdate',
					'class' 		=> 'ecpt_publishdate',
					'type' 			=> 'date',
					'rich_editor' 	=> 0,			
					'max' 			=> 0													
				),
												)
);			
			
add_action('admin_menu', 'ecpt_add_bookinformation_meta_box');
function ecpt_add_bookinformation_meta_box() {

	global $bookinformation_metabox;			
		
	add_meta_box($bookinformation_metabox['id'], $bookinformation_metabox['title'], 'ecpt_show_bookinformation_box', 'wps_books', 'normal', 'high', $bookinformation_metabox);
}

// function to show meta boxes
function ecpt_show_bookinformation_box()	{
	global $post;
	global $bookinformation_metabox;
	global $ecpt_prefix;
	
	// Use nonce for verification
	echo '<input type="hidden" name="ecpt_bookinformation_meta_box_nonce" value="', wp_create_nonce(basename(__FILE__)), '" />';
	
	echo '<table class="form-table">';

	foreach ($bookinformation_metabox['fields'] as $field) {
		// get current post meta data

		$meta = get_post_meta($post->ID, $field['id'], true);
		
		echo '<tr>',
				'<th style="width:20%"><label for="', $field['id'], '">', $field['name'], '</label></th>',
				'<td>';
		switch ($field['type']) {
			case 'text':
				echo '<input type="text" name="', $field['id'], '" id="', $field['id'], '" value="', $meta ? $meta : $field['std'], '" size="30" style="width:97%" /><br/>', '', $field['desc'];
				break;
			case 'date':
				echo '<input type="text" class="ecpt_datepicker" name="', $field['id'], '" id="', $field['id'], '" value="', $meta ? $meta : $field['std'], '" size="30" style="width:97%" />', '', $field['desc'];
				break;
			case 'upload':
				echo '<input type="text" class="ecpt_upload_field" name="', $field['id'], '" id="', $field['id'], '" value="', $meta ? $meta : $field['std'], '" size="30" style="width:80%" /><input class="upload_image_button" type="button" value="Upload Image" /><br/>', '', $field['desc'];
				break;
			case 'textarea':
				if($field['rich_editor'] == 1) {
					// this is the old method of enabling the RTE. Now it only needs the class name.
					//wp_tiny_mce(true, array('editor_selector' => $field['class'], 'remove_linebreaks' => false) );
					echo '<div style="width: 97%; border: 1px solid #DFDFDF;"><textarea name="', $field['id'], '" class="theEditor ', $field['class'], '" id="', $field['id'], '" cols="60" rows="8" style="width:97%">', $meta ? $meta : $field['std'], '</textarea></div>', '', $field['desc'];
				} else {
					echo '<div style="width: 100%;"><textarea name="', $field['id'], '" class="', $field['class'], '" id="', $field['id'], '" cols="60" rows="8" style="width:97%">', $meta ? $meta : $field['std'], '</textarea></div>', '', $field['desc'];				
				}
				break;
			case 'select':
				echo '<select name="', $field['id'], '" id="', $field['id'], '">';
				foreach ($field['options'] as $option) {
					echo '<option value="' . $option . '"', $meta == $option ? ' selected="selected"' : '', '>', $option, '</option>';
				}
				echo '</select>', '', $field['desc'];
				break;
			case 'radio':
				foreach ($field['options'] as $option) {
					echo '<input type="radio" name="', $field['id'], '" value="', $option, '"', $meta == $option ? ' checked="checked"' : '', ' />&nbsp;', $option;
				}
				echo '<br/>' . $field['desc'];
				break;
			case 'checkbox':
				echo '<input type="checkbox" name="', $field['id'], '" id="', $field['id'], '"', $meta ? ' checked="checked"' : '', ' />&nbsp;';
				echo $field['desc'];
				break;
			case 'slider':
				echo '<input type="text" rel="' . $field['max'] . '" name="' . $field['id'] . '" id="' . $field['id'] . '" value="' . $meta . '" size="1" style="float: left; margin-right: 5px" />';
				echo '<div class="ecpt-slider" rel="' . $field['id'] . '" style="float: left; width: 60%; margin: 5px 0 0 0;"></div>';		
				echo '<div style="width: 100%; clear: both;">' . $field['desc'] . '</div>';
				break;
		}
		echo     '<td>',
			'</tr>';
	}
	
	echo '</table>';
}	

add_action('save_post', 'ecpt_bookinformation_save');

// Save data from meta box
function ecpt_bookinformation_save($post_id) {
	global $post;
	global $bookinformation_metabox;
	
	// verify nonce
	if (!wp_verify_nonce($_POST['ecpt_bookinformation_meta_box_nonce'], basename(__FILE__))) {
		return $post_id;
	}

	// check autosave
	if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
		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 ($bookinformation_metabox['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);
		}
	}
}

								
function ecpt_export_ui_scripts() {

	global $ecpt_options;
?> 
<script type="text/javascript">
		jQuery(document).ready(function()
		{
			
			if(jQuery('.form-table .ecpt_upload_field').length > 0 ) {
				// Media Uploader
				window.formfield = '';

				jQuery('.upload_image_button').live('click', function() {
				window.formfield = jQuery('.ecpt_upload_field',jQuery(this).parent());
					tb_show('', 'media-upload.php?type=file&TB_iframe=true');
									return false;
					});

					window.original_send_to_editor = window.send_to_editor;
					window.send_to_editor = function(html) {
						if (window.formfield) {
							imgurl = jQuery('a','<div>'+html+'</div>').attr('href');
							window.formfield.val(imgurl);
							tb_remove();
						}
						else {
							window.original_send_to_editor(html);
						}
						window.formfield = '';
						window.imagefield = false;
					}
			}
			if(jQuery('.form-table .ecpt-slider').length > 0 ) {
				jQuery('.ecpt-slider').each(function(){
					var $this = jQuery(this);
					var id = $this.attr('rel');
					var val = jQuery('#' + id).val();
					var max = jQuery('#' + id).attr('rel');
					max = parseInt(max);
					//var step = $('#' + id).closest('input').attr('rel');
					$this.slider({
						value: val,
						max: max,
						step: 1,
						slide: function(event, ui) {
							jQuery('#' + id).val(ui.value);
						}
					});
				});
			}
			
			if(jQuery('.form-table .ecpt_datepicker').length > 0 ) {
				var dateFormat = 'mm-dd-yy';
				jQuery('.ecpt_datepicker').datepicker({dateFormat: dateFormat});
			}
		});
  </script>
<?php
}

function ecpt_export_datepicker_ui_scripts() {
	global $ecpt_base_dir;
	wp_enqueue_script('jquery-ui.min', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js', false, '1.8', 'all');
}
function ecpt_export_datepicker_ui_styles() {
	global $ecpt_base_dir;
	wp_enqueue_style('jquery-ui-css', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css', false, '1.8', 'all');
}

// these are for newest versions of WP
add_action('admin_print_scripts-post.php', 'ecpt_export_datepicker_ui_scripts');
add_action('admin_print_scripts-edit.php', 'ecpt_export_datepicker_ui_scripts');
add_action('admin_print_scripts-post-new.php', 'ecpt_export_datepicker_ui_scripts');
add_action('admin_print_styles-post.php', 'ecpt_export_datepicker_ui_styles');
add_action('admin_print_styles-edit.php', 'ecpt_export_datepicker_ui_styles');
add_action('admin_print_styles-post-new.php', 'ecpt_export_datepicker_ui_styles');

if ((isset($_GET['post']) && (isset($_GET['action']) && $_GET['action'] == 'edit') ) || (strstr($_SERVER['REQUEST_URI'], 'wp-admin/post-new.php')))
{
	add_action('admin_head', 'ecpt_export_ui_scripts');
}

Awesome! Simply awesome! Pippin told me he was trying to do this and I am very, very excited that he has accomplished this!

If you haven’t seen the introduction video, please check it out here:

Development Perspective Mini-Review

From a development perspective, Easy Content Types is a solid plugin, with a strong and active developer! However, overuse of the exported php code will lead to some redundant code for someone who doesn’t know much coding. Also, with frameworks, like Genesis, there are some difficulties that the plugin must overcome to be fully integrated with the particular framework. However, after talking with Pippin, he made some updates to the export code (reducing some of the potential redundancy) and single/archives post type templating in light of frameworks, which can be expected in the next release in the next few days.

In light of the upcoming meta box class that is being targeted for WordPress 3.3, it will drastically reduce the export code. However, there will be a quick and seemless update when the metabox_class is announced in beta RCs.

Plugin Giveaway

CLOSED.
I have one copy to give away. To enter, do the following:

  1. Tweet on Twitter: “Free Giveaway by @wp_smith: Easy Content Types Plugin for WordPress by @pippinspages http://wp.me/pSgPV-1f0″
  2. Share the link on Google Plus
  3. If you don’t have a Twitter account or a Google+ account, share the link on Facebook
  4. Then enter a comment below with the appropriate links answering the question, “Why should you get a copy of Easy Content Types by Pippin Williamson?”

One commenter will be chosen randomly on Friday to win. Only one comment per person will be counted.

post

Best Plugins for Creating Custom Post Types

Content Types

Understanding WordPress Custom Post Types

Do you hate coding and simply want a graphical user interface to create custom post types? Or would you rather use a plugin to save time to create custom post types? While I personally believe hand coding the custom post types and the metaboxes are easier, there are some really good plugins that will help you accomplish all that you want to accomplish with Custom Post Types.

So here are my Top Custom Post Type Creating Plugins.

Premium

  1. Easy Content Types: Easy Content Types provides an extremely easy to use and intuitive interface for creating custom post types, taxonomies, and meta boxes. It allows for custom categories, custom tags, and custom input fields.
  2. GD Custom Posts And Taxonomies Tools: Can be used to expand custom taxonomies and custom post types support. Plugin adds many tools including custom post types and taxonomies management and widget for taxonomies terms cloud.
  3. Post Type Constructor Kit: PCK is a suite of plugins consisting of the post type constructor kit, meta boxes kit, role manager kit, and widget kit giving the possibility of 15 different types of metaboxes including text, WYSIWYG, radio, checkbox, select box, image, file, date and time, tab, gallery, panorama viewer, contact form, comments, youtube, and Google map. This plugin also has a forum support channel apart from WordPress.
  4. WPMU Dev’s CustomPress: The ultimate plugin for transforming WordPress from a blogging platform into a full blown CMS system using your own custom post, taxonomies and custom field creator. And combine this with the Recent Custom Post Type Widget for even further usability.

Free

  1. Custom Post Type UI: Great interface, ability to create taxonomies, good support community. Lacks custom field creation functionality; however, only free plugin to export to proper universal PHP code. Plugin Site.
  2. More Types: Integrates perfectly with More Taxonomies, to create additional taxonomies besides Categories and Tags, and More Fields, to create additional input fields easily. More Types has the ability to assign additional features beyond the typical WordPress supports to include theme based features like genesis-seo, etc. While More Types is a standalone plugin, combined with the suite of More Plugins, it is robust and powerful. More Plugins Site.
  3. WP Easy Post Types: Can select columns to show. In-built custom field creation (albeit limited) that will be attached to your new custom post type, and each field will be saved in the WordPress database as a custom field to take advantage of the WordPress query rules. However, it has a somewhat “confusing” Admin menu and support is not free. This could be a premium plugin.
  4. Ultimate Post Type Manager: This is an Easy to use Plugin to Create, Customize, Manage Custom Post Type. Do all you want to do with you Posts. It can also be used with Ultimate Taxonomy Manager.
  5. Content Types: Content Types is a WordPress plugin that helps you create custom content types in WordPress. It allows for custom categories, custom tags, and custom input fields. From what I can tell, this is the only plugin that makes some metabox/custom fields required for posting.
  6. WP Post Type UI: Inspired by “Custom Post Type UI” this plugin that gives you what have always wanted for creating dynamic post types and custom taxonomies in WordPress. The UI is made in true WP style, with a smooth integration to give nice and easy access to create and edit post types and taxonomies.
  7. GD Custom Posts And Taxonomies Tools: Can be used to expand custom taxonomies and custom post types support. Plugin adds many tools including custom post types and taxonomies management and widget for taxonomies terms cloud. For a comparison with the pro version: see the comparison chart.
  8. Simple Custom Post Types: Makes managing custom post types even simpler, removing the need for you to write any code. Excerpt update your theme. This plugin provides a nice interface and easy access. The plugin provides almost all the parameters of the WordPress CPT API. It is possible to manage the permissions of custom post types such as articles or pages. Or create a full set of custom permissions.
  9. Custom Content Type Manager: Create custom content types (AKA post types), standardize custom fields for each type, including dropdowns and images. This gives WordPress CMS functionality making it easier to use WP for eCommerce or content-driven sites. Plugin Site.
  10. Custom Press: Custom Press allows you to easily add your own custom post types and custom taxonomies into WordPress, which you can also toggle on and off more advanced options for creating custom post types and custom taxonomies. It also features an ‘Embed Code’ option is available if you would prefer to put your custom post types and custom taxonomies directly into a theme or plugin.
  11. CMS Press: CMS Press opens up the ability to create and manage custom content types and taxonomies for your WordPress site. It adds the flexibility to have more than just posts and pages for content by allowing the user to register their own post_types that can use their separate theming from the post and page template along with its own permalink structure.
post

Helpful Custom Post Type and Custom Taxonomy Functions

Understanding WordPress Custom Post Types

Here are two great posts regarding custom post types’ functions: An Important Update: WordPress 3.0 Post Types And Taxonomies, from New2WP written by  Jared (@Tweeaks), and Custom Post Types in WordPress from Justin Tadlock (@justintadlock). that I wanted to reproduce in part in this series.

The following are functions you can use for various things related to post types. The function name is linked to the line in /wp-includes/post.php where it is created for those that would like to check out the source code which makes them work. I’ve also added a short description for each that is used in the source to describe them [slightly modified by Travis Smith].

Post Type Functions:

  • is_post_type() – Checks to see if current post is of a specified post type.
    <?php
    if ( is_post_type( 'zombie', $post_id ) )
    	echo 'This is a not a blog post.  It is a zombie!';
    else
    	echo 'This is not a zombie. [insert sad face]';
  • get_post_types( $post ) – Get a list of all registered post type objects.
    • $args - An array of key => value arguments to match against the post type objects.
    • $output - The type of output to return, either post type ‘names’ or ‘objects’. ‘names’ is the default.
    • $operator - The logical operation to perform. ‘or’ means only one element from the array needs to match; ‘and’ means all elements must match. The default is ‘and’.
    • Returns an array listing post type names or objects.
  • get_post_type_object() – Retrieves a post type object by name
    $post_type = get_post_type_object( 'zombie' );
    
    if ( $post_type->show_ui )
    	custom_function_name();
    
  • register_post_type() – Register a post type. Do not use before init.
    • A simple function for creating or modifying a post type based on the parameters given.
    • The function will accept an array (second optional parameter), along with a string for the post type name.
  • get_post_type_capabilities() – Builds an object with all post type capabilities out of a post type object.
  • Accepted keys of the capabilities array in the post type object:
    • edit_post - The meta capability that controls editing a particular object of this post type. Defaults to “edit_ . $capability_type” (edit_post).
    • edit_posts - The capability that controls editing objects of this post type as a class. Defaults to “edit_ . $capability_type . s” (edit_posts).
    • edit_others_posts - The capability that controls editing objects of this post type that are owned by other users. Defaults to “edit_others_ . $capability_type . s” (edit_others_posts).
    • publish_posts - The capability that controls publishing objects of this post type. Defaults to “publish_ . $capability_type . s” (publish_posts).
    • read_post - The meta capability that controls reading a particular object of this post type. Defaults to “read_ . $capability_type” (read_post).
    • read_private_posts - The capability that controls reading private posts.Defaults to “read_private . $capability_type . s” (read_private_posts).
    • delete_post - The meta capability that controls deleting a particular object of this post type. Defaults to “delete_ . $capability_type” (delete_post).
  • get_post_type_labels( $post_type_object ) – Builds an object with all post type labels out of a post type object.
  • Accepted keys of the label array in the post type object:
    • name - general name for the post type, usually plural. The same and overriden by $post_type_object->label. Default is Posts/Pages
    • singular_name - name for one object of this post type. Default is Post/Page
    • add_new - Default is Add New for both hierarchical and non-hierarchical types.
    • add_new_item - Default is Add New Post/Add New Page
    • edit_item - Default is Edit Post/Edit Page
    • new_item - Default is New Post/New Page
    • view_item - Default is View Post/View Page
    • search_items - Default is Search Posts/Search Pages
    • not_found - Default is No posts found/No pages found
    • not_found_in_trash - Default is No posts found in Trash/No pages found in Trash
    • parent_item_colon - This string isn’t used on non-hierarchical types. (In hierarchical ones the default is Parent Page)
  • _get_custom_object_labels() – Builds an object with custom-something object (post type, taxonomy) labels out of a custom-something object
  • add_post_type_support( $post_type, $feature ) – Register support of certain features for a post type.
  • All features are directly associated with a functional area of the edit screen, such as the editor or a meta box:
    • ‘title’,
    • ‘editor’,
    • ‘comments’,
    • ‘revisions’,
    • ‘trackbacks’
    • ‘author’,
    • ‘excerpt’,
    • ‘page-attributes’,
    • ‘thumbnail’,
    • ‘custom-fields’

    Additionally, the ‘revisions’ feature dictates whether the post type will store revisions, and the ‘comments’ feature dicates whether the comments count will show on the edit screen.

  • set_post_type( $post_id = 0, $post_type = ‘post’ ) – Updates the post type for the post ID.
    • $post_id Post ID to change post type. Not actually optional.
    • $post_type Optional, default is post. Supported values are ‘post’ or ‘page’ to name a few.
    • Return int Amount of rows changed. Should be 1 for success and 0 for failure.
  • get_posts() – Retrieve list of latest posts or posts matching criteria.
  • The defaults are:
    • ‘numberposts’ - Default is 5. Total number of posts to retrieve.
    • ‘offset’ - Default is 0. See { WP_Query::query() } for more.
    • ‘category’ - What category to pull the posts from.
    • ‘orderby’ - Default is ‘post_date’. How to order the posts.
    • ‘order’ - Default is ‘DESC’. The order to retrieve the posts.
    • ‘include’ - See { WP_Query::query() } for more.
    • ‘exclude’ - See { WP_Query::query() } for more.
    • ‘meta_key’ - See { WP_Query::query() } for more.
    • ‘meta_value’ - See { WP_Query::query() } for more.
    • ‘post_type’ - Default is ‘post’. Can be ‘page’, or ‘attachment’ to name a few.
    • ‘post_parent’ - The parent of the post or post type.
    • ‘post_status’ - Default is ‘published’. Post status to retrieve.

Functions For Taxonomies You Should Know About

The following are functions which you can use when working with taxonomies. I’m not going to link to the line of each function or include descriptions of each since the file which contains them is way smaller than posts.php where the post type functions are, so if you’re interested in viewing the source of these you should’ve have a hard time finding the line they are on.

The functions which make up taxonomies are located in /wp-includes/taxonomy.php of the WordPress source.

post

How to Change the Title Text for Your Custom Post Type

Understanding WordPress Custom Post Types

Have you ever wanted to use the Title section, but didn’t want to call it Title? Surely, many of you have wanted to change the text in the title entry bar from the standard ‘Enter title here’ to something more specific for your custom post type. Well, WordPress has a filter for it.

<?php
// Change 'Enter Title Here' text for a CPT
function wps_change_default_title( $title ){
     $screen = get_current_screen();
     $wps_cpt = 'wps_mycpt';
 
     if  ( $wps_cpt == $screen->post_type ) {
          $title = 'Enter Staff Members Name Here'; //change this to whatever you'd like
     }
 
     return $title;
}
 
add_filter( 'enter_title_here', 'wps_change_default_title' );