Example How To Add Meta Boxes To Edit Area

Additional fields, meta boxes, in the edit area of WordPress often are useful and easier for customers instead of using Custom Fields. A small Plugin will show you three options. Use it, make WordPress even better for your clients. Learn how easy it is to adjust the edit area in WordPress.

This Plugin adds 3 new field in a meta box:

  • Subtitle - a line without formatting
  • Additional information - a complete editor, you can even add attachments, it's almost like the standard content editor.
  • List data - It's possible to put in each line content, which will displayed as an unordered list. ul

WordPress edit area with own meta boxes

Each of these fields can be used in a theme template, since it has a template tag, which controlls the output. Only if you have data in a field it will be displayed. The following example will output the 3 fields.

<div <?php post_class() ?> id="post-<?php the_ID(); ?>">

    <h2><?php the_title(); ?></h2>

    <h3><?php if ( function_exists('the_DifferentTypeFacts') ) the_DifferentTypeFacts($post->ID, 'heading'); ?></h3>

    <div class="entry">

        <?php the_content('<p class="serif">Read the rest of this entry »</p>'); ?>

        <?php if ( function_exists('the_DifferentTypeFacts') ) the_DifferentTypeFacts($post->ID, 'additional-info'); ?>

        <?php if ( function_exists('the_DifferentTypeFacts') ) the_DifferentTypeFacts($post->ID, 'listdata'); ?>

Output of the contnt from the own meta boxes

This Plugin should be just an example, if you like it, you can adjust it to your liking. So you can provide a nice backend for your authors, without custom fields.

The Plugin takes care, that the meta boxes "Custom Fields" and "Trackbacks" aren't there anymore (remove_meta_box()); just another example for the usage of this Plugin. Here is the code and below you can find the link to download the Plugin, including readme, language file for German users and the necessary scripts.

<?php
/**
 * @package Different Type
 * @author Frank Bültge
 * @version 0.1
 */

/*
    Plugin Name: Different Type
    Plugin URI: http://bueltge.de/
    Description: Add different types to posts
    Author: Frank Bültge
    Version: 0.1
    License: GPL
    Author URI: http://bueltge.de/
    Last change: 21.03.2010 01:12:21
*/

/**
 * Example for use outside the loop:
 * <?php the_DifferentTypeFacts($post->ID); ?>
 * @param $id Integer - Post-ID
 * @param $type String - heading, additional-info, listdata (default is ''-empty)
 *
 * Example: <?php the_DifferentTypeFacts($post->ID, 'heading'); ?>
 */

//avoid direct calls to this file, because now WP core and framework has been used
if ( !function_exists('add_action') ) {
    header('Status: 403 Forbidden');
    header('HTTP/1.1 403 Forbidden');
    exit();
}

if ( function_exists('add_action') ) {
    //WordPress definitions
    if ( !defined('WP_CONTENT_URL') )
        define('WP_CONTENT_URL', get_option('siteurl') . '/wp-content');
    if ( !defined('WP_CONTENT_DIR') )
        define('WP_CONTENT_DIR', ABSPATH . 'wp-content');
    if ( !defined('WP_PLUGIN_URL') )
        define('WP_PLUGIN_URL', WP_CONTENT_URL.'/plugins');
    if ( !defined('WP_PLUGIN_DIR') )
        define('WP_PLUGIN_DIR', WP_CONTENT_DIR.'/plugins');
    if ( !defined('PLUGINDIR') )
        define( 'PLUGINDIR', 'wp-content/plugins' ); // Relative to ABSPATH.  For back compat.
    if ( !defined('WP_LANG_DIR') )
        define('WP_LANG_DIR', WP_CONTENT_DIR . '/languages');

    // plugin definitions
    define( 'FB_DT_BASENAME', plugin_basename(__FILE__) );
    define( 'FB_DT_BASEDIR', dirname( plugin_basename(__FILE__) ) );
    define( 'FB_DT_TEXTDOMAIN', 'different-types' );
}

if ( !class_exists( 'DifferentType' ) ) {
    class DifferentType {

        // constructor
        function DifferentType() {

            if (is_admin() ) {
                add_action( 'admin_init', array(&$this, 'on_admin_init') );
                add_action( 'wp_insert_post', array(&$this, 'on_wp_insert_post'), 10, 2 );
                add_action( 'init', array(&$this, 'textdomain') );
                register_uninstall_hook( __FILE__, array(&$this, 'uninstall') );
                add_action( "admin_print_scripts-post.php", array($this, 'enqueue_script') );
                add_action( "admin_print_scripts-post-new.php", array($this, 'enqueue_script') );
                add_action( "admin_print_scripts-page.php", array($this, 'enqueue_script') );
                add_action( "admin_print_scripts-page-new.php", array($this, 'enqueue_script') );
            }
        }

        // active for multilanguage
        function textdomain() {

            if ( function_exists('load_plugin_textdomain') )
                load_plugin_textdomain( FB_DT_TEXTDOMAIN, false, dirname( FB_DT_BASENAME ) . '/languages' );
        }

        // unsintall all postmetadata
        function uninstall() {

            $all_posts = get_posts('numberposts=0&post_type=post&post_status=');

            foreach( $all_posts as $postinfo) {

                delete_post_meta($postinfo->ID, '_different-types');

            }
        }

        // add script
        function enqueue_script() {
            wp_enqueue_script( 'tinymce4dt', WP_PLUGIN_URL . '/' . FB_DT_BASEDIR . '/js/script.js', array('jquery') );
        }

        // admin init
        function on_admin_init() {

            if ( !current_user_can( 'publish_posts' ) )
                return;

            add_meta_box( 'different_types',
                                    __( 'Different Types', FB_DT_TEXTDOMAIN ),
                                    array( &$this, 'meta_box' ),
                                    'post', 'normal', 'high'
                                    );

            // remove meta box for trackbacks
            remove_meta_box('trackbacksdiv', 'post', 'normal');
            // remove meta box for custom fields
            remove_meta_box('postcustom', 'post', 'normal');
        }

        // check for preview
        function is_page_preview() {
            $id = (int)$_GET['preview_id'];
            if ($id == 0) $id = (int)$_GET['post_id'];
            $preview = $_GET['preview'];
            if ($id > 0 && $preview == 'true') {
                global $wpdb;
                $type = $wpdb->get_results("SELECT post_type FROM $wpdb->posts WHERE ID=$id");
                if ( count($type) && ($type[0]->post_type == 'page') && current_user_can('edit_page') )
                    return true;
            }
            return false;
        }

        // after save post, save meta data for plugin
        function on_wp_insert_post($id) {
            global $id;

            if ( !isset($id) )
                $id = (int)$_REQUEST['post_ID'];
            if ( $this->is_page_preview() && !isset($id) )
                $id = (int)$_GET['preview_id'];

            if ( !current_user_can('edit_post') )
                return;

            if ( isset($_POST['dt-heading']) && $_POST['dt-heading'] != '' )
                $this->data['heading'] = esc_attr( $_POST['dt-heading'] );
            if ( isset($_POST['dt-additional-info']) && $_POST['dt-additional-info'] != '' )
                $this->data['additional-info'] = $_POST['dt-additional-info'];
            if ( isset($_POST['dt-listdata']) && $_POST['dt-listdata'] != '' )
                $this->data['listdata'] = esc_attr( $_POST['dt-listdata'] );

            if ( isset($this->data) && $this->data != '' )
                update_post_meta($id, '_different-types', $this->data);
        }

        // load post_meta_data
        function load_post_meta($id) {

            return get_post_meta($id, '_different-types', true);
        }

        // meta box on post/page
        function meta_box($data) {

            $value = $this->load_post_meta($data->ID);
            ?>
            <table id="dt-page-definition" width="100%" cellspacing="5px">
                <tr valign="top">
                    <td style="width:20%;"><label for="dt-heading"><?php _e( 'Subtitle:', FB_DT_TEXTDOMAIN ); ?></label></td>
                    <td><input type="text" id="dt-heading" name="dt-heading" class="heading form-input-tip" size="16" autocomplete="off" value="<?php echo $value['heading']; ?>" tabindex="6" style="width:99.5%"/></td>
                </tr>
                <tr valign="top">
                    <td><label for="dt-additional-info"><?php _e( 'Additional information:', FB_DT_TEXTDOMAIN ); ?></label></td>
                    <td><textarea cols="16" rows="5" id="dt-additional-info" name="dt-additional-info" class="additional-info form-input-tip code" size="20" autocomplete="off" tabindex="6" style="width:90%"/><?php echo wpautop( $value['additional-info'] ); ?></textarea>
                        <table id="post-status-info" cellspacing="0" style="line-height: 24px;">
                            <tbody>
                                <tr>
                                    <td> </td>
                                    <td> </td>
                                </tr>
                            </tbody>
                        </table>
                    </td>
                </tr>
                <tr valign="top">
                    <td><label for="dt-listdata"><?php _e( 'Listdata:', FB_DT_TEXTDOMAIN ); ?></label></td>
                    <td><textarea cols="16" rows="10" id="dt-listdata" name="dt-listdata" class="listdata form-input-tip" size="20" autocomplete="off" tabindex="6" style="width:99.5%"/><?php echo $value['listdata']; ?></textarea><br /><small><?php _e( 'One list per line', FB_DT_TEXTDOMAIN ) ?></small></td>
                </tr>
            </table>
            <?php
        }

        // return facts incl. markup
        function get_DifferentTypeFacts($id, $type, $value) {

            if (!$value)
                return false;
            if ( $type == '' )
                return false;

            if ( 'heading' == $type && '' != $value['heading'] )
                return $value['heading'];
            if ( 'additional-info' == $type && '' != $value['additional-info'] )
                return wpautop( wptexturize($value['additional-info']) );
            if ( 'listdata' == $type && '' != $value['listdata'] ) {
                $return = '';
                $listdatas = preg_split("/\r\n/", $value['listdata'] );

                foreach ( (array) $listdatas as $key => $listdata ) {

                    $return .= '<li>' . trim($listdata) . '</li>';

                }
                return '<ul>' . $return . '</ul>'. "\n";
            }
        }

        // echo facts, if exists
        function DifferentTypeFacts($id, $type, $string) {

            if ( $id ) {
                $value = $this->load_post_meta($id);

                echo $this->get_DifferentTypeFacts($id, $type, $value);
            }
        }

    } // End class

    // instance class
    $DifferentType = new DifferentType();

    // use in template
    function the_DifferentTypeFacts($id, $type = '', $string = '') {
        global $DifferentType;

        $DifferentType->DifferentTypeFacts($id, $type, $string);
    }

} // End if class exists statement
?>

