Metabox重复字段-单选按钮未正确保存

时间:2014-02-21 作者:EHerman

我有多个单选按钮设置在一个自定义帖子类型的元框内。我创建了这样的元盒:

    add_action(\'admin_init\', \'add_meta_boxes\', 1);
    function add_meta_boxes() {
        add_meta_box( \'repeatable_fields\', \'Top 10 Movie List\', \'repeatable_meta_box_display\', \'cpt_top_ten_list\', \'normal\', \'default\');
    }

    function repeatable_meta_box_display() {
        global $post;
        $repeatable_fields = get_post_meta($post->ID, \'repeatable_fields\', true);
        wp_nonce_field( \'repeatable_meta_box_nonce\', \'repeatable_meta_box_nonce\' );

     if ( $repeatable_fields ) :

    // set a variable so we can append it to each row
    $num = 0;
    $second_num = 0;

    foreach ( $repeatable_fields as $field ) {
    $num++;

<div class=" playbackformat-holder-<?php echo $num; ?> playbackformat-holder">
    <form id="playback-form-<?php echo $num; ?>">
        <label for="dvd-<?php echo $num; ?>">
        <input type="radio" class="playbackformat-holder-radiobutton" value="dvd" name="playback_format[<?php echo $second_num; ?>]" id="dvd-<?php echo $num; ?>" <?php if($field[\'playback_format\'] == \'dvd\') { echo \'checked\'; } ?>>DVD
        </label>

        <label for="bluray-<?php echo $num; ?>">
        <input type="radio" class="playbackformat-holder-radiobutton" value="bluray" name="playback_format[<?php echo $second_num; ?>]" id="bluray-<?php echo $num; ?>" <?php if($field[\'playback_format\'] == \'bluray\') { echo \'checked\'; } ?>>Bluray
        </label><br>    

        <label for="3d-<?php echo $num; ?>">
        <input type="radio" class="playbackformat-holder-radiobutton" value="3d" name="playback_format[<?php echo $second_num; ?>]" id="3d-<?php echo $num; ?>" <?php if($field[\'playback_format\'] == \'3d\') { echo \'checked\'; } ?>>3d
        </label><br />
    </form>     
</div>
second_num++;
}
这是我的save函数,用于将数据存储到数组中。

add_action(\'save_post\', \'repeatable_meta_box_save\', 10, 2);
function repeatable_meta_box_save($post_id) {

    if ( ! isset( $_POST[\'repeatable_meta_box_nonce\'] ) ||
    !wp_verify_nonce( $_POST[\'repeatable_meta_box_nonce\'], \'repeatable_meta_box_nonce\' ) )
    return;

    if (defined(\'DOING_AUTOSAVE\') && DOING_AUTOSAVE)
    return;

    if (!current_user_can(\'edit_post\', $post_id))
    return;

    $old = get_post_meta($post_id, \'repeatable_fields\', true);
    $new = array();

    $playbackFormats = $_POST[\'playback_format\'];


    $count = count( $names ) - 1;

    for ( $i = 0; $i < $count; $i++ ) {

    // currently only storing the last stored radio value
    $new[$i][\'playback_format\'] = $playbackFormats[$i];

    // save movie description
     // and however you want to sanitize
    if ( !empty( $new ) && $new != $old ) {
        update_post_meta( $post_id, \'repeatable_fields\', $new );
    } elseif ( empty($new) ) {
        delete_post_meta( $post_id, \'repeatable_fields\', $old );
    }

}
我面临的问题是,假设我有三排。如果将第一个设置为DVD,第二个设置为bluray,第三个设置为3D,则最后一个值存储为3D。所有其他[\'playback_format\'] 存储为“null”。

按照我的设置方式,似乎应该妥善保存。这是一个精简版。我有正确存储的输入字段,但单选按钮一直是一个主要问题。

看起来我的保存功能应该存储[\'playback_format\'] 在数组中的适当位置。但只有一家商店。我已经让它为所有三行存储相同的值,但无法为每一行获取唯一的值,也不知道为什么。

任何帮助都将不胜感激,因为这是拼图的最后一块!

谢谢(下面的屏幕截图提供了视觉帮助)

repeatable rows - visual aid

以下是var_dump($field); 将数据存储在上面的屏幕截图中之后。

array(4) { 
 ["name"]=> string(116) "http://onecinephile.staging.wpengine.com/wp-content/uploads/2014/01/lon-chaney-phantom-hunchback-penalty-300x280.jpg" 
 ["select"]=> string(14) "Test #2" 
 ["url"]=> string(35) "Testing movie description #2" 
 ["playback_format"]=> string(3) "dvd" 
} 

array(4) { 
 ["name"]=> string(103) "http://onecinephile.staging.wpengine.com/wp-content/uploads/2014/01/spencer-tracy-boys-town-300x225.jpg" 
 ["select"]=> string(14) "Test #1" 
 ["url"]=> string(35) "Testing movie description #1" 
 ["playback_format"]=> NULL 
} 

array(4) { 
 ["name"]=> string(100) "http://onecinephile.staging.wpengine.com/wp-content/uploads/2014/01/Ronald-and-Madeleine-225x300.jpg" ["select"]=> string(14) "Test #3
 ["url"]=> string(35) "Testing movie description #3" 
 ["playback_format"]=> NULL 
}

1 个回复
最合适的回答,由SO网友:helgatheviking 整理而成

所以我在练习后回到这里,实现了一些炼金术设置,这意味着所有输入都有如下名称name="_movies[3][title]" 其中3是循环中的迭代。

创建元框

// metaboxes should be registered on the add_meta_boxes hook
add_action(\'add_meta_boxes\', \'add_meta_boxes\' );
function add_meta_boxes() {
    add_meta_box( \'repeatable_fields\', \'Top 10 Movie List\', \'repeatable_meta_box_display\', \'cpt_top_ten_list\', \'normal\', \'default\');
}


function repeatable_meta_box_display( $post ) { 

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

if ( empty( $repeatable_fields ) ){
    $repeatable_fields[] = array ( 
                                \'image\' => \'\',
                                \'title\' => \'\',
                                \'playback_format\' => \'dvd\',
                                \'description\' => \'\' );
}

wp_nonce_field( \'hhs_repeatable_meta_box_nonce\', \'hhs_repeatable_meta_box_nonce\' ); 
?> 

<table id="repeatable-fieldset-one" class="widefat fixed" cellspacing="0" style="width:100%;"> 
<thead> 
<tr> 
<th style="width:25px;" scope="col">Rank</th> 
<th style="width:170px;" scope="col">Image</th> 
<th width="145px" scope="col">Movie Title</th> 
<th width="300px" scope="col">Movie Description</th> 
<th width="8%" scope="col">Re-Order</th> 
</tr> 
</thead> 
<tbody> 


<?php 

// set a variable so we can append it to each row 
$i = 1; 

foreach ( $repeatable_fields as $field ) { ?>

<tr class="single-movie-row ui-state-default"> 

    <td> 
    <label for="_movies[<?php echo $i;?>][rank]"> 
    <input name="_movies[<?php echo $i;?>][rank]" id="_movies[<?php echo $i;?>][rank]" class="movie_rank_number" disabled="disabled" type="text" value="# <?php echo $i;?>" /> 
    </label>    
    </td> 

    <td> 
    <label for="_movies[<?php echo $i;?>][image]"> 
    <input name="_movies[<?php echo $i;?>][image]" class="upload_image" id="_movies[<?php echo $i;?>][image]" type="text" size="36" value="<?php echo esc_attr( $field[\'image\'] );?>" /> 
    <input class="upload_image_button" id="_movies[<?php echo $i;?>][upload_image_button]" type="button" value="Upload Image" /> 
    </label> 
    </td> 

    <td> 
    <!-- title field --> 
    <textarea name="_movies[<?php echo $i;?>][title]" id="_movies[<?php echo $i;?>][title]" class="title_tinymce_editor"><?php echo esc_html( $field[\'title\'] );?></textarea> 

    <div class="playbackformat-holder"> 

    <label for="_movies[<?php echo $i;?>][playback_format][dvd]"> 
    <input type="radio" id="_movies[<?php echo $i;?>][playback_format][dvd]" name="_movies[<?php echo $i;?>][playback_format]" value="dvd" <?php checked( $field[\'playback_format\'], \'dvd\' ); ?> />DVD 
    </label> 
    <label for="_movies[<?php echo $i;?>][playback_format][bluray]"> 
    <input type="radio" id="_movies[<?php echo $i;?>][playback_format][bluray]" name="_movies[<?php echo $i;?>][playback_format]" value="bluray" <?php checked( $field[\'playback_format\'], \'bluray\' ); ?> />Bluray 
    </label><br>    
    <label for="_movies[<?php echo $i;?>][playback_format][3d]"> 
    <input type="radio" id="_movies[<?php echo $i;?>][playback_format][3d]" name="_movies[<?php echo $i;?>][playback_format]" value="3d" <?php checked( $field[\'playback_format\'], \'3d\' ); ?> />3d 
    </label><br />  

    </div> 

    </td> 

    <td>
    <textarea id="_movies[<?php echo $i;?>][description]" name="_movies[<?php echo $i;?>][description]" class="movie_description_editor_hidden"><?php echo esc_html( $field[\'description\'] );?></textarea>
    </td> 

    <td>
    <a class="button remove-row" href="#">Remove Row</a><img src="<?php echo get_template_directory_uri() ?>/images/draggable-icon.png" alt="sortable icon" class="jQuerySortableIcon">
    </td> 

</tr> 

<?php $i++; } ?>


<!-- empty hidden one for jQuery --> 
<tr class="empty-row screen-reader-text single-movie-row"> 

    <td> 
    <label for="_movies[%s][rank]"> 
    <input name="_movies[%s][rank]" id="_movies[%s][rank]" class="movie_rank_number" disabled="disabled" type="text" value="" /> 
    </label>    
    </td> 

    <td> 
    <label for="_movies[%s][image]"> 
    <input name="_movies[%s][image]" class="upload_image" id="_movies[%s][image]" type="text" size="36" value="" /> 
    <input class="upload_image_button" id="_movies[<?php echo $i;?>][upload_image_button]" type="button" value="Upload Image" /> 
    </label> 
    </td> 

    <td> 
    <!-- title field --> 
    <textarea name="_movies[%s][title]" id="_movies[%s][title]" class="title_tinymce_editor"></textarea> 

    <div class="playbackformat-holder"> 

    <label for="_movies[%s][playback_format][dvd]"> 
    <input type="radio" id="_movies[%s][playback_format][dvd]" name="_movies[%s][playback_format]" value="dvd" <?php checked( \'dvd\', \'dvd\' ); ?> />DVD 
    </label> 
    <label for="_movies[%s][playback_format][bluray]"> 
    <input type="radio" id="_movies[%s][playback_format][bluray]" name="_movies[%s][playback_format]" value="bluray" />Bluray 
    </label><br>    
    <label for="_movies[%s][playback_format][3d]"> 
    <input type="radio" id="_movies[%s][playback_format][3d]" name="_movies[%s][playback_format]" value="3d" />3d 
    </label><br />  

    </div> 

    <!-- drop down or checkbox\'s with release formats --> 
    </td> 

    <td>
    <textarea id="_movies[%s][description]" name="_movies[%s][description]" class="movie_description_editor_hidden"></textarea>
    </td> 


    <td>
    <a class="button remove-row" href="#">Remove Row</a><img src="<?php echo get_template_directory_uri() ?>/images/draggable-icon.png" alt="sortable icon" class="jQuerySortableIcon">
    </td> 

</tr> 

</tbody> 
</table> 

<p id="add-row-p-holder"><a id="add-row" class="btn btn-small btn-success" href="#">Insert Another Row</a></p> 
<?php 
}
保存元现在相对容易,因为名称中的数组为我们设置了元:

add_action(\'save_post\', \'hhs_repeatable_meta_box_save\', 10, 2); 
function hhs_repeatable_meta_box_save($post_id) { 

if ( ! isset( $_POST[\'hhs_repeatable_meta_box_nonce\'] ) || 
!wp_verify_nonce( $_POST[\'hhs_repeatable_meta_box_nonce\'], \'hhs_repeatable_meta_box_nonce\' ) ) 
return; 

if (defined(\'DOING_AUTOSAVE\') && DOING_AUTOSAVE) 
return; 

if (!current_user_can(\'edit_post\', $post_id)) 
return; 

$clean = array(); 

if  ( isset ( $_POST[\'_movies\'] ) && is_array( $_POST[\'_movies\'] ) ) :

    foreach ( $_POST[\'_movies\'] as $i => $movie ){

    // skip the hidden "to copy" div
    if( $i == \'%s\' ){ 
        continue;
    }

$playback_formats = array ( \'dvd\', \'bluray\', \'3d\' );

    $clean[] = array( 
        \'image\' => isset( $movie[\'image\'] ) ? sanitize_text_field( $movie[\'image\'] ) : null,
        \'title\' => isset( $movie[\'title\'] ) ? sanitize_text_field( $movie[\'title\'] ) : null,
        \'playback_format\' => isset( $movie[\'playback_format\'] ) && in_array( $movie[\'playback_format\'], $playback_formats ) ? $movie[\'playback_format\'] : null,
        \'description\' => isset( $movie[\'description\'] ) ? sanitize_text_field( $movie[\'description\'] ) : null,
        );

}

endif;

// save movie data 
if ( ! empty( $clean ) ) { 
    update_post_meta( $post_id, \'repeatable_fields\', $clean ); 
} else
    delete_post_meta( $post_id, \'repeatable_fields\' ); 
}
我会说,我遇到了我们在聊天中谈到的同一个问题。。。。在经历了这一切之后,我仍然在运行第二台和第三台“playback\\u格式”收音机,而不是晚间发布的时候,我几乎疯了。但最后,我注意到你正在用<form> 要素我确信这就是问题所在,因为我一摆脱它,它就奏效了。

我建议你试着减少额外的<Form> 首先查看代码,看看这是否解决了问题。这可能是您的其余代码工作。如果不是,那么我很确定我的现在是。。。然而,我已经更改了一些名称和ID,因此这可能会影响依赖于此的其余工作。

最后,关于我是如何改变一切的,我需要修改你的添加行JS。这里进行了简化,因为我不想处理tinyMCE编辑器,所以我只留下文本区域用于测试目的。

使用Javascript复制行

/*********************** Add Row Button Click *****************************/ 

$( \'#add-row\' ).click(function() { 
var rowCount = $(\'#repeatable-fieldset-one\').find(\'.single-movie-row\').not(\':last-child\').size(); 
var newRowCount = rowCount + 1;

var row = $( \'.empty-row.screen-reader-text\' ).clone(true); 

// Loop through all inputs
row.find(\'input, textarea, label\').each(function(){ 

    if ( !! $(this).attr(\'id\') )
        $(this).attr(\'id\',  $(this).attr(\'id\').replace(\'[%s]\', \'[\' + newRowCount + \']\') );  // Replace for

    if ( !! $(this).attr(\'name\') )
        $(this).attr(\'name\',  $(this).attr(\'name\').replace(\'[%s]\', \'[\' + newRowCount + \']\') );  // Replace for

    if ( !! $(this).attr(\'for\') )
        $(this).attr(\'for\',  $(this).attr(\'for\').replace(\'[%s]\', \'[\' + newRowCount + \']\') );  // Replace for

});

row.removeClass( \'empty-row screen-reader-text\' ).find(\'.movie_rank_number\').val(\'# \'+newRowCount);
row.insertBefore( \'.empty-row\' ); 

// if row count hits 10, hide the add row button 
if ( newRowCount == 10 ) { 
jQuery(\'#add-row\').fadeOut(); 
} 

return false; 
});

结束