I am working on a meta box for events. Each event has it's own page with a meta box for the line-up, background image, tickets page URL and some text.

To create the line-up I would like to use the repeatable fields from the "Reusable Custom Meta Boxes tutorial" from WP Tuts +: http://wp.tutsplus.com/tutorials/reusable-custom-meta-boxes-part-1-intro-and-basic-fields/.

However, I don't know how to add multiple fields within the repeatable fields. This is the idea:

- Text field: Name of the artist
- Text field: Artist website
- Checkbox: Headliner (Yes or no)

This is the code from the tutorial:

function meta_box_callback($fields, $page) {
    global $post;
    echo '<input type="hidden" name="'.$page.'_meta_box_nonce" value="'.wp_create_nonce(basename(__FILE__)).'" />';

    // Begin the field table and loop
    echo '<table class="form-table cpt">';
    foreach ($fields as $field) {
        // get value of this field if it exists for this post
        if ($field['label'])    $label      = $field['label'];
        if ($field['desc'])     $desc       = '<span class="description">'.$field['desc'].'</span>';
        if ($field['id'])       $id         = $field['id'];
        if ($field['type'])     $type       = $field['type'];
        if ($field['value'])    $value      = $field['value'];
        if ($field['options'])  $options    = $field['options'];

        $meta   = get_post_meta($post->ID, $id, true);
        // begin a table row with
        echo '<tr>
                <th class="cpt_title"><label for="'.$id.'">'.$label.'</label></th>
                <td class="cpt_content">';
                switch($field['type']) {
                    case 'repeatable':
                        echo '<a class="repeatable-add button" href="#">+</a>
                                <ul id="'.$field['id'].'-repeatable" class="custom_repeatable">';
                        $i = 0;
                        if ($meta) {
                            foreach($meta as $row) {
                                echo '<li><span class="sort hndle">|||</span>
                                            <input type="text" name="'.$field['id'].'['.$i.']" id="'.$field['id'].'" value="'.$row.'" size="30" />
                                            <a class="repeatable-remove button" href="#">-</a></li>';
                        } else {
                            echo '<li><span class="sort hndle">|||</span>
                                        <input type="text" name="'.$field['id'].'['.$i.']" id="'.$field['id'].'" value="" size="30" />
                                        <a class="repeatable-remove button" href="#">-</a></li>';
                        echo '</ul>
                            <span class="description">'.$field['desc'].'</span>';
                } // switch
        echo '</td></tr>';
    } // foreach
    echo '</table>'; // table
function meta_box_save($post_id, $fields, $page) {

    // verify nonce
    if (!wp_verify_nonce($_POST[$page.'_meta_box_nonce'], basename(__FILE__))) 
        return $post_id;
    // check autosave
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
        return $post_id;
    // check permissions
    if ($page != $_POST['post_type']) {
        if (!current_user_can('edit_page', $post_id))
            return $post_id;
        } elseif (!current_user_can('edit_post', $post_id)) {
            return $post_id;

    // loop through fields and save the data
    foreach ($fields as $field) {
        if($field['type'] == 'tax_select') {
            // save taxonomies
            $term = $_POST[$field['id']];
            wp_set_object_terms( $post_id, $term, $field['id'] );
        else {
            // save the rest
            $old = get_post_meta($post_id, $field['id'], true);
            $new = $_POST[$field['id']];
            if ($new && $new != $old) {
                update_post_meta($post_id, $field['id'], $new);
            } elseif ('' == $new && $old) {
                delete_post_meta($post_id, $field['id'], $old);
    } // foreach

Hope you guys can help me out :-).


Try Fieldmanager. It was built with repeating groups being priority #1. Your new code would look something like this:

add_action( 'init', function() {
    $fm = new Fieldmanager_Group( array(
        'name'           => 'artists',
        'limit'          => 0,
        'label'          => 'New Artist',
        'label_macro'    => array( 'Artist: %s', 'name' ),
        'add_more_label' => 'Add another Artist',
        'children'       => array(
            'name'      => new Fieldmanager_Textfield( 'Name' ),
            'website'   => new Fieldmanager_Link( 'Website' ),
            'headliner' => new Fieldmanager_Checkbox( 'Headliner' )
        ) );
    $fm->add_meta_box( 'Artists', array( 'post' ) );
} );

Disclosure: The company I work for open-sources this plugin.

Not the answer you're looking for? Browse other questions tagged or ask your own question.