Adding multiple meta-boxes to a custom post type in wordpress

BIOS picture BIOS · Dec 16, 2012 · Viewed 24.2k times · Source

I have the following code which adds a custom post type to the admin dash and a custom meta box to the post edit window:

function teasers_custom_init() {
  $labels = array(
    'name' => 'Teasers',
    'singular_name' => 'Teaser',
    'add_new' => 'Add New',
    'add_new_item' => 'Add New Teasers',
    'edit_item' => 'Edit Teaser',
    'new_item' => 'New Teaser',
    'all_items' => 'All Teasers',
    'view_item' => 'View Teaser',
    'search_items' => 'Search Teasers',
    'not_found' =>  'No teasers found',
    'not_found_in_trash' => 'No teasers found in Trash', 
    'parent_item_colon' => 'Parent Page',
    'menu_name' => 'Teasers'
  );

  $args = array(
    'labels' => $labels,
    'description' => 'set slider panels with loop times',
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true, 
    'show_in_menu' => true, 
    'query_var' => true,
    'rewrite' => array( 'slug' => 'Teasers' ),
    'capability_type' => 'page',
    'has_archive' => true, 
    'hierarchical' => true,
    'menu_position' => 60,
    'supports' => array( 'title', 'thumbnail', 'page-attributes'), 

  ); 

  register_post_type( 'teasers', $args );
}
add_action( 'init', 'teasers_custom_init' );


//adding the meta box when the admin panel initialises
add_action("admin_init", "admin_init");
// this adds the save teaser function on save post
add_action('save_post', 'save_teaser');

function admin_init(){
    add_meta_box('teaser_loop', 'Loop Time', 'loop_meta', 'teasers', 'normal', 'default');
}
// callback function of add meta box that displays the meta box in the post edit screen
function loop_meta($post, $args){

    $teaser_loop = get_post_meta($post->ID, 'teaser_loop', true);

?>
    <label>Teaser Loop: </label><input type="text" name="teaser_loop" value="<?php echo $teaser_loop; ?>" /><br/>

<?php

}

// saving the teaser
function save_teaser(){
    global $post;
    update_post_meta($post->ID, 'teaser_loop', $_POST['teaser_loop']);  
}

My question is if I want to add an additional meta box, what is the best approach?

I tried adding another add_meta_box call in admin_init function and also created an additional callback function for this meta box html but nothing was generated on the front end. Any pointers would be great.

EDIT: So this is how I did it for more than one meta box (this works):

//adding the meta box when the admin panel initialises
    add_action("admin_init", "admin_init");
    // this adds the save teaser function on save post
    add_action('save_post', 'save_teaser');
    function admin_init(){
        add_meta_box('teaser_loop', 'Loop Time', 'loop_meta_1', 'teasers', 'normal', 'default');
        add_meta_box('teaser_link', 'Teaser Link', 'loop_meta_2', 'teasers', 'normal', 'default');
    }
    // back function of add meta box that displays the meta box in the post edit screen
    function loop_meta_1($post, $args){


        $teaser_loop = get_post_meta($post->ID, 'teaser_loop', true);

?>
    <label>Teaser Loop: </label><input type="text" name="teaser_loop" value="<?php echo $teaser_loop; ?>" /><br/>

<?php

}

    function loop_meta_2($post, $args){

        $teaser_link = get_post_meta($post->ID, 'teaser_link', true);

?>
    <label>Teaser Link: </label><input type="text" name="teaser_link" value="<?php echo $teaser_link; ?>" /><br/>

<?php

}

// saving the teaser
function save_teaser(){
    global $post;
    update_post_meta($post->ID, 'teaser_loop', $_POST['teaser_loop']);
    update_post_meta($post->ID, 'teaser_link', $_POST['teaser_link']);
}

Answer

brasofilo picture brasofilo · Oct 7, 2013

It can be completely encapsulated in a class. Here, I'm not dealing with adding the Custom Post Type, and there are only two simple output fields, text and checkbox. A full fledged working code should take care of each of the desired input types.

<?php
/**
 * Plugin Name: Sample Dynamic Meta Boxes
 * Plugin URI:  http://stackoverflow.com/q/13903529/1287812
 * Author:      brasofilo
 */
class B5F_Dynamic_Meta_Boxes 
{
    private $boxes;

    # Safe to start up
    public function __construct( $args )
    {
        $this->boxes = $args;
        add_action( 'plugins_loaded', array( $this, 'start_up' ) );
    }

    public function start_up()
    {
        add_action( 'add_meta_boxes', array( $this, 'add_mb' ) );
    }

    public function add_mb()
    {
        foreach( $this->boxes as $box )
            add_meta_box( 
                $box['id'], 
                $box['title'], 
                array( $this, 'mb_callback' ), 
                $box['post_type'], 
                isset( $box['context'] ) ? $box['context'] : 'normal', 
                isset( $box['priority'] ) ? $box['priority'] : 'default', 
                $box['args']
            );
    }

    # Callback function, uses helper function to print each meta box
    public function mb_callback( $post, $box )
    {
        switch( $box['args']['field'] )
        {
            case 'textfield':
                $this->textfield( $box, $post->ID );
            break;
            case 'checkbox':
                $this->checkbox( $box, $post->ID );
            break;
        }
    }

    private function textfield( $box, $post_id )
    {
        $post_meta = get_post_meta( $post_id, $box['id'], true );
        printf(
            '<label>%s: <input type="text" name="%s" value="%s" /></label> <small>%s</small><br/>',
            $box['title'],
            $box['id'],
            $post_meta,
            $box['args']['desc']
        );
    }

    private function checkbox( $box, $post_id )
    {
        $post_meta = get_post_meta( $post_id, $box['id'], true );
        printf(
            '<label>%s: </label><input type="checkbox" name="%s" %s /> <small>%s</small><br/>',
            $box['title'],
            $box['id'],
            checked( 1, $post_meta, false ),
            $box['args']['desc']
        );
    }
}

# ADD TWO META BOXES - DIFFERENT POST TYPES - DIFFERENT CONTEXTS AND PRIORITIES
$args = array(
    array(
        'id' => 'teaser_loop',
        'title' => 'Loop Time',
        'post_type' => 'post',
        'args' => array(
            'desc' => 'Enter the time',
            'field' => 'textfield',
        )
    ),
    array(
        'id' => 'teaser_link',
        'title' => 'Loop Link',
        'post_type' => 'page',
        'context' => 'side',
        'priority' => 'high',
        'args' => array(
            'desc' => 'Open link',
            'field' => 'checkbox',
        )
    ),
);
new B5F_Dynamic_Meta_Boxes( $args );

# ADD ANOTHER META BOX TO ANOTHER POST TYPE
$more_args = array(
    array(
        'id' => 'extra_box',
        'title' => 'And another one',
        'post_type' => 'teaser',
        'args' => array(
            'desc' => 'Open link',
            'field' => 'textfield',
        )
    ),
);
new B5F_Dynamic_Meta_Boxes( $more_args );

This is just a skeleton, from here there's a lot to be written. Some examples: