Adding Custom Meta Boxes to the WordPress Admin Interface

    Narayan Prusty

    WordPress lets us add custom meta boxes to posts, pages and custom post types via the admin interface. WordPress also provides APIs to customize the default meta boxes.

    In this tutorial, I will show you how to add new custom meta boxes, save custom meta data, validate meta data, retrieve custom meta data on the front end and also remove the default meta boxes.

    What is a Custom Meta Box?

    Custom meta boxes allow users to add additional information to posts, pages and custom post types, apart from the default set of information that WordPress takes using default meta boxes. Plugins and Themes can use custom meta boxes to take additional structured user input.

    Custom meta boxes can also be added to the dashboard and attached to the admin interface. WordPress dashboard widgets are actually meta boxes.

    In addition to the meta boxes, you can also edit the contents and appearance of the Admin Bar that is seen by those who are logged in to the admin interface.

    Editor, Custom Fields, Featured Image, Categories, and Tags on a post, page or custom post page admin interface are default meta boxes. They are created by the WordPress core.

    Custom Meta Box vs Custom Fields

    Custom fields allow users to add key/value pairs of data to a post, page or custom post type. But meta boxes can have many varieties of input fields such as color picker, file upload, drop downs, and so on.

    What is Meta Data?

    Meta Data are values of the form fields embedded in Custom Meta Boxes. WordPress stores them as key/value pairs, such as meta key and meta value. Meta key is the name of the form field and meta value is the form field value.

    Creating a Meta Box

    add_meta_box function is used to create custom meta boxes. This function is only responsible for registering and displaying custom meta boxes.

    Here is the code to add a custom meta box to WordPress posts:

    function custom_meta_box_markup()
    function add_custom_meta_box()
        add_meta_box("demo-meta-box", "Custom Meta Box", "custom_meta_box_markup", "post", "side", "high", null);
    add_action("add_meta_boxes", "add_custom_meta_box");

    add_meta_box should be called inside add_meta_boxes hook.

    add_meta_box takes 7 arguments. Here are the list of arguments:

    1. $id: Every meta box is identified by WordPress uniquely using its id. Provide an id and remember to prefix it to prevent overriding.
    2. $title: Title of the meta box on the admin interface.
    3. $callback: add_meta_box calls the callback to display the contents of the custom meta box.
    4. $screen: Its used to instruct WordPress in which screen to display the meta box. Possible values are "post", "page", "dashboard", "link", "attachment" or "custom_post_type" id. In the above example we are adding the custom meta box to WordPress posts screen.
    5. $context: Its used to provide the position of the custom meta on the display screen. Possible values are "normal", "advanced" and "side". In the above example we positioned the meta box on side.
    6. $priority: Its used to provide the position of the box in the provided context. Possible values are "high", "core", "default", and "low". In the above example we positioned the meta box
    7. $callback_args: Its used to provide arguments to the callback function.

    Here is how the meta box looks:

    Custom WordPress Meta Box

    Here, the custom meta box content is empty because we haven’t yet populated the content.

    Displaying Fields in a Custom Meta Box

    For demonstration purpose I will add a text input, drop down and a checkbox form field to the custom meta box.

    Here is the code:

    function custom_meta_box_markup($object)
        wp_nonce_field(basename(__FILE__), "meta-box-nonce");
                <label for="meta-box-text">Text</label>
                <input name="meta-box-text" type="text" value="<?php echo get_post_meta($object->ID, "meta-box-text", true); ?>">
                <label for="meta-box-dropdown">Dropdown</label>
                <select name="meta-box-dropdown">
                        $option_values = array(1, 2, 3);
                        foreach($option_values as $key => $value) 
                            if($value == get_post_meta($object->ID, "meta-box-dropdown", true))
                                    <option selected><?php echo $value; ?></option>
                                    <option><?php echo $value; ?></option>
                <label for="meta-box-checkbox">Check Box</label>
                    $checkbox_value = get_post_meta($object->ID, "meta-box-checkbox", true);
                    if($checkbox_value == "")
                            <input name="meta-box-checkbox" type="checkbox" value="true">
                    else if($checkbox_value == "true")
                            <input name="meta-box-checkbox" type="checkbox" value="true" checked>

    Here is how the code works:

    • First we set the nonce field so that we can prevent CSRF attack when the form is submitted.
    • get_post_meta is used to retrieve meta data from the database. If no such meta data is present, it returns an empty string. If your user has already submitted the form earlier, then we use the meta data stored in database. Otherwise, we switch to the default value.

    Here is how the meta box looks now:

    Custom WordPress Meta Box Expanded

    Storing Meta Data

    Now we need to store the custom meta data when a user submits the form; need to save the post.

    Here is the code to save meta data when a user clicks on the ‘save draft’ or ‘publish’ button:

    function save_custom_meta_box($post_id, $post, $update)
        if (!isset($_POST["meta-box-nonce"]) || !wp_verify_nonce($_POST["meta-box-nonce"], basename(__FILE__)))
            return $post_id;
        if(!current_user_can("edit_post", $post_id))
            return $post_id;
        if(defined("DOING_AUTOSAVE") && DOING_AUTOSAVE)
            return $post_id;
        $slug = "post";
        if($slug != $post->post_type)
            return $post_id;
        $meta_box_text_value = "";
        $meta_box_dropdown_value = "";
        $meta_box_checkbox_value = "";
            $meta_box_text_value = $_POST["meta-box-text"];
        update_post_meta($post_id, "meta-box-text", $meta_box_text_value);
            $meta_box_dropdown_value = $_POST["meta-box-dropdown"];
        update_post_meta($post_id, "meta-box-dropdown", $meta_box_dropdown_value);
            $meta_box_checkbox_value = $_POST["meta-box-checkbox"];
        update_post_meta($post_id, "meta-box-checkbox", $meta_box_checkbox_value);
    add_action("save_post", "save_custom_meta_box", 10, 3);

    Here is how the code works:
    save_post hook’s callback is triggered when a post, page and custom post type is saved. We attached a callback to save meta data.
    – We verify the nonce. If the nonce is not present or invalid then we don’t save the return the callback.
    – We check whether the current logged in admin user has permission to save meta data for that post type. If the user doesn’t have permission, then we return the callback.
    – We check if the post is being auto saved. If the save is auto saved, then we return the callback.
    – Final check is whether the post type is the same as the meta box post type. If not, then we return the callback.
    – We retrieve the values of the form fields using PHP $_POST variable and save them in database using update_post_meta. update_post_meta create a new meta data key/value in the database if the key is not present, otherwise it updates the key value.

    Removing a Meta Box

    We can remove custom meta boxes and the default WordPress core meta boxes using remove_meta_box. To remove a meta box you need its ID, screen and content.

    Here are the IDs of some important default meta boxes:

    • ‘authordiv’ – Author metabox
    • ‘categorydiv’ – Categories metabox
    • ‘commentstatusdiv’ – Comments status metabox (discussion)
    • ‘commentsdiv’ – Comments metabox
    • ‘formatdiv’ – Formats metabox
    • ‘pageparentdiv’ – Attributes metabox
    • ‘postcustom’ – Custom fields metabox
    • ‘postexcerpt’ – Excerpt metabox
    • ‘postimagediv’ – Featured image metabox
    • ‘revisionsdiv’ – Revisions metabox
    • ‘slugdiv’ – Slug metabox
    • ‘submitdiv’ – Date, status, and update/save metabox
    • ‘tagsdiv-post_tag’ – Tags metabox
    • ‘{$tax-name}div’ – Hierarchical custom taxonomies metabox
    • ‘trackbacksdiv’ – Trackbacks metabox

    Here is the code to remove custom fields meta box:

    function remove_custom_field_meta_box()
        remove_meta_box("postcustom", "post", "normal");
    add_action("do_meta_boxes", "remove_custom_field_meta_box");

    Here we triggered remove_meta_box in do_meta_boxes hook. But you cannot always call remove_meta_box inside it. For example, to remove dashboard widgets you need to call it inside wp_dashboard_setup hook.

    Final Thoughts

    WordPress Meta Box APIs are very useful if you are building a plugin or theme. SEO, Post Series, and Related Content plugins make use of custom meta boxes to take additional user information for posts.