Advertisement
Scroll to top

For a lot of WordPress projects these days we use custom post types. The WordPress development team created some handy methods to integrate them into your projects. But when you use custom post types, taxonomies and meta boxes frequently, it's quite probable that you're going to repeat yourself. That's why we are going to use the power of these WordPress functions to build a more powerful class, which we can use to quickly register post types, taxonomies and meta boxes.


Call Our Class

This is how we call our class when it's done.

1
2
	include('custom-post-type.php');
3
    
4
	$book = new Custom_Post_Type( 'Book' );
5
	$book->add_taxonomy( 'category' );
6
	$book->add_taxonomy( 'author' );
7
	
8
	$book->add_meta_box( 
9
		'Book Info', 
10
		array(
11
			'Year' => 'text',
12
			'Genre' => 'text'
13
		)
14
	);
15
	
16
	$book->add_meta_box( 
17
		'Author Info', 
18
		array(
19
			'Name' => 'text',
20
			'Nationality' => 'text',
21
			'Birthday' => 'text'
22
		)
23
	);

Step 1 The Class, Properties and Methods

We start off with creating the class, main properties, constructor and methods. In this tutorial we will fill them with our programming logic.

1
2
	class Custom_Post_Type
3
	{
4
		public $post_type_name;
5
		public $post_type_args;
6
		public $post_type_labels;
7
		
8
		/* Class constructor */
9
		public function __construct()
10
		{
11
			
12
		}
13
		
14
		/* Method which registers the post type */
15
		public function register_post_type()
16
		{
17
			
18
		}
19
		
20
		/* Method to attach the taxonomy to the post type */
21
		public function add_taxonomy()
22
		{
23
			
24
		}
25
		
26
		/* Attaches meta boxes to the post type */
27
		public function add_meta_box()
28
		{
29
			
30
		}
31
		
32
		/* Listens for when the post type being saved */
33
		public function save()
34
		{
35
			
36
		}
37
	}

Step 2 The Constructor

Within the constructor we create some important variables, which are used within the entire class. We also call add_action to register the post type and we listen for when the post type is being saved, so we can save our post's meta data. If the post type exists, the add_action is not called, but the $post_type_name is set, so we can add taxonomies and meta boxes to it.

1
2
	public function __construct( $name, $args = array(), $labels = array() )
3
	{
4
		// Set some important variables

5
		$this->post_type_name		= strtolower( str_replace( ' ', '_', $name ) );
6
		$this->post_type_args 		= $args;
7
		$this->post_type_labels 	= $labels;
8
		
9
		// Add action to register the post type, if the post type does not already exist

10
		if( ! post_type_exists( $this->post_type_name ) )
11
		{
12
			add_action( 'init', array( &$this, 'register_post_type' ) );
13
		}
14
		
15
		// Listen for the save post hook

16
		$this->save();
17
	}

Step 3 Register the Post Type

Within the register_post_type method, which gets called by the add_action in the constructor, we first determine the name (capitalized) and the plural. With this name and plural we build our labels for the post type and overwrite (and merge) them with the given labels from the $this->post_type_labels variable. Then we create our arguments with the same principle.

1
2
	public function register_post_type()
3
	{
4
		//Capitilize the words and make it plural

5
		$name 		= ucwords( str_replace( '_', ' ', $this->post_type_name ) );
6
		$plural 	= $name . 's';
7
		
8
		// We set the default labels based on the post type name and plural. We overwrite them with the given labels.

9
		$labels = array_merge(
10
		
11
			// Default

12
			array(
13
				'name' 					=> _x( $plural, 'post type general name' ),
14
				'singular_name' 		=> _x( $name, 'post type singular name' ),
15
				'add_new' 				=> _x( 'Add New', strtolower( $name ) ),
16
				'add_new_item' 			=> __( 'Add New ' . $name ),
17
				'edit_item' 			=> __( 'Edit ' . $name ),
18
				'new_item' 				=> __( 'New ' . $name ),
19
				'all_items' 			=> __( 'All ' . $plural ),
20
				'view_item' 			=> __( 'View ' . $name ),
21
				'search_items' 			=> __( 'Search ' . $plural ),
22
				'not_found' 			=> __( 'No ' . strtolower( $plural ) . ' found'),
23
				'not_found_in_trash' 	=> __( 'No ' . strtolower( $plural ) . ' found in Trash'), 
24
				'parent_item_colon' 	=> '',
25
				'menu_name' 			=> $plural
26
			),
27
			
28
			// Given labels

29
			$this->post_type_labels
30
			
31
		);
32
		
33
		// Same principle as the labels. We set some defaults and overwrite them with the given arguments.

34
		$args = array_merge(
35
		
36
			// Default

37
			array(
38
				'label' 				=> $plural,
39
				'labels' 				=> $labels,
40
				'public' 				=> true,
41
				'show_ui' 				=> true,
42
				'supports' 				=> array( 'title', 'editor' ),
43
				'show_in_nav_menus' 	=> true,
44
				'_builtin' 				=> false,
45
			),
46
			
47
			// Given args

48
			$this->post_type_args
49
			
50
		);
51
		
52
		// Register the post type

53
		register_post_type( $this->post_type_name, $args );
54
	}

