WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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 :-).

share|improve this question
try WPALCHEMY! metabox class, easy and flexible. – Kamaal ABOOTHALIB Dec 16 '12 at 7:20
well I'm currently working on this issue as well, I already able to generate the group field, it's just still don't know how to save the array for each multifield. If you find any useful resource, please share with me. here is my result pastebin.com/wqfdUMC6 – nonsensecreativity Jan 4 '13 at 22:11
Old question but I am going to link it to my answer to a very similar question: wordpress.stackexchange.com/a/135513/6477 – helgatheviking May 16 '14 at 23:24

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.

share|improve this answer

protected by Community Jan 4 '13 at 20:35

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

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