Add meta box to a custom post type

Before adding a metabox to a custom post type we need to create the custom post type.
Check this post where you can find a full class to create your custom post type.

So following on this example our custom post type is cpt_examples.

In the __construct function of our custom post type class add the following:

1
2
add_action( 'add_meta_boxes', array( $this, 'add_meta_box') );
add_action( 'save_post',      array( $this, 'save_meta_box_data' ) );

And then create the functions in the class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
 * add_meta_box
 */
public function add_meta_box(){
 
	add_meta_box( 'cpt_examples_meta', 'CPT Examples Extra Info', array( $this, 'display_meta_form' ), 'cpt_examples', 'advanced', 'high' );
}
 
/**
 * display_meta_form	
 */
 
public function display_meta_form( $post ) {
 
	wp_nonce_field( 'cptexamples_meta_box', 'cptexamples_meta_box_nonce' );
 
	$my_first_field  = get_post_meta( $post->ID, 'cpt_first_meta_field', true );
	$my_second_field = get_post_meta( $post->ID, 'cpt_second_meta_field', true );
 
		echo '<div class="wrap">';
		echo '<label for="cpt_first_meta_field">' . _e( 'First Meta Field', 'cpt_domain' ) . '</label> <br/>';
		echo '<input class="text" type="text" id="cpt_first_meta_field" name="cpt_first_meta_field" value="' . esc_attr( $my_first_field ) . '"   />';
		echo '</div>';
 
		echo '<div class="wrap">';
		echo '<label for="cpt_second_meta_field">' . _e( 'Second Meta Field', 'cpt_domain' ) . '</label>  <br/>';
		echo '<input class="text" type="text" id="cpt_second_meta_field" name="cpt_second_meta_field" value="' . esc_attr( $my_second_field ) . '"   />';
		echo '</div>';
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
 * save_meta_box_data
 * function called on save_post hook to sanitize and save the data
 */
 
public function save_meta_box_data( $post_id ){
 
  // Check if nonce is set.
    if ( ! isset( $_POST['cptexamples_meta_box_nonce'] ) ) {
	  return;
    }
 
  // Verify that the nonce is valid.
    if ( ! wp_verify_nonce( $_POST['cptexamples_meta_box_nonce'], 'cptexamples_meta_box' ) ) {
	   return;
    }
 
  // If autosave, don't do anything
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
	  return;
    }
 
  // Check the user's permissions.
    if ( isset( $_POST['post_type'] ) && $_POST['post_type'] == 'cpt_examples' ) {
            if ( ! current_user_can( 'edit_page', $post_id ) ) {
		     return;
	    }
 
    } else {
            if ( ! current_user_can( 'edit_post', $post_id ) ) {
		     return;
	    }
    }
 
   // Save the information into the database
       if ( isset( $_POST['cpt_first_meta_field'] ) ) {
 
             $my_first_meta_field = sanitize_text_field( $_POST['cpt_first_meta_field'] );
	     update_post_meta( $post_id, 'cpt_first_meta_field', $my_first_meta_field );
	}
 
       if ( isset( $_POST['cpt_second_meta_field'] ) ) {
 
             $my_second_meta_field = sanitize_text_field( $_POST['cpt_second_meta_field'] );
	     update_post_meta( $post_id, 'cpt_second_meta_field', $my_second_meta_field );
	}
 
 
}

Also view this snippet to add the meta box just after the title.

Create custom post type from a plugin

The Class file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
<?php 
/** 
 * @package    WPtips
 * @subpackage Custom Post Type Example
 * @author     Lucy Tomás
 * @since      1.0
 */
 
