Adding Meta Boxes to Post Types in WordPress

By Collins Agbonghama

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>';
}

text area meta box

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.

global notice demo

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.

Recommended
Sponsors
Get the latest in WordPress, once a week, for free.