Skip to content

Add A Meta Box In WordPress

Creating the options pages is something we’ve touched upon previously here on [wp], and whilst developing my soon-to-be-released WordPress [theme], Biblioteca, I wanted to add some options to the post writing page, and in this post I’m going to be sharing how I did it.

How the in-post options work

Basically, we’re going to be adding some boxes to the post and page writing pages that give our users a number of options, including customising the <title> tag, the meta description and the URL of a featured image:

WordPress login

These options get displayed immediately below the post/page writing area, and the user can enter text. This text, when the post is saved gets saved as custom fields. For example, on this post I’ll enter some text “Hello. This is a test.”  in the “Image” field. The results are below:

post options

So that proves it works! Let’s get straight into implementing it. First off, all credits go to Justin Tadlock – code comes more or less straight out of Hybrid.

Making the in post options

The first thing you need to do in order to make your own in post options is to open up your functions.php file. This is the file that gives you a lot of power, but can also totally wreck your theme – power comes with responsibility! Always have a backup readily to hand.

The first code to add is the following, which does the job of adding the box to the admin menu:

<?php
/**
Made with the help of a tutorial at WPShout.com => https://wpshout.com.

Courtesy of the Hybrid theme - themehybrid.com

/* Add a new meta box to the admin menu. */
	add_action( 'admin_menu', 'hybrid_create_meta_box' );

/* Saves the meta box data. */
	add_action( 'save_post', 'hybrid_save_meta_data' );

/**
 * Function for adding meta boxes to the admin.
 * Separate the post and page meta boxes.

function hybrid_create_meta_box() {
	global $theme_name;

	add_meta_box( 'post-meta-boxes', __('Post options'), 'post_meta_boxes', 'post', 'normal', 'high' );
	add_meta_box( 'page-meta-boxes', __('Post options'), 'page_meta_boxes', 'page', 'normal', 'high' );
}

With that added, the next step is to start an array which will be the text used by the options page. The ‘name’ is the name of the custom field that will be generated by the options. Next is the text displayed on the right and finally the ‘type’ is what type of box the theme is to display; either the large textarea or the smaller single line text:

function hybrid_post_meta_boxes() {

	/* Array of the meta box options. */
	$meta_boxes = array(
		'title' => array( 'name' => 'Title', 'title' => __('Title', 'hybrid'), 'type' => 'text' ),
		'description' => array( 'name' => 'Description', 'title' => __('Description', 'hybrid'), 'type' => 'textarea' ),
		'image' => array( 'name' => 'Image', 'title' => __('Image:', 'hybrid'), 'type' => 'text' ),
		'featured' => array( 'name' => 'Featured', 'title' => __('Featured img:', 'hybrid'), 'type' => 'text' ),

	);

	return apply_filters( 'hybrid_post_meta_boxes', $meta_boxes );
}

You’ll notice the last bit of code is for pages only, where no featured image option is added.

Next, the code that displays the boxes and formats them:

function post_meta_boxes() {
	global $post;
	$meta_boxes = hybrid_post_meta_boxes(); ?>

	<table class="form-table">
	<?php foreach ( $meta_boxes as $meta ) :

		$value = get_post_meta( $post->ID, $meta['name'], true );

		if ( $meta['type'] == 'text' )
			get_meta_text_input( $meta, $value );
		elseif ( $meta['type'] == 'textarea' )
			get_meta_textarea( $meta, $value );
		elseif ( $meta['type'] == 'select' )
			get_meta_select( $meta, $value );

	endforeach; ?>
	</table>
<?php
}

/**
 * Displays meta boxes on the Write Page panel.  Loops
 * through each meta box in the $meta_boxes variable.
 * Gets array from hybrid_page_meta_boxes()
 *
 * @since 0.3
 */
function page_meta_boxes() {
	global $post;
	$meta_boxes = hybrid_page_meta_boxes(); ?>

	<table class="form-table">
	<?php foreach ( $meta_boxes as $meta ) :

		$value = stripslashes( get_post_meta( $post->ID, $meta['name'], true ) );

		if ( $meta['type'] == 'text' )
			get_meta_text_input( $meta, $value );
		elseif ( $meta['type'] == 'textarea' )
			get_meta_textarea( $meta, $value );
		elseif ( $meta['type'] == 'select' )
			get_meta_select( $meta, $value );

	endforeach; ?>
	</table>
<?php
}