// Exit if accessed directly
if ( !defined( 'ABSPATH' ) ) exit;
 
 
if( !class_exists( 'CPT_Example' )){
 
class CPT_Example {
 
	/**
	 * constructor
	 * @since 1.0
	 */
 
	public function __construct() {
 
		add_action( 'init', 		     array( $this, 'register_posttype'));
		add_filter( 'post_updated_messages', array( $this, 'custom_post_type_messages'));
		add_action( 'admin_head',            array( $this, 'custom_post_type_help' ) );
		add_filter( 'template_include',      array( $this, 'post_type_template'));
 
	}	
 
	/**
	 * register_posttype
	 * @since 1.0
	 */
 
	public function register_posttype() {
 
		$labels = array(
					'name'               => __('CPT Examples', 'cpt_domain'),
					'singular_name'      => __('CPT Example', 'cpt_domain'),
					'menu_name'          => __('CPT Examples', 'cpt_domain'),
					'name_admin_bar'     => __('CPT Example', 'cpt_domain'),
					'add_new'            => __('Add new', 'cpt_domain'),
					'add_new_item'       => __('Add new CPT Example', 'cpt_domain'),
					'new_item'           => __('New CPT Example', 'cpt_domain'),
					'edit_item'          => __('Edit CPT Example', 'cpt_domain'),
					'view_item'          => __('View CPT Examples', 'cpt_domain'),
					'all_items'          => __('All CPT Examples', 'cpt_domain'),
					'search_items'       => __('Search CPT Examples', 'cpt_domain'),
					'parent_item_colon'  => __('CPT Example parent', 'cpt_domain'),
					'not_found'          => __('No CPT Example found', 'cpt_domain'),
					'not_found_in_trash' => __('No CPT Example in trash', 'cpt_domain')
		);
 
 
		$slug = get_theme_mod( 'ctp_example_permalink' );
  		$slug = ( empty( $slug ) ) ? 'cpt-example' : $slug;
 
 
 		$args = array( 
			'public'        => true, 
			'labels'        => $labels,
			'description'   => __('CPT Examples', 'cpt_domain'),
			'menu_icon'     => 'dashicons-groups',
			'menu_position' => 5,
			'has_archive' 	=> true,
			'supports'      => array( 'title', 'editor', 'thumbnail'),
			'rewrite'     	=> array( 'slug' => $slug )
 
		);
 
		register_post_type( 'cpt_examples', $args );
 
	}
 
	/**
	 * custom_post_type_messages
	 * @since 1.0
	 */
 
	public function custom_post_type_messages( $messages ) {
 
		$post = get_post();
 
			$messages['cpt_examples'] = array(
				0  => '',
				1  => __('CTP Example updated', 'cpt_domain'),
				2  => __('Custom field updated', 'cpt_domain'),
				3  => __('Custom field deleted', 'cpt_domain'),
				4  => __('CTP Example updated', 'cpt_domain'),
				5  => isset( $_GET['revision'] ) ? sprintf( __('CTP Example restored to revision', 'cpt_domain') . ' %s',wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
				6  => __('CTP Example published', 'cpt_domain'),
				7  => __('CTP Example saved', 'cpt_domain'),
				8  => __('CTP Example sent', 'cpt_domain'),
				9  => sprintf(
					__('CTP Example programed for', 'cpt_domain') . ': <strong>%1$s</strong>.',
					date_i18n( 'M j, Y @ G:i', strtotime( $post->post_date ) )
				),
				10 => __('Draft CTP Example updated', 'cpt_domain')
			);
 
 
		return $messages;
 
	}
 
	/**
	 * custom_post_type_help
	 * @since 1.0
	 */
 
	public function custom_post_type_help() {
 
 
		$screen = get_current_screen();
 
		if ( $screen->post_type != 'cpt_examples' ) {
			return;
		}
 
		$basics = array(
			'id'      => 'cpt_examples_basics',
			'title'   => 'Basic help CPT Examples',
			'content' => '<p>From this section you can view a list of CPT Examples.</p>
                                      <p>Click on one of them to Edit or click on Add New to create a new one.</p>'
		);
 
		$formatting = array(
			'id'      => 'cpt_examples_formating',
			'title'   => 'Creation of a CPT Example',
			'content' => '<p>Fill in the form with title and text .</p>'
 
		);
 
		$screen->add_help_tab( $basics );
		$screen->add_help_tab( $formatting );
 
 	}
 
	/**
	 * post_type_template
	 * @since 1.0
	 */
 
	function post_type_template( $original_template ) {
 
 
		  if ( is_post_type_archive('cpt_examples') ) {
 
		    load_template( plugin_dir_path( __FILE__ ) . 'templates/cpt_examples.php');
 
		  } else {
 
		    return $original_template;
		  }
 
	}
 
}// class
 
}

You can see on this other post how to add Meta Boxes with extra form fields for this custom post type class.