Written by Bill EricksonPublished on March 31, 2011Updated on December 21, 2018
Overview
What is metadata?
Metadata is information about an object (like a post) and consists of a key and a value. For instance, when you use a page template, the name of the template used by the page is stored as metadata using the key _wp_page_template. You can add your own metadata to store anything you’d like.
This article focuses on post meta, which is metadata attached to a post of any content type (post, page, or custom post type). There is also user meta (attached to users) and term meta (attached to taxonomy terms, like categories and tags).
What is a metabox? A metabox is simply a box that lets you edit metadata. While WordPress already includes a simple “Custom Fields” metabox (screenshot), it’s best to build your own metabox, which will look better and be easier to use.
A common use for metaboxes is to store structured data that is then displayed by the theme. This allows you to separate the data entry from visual presentation. Instead of trying to get the markup just right on a pricing table, create a “Pricing Table” metabox to collect the fields and let the theme take care of the markup.
How to use meta in your theme? WordPress has a simple function for accessing post meta: get_post_meta( $post_id, $key, true );. See the WordPress Code Reference for more information on its usage.
Depending on the plugin you use and the complexity of the fields you build, you may choose to use plugin-specific functions to access metadata. For instance, with Carbon Fields you can use carbon_get_post_meta( $post_id, $key );. Always first check that the function exists( if( function_exists( 'carbon_get_post_meta' ) ) ) so your site doesn’t break if the plugin is deactivated.
Creating Metaboxes with Plugins
The simplest way to create a metabox is to use a “metabox plugin” to do the heavy lifting. You describe the fields you want and the plugin takes care of actually building the metabox and saving the data.
If you will be publicly distributing a plugin, it’s best to build the metabox directly in the plugin itself rather than require a second plugin to be installed. Here are two examples of plugins that use custom metaboxes:
I’ll walk you through building the metabox for this page using three popular metabox plugins.
Advanced Custom Fields
Advanced Custom Fields is the most popular plugin for creating metaboxes. You can easily build a metabox from the WordPress backend with no code at all. You can use the Local JSON feature to save your metabox settings in your theme so it can be version controlled. While the free version of the plugin includes many basic field types, this tutorial uses the “Repeater” field which is only available in ACF Pro.
In the backend of your site, go to Custom Fields > Field Groups and click “Add New”. Give your metabox a name at the top, then click “Add Field” to add your fields. Here is a list of the available field types.
I’m adding a repeater field, and inside of that I’m adding some text, textarea, and checkbox fields. I’m also setting the “width” on the first 3 fields to 33% so they appear in three columns.
In the “Location” section you can set rules that determine where this metabox appears. I’m limiting this metabox to appear on pages using the “Plugins (ACF)” template.
To access the data in your theme, you can either use the WordPress core function get_post_meta() or the ACF functions. I’m using the ACF functions in the template file below. Here’s the raw metadata stored in the database.
To keep the example simple and easily comparable between plugins, I’m putting all the data into an array and passing it to a function that builds the plugin listing.a
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Carbon Fields is another great metabox tool. You build metaboxes using code rather than a UI like AC. The code is modern and easy to read, and the resulting metaboxes look great. It takes the best from both ACF and CMB2 and improves upon it. They are also working on a block builder for the new block editor.
Installing the plugin is more difficult than the others. While there is a Carbon Fields plugin in the WordPress plugin repository, it’s not up-to-date. They made non-backwards-compatible changes and decided not to update the plugin repo. You can either use Composer or download the plugin here.
Once installed and active, create carbon-fields.php file in your core functionality plugin (preferred) or theme. See the documentation for more information on how to build a metabox.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
I have it set to ->set_collapsed( true ) so when you load the page you only see the small header bars (like “Genesis Title Toggle” below), but in this screenshot I’ve expanded the second entry.
I’m using the plugin functions for accessing the metadata. In case you’re curious, here’s the raw metadata that’s saved to the database. It isn’t as easy to follow as ACF or CMB2 so I definitely recommend using the plugin functions. While it is all stored as separate meta, on “complex” fields carbon_get_post_meta() will return a single array containing all the data.
Here’s the template file:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CMB2 is the most developer focused of these three plugins. It’s infinitely extensible and often used in large projects since every aspect can be customized, including custom styles for the metabox. But it can be a bit difficult to learn and doesn’t look as good out of the box as the other plugins I’ve covered.
You can either use the WordPress plugin (as I have done) or include the CMB2 code directly in your theme/plugin. It’s smart enough to only load once when multiple copies are enqueued, and always select the most recent version.
In my core functionality plugin I created cmb2.php and added the following:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CMB2 uses the standard WordPress function get_post_meta() for retrieving meta, so there are no plugin-specific functions you need to learn.
Because we are using the “Group” field type for repeatable fields, it stores all of that data in a single post_meta field as a serialized array (see the raw metadata here), which WordPress unserializes into a standard array. Here’s the page template code:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
A hybrid WordPress theme uses theme.json to define styles and customize the block editor while also using traditional PHP template files. Hybrid themes leverage the block editor for content but…
I frequently work with food bloggers to improve the design, speed, and functionality of their websites. The recipe card is the most important element on the page. It should be…
A detailed guide to importing recipes from *any* theme or plugin to WP Recipe Maker.
Reader Interactions
Comments are closed. Continue the conversation with me on Twitter: @billerickson
Comments
Pietsays
Hi Bill,
Thanks for the great code, this is really helpful!
One thing I cannot seem to get working is saving the values of checkboxes and/or radio buttons. They show in the backend, but when I tick a box or select a radio button and click Update, it comes back empty. Am I forgetting something?
Pietsays
I can only get it working when using type=> multicheck
Bill Ericksonsays
I just tested it and it works fine for me. Here’s what I used:
Thanks for your reply Bill, it was my own silly mistake, got it working too now and it does a tremendous job! Thanks!
Pietsays
I have one last question. Before I was using your class, I used another, similar metabox class by deluxeblogtips (http://senl.in/q2zpAV). That was all working fine until WP 3.1.4. Upon the release of WP 3.2 the script broke the wysiwyg editor, so I needed to find an alternative. I am therefore very happy that I found your script (recommended by a friend).
One of the features the other script had though was the ability to upload multiple images. I have seen that your script also has an image upload field, but I am wondering whether that also works for multiple images and whether it will be possible to sort those images after upload.
If it is possible, then that’s great of course. If not, then it might be an idea to try to implement that functionality in your script too?
Bill Ericksonsays
I believe the image upload type only allows one image, which is the most common use case. If you want multiple images uploaded I recommend turning on the editor and using the Media Uploader, or just adding to the media uploader to the post type. That way you can use the gallery feature.
Pietsays
OK thanks, will try out the various options then.
Pietsays
Hi again Bill, I seem to be running into the same problem as with the other script: the wysiwyg-editor is not showing up, screenshot: http://senl.in/oDmcUd
The code I used is exactly according the example-functions:
array(
‘name’ => ‘Review Summary’,
‘desc’ => ”,
‘id’ => $prefix . ‘summary’,
‘type’ => ‘wysiwyg’,
‘std’ => ‘some default text’
),
Has this happened before to anyone? I am using a TwentyTen child theme and have upgraded to WP 3.2
OK sorry to fill your comment line, it must be a bug somewhere in my theme or one of the plugins I use. Just tried it on a vanilla local install and there the editor actually does show up.
Pietsays
our replies crossed… i will post on github for this issue then! thanks!
Hi Bill. I’m very inexperienced with WordPress and PHP but your metabox code, and this article, has made the creation/implementation of Custom Meta Boxes super easy, so thank you! I’ve implemented CMBs for a custom-post-type but have since been mulling over other ways to use them and wondered if it’s possible to show CMBs on a specific page only? I hoped that ‘pages’ => array(‘page_name’) would work but it does not.
Bill Ericksonsays
Unfortunately no, you can’t display it on a specific page. But you could use CSS to hide the metabox on all pages except the one you want it on. It’s beyond the scope of this post, so search around for Admin CSS.
Tomsays
Ah-ha, thanks for the tip! I’ll have a search round.
Tomsays
Just thought I would follow this up in case any one else is interested. Kevin Learyhas a useful article that basically walks you through exactly what’s needed.
@Alex I’ve added page-specific code to the metabox script for a few client projects and do want to add it to the core. But I have another feature that’s more important and will most likely result in a complete rewrite, which is why I’ve held off.
I want to rebuild it so you can easily add new field types without editing the core (you add the code either to your theme or plugin). It would be done with a filter or hook, and then all the default field types will also be added through that means.
Once I have this built it should be pretty easy to add page-specific filtering of the metabox.
Vincent Kranendonksays
Thanks for the great code Bill, just a small question left. I managed to create one box with multiple fields in them. Is it possible to create multiple boxes (for example one on the left and one right) and how? Thanks again!
Bill Ericksonsays
Yes, you can create multiple boxes, just duplicate the code you used to create the first box and change its title and id. But each one will be a full metabox – you won’t be able to float them next to each other (except with additional CSS).
Kelly Annesays
Wonderful script.
I have had some problems with the file-upload function, specifically using a custom post type where I have disabled the default wordpress wysiwyg box. In this instance, the thickbox with the file upload dialogue opens WAY off page – lower-left corner, about 300px below the footer. It works fine in another CPT where I have enabled the default wysiwyg.
I’m wondering if this is a known bug, and if there is a way to fix it. I am going to enable the default WYSIWYG for the CPT for the time being, but it would be ideal if I could still use file upload without using the default WYSIWYG.
If it’s not on there, please create a ticket. But none of us have been that successful with fixing WYSIWYG issues.
Alan Smithsays
Bill,
Would it be possible to use a metabox to add a URL and then when the page is called via a link within the site, page launches a new window and displays the URL in the metabox? Almost like a 301 redirect, but in a new window.
Alan Smith
Media317
Bill Ericksonsays
Yes, the metabox could collect the URL, but I don’t know what technique you’d use to automatically open a page in a new window without it being blocked by most browsers.
Alan Smithsays
If I use the wp_redirect(), can I add the target=”_blank” in the command? Is there a way to add the target?
Alan Smith
Media317
Bill Ericksonsays
Not to my knowledge. wp_redirect() always opens in the same window.
Grégoire Noyellesays
Hi Bill
Thanks a lot for you’re tutorial. When you use Genesis, I wonder if there is a way to change the priority of Genesis Meta box to put your own meta meta box above them
Bill Ericksonsays
If you change the priority of your metabox to high (from low in the example below) it should show up above the Genesis metaboxes.
You could remove the function that adds the metaboxes and duplicate it in your child theme using the “low” priority, this isn’t future compatible. If Genesis comes out with new/updated/removed metaboxes, your code won’t reflect that.
Grégoire Noyellesays
OK thanks a lot Bill. I will give a try 🙂
Robsays
Hi Bill, awesome script! One problem I’m running into though. The “Add Image” or “Add Gallery” features in the WYSIWYG editor are not working correctly. I can upload and do all that jazz, but as soon as I try to “insert into post” I get a “Too much recursion” error in the console in Firebug and the image editor lightbox goes blank. It looks like there is something wacky going on in the jquery.cmbScripts.js file on line 81 “window.original_send_to_editor(html);” I’m having some trouble getting this to work. Any ideas?
Piet says
Hi Bill,
Thanks for the great code, this is really helpful!
One thing I cannot seem to get working is saving the values of checkboxes and/or radio buttons. They show in the backend, but when I tick a box or select a radio button and click Update, it comes back empty. Am I forgetting something?
Piet says
I can only get it working when using type=> multicheck
Bill Erickson says
I just tested it and it works fine for me. Here’s what I used:
array(
‘name’ => ‘Sample Checkbox’,
‘desc’ => ”,
‘id’ => $prefix.’checkbox’,
‘type’ => ‘checkbox’
)
Piet says
Thanks for your reply Bill, it was my own silly mistake, got it working too now and it does a tremendous job! Thanks!
Piet says
I have one last question. Before I was using your class, I used another, similar metabox class by deluxeblogtips (http://senl.in/q2zpAV). That was all working fine until WP 3.1.4. Upon the release of WP 3.2 the script broke the wysiwyg editor, so I needed to find an alternative. I am therefore very happy that I found your script (recommended by a friend).
One of the features the other script had though was the ability to upload multiple images. I have seen that your script also has an image upload field, but I am wondering whether that also works for multiple images and whether it will be possible to sort those images after upload.
If it is possible, then that’s great of course. If not, then it might be an idea to try to implement that functionality in your script too?
Bill Erickson says
I believe the image upload type only allows one image, which is the most common use case. If you want multiple images uploaded I recommend turning on the editor and using the Media Uploader, or just adding to the media uploader to the post type. That way you can use the gallery feature.
Piet says
OK thanks, will try out the various options then.
Piet says
Hi again Bill, I seem to be running into the same problem as with the other script: the wysiwyg-editor is not showing up, screenshot: http://senl.in/oDmcUd
The code I used is exactly according the example-functions:
array(
‘name’ => ‘Review Summary’,
‘desc’ => ”,
‘id’ => $prefix . ‘summary’,
‘type’ => ‘wysiwyg’,
‘std’ => ‘some default text’
),
Has this happened before to anyone? I am using a TwentyTen child theme and have upgraded to WP 3.2
Bill Erickson says
I’ve had some issues with the WYSIWYG as well. TinyMCE in WP just doesn’t work well when you try and put it in metaboxes. If you can describe the specific issue and how to replicate it, please post as an official issue on Github: https://github.com/jaredatch/Custom-Metaboxes-and-Fields-for-WordPress/issues/
Piet says
OK sorry to fill your comment line, it must be a bug somewhere in my theme or one of the plugins I use. Just tried it on a vanilla local install and there the editor actually does show up.
Piet says
our replies crossed… i will post on github for this issue then! thanks!
Piet says
posted via https://github.com/jaredatch/Custom-Metaboxes-and-Fields-for-WordPress/issues/15
Tom says
Hi Bill. I’m very inexperienced with WordPress and PHP but your metabox code, and this article, has made the creation/implementation of Custom Meta Boxes super easy, so thank you! I’ve implemented CMBs for a custom-post-type but have since been mulling over other ways to use them and wondered if it’s possible to show CMBs on a specific page only? I hoped that ‘pages’ => array(‘page_name’) would work but it does not.
Bill Erickson says
Unfortunately no, you can’t display it on a specific page. But you could use CSS to hide the metabox on all pages except the one you want it on. It’s beyond the scope of this post, so search around for Admin CSS.
Tom says
Ah-ha, thanks for the tip! I’ll have a search round.
Tom says
Just thought I would follow this up in case any one else is interested. Kevin Learyhas a useful article that basically walks you through exactly what’s needed.
Alex says
This is the solution to specific page meta box http://www.farinspace.com/page-specific-wordpress-meta-box/ . Would it be possible to integrate this code to CMB ? I was able to get it working on my clients’ sites…
Bill Erickson says
@Alex I’ve added page-specific code to the metabox script for a few client projects and do want to add it to the core. But I have another feature that’s more important and will most likely result in a complete rewrite, which is why I’ve held off.
I want to rebuild it so you can easily add new field types without editing the core (you add the code either to your theme or plugin). It would be done with a filter or hook, and then all the default field types will also be added through that means.
Once I have this built it should be pretty easy to add page-specific filtering of the metabox.
Vincent Kranendonk says
Thanks for the great code Bill, just a small question left. I managed to create one box with multiple fields in them. Is it possible to create multiple boxes (for example one on the left and one right) and how? Thanks again!
Bill Erickson says
Yes, you can create multiple boxes, just duplicate the code you used to create the first box and change its title and id. But each one will be a full metabox – you won’t be able to float them next to each other (except with additional CSS).
Kelly Anne says
Wonderful script.
I have had some problems with the file-upload function, specifically using a custom post type where I have disabled the default wordpress wysiwyg box. In this instance, the thickbox with the file upload dialogue opens WAY off page – lower-left corner, about 300px below the footer. It works fine in another CPT where I have enabled the default wysiwyg.
I’m wondering if this is a known bug, and if there is a way to fix it. I am going to enable the default WYSIWYG for the CPT for the time being, but it would be ideal if I could still use file upload without using the default WYSIWYG.
Thank you!
Bill Erickson says
I’m not sure if that specific issues is known, but here’s the list of current issues (most relating to the WYSIWYG): https://github.com/jaredatch/Custom-Metaboxes-and-Fields-for-WordPress/issues?sort=created&direction=desc&state=open
If it’s not on there, please create a ticket. But none of us have been that successful with fixing WYSIWYG issues.
Alan Smith says
Bill,
Would it be possible to use a metabox to add a URL and then when the page is called via a link within the site, page launches a new window and displays the URL in the metabox? Almost like a 301 redirect, but in a new window.
Alan Smith
Media317
Bill Erickson says
Yes, the metabox could collect the URL, but I don’t know what technique you’d use to automatically open a page in a new window without it being blocked by most browsers.
Alan Smith says
If I use the wp_redirect(), can I add the target=”_blank” in the command? Is there a way to add the target?
Alan Smith
Media317
Bill Erickson says
Not to my knowledge. wp_redirect() always opens in the same window.
Grégoire Noyelle says
Hi Bill
Thanks a lot for you’re tutorial. When you use Genesis, I wonder if there is a way to change the priority of Genesis Meta box to put your own meta meta box above them
Bill Erickson says
If you change the priority of your metabox to high (from low in the example below) it should show up above the Genesis metaboxes.
You could remove the function that adds the metaboxes and duplicate it in your child theme using the “low” priority, this isn’t future compatible. If Genesis comes out with new/updated/removed metaboxes, your code won’t reflect that.
Grégoire Noyelle says
OK thanks a lot Bill. I will give a try 🙂
Rob says
Hi Bill, awesome script! One problem I’m running into though. The “Add Image” or “Add Gallery” features in the WYSIWYG editor are not working correctly. I can upload and do all that jazz, but as soon as I try to “insert into post” I get a “Too much recursion” error in the console in Firebug and the image editor lightbox goes blank. It looks like there is something wacky going on in the jquery.cmbScripts.js file on line 81 “window.original_send_to_editor(html);” I’m having some trouble getting this to work. Any ideas?
Bill Erickson says
Hmm, I haven’t seen that issue before. Can you post it on the issues section of github: https://github.com/jaredatch/Custom-Metaboxes-and-Fields-for-WordPress/issues?sort=created&direction=desc&state=open
Rob says
I added it, thanks
Scott says
Excellent script and nice to you responding to issues, however preliminary or elaborate, well after its release.
Kudos.