/**
 * Outputs a text input box with arguments from the
 * parameters.  Used for both the post/page meta boxes.
 *
 * @since 0.3
 * @param array $args
 * @param array string|bool $value
 */
function get_meta_text_input( $args = array(), $value = false ) {

	extract( $args ); ?>

	<tr>
		<th style="width:10%;">
			<label for="<?php echo $name; ?>"><?php echo $title; ?></label>
		</th>
		<td>
			<input type="text" name="<?php echo $name; ?>" id="<?php echo $name; ?>" value="<?php echo wp_specialchars( $value, 1 ); ?>" size="30" tabindex="30" style="width: 97%;" />
			<input type="hidden" name="<?php echo $name; ?>_noncename" id="<?php echo $name; ?>_noncename" value="<?php echo wp_create_nonce( plugin_basename( __FILE__ ) ); ?>" />
		</td>
	</tr>
	<?php
}

/**
 * Outputs a select box with arguments from the
 * parameters.  Used for both the post/page meta boxes.
 *
 * @since 0.3
 * @param array $args
 * @param array string|bool $value
 */
function get_meta_select( $args = array(), $value = false ) {

	extract( $args ); ?>

	<tr>
		<th style="width:10%;">
			<label for="<?php echo $name; ?>"><?php echo $title; ?></label>
		</th>
		<td>
			<select name="<?php echo $name; ?>" id="<?php echo $name; ?>">
			<?php foreach ( $options as $option ) : ?>
				<option <?php if ( htmlentities( $value, ENT_QUOTES ) == $option ) echo ' selected="selected"'; ?>>
					<?php echo $option; ?>
				</option>
			<?php endforeach; ?>
			</select>
			<input type="hidden" name="<?php echo $name; ?>_noncename" id="<?php echo $name; ?>_noncename" value="<?php echo wp_create_nonce( plugin_basename( __FILE__ ) ); ?>" />
		</td>
	</tr>
	<?php
}

/**
 * Outputs a textarea with arguments from the
 * parameters.  Used for both the post/page meta boxes.
 *
 * @since 0.3
 * @param array $args
 * @param array string|bool $value
 */
function get_meta_textarea( $args = array(), $value = false ) {

	extract( $args ); ?>

	<tr>
		<th style="width:10%;">
			<label for="<?php echo $name; ?>"><?php echo $title; ?></label>
		</th>
		<td>
			<textarea name="<?php echo $name; ?>" id="<?php echo $name; ?>" cols="60" rows="4" tabindex="30" style="width: 97%;"><?php echo wp_specialchars( $value, 1 ); ?></textarea>
			<input type="hidden" name="<?php echo $name; ?>_noncename" id="<?php echo $name; ?>_noncename" value="<?php echo wp_create_nonce( plugin_basename( __FILE__ ) ); ?>" />
		</td>
	</tr>
	<?php
}

And finally, saving the options entered as custom fields:

/**
 * Loops through each meta box's set of variables.
 * Saves them to the database as custom fields.
 *
 * @since 0.3
 * @param int $post_id
 */
function hybrid_save_meta_data( $post_id ) {
	global $post;

	if ( 'page' == $_POST['post_type'] )
		$meta_boxes = array_merge( hybrid_page_meta_boxes() );
	else
		$meta_boxes = array_merge( hybrid_post_meta_boxes() );

	foreach ( $meta_boxes as $meta_box ) :

		if ( !wp_verify_nonce( $_POST[$meta_box['name'] . '_noncename'], plugin_basename( __FILE__ ) ) )
			return $post_id;

		if ( 'page' == $_POST['post_type'] && !current_user_can( 'edit_page', $post_id ) )
			return $post_id;

		elseif ( 'post' == $_POST['post_type'] && !current_user_can( 'edit_post', $post_id ) )
			return $post_id;

		$data = stripslashes( $_POST[$meta_box['name']] );

		if ( get_post_meta( $post_id, $meta_box['name'] ) == '' )
			add_post_meta( $post_id, $meta_box['name'], $data, true );

		elseif ( $data != get_post_meta( $post_id, $meta_box['name'], true ) )
			update_post_meta( $post_id, $meta_box['name'], $data );

		elseif ( $data == '' )
			delete_post_meta( $post_id, $meta_box['name'], get_post_meta( $post_id, $meta_box['name'], true ) );

	endforeach;
}
?>

