Повторяющиеся поля метабокса - переключатели не сохраняются правильно
У меня есть несколько переключателей, настроенных внутри метабокса в пользовательском типе записи. Я создал метабокс следующим образом:
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++;
}
А вот моя функция сохранения для хранения данных в массиве.
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']
хранятся как "нулевые".
То, как у меня все устроено, выглядит так вещи должны быть сохранены должным образом. Это урезанная версия. У меня есть поля ввода, которые хранятся правильно, но переключатели были серьезной проблемой.
Похоже, что моя функция сохранения должна хранить каждый ['playback_format']
в соответствующем месте в массиве. Но только один магазин. Я заставил его хранить одно и то же значение для всех трех строк, но не могу получить уникальное значение для каждой строки и не знаю, почему.
Любая помощь будет признательна, так как это последняя часть головоломка!
Спасибо! (Скриншот ниже для наглядного пособия)
Вот значение 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 answers
Поэтому я вернулся к этому после практики и реализовал некоторые настройки алхимии, что означает, что все входные данные имеют такие имена, как 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_format" не было вечерней публикацией. Но, наконец, я заметил, что вы упаковываете радиоприемники в элемент <form>
. Я убежден, что в этом и есть проблема, потому что, как только я от нее избавился, она сработала.
Я бы посоветовал вам сначала удалить этот дополнительный <Form>
из вашего кода, чтобы посмотреть, решит ли это проблему. Возможно, это работает остальная часть вашего кода. Если нет, то я почти уверен, что мой сейчас... однако я изменил некоторые имена и некоторые идентификаторы, чтобы вероятно, повлияет на остальную часть работы, которая опирается на это.
И, наконец, b/c того, как я все изменил, мне нужно было изменить ваш 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;
});