Código PHP:
   <?
 
// Add the Meta Box
function add_custom_meta_box() {
    add_meta_box(
        'custom_meta_box', // $id
        'Custom Meta Box', // $title 
        'show_custom_meta_box', // $callback
        'post', // $page
        'normal', // $context
        'high'); // $priority
}
add_action('add_meta_boxes', 'add_custom_meta_box');
 
// Field Array
$prefix = 'custom_';
$custom_meta_fields = array(
 
    array(
        'label'    => 'Repeatable',
        'desc'    => 'A description for the field.',
        'id'    => $prefix.'repeatable',
        'type'    => 'repeatable'
    )
);
 
// enqueue scripts and styles, but only if is_admin
if(is_admin()) {
    wp_enqueue_script('jquery-ui-datepicker');
    wp_enqueue_script('jquery-ui-slider');
    wp_enqueue_script('custom-js', get_template_directory_uri().'/js/custom-js.js');
    wp_enqueue_style('jquery-ui-custom', get_template_directory_uri().'/css/jquery-ui-custom.css');
}
 
// add some custom js to the head of the page
add_action('admin_head','add_custom_scripts');
function add_custom_scripts() {
    global $custom_meta_fields, $post;
    
    $output = '<script type="text/javascript">
                jQuery(function() {';
    
    foreach ($custom_meta_fields as $field) { // loop through the fields looking for certain types
        // date
        if($field['type'] == 'date')
            $output .= 'jQuery(".datepicker").datepicker();';
        // slider
        if ($field['type'] == 'slider') {
            $value = get_post_meta($post->ID, $field['id'], true);
            if ($value == '') $value = $field['min'];
            $output .= '
                    jQuery( "#'.$field['id'].'-slider" ).slider({
                        value: '.$value.',
                        min: '.$field['min'].',
                        max: '.$field['max'].',
                        step: '.$field['step'].',
                        slide: function( event, ui ) {
                            jQuery( "#'.$field['id'].'" ).val( ui.value );
                        }
                    });';
        }
    }
    
    $output .= '});
        </script>';
        
    echo $output;
}
 
// The Callback
function show_custom_meta_box() {
    global $custom_meta_fields, $post;
    // Use nonce for verification
    echo '<input type="hidden" name="custom_meta_box_nonce" value="'.wp_create_nonce(basename(__FILE__)).'" />';
    
    // Begin the field table and loop
    echo '<table class="form-table">';
    foreach ($custom_meta_fields as $field) {
        // get value of this field if it exists for this post
        $meta = get_post_meta($post->ID, $field['id'], true);
        // begin a table row with
        echo '<tr>
                <th><label for="'.$field['id'].'">'.$field['label'].'</label></th>
                <td>';
                switch($field['type']) {
                    // text
                    // repeatable
                    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>';
                                $i++;
                            }
                        } 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>';
                    break;
                } //end switch
        echo '</td></tr>';
    } // end foreach
    echo '</table>'; // end table
}
 
function remove_taxonomy_boxes() {
    remove_meta_box('categorydiv', 'post', 'side');
}
add_action( 'admin_menu' , 'remove_taxonomy_boxes' );
 
// Save the Data
function save_custom_meta($post_id) {
    global $custom_meta_fields;
    
    // verify nonce
    if (!wp_verify_nonce($_POST['custom_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 ($custom_meta_fields as $field) {
        if($field['type'] == 'tax_select') continue;
        $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);
        }
    } // enf foreach
    
    // save taxonomies
    $post = get_post($post_id);
    $category = $_POST['category'];
    wp_set_object_terms( $post_id, $category, 'category' );
}
add_action('save_post', 'save_custom_meta');
 
?>    El codigo funciona bien, pero solo para 1 campo, se repite todas las veces que sea necesario, sin problemas, pero como consigo meter varios campos en la parte que se repite?
Código PHP:
       // repeatable
                    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>';
                                $i++;
                            }
                        } 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>';
                    break; 
    pero no consigo realizarlo, como añado al foreach otro campo mas y que me lo guarde correctamente?
este es el .js por si alguien se anima a probrar
Código Javascript:
 Ver original
 jQuery(function(jQuery) { jQuery('.repeatable-add').click(function() { field = jQuery(this).closest('td').find('.custom_repeatable li:last').clone(true); fieldLocation = jQuery(this).closest('td').find('.custom_repeatable li:last'); jQuery('input', field).val('').attr('name', function(index, name) { return name.replace(/(\d+)/, function(fullMatch, n) { return Number(n) + 1; }); }) field.insertAfter(fieldLocation, jQuery(this).closest('td')) return false; }); jQuery('.repeatable-remove').click(function(){ jQuery(this).parent().remove(); return false; }); jQuery('.custom_repeatable').sortable({ opacity: 0.6, revert: true, cursor: 'move', handle: '.sort' }); });
 