And we’re done creating the options! Next, we’re going to be implementing these options.

Giving the user the option to change the title tag without a plugin

The first field/option we offered was “Title”. Obviously we’re going to use this as the <title> tag for our post. How? As you may recall, the text input into the boxes gets spitted out as a custom field, so we can display the “Title” as the title tag with the following (open up the header.php):

<title><?php echo get_post_meta($post->ID, "Title", true); ?></title>

But that would be a seriously bad idea. What if it’s the homepage?! What if there is no custom field?! The folllowing is much better; it should be used in conjunction with your current SEO’d setup, will only display on posts and pages and has an option for if no custom field exists:

<?php if ( is_single() || is_page() ) { ?><?php $title = get_post_meta($post->ID, 'Title', true);  if ($title) { ?>
<?php echo get_post_meta($post->ID, "Title", true); ?> | <?php bloginfo('name'); ?>
<?php } else { ?>
<?php wp_title(''); ?> | <?php bloginfo('name'); ?>
<?php } ?>
<?php } ?>

Giving the user the option to change the meta description without a plugin

The second field was ‘Description’. This is your meta description, an important part of your SEO strategy. Similar code to the above will display the content of the box, but with a fall back for if no custom field exists:

lt;?php if (is_single() || is_page() ) : if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<meta name="description" content="<?php $description = get_post_meta($post->ID, 'Description', true);  if ($description) { ?><?php echo get_post_meta($post->ID, "Description", true); ?>
<?php } else { ?><?php the_excerpt_rss(); ?><?php } ?>" />
<?php endwhile; endif; elseif(is_home()) : ?>
<meta name="description" content="<?php bloginfo('description'); ?>" />
<?php endif; ?>

Displaying images

The final field was the URL for a ‘featured’ image. We can integrate this into our WordPress theme with the following:

<?php $postimageurl = get_post_meta($post->ID, 'Image', true); if ($postimageurl) { ?>
<img src="<?php bloginfo('template_url'); ?>/scripts/timthumb.php?src=<?php echo get_post_meta($post->ID, "Image", true); ?>&h=250&w=250&zc=1" alt="">  <?php }else { ?>  <img src="<?php bloginfo('template_url'); ?>/images/noimage.jpg" alt="No image available" />
<?php } ?>

Concluding

With that, we’re finished creating our in post options! The download for the code is available at the top of the post. This is a brilliant, simple and effective way to improve your WordPress theme.

If you have enjoyed this post, please take a second to save it to your favourite social bookmarking site with the links below and even [s] or [t]! Any questions, suggestions or queries, please do leave a comment.

Yay! 🎉 You made it to the end of the article!
Alex Denning

35 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
kapil
February 17, 2012 10:36 am

I want to change my front page meta and title.please help me anyone, how can I manage by function hybrid_document_title();

dustin
January 5, 2012 4:39 pm

Thanks so much for this tutorial!

Petra
December 8, 2011 5:05 pm

Thanks for the tutorial. I tried to implement your code and seems to be working fine, only that I am getting two sets of custom fields: I get my own custom write panel with custom fields and the one that comes with WordPress. For some reason when I add a custom field in my custom write panel, it also automatically adds it into a default custom field panel, so I have two custom fields with the same name and content. Any ideas why and how to resolve this problem? I am using the latest version of WordPress.

Marco Berrocal
October 17, 2011 7:02 pm

Does anybody know how to loop this? Say I want to do a slider for pages with the meta box set to TRUE or something, and then I want to grab all pages or posts with that condition?

Michael
February 25, 2011 10:52 am

Hi, I’ve stumbled across your code and it is the perfect solution for what I need to do but when I try putting it in to my functions.php file it gives me the following error

Warning: Cannot modify header information – headers already sent by (output started at /usr/var/www/localhost/htdocs/oowebsite/wp-includes/plugin.php:395) in /usr/var/www/localhost/htdocs/oowebsite/wp-admin/theme-editor.php on line 89

I’m inserting it directly at the top of the functions file to call it as early as possible, am I putting it in the wrong place? Any feeback very much obliged.

anuj
February 17, 2011 8:14 pm

i must say that simply gr8 tip 🙂

Patricia
December 3, 2010 2:12 am