Step 3 Add Some Taxonomies

First we check if the $name parameter is empty. When it is, we do nothing. When it's not, we create three variables in which we store the information for the taxonomy: $taxonomy_name, $taxonomy_labels and $taxonomy_args.

1
2
	public function add_taxonomy( $name, $args = array(), $labels = array() )
3
	{
4
		if( ! empty( $name ) )
5
		{
6
			// We need to know the post type name, so the new taxonomy can be attached to it.

7
			$post_type_name = $this->post_type_name;
8
9
			// Taxonomy properties

10
			$taxonomy_name		= strtolower( str_replace( ' ', '_', $name ) );
11
			$taxonomy_labels	= $labels;
12
			$taxonomy_args		= $args;
13
14
			/* More code coming */
15
		}
16
	}

After we've done the first checks and then set some variables, we're going to register the post type. But first we check if the taxonomy already exists.

1
2
	if( ! taxonomy_exists( $taxonomy_name ) )
3
	{
4
		/* Create taxonomy and attach it to the object type (post type) */
5
	}
6
	else
7
	{
8
		/* The taxonomy already exists. We are going to attach the existing taxonomy to the object type (post type) */
9
	}

If the taxonomy doesn't exist, we register it. We use an add_action, but not in the normal way. Normally, the second parameter of the add_action is the name of a function, but since we use different parameters each time, we are going to pass a nameless function (Note: this feature requires PHP 5.3+) and use the use() function. With the use() function we can pass variables to the nameless function. This time we need to pass $taxonomy_name, $post_type_name and $taxonomy_args to register the taxonomy.

1
2
	//Capitilize the words and make it plural

3
	$name 		= ucwords( str_replace( '_', ' ', $name ) );
4
	$plural 	= $name . 's';
5
	
6
	// Default labels, overwrite them with the given labels.

7
	$labels = array_merge(
8
	
9
		// Default

10
		array(
11
			'name' 					=> _x( $plural, 'taxonomy general name' ),
12
			'singular_name' 		=> _x( $name, 'taxonomy singular name' ),
13
		    'search_items' 			=> __( 'Search ' . $plural ),
14
		    'all_items' 			=> __( 'All ' . $plural ),
15
		    'parent_item' 			=> __( 'Parent ' . $name ),
16
		    'parent_item_colon' 	=> __( 'Parent ' . $name . ':' ),
17
		    'edit_item' 			=> __( 'Edit ' . $name ),
18
		    'update_item' 			=> __( 'Update ' . $name ),
19
		    'add_new_item' 			=> __( 'Add New ' . $name ),
20
		    'new_item_name' 		=> __( 'New ' . $name . ' Name' ),
21
		    'menu_name' 			=> __( $name ),
22
		),
23
24
		// Given labels

25
		$taxonomy_labels
26
27
	);
28
29
	// Default arguments, overwritten with the given arguments

30
	$args = array_merge(
31
32
		// Default

33
		array(
34
			'label'					=> $plural,
35
			'labels'				=> $labels,
36
			'public' 				=> true,
37
			'show_ui' 				=> true,
38
			'show_in_nav_menus' 	=> true,
39
			'_builtin' 				=> false,
40
		),
41
42
		// Given

43
		$taxonomy_args
44
45
	);
46
	
47
	// Add the taxonomy to the post type

48
	add_action( 'init',
49
		function() use( $taxonomy_name, $post_type_name, $args )
50
		{
51
			register_taxonomy( $taxonomy_name, $post_type_name, $args );
52
		}
53
	);

When the taxonomy doesn't exist, we only attach it to our post type. Just like before, we use a nameless function and the use() function. This time we only need to pass $taxonomy_name and $post_type_name.

1
2
	add_action( 'init',
3
		function() use( $taxonomy_name, $post_type_name )
4
		{
5
			register_taxonomy_for_object_type( $taxonomy_name, $post_type_name );
6
		}
7
	);

Step 4 Meta Boxes

For registering meta boxes, we need the post type name, so first we determine that. After that we need some variables for the meta box itself and we make the custom meta fields global, so we can access them in the save hook. We won't cover too much detail here, because Tammy Hart made a very useful tutorial about reusable meta boxes already.

1
2
	public function add_meta_box( $title, $fields = array(), $context = 'normal', $priority = 'default' )
3
	{
4
		if( ! empty( $title ) )
5
		{
6
			// We need to know the Post Type name again

7
			$post_type_name = $this->post_type_name;
8
9
			// Meta variables

10
			$box_id 		= strtolower( str_replace( ' ', '_', $title ) );
11
			$box_title		= ucwords( str_replace( '_', ' ', $title ) );
12
			$box_context	= $context;
13
			$box_priority	= $priority;
14
			
15
			// Make the fields global

16
			global $custom_fields;
17
			$custom_fields[$title] = $fields;
18
			
19
			/* More code coming */
20
		}
21
		
22
	}

