Adding Meta Boxes to Post Types in WordPress
If you’ve ever used WordPress to build a website for yourself or a client, or you work for a company whose website is powered by WordPress, you would have seen and used meta boxes.
In the past, we’ve covered adding custom meta boxes to WordPress. In this article, we’ll go two steps further explaining their relationship and integration with post types, including how to use the data saved in a meta box in the WordPress front-end.
Adding Meta Boxes to Post Types Screen
Most (if not all) of the PHP functions, their parameters and Action
hooks that are handy in creating meta boxes have been covered by Narayan Prusty.
To add a meta box to the any post type editing screen, the add_meta_box()
is used and subsequently hooked to the add_meta_boxes
action.
The code below adds a metabox to the post
edit screen. Take note of global_notice_meta_box_callback
, the function that is called to display the form field(s) in the meta box. We’ll come to that later.
function global_notice_meta_box() {
add_meta_box(
'global-notice',
__( 'Global Notice', 'sitepoint' ),
'global_notice_meta_box_callback',
'post'
);
}
add_action( 'add_meta_boxes', 'global_notice_meta_box' );
To add a meta box to a number of post types screens – post
, page
and a book
custom post type; create an array of the post types, iterate over the array and use add_meta_box()
to add the meta box to them.
function global_notice_meta_box() {
$screens = array( 'post', 'page', 'book' );
foreach ( $screens as $screen ) {
add_meta_box(
'global-notice',
__( 'Global Notice', 'sitepoint' ),
'global_notice_meta_box_callback',
$screen
);
}
}
add_action( 'add_meta_boxes', 'global_notice_meta_box' );
To add a meta box to all existing post types and those to be created in future, use get_post_types()
to get an array of the post types and then replace the value of $screen
above with it.
function global_notice_meta_box() {
$screens = get_post_types();
foreach ( $screens as $screen ) {
add_meta_box(
'global-notice',
__( 'Global Notice', 'sitepoint' ),
'global_notice_meta_box_callback',
$screen
);
}
}
add_action( 'add_meta_boxes', 'global_notice_meta_box' );
Adding a meta box to all existing and new post types can also be done by leaving out the third ($screen
) argument like so:
function global_notice_meta_box() {
add_meta_box(
'global-notice',
__( 'Global Notice', 'sitepoint' ),
'global_notice_meta_box_callback'
);
}
add_action( 'add_meta_boxes', 'global_notice_meta_box' );
A meta box can also be restricted to a post type (book
in this example) by appending the post type name to add_meta_boxes
action hook as follows:
function global_notice_meta_box() {
add_meta_box(
'global-notice',
__( 'Global Notice', 'sitepoint' ),
'global_notice_meta_box_callback'
);
}
add_action( 'add_meta_boxes_book', 'global_notice_meta_box' );
Among the array argument used by register_post_type()
for customizing a custom post type is the register_meta_box_cb
in which its value is a callback function that is called when setting up the meta boxes.
Say we created a book
custom post type with the following code:
function book_cpt() {
$args = array(
'label' => 'Books',
'public' => true,
'register_meta_box_cb' => 'global_notice_meta_box'
);
register_post_type( 'book', $args );
}
add_action( 'init', 'book_cpt' );
Adding the add_meta_box()
function definition for creating a meta box inside a global_notice_meta_box
PHP function (value of register_meta_box_cb
above) will add the meta box to the book
custom post type edit screen.
And again, here is our example global_notice_meta_box
function.
function global_notice_meta_box() {
add_meta_box(
'global-notice',
__( 'Global Notice', 'sitepoint' ),
'global_notice_meta_box_callback'
);
}
So far, we’ve learned the various ways of registering or adding meta boxes to WordPress. We are yet to create the global_notice_meta_box_callback
function that will contain the form field of our meta box.
Below is the code for the global_notice_meta_box_callback
function that will include a text area field in the meta box.
function global_notice_meta_box_callback( $post ) {
// Add a nonce field so we can check for it later.
wp_nonce_field( 'global_notice_nonce', 'global_notice_nonce' );
$value = get_post_meta( $post->ID, '_global_notice', true );
echo '<textarea style="width:100%" id="global_notice" name="global_notice">' . esc_attr( $value ) . '</textarea>';
}
The save_post
action hook handles saving the data entered into the text area when the post is saved as draft or published.
/**
* When the post is saved, saves our custom data.
*
* @param int $post_id
*/
function save_global_notice_meta_box_data( $post_id ) {
// Check if our nonce is set.
if ( ! isset( $_POST['global_notice_nonce'] ) ) {
return;
}
// Verify that the nonce is valid.
if ( ! wp_verify_nonce( $_POST['global_notice_nonce'], 'global_notice_nonce' ) ) {
return;
}
// If this is an autosave, our form has not been submitted, so we don't want to do anything.
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
// Check the user's permissions.
if ( isset( $_POST['post_type'] ) && 'page' == $_POST['post_type'] ) {
if ( ! current_user_can( 'edit_page', $post_id ) ) {
return;
}
}
else {
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
}
/* OK, it's safe for us to save the data now. */
// Make sure that it is set.
if ( ! isset( $_POST['global_notice'] ) ) {
return;
}
// Sanitize user input.
$my_data = sanitize_text_field( $_POST['global_notice'] );
// Update the meta field in the database.
update_post_meta( $post_id, '_global_notice', $my_data );
}
add_action( 'save_post', 'save_global_notice_meta_box_data' );
To put the data that would be entered into the meta box text area to use, we’ll display the data before the post content that it’s saved against is displayed.
function global_notice_before_post( $content ) {
global $post;
// retrieve the global notice for the current post
$global_notice = esc_attr( get_post_meta( $post->ID, '_global_notice', true ) );
$notice = "<div class='sp_global_notice'>$global_notice</div>";
return $notice . $content;
}
add_filter( 'the_content', 'global_notice_before_post' );
Code Explanation
First, we created a global_notice_before_post
function hooked into the_content
filter with a $content
parameter which contains the post content.
Inside the function, we include the global $post
variable that contains the WP_Post
object of the current post that is being viewed.
The global notice saved against a given post is retrieved by get_post_meta
and saved to $global_notice
variable.
The notice is then wrapped in a div
and saved to the $notice
variable.
And finally, $notice
which holds the global notice is concatenated to $content
which is the actual post content.
Below is a screenshot of a post with the global notice before the post content.
Summary
In this tutorial, we learned a number of ways to register meta boxes to WordPress administrative screens and how to restrict them to post types.
We also reviewed how to add form fields to a meta box and how to save data entered into it when a post is saved or published.
Finally, we covered how to put into practical use the data entered into a meta box.
In a future article we’ll cover how to add a contextual help tab to the post types administrative screens.
If you have any questions or contributions, we’d love to hear them in the comments.