Adding Meta Boxes to Post Types in WordPress

    Collins Agbonghama
    Collins Agbonghama
    Share

    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.

    Frequently Asked Questions about Adding Meta Boxes to Post Types in WordPress

    What is a Meta Box in WordPress?

    A Meta Box in WordPress is a draggable box displayed in the administrative interface. These boxes are used to present additional input fields that allow users to customize the functionality and layout of different types of posts. They can be added to posts, pages, and custom post types. Meta Boxes can contain various types of fields, including text, checkboxes, select options, and more.

    How do I add a Meta Box to a custom post type in WordPress?

    To add a Meta Box to a custom post type in WordPress, you need to use the ‘add_meta_box()’ function. This function allows you to specify the Meta Box ID, title, callback function, post type, context, and priority. The callback function is used to output the content of the Meta Box.

    Can I add multiple Meta Boxes to a single post type?

    Yes, you can add multiple Meta Boxes to a single post type. Each Meta Box should have a unique ID to avoid conflicts. You can use the ‘add_meta_box()’ function multiple times with different parameters to add multiple Meta Boxes.

    How do I save the data entered into the Meta Box fields?

    To save the data entered into the Meta Box fields, you need to hook a function to the ‘save_post’ action. This function should check the nonce, verify the current user’s permissions, and then use the ‘update_post_meta()’ or ‘add_post_meta()’ function to save the Meta Box data to the database.

    How do I display the Meta Box data on the front end?

    To display the Meta Box data on the front end, you can use the ‘get_post_meta()’ function within the Loop. This function retrieves the Meta Box data from the database and returns it as a string, which you can then echo out in your template files.

    Can I add Meta Boxes to pages as well as posts?

    Yes, you can add Meta Boxes to pages as well as posts. When using the ‘add_meta_box()’ function, you can specify the post type as ‘page’ to add a Meta Box to pages.

    How do I remove a Meta Box from a post type?

    To remove a Meta Box from a post type, you can use the ‘remove_meta_box()’ function. This function requires the Meta Box ID and the post type as parameters.

    Can I customize the position of the Meta Box in the post editing screen?

    Yes, you can customize the position of the Meta Box in the post editing screen. The ‘context’ parameter of the ‘add_meta_box()’ function determines the position of the Meta Box. Possible values are ‘normal’, ‘side’, and ‘advanced’.

    Can I add Meta Boxes to custom post types created by plugins?

    Yes, you can add Meta Boxes to custom post types created by plugins. You just need to know the slug of the custom post type, which you can then use as the ‘post_type’ parameter in the ‘add_meta_box()’ function.

    How do I style the Meta Box and its fields?

    You can style the Meta Box and its fields using CSS. The Meta Box will have a class of ‘postbox’, and you can add your own classes to the fields within the Meta Box. You can then target these classes in your CSS to apply styles.