When we set the variables and globals, we register the meta box with an add_action. Like before, we use a nameless function. This time we need $box_id, $box_title, $post_type_name, $box_context, $box_priority and $fields.

1
2
	add_action( 'admin_init',
3
		function() use( $box_id, $box_title, $post_type_name, $box_context, $box_priority, $fields )
4
		{
5
			add_meta_box(
6
				$box_id,
7
				$box_title,
8
				function( $post, $data )
9
				{
10
					global $post;
11
					
12
					// Nonce field for some validation

13
					wp_nonce_field( plugin_basename( __FILE__ ), 'custom_post_type' );
14
					
15
					// Get all inputs from $data

16
					$custom_fields = $data['args'][0];
17
					
18
					// Get the saved values

19
					$meta = get_post_custom( $post->ID );
20
					
21
					// Check the array and loop through it

22
					if( ! empty( $custom_fields ) )
23
					{
24
						/* Loop through $custom_fields */
25
						foreach( $custom_fields as $label => $type )
26
						{
27
							$field_id_name 	= strtolower( str_replace( ' ', '_', $data['id'] ) ) . '_' . strtolower( str_replace( ' ', '_', $label ) );
28
							
29
							echo '<label for="' . $field_id_name . '">' . $label . '</label><input type="text" name="custom_meta[' . $field_id_name . ']" id="' . $field_id_name . '" value="' . $meta[$field_id_name][0] . '" />';
30
						}
31
					}
32
				
33
				},
34
				$post_type_name,
35
				$box_context,
36
				$box_priority,
37
				array( $fields )
38
			);
39
		}
40
	);

Step 5 Save the Post's Meta Data

Save all the post's meta data. We loop through them, using the global $custom_fields. This is also a quick coverage, see Tammy Hart's tutorial about reusable meta boxes.

1
2
	public function save()
3
	{
4
		// Need the post type name again

5
		$post_type_name = $this->post_type_name;
6
	
7
		add_action( 'save_post',
8
			function() use( $post_type_name )
9
			{
10
				// Deny the WordPress autosave function

11
				if( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return;
12
13
				if ( ! wp_verify_nonce( $_POST['custom_post_type'], plugin_basename(__FILE__) ) ) return;
14
			
15
				global $post;
16
				
17
				if( isset( $_POST ) && isset( $post->ID ) && get_post_type( $post->ID ) == $post_type_name )
18
				{
19
					global $custom_fields;
20
					
21
					// Loop through each meta box

22
					foreach( $custom_fields as $title => $fields )
23
					{
24
						// Loop through all fields

25
						foreach( $fields as $label => $type )
26
						{
27
							$field_id_name 	= strtolower( str_replace( ' ', '_', $title ) ) . '_' . strtolower( str_replace( ' ', '_', $label ) );
28
							
29
							update_post_meta( $post->ID, $field_id_name, $_POST['custom_meta'][$field_id_name] );
30
						}
31
					
32
					}
33
				}
34
			}
35
		);
36
	}

Step 6 Optimize

As you can see we use strtolower( str_replace( ' ', '_', $string ) ) and ucwords( str_replace( '_', ' ', $string ) ) a number of times. The reason of creating this class is that we don't repeat ourselves, so we don't want to do that in this part either. That's why we create some helper methods. In this way we can do this: $name = self::beautify( $string ); instead of $name = strtolower( str_replace( ' ', '_', $title ) );

1
2
	public static function beautify( $string )
3
	{
4
		return ucwords( str_replace( '_', ' ', $string ) );
5
	}
6
	
7
	public static function uglify( $string )
8
	{
9
		return strtolower( str_replace( ' ', '_', $string ) );
10
	}

Another point is the plural forms we create. We just create them by adding an 's' to the word. But what happens when the word ends with a 'y'? For this reason we create a helper method to determine the plural form of a word. Now we can easily do this: $plural = self::pluralize( $string ) and the plural form of our word will be determined.

1
2
	public static function pluralize( $string )
3
	{
4
		$last = $string[strlen( $string ) - 1];
5
		
6
		if( $last == 'y' )
7
		{
8
			$cut = substr( $string, 0, -1 );
9
			//convert y to ies

10
			$plural = $cut . 'ies';
11
		}
12
		else
13
		{
14
			// just attach an s

15
			$plural = $string . 's';
16
		}
17
		
18
		return $plural;
19
	}

Wrap up

And now we're done. You can now use this class to easily register post types, taxonomies and meta boxes. If you have any suggestions or questions, just leave a comment, so we can talk about it. Hope to see you next time!

Also, I would like to give some credit to Jeffrey Way. I used his class as inspiration for my class and for this tutorial. Also, I would like to give some credit to Tammy Hart, for building the reusable meta boxes tutorial. Take a look at their work.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.