
Learning how to create custom WordPress meta boxes allow you to make professional UI elements for yourself and your clients. This WordPress meta box tutorial will show you how to add admin UI elements to the edit post/page screens.
Important Before you begin reading, you might want to read Take Your WordPress Meta Box to the Next Level. This PHP class will let you create meta boxes fast with the flexibility you need as a developer. Full documentation walks you step-by-step. Create custom WordPress Meta Box UI elements for your projects with ease.
Creating a custom WordPress meta box lets you make clean UI elements for you and your clients. The default WordPress custom fields are functional, but IMHO, and if you can pull it off, using a WordPress meta box is the way to go. It will give your project that professional touch.
This WordPress meta box tutorial will show you how to quickly add a clean UI for some custom fields. You will even learn how you can hide these fields and prevent them from appearing in the custom fields area.
Getting Started with WordPress Meta Boxes
The code for your meta box will pretty much go in one of two places: in a plugin file or in your functions.php file. This tutorial will cover the latter (for those of you creating plugins, you will be able to adapt the code for your use as well). I like tutorials with code examples and lots of comments, with that said, lets dive right in:
I recommend that you download the sample files or cut + paste the code and markup below in the appropriate places as indicated. There are three sample files (you will also need to create a folder and name it custom):
/current_theme_folder/functions.php /current_theme_folder/custom/meta.php /current_theme_folder/custom/meta.css
/current_theme_folder/functions.php file:
<?php
define('MY_WORDPRESS_FOLDER',$_SERVER['DOCUMENT_ROOT']);
define('MY_THEME_FOLDER',str_replace("\\",'/',dirname(__FILE__)));
define('MY_THEME_PATH','/' . substr(MY_THEME_FOLDER,stripos(MY_THEME_FOLDER,'wp-content')));
add_action('admin_init','my_meta_init');
function my_meta_init()
{
// review the function reference for parameter details
// http://codex.wordpress.org/Function_Reference/wp_enqueue_script
// http://codex.wordpress.org/Function_Reference/wp_enqueue_style
//wp_enqueue_script('my_meta_js', MY_THEME_PATH . '/custom/meta.js', array('jquery'));
wp_enqueue_style('my_meta_css', MY_THEME_PATH . '/custom/meta.css');
// review the function reference for parameter details
// http://codex.wordpress.org/Function_Reference/add_meta_box
// add a meta box for each of the wordpress page types: posts and pages
foreach (array('post','page') as $type)
{
add_meta_box('my_all_meta', 'My Custom Meta Box', 'my_meta_setup', $type, 'normal', 'high');
}
// add a callback function to save any data a user enters in
add_action('save_post','my_meta_save');
}
function my_meta_setup()
{
global $post;
// using an underscore, prevents the meta variable
// from showing up in the custom fields section
$meta = get_post_meta($post->ID,'_my_meta',TRUE);
// instead of writing HTML here, lets do an include
include(MY_THEME_FOLDER . '/custom/meta.php');
// create a custom nonce for submit verification later
echo '<input type="hidden" name="my_meta_noncename" value="' . wp_create_nonce(__FILE__) . '" />';
}
function my_meta_save($post_id)
{
// authentication checks
// make sure data came from our meta box
if (!wp_verify_nonce($_POST['my_meta_noncename'],__FILE__)) return $post_id;
// check user permissions
if ($_POST['post_type'] == 'page')
{
if (!current_user_can('edit_page', $post_id)) return $post_id;
}
else
{
if (!current_user_can('edit_post', $post_id)) return $post_id;
}
// authentication passed, save data
// var types
// single: _my_meta[var]
// array: _my_meta[var][]
// grouped array: _my_meta[var_group][0][var_1], _my_meta[var_group][0][var_2]
$current_data = get_post_meta($post_id, '_my_meta', TRUE);
$new_data = $_POST['_my_meta'];
my_meta_clean($new_data);
if ($current_data)
{
if (is_null($new_data)) delete_post_meta($post_id,'_my_meta');
else update_post_meta($post_id,'_my_meta',$new_data);
}
elseif (!is_null($new_data))
{
add_post_meta($post_id,'_my_meta',$new_data,TRUE);
}
return $post_id;
}
function my_meta_clean(&$arr)
{
if (is_array($arr))
{
foreach ($arr as $i => $v)
{
if (is_array($arr[$i]))
{
my_meta_clean($arr[$i]);
if (!count($arr[$i]))
{
unset($arr[$i]);
}
}
else
{
if (trim($arr[$i]) == '')
{
unset($arr[$i]);
}
}
}
if (!count($arr))
{
$arr = NULL;
}
}
}
?>
/current_theme_folder/custom/meta.php file:
<div class="my_meta_control"> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras orci lorem, bibendum in pharetra ac, luctus ut mauris. Phasellus dapibus elit et justo malesuada eget <code>functions.php</code>.</p> <label>Name</label> <p> <input type="text" name="_my_meta[name]" value="<?php if(!empty($meta['name'])) echo $meta['name']; ?>"/> <span>Enter in a name</span> </p> <label>Description <span>(optional)</span></label> <p> <textarea name="_my_meta[description]" rows="3"><?php if(!empty($meta['description'])) echo $meta['description']; ?></textarea> <span>Enter in a description</span> </p> </div>
/current_theme_folder/custom/meta.css file:
.my_meta_control .description
{ display:none; }
.my_meta_control label
{ display:block; font-weight:bold; margin:6px; margin-bottom:0; margin-top:12px; }
.my_meta_control label span
{ display:inline; font-weight:normal; }
.my_meta_control span
{ color:#999; display:block; }
.my_meta_control textarea, .my_meta_control input[type='text']
{ margin-bottom:3px; width:99%; }
.my_meta_control h4
{ color:#999; font-size:1em; margin:15px 6px; text-transform:uppercase; }
If you’ve set everything up correctly you should see the following meta box in a edit post or edit page screen:

Using The Meta Box Values In Your Template
Being able to create the values is just the first part, now you need to do something with those values. Most likely you will be displaying the values in your post or page templates.
Remember the example above uses a single variable (_my_meta) to store values as an array, so when you get the meta value back from WordPress it will be an array and you will have to access the values using array syntax. Doing this is pretty straight forward:
$my_meta = get_post_meta($post->ID,'_my_meta',TRUE); echo $my_meta['name']; echo $my_meta['description'];
The global $post variable should always be available, but here are some other methods you can use to get the current post or page ID which you will need to use with get_post_meta():
// using $post global variable
echo $post->ID;
// get a page by its path (recommended over using a page ID)
$page = get_page_by_path('company/contact-us');
echo $page->ID;
// if you are working in the loop
echo get_the_ID();
The above code and markup will help you produce clean UI elements for your next WordPress project. Like any tutorial, consider this a starting point for you to do great things. I hope you’ve enjoyed!

Tyler, as you’ve already noticed, the code uses an array to store its data. The
my_meta_clean()function will clean that array when items are deleted (are emptied). For instance: when you clear the data from a form field the array will be cleaned.I am going to be working on a new version of the WordPress Meta Box PHP class which will allow the developer to choose how the data is stored, via an array or via the classic WordPress name/value scheme.
You need to add
add_action('edit_post','my_meta_save');to themy_meta_initfunction. That will save changes.Keep in mind that
edit_postaction gets fired on post/page edit and on comment add/edit … here is what WordPress says aboutedit_post:“Runs when a post or page is updated/edited, including when a comment is added or updated”
I believe the
save_posthook is the correct action to use in this case.That’s EXACTLY what I’m after… thanks so much
This is just awesome! I created a custom post type but I also wanted to have specific information included and I searched and searched and couldn’t find anything that worked. Until your tutorial! Works perfectly! Thank you very much!
One thing though I took out the wp_enque_style for the meta.css as it wasn’t working and just did a link to the style sheet in the meta.php file. Works like a charm.
Also to Christopher B – A big thanks to you as well – u ran into some issues I was having i.e. defining the post type and after reading all your comments (lol) i got it to work. Nicely done.
Hey Dimas,
In what way is it possible to import meta data using CSV format?
I took a look at the SQL backend and saw that it makes an array in the meta field and I am not sure of a plugin that could do something like that.
I do recall a CSV importer but I dont believe it does meta data..
Noel, I think the default WordPress export/import functionality will work with
wp_postmetadata as well.If you were to write a plugin to do this, it shouldn’t be too hard either, you basically would have to select * from a table and write it as a CSV file with PHP. Unfortunately I don’t know of anything that would do this easily for WordPress.
If you can’t find anything ready available you mighty be able to do it with phpMyAdmin as a data export, additionally I use Navicat for MySQL and it has options to export MySQL tables as CSV and the like.
Where are these fields being saved? I don’t see them in the custom post meta, and I don’t see where to specify where it’s saved.
Matt, the above example saves all the data as a serialized array in the wp_postmeta table (“_my_meta” in the example above) … If you haven’t yet taken a look at wpalchemy, it uses the same technique but also provides a way to save individual entries, plus a lot more options…
Hi, I use more and more your great function it’s helpfull.
However I’ve a problem.
In a custom template page I try make a custom query to order shop by zip code
:
the_meta();
$zipcodep=$meta['zipcode];
?>
–
the query don’t work (query_posts(‘post_type=shops)), works.
I hope you can help me!
Thank so much for this, Dimas. I was beating my head against the wall with Sitepoint’s article on this. You’ve made some drastic improvements here, and it’s working great for me!
Nate, be sure to take a look at wpalchemy for even easier meta box creation.
Hi Dimas, i’ve been reading through your info on meta boxes and post types. I’m pretty stuck on a couple of things, any help would be great!
1) I’ve added to custom post types to a site, they work fine. The problem is the meta boxes I add on the page then show up in all other pages (normal pages, not just the custom post type) once the page has been published. The show up as custom fields. There are now lots of them and I could really do with getting rid of them, can’t i just limit them to the page i want them to show on?
2) This is related to your meta box stuff. Rather than make a custom post type for my home page, i’d like to make a completely bespoke layout in the admin area. When editing a page with my home.php template i’d like to style 4 boxes, the same as the look on the front-end. This makes it obvious which bit your editing and looks just like the page. I would also need tinyMCE to show up in each one i suppose, so the client could choose links/headings/etc. Ive followed your article on adding meta boxes, I managed to get one to show up on the home.php template but it didn’t look right, and all the other stuff like title, editor, revisions etc were still there. I have a feeling this might be because i need the remove_meta_box function or whatever it is. Any ideas at all how i go about achieving this custom back end?
Sorry for the long post, but i’m pretty damn stuck
Thanks, Dan
Dan, be sure to take a look at wpalchemy for even easier meta box creation … this should help you out, using tinyMCE within the meta boxes is a little bit more tricky, I have a post related to that also.
Top notch tutorial! Does anyone know how to enable wpautop on the custom meta created in the above example?
Thanks for sharing. What is the license on this?
Great tutorial, truly helpful.
I had two quick questions:
1. I would like to pull the Metabox title to display next to the data, how would I do that?
2. One of my fields is an img url, how would I pull this onto the page?
Thanks in advance,
14ner
@14ner, please have a look at wpalchemy … its all the above, but better, packaged up for you … with good documentation …
This is a great tutorial, but you missed out the part about custom meta boxes in a plugin menu screen, for example a settings area. I have written a quick article to show also how simple that is!
http://thewebsolutionprovider.com/wordpress/wordpress-tutorials/custom-wordpress-meta-box-for-your-plugins/
You are a fkn legend. This helped me so much, and now i’ve converted it to do options pages etc as well.
Thanks for this post, just found it on Google and it’s answered a few questions. Now on to the actual development!
I have to second Andy’s question. Does anyone know the approach to adding the wpautop filter to the textarea meta boxes?
when i went through as per the tutorial it is success. But the main problem that occured to me is when i tried to change the custom menta field value it is not working. Do you have any idea i would be grateful to you.
I’m trying to put a input file, but it doest work. Can you help me? Thanks
Andrea, take a look at WPAlchemy, you can use the
save_actionand look at the$_FILESphp global.