WordPress Meta Boxes

How to remove default metaboxes, how to create your own custom metabox on the fly. The complete tutorial.

April 17, 2013 / #Metaboxes, #wp-admin

This post consists of three parts. In the first part I will tell you everything about default WordPress metaboxes. In the second part I will show how to create your own simple custom metabox. And in the third part, the most interesting part, I will give you ready-to-use metabox class and show how to create metaboxes on the fly.

I. Default Meta Boxes #

How to remove WordPress default post meta boxes using remove_meta_box() function #

Function remove_meta_box() allows you to remove any of default metaboxes. Do not forget to use this function inside the admin_menu action (see examples below).

remove_meta_box( $id, $screen, $context );
ID of the metabox. It matches the id="" HTML attribute of the div element.
Type of the admin page to remove metabox from. Can accept the following values:

  • post – this means that a metabox should be removed from all post edit pages
  • page – all page edit pages
  • any registered custom post type
Metabox position – normal, advanced or side. I think the value of this parameter doesn’t have much effect for default meta boxes, because the specified metabox will be removed anyway.

All default metaboxes with their IDs and examples are listed below.

Discussion Metabox in WordPress admin area


function rudr_remove_commentstatusdiv(){
	remove_meta_box( 'commentstatusdiv', 'post', 'normal' );
add_action( 'admin_menu', 'rudr_remove_commentstatusdiv' )

Insert the code above to you theme functions.php to remove the «Discussion» meta box from post edit pages. This work will work good for the following meta boxes (just do not forget to change the ID in the first function parameter).

Slug metabox allows you to change the post slug.


The «Comments» meta box will be shown only for published posts (or for another published custom post type with comments support).

WordPress Comments Metabox. The post comments will be displayed in it.


Excerpt Meta Box


In «Author» meta box you can change current post author.

Author Meta Box


The «Revision» meta box will be shown only for posts with revisions.

Revision Metabox


I think you already know about WordPress Custom Fields. On the screenshot below is the «Custom Fields» meta box. As you can see I use it to set article SEO titles and meta descriptions.

Cusom Fields Meta Box


Send Trackbacks Metabox


Categories Metabox


Tags Metabox


function rudr_remove_taxonomy_metaboxes() {
	remove_meta_box( 'categorydiv', $post_type, 'side' ); // remove Categories metabox
	remove_meta_box( 'tagsdiv-post_tag', $post_type, 'side' ); // remove Tags metabox
	$custom_taxonomy_slug = 'genre'; // this is custom taxonomy slug
	$custom_post_type = 'game'; // custom post type
	remove_meta_box( $custom_taxonomy_slug . 'div', $custom_post_type, 'side' );
add_action( 'admin_menu', 'rudr_remove_taxonomy_metaboxes' );

As you can see in the above example, you can remove any custom taxonomy metaboxes by specifying id as {custom_taxonomy_slug}div. This rule works for categories as well, but doesn’t work for post tags.

The «Featured Image» metabox will be displayed only for supported post types (read about this in the next part of the post).

Featured Image Metabox


The «Page Attributes» metabox is displayed only for pages by default.

Page Attributes Metabox


Publish Metabox


Another way of removing or adding WordPress default meta boxes using remove_post_type_support() and add_post_type_support() functions #

There is another way to remove (or add) any default metaboxes for posts, pages or custom post types. Both add_post_type_support() and remove_post_type_support() functions should be called using init action hook (you can see it in examples below).

remove_post_type_support( $post_type, $supports ) // to remove
add_post_type_support( $post_type, $supports ) // to add

Functions parameters are the same.

post, page or any custom post type
metabox to remove (or to add), it can accept the following values:

  • thumbnail — Featured Image metabox
  • author — Author metabox
  • excerpt — Excerpt metabox
  • trackbacks — Send trackbacks metabox
  • custom-fields — Custom Fields metabox
  • comments — Comments metabox
  • revisions — Revisions metabox
  • page-attributes — Page Attributes metabox

It also allows you to add/remove such areas as title or content editor:

  • title
  • editor

Simple example — let’s add «Page Attributes» metabox to the post edit:

function rudr_add_page_attributes_to_posts() {
	add_post_type_support( 'post', 'page-attributes' );
add_action('init', 'rudr_add_page_attributes_to_posts');

And remove the same metabox from pages:

function rudr_remove_page_attributes() {
	remove_post_type_support( 'page', 'page-attributes' );
add_action('init', 'rudr_remove_page_attributes');

Add meta boxes for a Custom Post Type when registering it #

Before using add_post_type_support() make sure, that you can not add the metabox support in register_post_type() function.

function rudr_register_post_type(){
	$args = array(
		'public' => true,
		'supports' => array( 'title', 'editor', 'author' ) // specify it here
	register_post_type('truepost', $args);
add_action( 'init', 'rudr_register_post_type' );

II. Create your own Custom Meta Box. Simple way. #

Custom metaboxes allow you to store parameters in post custom fields. So, you can find custom metabox data in wp_postmeta table in the database or in the «Custom Fields» default metabox. You can get the meta data using this function:

$value = get_post_meta( $post_id, $meta_key, true);

The process of creating your own custom metabox consists of two simple steps.

Step 1. Meta box HTML #

All the code below you can insert into your current theme functions.php file.

function rudr_add_a_metabox() {
		'rudr_metabox', // metabox ID, it also will be the HTML id attribute
		'My custom metabox', // title
		'rudr_display_metabox', // this is a callback function, which will print HTML of our metabox
		'post', // post type or post types in array
		'normal', // position on the screen where metabox should be displayed (normal, side, advanced)
		'default' // priority over another metaboxes on this page (default, low, high, core)
add_action( 'admin_menu', 'rudr_add_a_metabox' );
 * you can also use these action hooks:
 * add_action( 'add_meta_boxes', 'rudr_add_a_metabox' );
 * for WordPress < 3.0:
 * add_action( 'admin_init', 'rudr_add_a_metabox', 1 );

And here is the callback function. It depends on what you want to display in your metabox.

function rudr_display_metabox( $post ) {
	 * needed for security reasons
	wp_nonce_field( basename( __FILE__ ), 'rudr_metabox_nonce' );
	 * text field
	$html = '<p><label>SEO title <input type="text" name="rudr_title" value="' . esc_attr( get_post_meta($post->ID, 'rudr_title',true) )  . '" /></label></p>';
	 * checkbox
	$html .= '<p><label><input type="checkbox" name="rudr_noindex" ';
	$html .= checked( get_post_meta($post->ID, 'rudr_noindex',true), 'on', false );
	$html .= ' /> Turn off page visibility for search engines</label></p>';
	 * print all of this
	echo $html;

Let’s see what we got:

Custom Metabox in WordPress

But now we have a little problem — our metabox doesn’t save the data. So, let’s go to the next step.

Step 2. Save meta box data #

If you are using this metabox on the page edit screen or for a custom post type, don’t forget to redefine supported post types on line 19, otherwise metabox data won’t be saved.

Function update_post_meta (line 20-21) should be called for each input/textarea field in your metabox.

function rudr_save_post_meta( $post_id, $post ) {
	 * Security checks
	if ( !isset( $_POST['rudr_metabox_nonce'] ) 
	|| !wp_verify_nonce( $_POST['rudr_metabox_nonce'], basename( __FILE__ ) ) )
		return $post_id;
	 * Check current user permissions
	$post_type = get_post_type_object( $post->post_type );
	if ( !current_user_can( $post_type->cap->edit_post, $post_id ) )
		return $post_id;
	 * Do not save the data if autosave
	if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) 
		return $post_id;
	if ($post->post_type == 'post') { // define your own post type here
		update_post_meta($post_id, 'rudr_title', trim( $_POST['rudr_title'] ) );
		update_post_meta($post_id, 'rudr_noindex', $_POST['rudr_noindex']);
	return $post_id;
add_action( 'save_post', 'rudr_save_post_meta', 10, 2 );

III. PHP Class for Creating Custom Meta Boxes On The Fly #

First of all… this is just a fantastic thing! And here are some advantages:

  • Once created the class, you can use it anytime and anywhere.
  • You can create new metaboxes really on the fly.
  • You do not have to edit HTML each time when creating a new metabox.
  • All you need is to add a couple of parameters in the array.

My class is big enough, it contains such fields like google maps, multiselect, image and file uploaders, textarea, TinyMCE editor, colorpicker etc, so I won’t insert the full code into this post, but you can download the full class like a WordPress plugin here.

Well, I should show you the example, so, here are the part of my class, only with text field and checkbox field and withoud security and capability checks.

class trueMetaBox {
	/* construct function, add meta box and save action hooks */
	function __construct($options) {
		$this->options = $options;
		$this->prefix = $this->options['id'] .'_';
		add_action( 'add_meta_boxes', array( &$this, 'create' ) );
		add_action( 'save_post', array( &$this, 'save' ), 1, 2 );
	/* function that creates the metabox */
	function create() {
		/* for each post type defined */
		foreach ($this->options['post_type'] as $post_type):
			add_meta_box( $this->options['id'], $this->options['name'], array(&$this, 'fill'), $post_type, $this->options['position'], $this->options['priority']);
	/* meta box html */
	function fill(){
		global $post;
		if( isset( $this->options['args'] ) ):
			$metabox_html = '<table class="form-table"><tbody>';
			/* for each option defined */
			foreach ( $this->options['args'] as $param ):
					$metabox_html .= '<tr>';
					/* get option value and set default parameters */
					if( !$value = get_post_meta($post->ID, $this->prefix . $param['id'] , true) )
						if( isset( $param['default'] ) )
							$value = $param['default'];
					switch ( $param['type'] ) :
						/* <input type=text> */
						case 'text':{
							$metabox_html .= '<th style="font-weight:normal"><label for="' . $this->prefix . $param['id'] . '">' . $param['label'] . '</label></th><td><input name="' . $this->prefix .$param['id'] . '" type="text" id="' . $this->prefix .$param['id'] . '" value="' . esc_attr($value) . '" ';
							$metabox_html .= 'class="regular-text" /><br />';
							if( isset( $param['description'] ) )
								$metabox_html .= '<span class="description">' . $param['description'] . '</span>';
							$metabox_html .= '</td>';
						/* <input type=checkbox> */
						case 'checkbox':{
							$metabox_html .= '<th style="font-weight:normal"><label for="' . $this->prefix .$param['id'] . '">' . $param['label'] . '</label></th><td><label for="' . $this->prefix .$param['id'] . '"><input name="' . $this->prefix .$param['id'] . '" type="checkbox" id="' . $this->prefix .$param['id'] . '"';
							if( $value == 'on')
								$metabox_html .= ' checked="checked"';
							$metabox_html .= ' />';
							if( isset( $param['description'] ) )
								$metabox_html .= '<span class="description">' . $param['description'] . '</span>';
							$metabox_html .= '</td>';
					$metabox_html .= '</tr>';
			$metabox_html .= '</tbody></table>';
			/* echo metabox content*/
			echo $metabox_html;
	function save( $post_id, $post ){
		/* if this post type do not have metabox */
		if ( !in_array($post->post_type, $this->options['post_type']))
		foreach ( $this->options['args'] as $param ) {
				if ( isset( $_POST[ $this->prefix . $param['id'] ] ) && trim( $_POST[ $this->prefix . $param['id'] ] ) ) {
					update_post_meta( $post_id, $this->prefix . $param['id'], $_POST[ $this->prefix . $param['id'] ] );
				} else {
					delete_post_meta( $post_id, $this->prefix . $param['id'] );

Do you remember the «My custom metabox» form the part 2 of this post?

Custom Metabox in WordPress

Now let’s create it using our class!

$options = array(
		'id'	=>	'rudr', // metabox ID, this is also used as custom field prefix
		'name'	=>	'My custom metabox', // title
		'post_type'	=>	array('post'), // post types
		'position'	=>	'normal', // position
		'priority'	=>	'high', // priority
		'args'	=>	array(
				'id'			=> 'title',
				'label'			=> 'Seo title',
				'type'			=> 'text'
				'id'	=> 'noindex',
				'label'	=> 'Robots noindex',
				'description' => 'Turn off page visibility for search engines',
				'type'	=> 'checkbox'
if( class_exists( 'trueMetaBox' ) ) {
	foreach ($options as $option) {
		$truemetabox = new trueMetaBox($option);

Here we go.

Create Custom metabox in WordPress using PHP class

As I told you before you can download the full version of the class as a plugin (with support of google maps, multiselect, image and file uploaders, textarea, TinyMCE editor, colorpicker etc).

Only the best of WordPress

once a week, no spam

Comments 2

  • Like your tut! I get this 'Notice: Undefined variable: html in C:\xampp\htdocs\sites\test-wordpress\wp-content\themes\wordpress-test\functions.php on line 879'.

    If I use

    $html = '<p><label>SEO title <input type="text" name="seotitle" value="' . get_post_meta($post->ID, 'true_title',true) . '" /></label></p>';

    instead of

    $html .= '<p><label>SEO title <input type="text" name="seotitle" value="' . get_post_meta($post->ID, 'true_title',true) . '" /></label></p>';

    the Notice goes away. Thanks, Jamie

    function true_display_metabox($post) {
    	// needs for security checks
    	wp_nonce_field( basename( __FILE__ ), 'true_metabox_nonce' );
    	// lets add a simple textarea field
    	$html .= '<p><label>SEO title <input type="text" name="seotitle" value="' . get_post_meta($post->ID, 'true_title',true) . '" /></label></p>';
    	// add a checkbox
    	$html .= '<p><label><input type="checkbox" name="noindex"';
    	$html .= (get_post_meta($post->ID, 'true_noindex',true) == 'on') ? ' checked="checked"' : '';
    	$html .= ' /> Turn off page visibility for search engines</label></p>';
    	// print all of this
    	echo $html;

Leave your question or feedback

Please, enter a comment
Please, enter a name
Incorrect email