You can find the complete Plugin at github.

Comments are closed.

19 comments

  1. Adam Wood

    The "More Fields" plugin provides this capability in a pretty robust format- allowing you to create meta boxes, and then define special post and page types utilizing different meta fields. Sort of an entry-level "Pods" meets "Custom Post Type."
    I used it on an architect's portfolio:
    http://hndarchitects.com
    So that the client could easily populate new project pages without knowing any code (she just fills in boxes: project description, image urls, etc) and the theme displays everything correctly, resizes pics, etc.
    Great way to keep your client from breaking a complex layout (although, it does look like butt when she doesn't put something in to every box).

    Also using it on:
    http://musicforsunday.com
    for posts in the "New Music" Category and in the "Sundays and Feasts Music Suggestions," since both post types need to display a whole bunch of formatted info.

    The plugin is great for any blog where you're going to be creating a lot of posts with similarly formatted information: book reviews, product reviews, project portfolios, people profiles.

    There is a small bug in the code (you'll find it when you start using it), but the Google will show you a quick fix and then smooth sailing.

  2. Alex

    Ooops!
    different-type plugin in conflict with SyntaxHighlighter Evolved plugin
    For example: i am writing
    [sourcecode]

    [/sourcecode]
    but i see
    [sourcecode]<?php if ( function_exists( .......

    it is pity, but i deactivated different-type plugin

  3. Alvin

    This code is great, I have been using a plugin Magic Fields for clients, but the danger is that a tinkering client can 'accidently' erase entire fields - which then have to be recreated. So i have effectively been hiding it from clients.

    I may use this as a base for simpler sites from here on in. I will give it a go on a Not For Profit site i am starting today and see how that pans out.

    Thanks.

  4. Lane

    Nice post. Very clean. How would you add a thumbnail field with this?

  5. WP-sites

    Just trialing WP 3.0 beta and experimenting with adding meta boxes to the edit area.

    The adittional information field in your plugin isn't working on my install. Adding 'theEditor' to the list of classes should seems to sort it.

    class="additional-info form-input-tip code theEditor"

  6. Pete

    How would you go about applying this to a specific page only?

  7. Paul

    @Frank

    First of all, thanks for writing this up.
    I've been wanting this for ages, so this is like a dream comes true.

    I was hoping that you put this up in official WordPress Plugin repository.

    Any chance ?

  8. David

    Thanks you so much for this post--I'm new to WP development and have been looking for a way to add my own custom fields that gives me finer control of the admin interface and hides the configuration from clients (so they don't break their own site!).

    This post gave me a huge boost up the learning curve.

    FOLLOW UP QUESTION
    If I wanted to show different meta boxes for different page templates, how would I approach that? For example my main page template has 1 subtitle, but my "overview page template" has 3 areas each with their own subtitle. When a user selects "overview page template" in the admin, I would like the edit area to display additional meta boxes.

    Thanks for pointing me in the right direction!

  9. Christopher

    I second Pete's and David's question. That is perfect, but how do we do this for different templates. That is I've created two custom post types. How do I assign meta boxes to one and different ones to another. Or is their a good reference somewhere on how to go about this? Thank you!

  10. Christopher

    Also I see an option for a text field. text box, and list box, what code who wont use to capture a radio box?

  11. eavasi

    Realy this function is provided with WordPress plugin All in SEO Pack?

  12. David

    FYI, I figured out how to add meta boxes for specific page templates.

    Simply check the $post->page_template to see if it matches the filename of the template you're looking for as follows:

    if( function_exists( 'add_meta_box' ) && IsSet($post,$post->page_template)) {
    if ($post->page_template == 'page.php')) {
    add_meta_box( ....);
    }
    }

    NEXT QUESTION
    How to add a file upload field that handles images in a WordPressy way (ideally can select from media already uploaded, does resizing, etc).

  13. Ken Newman

    For those of you asking about different page types, the easiest way is to change instances of 'post' to 'page' or if you are using custom post types, 'movie'. The functionality you are looking for is in the core function 'add_meta_box' and http://codex.wordpress.org/Function_Reference/add_meta_box is the reference you are looking for.

    To Frank, Thanks for this example. Much better then what I found else where. Hopefully the "3.org" update includes info like this in the codex!

  14. Ken Newman

    The link to the repository should be http://github.com/bueltge/different-type

  15. Stace

    Great tutorial! Thanks very much.

    Wondering how I might add additional fields - not a new field but, say a second or third list data field. Sort of like what happens when you click 'Add Custom Field' in the Custom Fields box.

    I'm totally lost on this so any thoughts or suggestions appreciated!

  16. AJ

    Really great tutorial. I have always wondered how to add them but could never find the right name to search - "meta boxes". This post is very handy, will definitely try adding one or two to my next free theme release.

  17. Hdmi Over Cat5

    I am trying to implement a custom post type and custom meta box for one of my client.

    As I recognized, there is a little bug, when you initilaze the first register_post_type by using admin_init , if your rewritng setting is true you recieve 404 error.

    But if you go to the Settings->permalinks area then doing nothing just close. Your slug will work as normal. I couldn't find the reason, why this occurs.

    Also, adding a meta box to custome post type is a bit unclear at the wordpress codex page.

  18. Erik

    Hey, I have an easy example of how to add different kinds of meta boxes to posts, pages, and custom posts here. I'd love to know what you think.

    Thanks.

One pingback

  1. WordPress Picks for the Week [04/07] | Techtites