Hi, I really like the way this is done. Would it be recommended to insert a custom field with keywords as well or is this not needed anymore?

Fighting Reality
November 26, 2010 9:10 pm

[…] that were as straight-forward as I was hoping there would be. The best tutorial I found was located here. The problem with this tutorial was that it didn’t spell it out clearly enough for me. It was […]

acepek
August 27, 2010 7:59 pm

Thank you very much for this! I have changed it a bit to suit my needs by adding extra metaboxes. These all display fine but only the first set (the first 5) save! Of course there is something I need to change to make it save the extras but alas, I am just a tinkerer not a master… $meta_boxes = array( 'url' => array( 'name' => 'URL', 'title' => __('Video URL:', 'hybrid'), 'type' => 'text' ), 'title' => array( 'name' => 'Title', 'title' => __('Title:', 'hybrid'), 'type' => 'text' ), 'description' => array( 'name' => 'Description', 'title' => __('Description:', 'hybrid'), 'type' => 'text' ), 'preroll' => array( 'name' => 'Preroll', 'title' => __('Preroll?', 'hybrid'),'options' => array('','Yes'), 'type' => 'select' ), 'link' => array( 'name' => 'link', 'title' => __('link:', 'hybrid'), 'type' => 'tag' ), 'url1' => array( 'name' => 'URL1', 'title' => __('Video URL:', 'hybrid'), 'type' => 'text' ), 'title1' => array( 'name' => 'Title1', 'title' => __('Title:', 'hybrid'), 'type' => 'text' ), 'description1' => array( 'name' => 'Description1', 'title' => __('Description:', 'hybrid'), 'type' => 'text' ), 'preroll1' => array( 'name' => 'Preroll1', 'title' => __('Preroll?', 'hybrid'),'options' => array('','Yes'), 'type' => 'select' ), 'link1' => array( 'name' => 'link1', 'title'… Read more »

Extension:103
August 15, 2010 8:37 pm

im hoping you can help me out with this one. i have had this code in my theme from theme hybrid for over a year now. and noticed no problems. now i have been developing a theme for entry into the wordpress theme directory.

after going through all the usually stuff i came to debug the theme. i keep getting an error saying this

“Notice: Undefined index: post_type in……”

and

“Notice: Undefined index: Title_noncename in ……”

now this issue is coming from the hybrid_save_meta_data function, heres the code for reference

does anyone have a solution to this?

i have a okay understanding of php but this is a real issue and i cant figure it out.

chris
August 9, 2010 9:23 am

How to use select:


'password' => array(
'name' => 'password',
'title' => __('Password Protection'),
'options' => array(
'No',
'Yes'
),
'type' => 'select' )

philip
September 25, 2010 9:48 am
Reply to  chris

thanks Chris but how you call an if statement here?

i need to make a show/hide dropdown,
if is show
//get php file
else
//do nothing

thanks a lot!

Using WordPress As A CMS | WPShout.com
July 13, 2010 4:43 pm

[…] Each offer is a post but we only want one line of text briefly describing the offer. We've built a custom meta box to allow an easy way of adding custom fields to posts. The custom field contains information about […]

Josh Byers
June 23, 2010 6:54 am

Regarding only showing custom meta boxes when a certain page template is selected I have this solution which works great:


$post_id = $_GET['post'] ? $_GET['post'] : $_POST['post_ID'] ;
$template_file = get_post_meta($post_id,'_wp_page_template',TRUE);

if ($template_file == 'attorneys.php') { // this will only show on pages that have been saved with the attorneys template

Just replace “attorneys.php” with the name of your template file,
Include the custom meta box code and close out the open brace.

philip
April 25, 2010 1:09 pm

thanks a lot for this help.

i try to use it with qtranslate with ( [:en] ) and ( ) tags but with no luck.
is a way to make it work with qtranslate tags also?

thanks a lot again!

philip

Paul
February 1, 2010 10:57 pm

What
return apply_filters( ‘hybrid_post_meta_boxes’, $meta_boxes );

do ?

I’m interested why you use apply_filter instead of add_filter ?

Jason
January 11, 2010 12:30 am

Great post! Very helpful.

Quick question though…

Is there any way to make the meta box show only when a specific page template is selected?

Jason
January 18, 2010 5:23 pm
Reply to  Jason

Thanks for the reply! It’s funny you linked to that post. I’ve been following ThemeShaper tutorials in building my little WP framework over the last couple of months.

As far as making a meta box show on a Page Write admin page only when a specific page template is selected, I ended up just using javascript.

I figured any solution with PHP would not allow the user to see the new meta box until they actually saved the page and came back to editing it again (which wouldn’t make sense).

Karl Bedingfield
January 1, 2010 11:11 am

Fantastic tutorial!

Just one question. I would like to put a brief description under each input field as a reminder to what each input does.

How would I do that?

Thanks,
Karl

Yes_Pap
December 14, 2009 10:05 pm

Hello,

Do you know how to use the select option ?

I want to create a select meta boxe with a true/false choice.

Thx for your help.

Yes_Papa@mac.com
December 16, 2009 9:46 pm
Reply to  Yes_Pap

Any ideas how to do this ?

Could give me an example ?

Thx for your help.

WordPress as a Tumblelog, CMS: Advanced Uses of WordPress | WPShout.com
December 1, 2009 7:10 pm

[…] the first post – WPShout – is actually a link to WPShout. How? Using Biblioteca’s custom write meta box thingys (I still don’t know the technical term!) I can create a new post which contains the link and […]

Brian
October 28, 2009 2:46 pm

Hi Alex,

I love the tutorial, opens up many possibilities within the CMS.

However, when I copy and paste your code into my functions file it works a treat, but when I change the names of the meta boxes in the array they are not saved as custom fields. Everything shows up as it should on screen in the ‘write page’ area, but on save nothing happens.

Any ideas?

Here is an example of one line – ‘header paragraph’ => array( ‘name’ => ‘Header Paragraph’, ‘title’ => __(‘Header Paragraph’, ‘hybrid’), ‘type’ => ‘text’ ),

Many thanks,

Brian

How To: Display Quotes From A Random Post in WordPress | WPShout.com
October 21, 2009 3:02 pm

[…] in the sidebar of our blog.HypothesisUse of custom fields to pull data from posts. Preferably custom write panels to spice it up a bit.Loop (preferably without replacing the loop already in use) to pull a random […]

Free WordPress (Portfolio/Personal Blog) Theme: Happy Go Try | WPShout.com
October 20, 2009 7:18 am

[…] and it inherits all of Biblioteca’s advanced features – a nice theme options page, in post SEO options, threaded comments, a ton of widget ready area etc.The theme would look great on a personal blog or […]

Free WordPress (Magazine/Framework/Bloggy/Tech Blog) Theme: Biblioteca | WPShout.com
September 15, 2009 4:30 pm

[…] Create An In-Post (Theme) Options (Meta) Box in WordPress […]

10 Awesome Things To Do With WordPress’ Custom Fields | WPShout.com
August 25, 2009 8:28 pm

[…] Create An In-Post (Theme) Options (Meta) Box in WordPress […]

Comment Guidelines Violation 3
August 25, 2009 10:47 am

Wow! this is very nice tips for modify WordPress feature. Thank you so much!

Or start the conversation in our Facebook group for WordPress professionals. Find answers, share tips, and get help from other WordPress experts. Join now (it’s free)!

35
0
Would love your thoughts, please comment.x

Most Searched Articles

Best JavaScript Libraries and Frameworks: Try These 14 in 2024

In this post, we look at the best JavaScript libraries and frameworks to try out this year. Why? Well, with JavaScript being available in every web browser, this makes it the most accessible programming language of ...

20 Best Free WordPress Themes for 2024 (Responsive, Mobile-Ready, Beautiful)

If you're looking for only the best free WordPress themes in the market for this year, then you're in the right place. We have more than enough such themes for you right ...

12 Best WordPress Hosting Providers of 2024 Compared and Tested

Looking for the best WordPress hosting that you can actually afford? We did the testing for you. Here are 10+ best hosts on the market ...

Handpicked Articles

How to Make a WordPress Website: Ultimate Guide for All Users – Beginners, Intermediate, Advanced

Many people wonder how to make a WordPress website. They’ve heard about WordPress, its incredible popularity, excellent features and designs, and now they want to join the pack and build a WordPress website of their own. So, where does one get ...

How to Start an Ecommerce Business: Ultimate Guide for 2024

Is this going to be the year you learn how to start an eCommerce business from scratch? You’re certainly in the right place! This guide will give you a roadmap to getting from 0 to a fully functional eCommerce business. ...