Вопрос или проблема
Углубляясь в Сохранение повторяемых полей метабокса …
Я создал метабокс с серией полей, которые можно повторять. Однако в этих полях я хотел бы создать еще одно поле под названием «Выборы» и сделать его повторяемым внутри каждой группы.
Мне удалось настроить дополнительное поле и сделать его повторяемым, но у меня нет представления о том, как сохранить значение нового повторяемого поля. Новое поле, которое я пытался создать, находится в закомментированных частях кода ниже, а также мои попытки сохранить его
function poll_potential_results() {
$options = array (
'Вариант 1' => 'option1',
'Вариант 2' => 'option2',
);
return $options;
}
add_action('admin_init', 'poll_add_metaboxes', 1);
function poll_add_metaboxes() {
add_meta_box( 'Dicey', 'Вопросы и Варианты', 'poll_metabox', 'quizzes', 'normal', 'default');
}
function poll_metabox() {
global $post;
$repeat_fields = get_post_meta($post->ID, 'repeat_fields', true);
$options = poll_potential_results();
wp_nonce_field( 'poll_metabox_nonce', 'poll_metabox_nonce' );
?>
<script type="text/javascript">
jQuery(document).ready(function( $ ){
$( '#add-row' ).on('click', function() {
var row = $( '.empty-row.screen-reader-text' ).clone(true);
row.removeClass( 'empty-row screen-reader-text' );
row.insertAfter( '#repeatable_row' );
return false;
});
$( '.remove-row' ).on('click', function() {
$(this).parents('tr').remove();
return false;
});
/*$('#add-choice' ).on('click',function() {
var choicenew = $(this).closest('tr' ).clone(true);
var choice = $(this ).closest('tr');
choicenew.insertAfter(choice);
return false;
})*/
});
</script>
<table id="repeatable_row" width="100%"><tbody>
<?php if ( $repeat_fields ) : foreach ( $repeat_fields as $field ) { ?>
<tr><td><table>
<tr>
<td colspan="3"><input type="text" class="widefat" name="name[]" value="<?php if($field['name'] != '') echo esc_attr( $field['name'] ); ?>" /></td>
</tr>
<tr>
<!--<td><a id="add-choice" class="button" href="#">Добавить выбор</a></td>-->
<!--<td><input type="text" class="widefat" name="choice[]" value="<?php //if($field['choice'] != '') echo esc_attr( $field['choice'] ); ?>" /></td>-->
<td><input type="text" class="widefat" name="url[]" value="<?php if ($field['url'] != '') echo esc_attr( $field['url'] ); else echo 'http://'; ?>" /></td>
<td>
<select name="select[]">
<?php foreach ( $options as $label => $value ) : ?>
<option value="<?php echo $value; ?>"<?php selected( $field['select'], $value ); ?>><?php echo $label; ?></option>
<?php endforeach; ?>
</select>
</td>
<td><a class="button remove-row" href="#">Удалить</a></td>
</tr>
</table></td></tr>
<?php } else : ?>
<tr><td><table>
<tr>
<td colspan="3"><input type="text" class="widefat" name="name[]" /></td>
</tr>
<tr>
<!--<td><a id="add-choice" class="button" href="#">Добавить выбор</a></td>-->
<!--<td><input type="text" class="widefat" name="choice[]" /></td>-->
<td><input type="text" class="widefat" name="url[]" value="http://" /></td>
<td>
<select name="select[]">
<?php foreach ( $options as $label => $value ) : ?>
<option value="<?php echo $value; ?>"><?php echo $label; ?></option>
<?php endforeach; ?>
</select>
</td>
<td><a class="button remove-row" href="#">Удалить</a></td>
</tr>
</table></td></tr>
<?php endif; ?>
<!-- пустая скрытая строка для jQuery -->
<tr class="empty-row screen-reader-text"><td><table>
<tr>
<td colspan="3"><input type="text" class="widefat" name="name[]" /></td>
</tr>
<tr>
<!--<td><a id="add-choice" class="button" href="#">Добавить выбор</a></td>-->
<!--<td><input type="text" class="widefat" name="choice[]" /></td>-->
<td><input type="text" class="widefat" name="url[]" value="http://" /></td>
<td>
<select name="select[]">
<?php foreach ( $options as $label => $value ) : ?>
<option value="<?php echo $value; ?>"><?php echo $label; ?></option>
<?php endforeach; ?>
</select>
</td>
<td><a class="button remove-row" href="#">Удалить</a></td>
</tr>
</table></td></tr>
</tbody>
</table>
<p><a id="add-row" class="button" href="#">Добавить еще</a></p>
<?php }
add_action('save_post', 'poll_metabox_save');
function poll_metabox_save($post_id) {
if ( ! isset( $_POST['poll_metabox_nonce'] ) || ! wp_verify_nonce( $_POST['poll_metabox_nonce'], 'poll_metabox_nonce' ) ) return;
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (!current_user_can('edit_post', $post_id)) return;
$old = get_post_meta($post_id, 'repeat_fields', true);
$new = array();
//$newchoice = $new[$j];
//$newchoice = $new;
//
$options = poll_potential_results();
$names = $_POST['name'];
//$choices = $_POST['choice'];
$selects = $_POST['select'];
$urls = $_POST['url'];
$count = count( $names );
//$countchoices = count($choices);
for ( $i = 0; $i < $count; $i++ ) {
if ( $names[$i] != '' ) {
$new[$i]['name'] = stripslashes( strip_tags( $names[$i] ) );
//for ( $j = 0; $j < $countchoices; $j++) {
// if ( $choices[$j] != '') {
// $newchoice[$j]['choice'] = stripslashes(strip_tags($choices[$j]));
// }
//}
if ( in_array( $selects[$i], $options ) ) $new[$i]['select'] = $selects[$i];
else $new[$i]['select'] = '';
if ( $urls[$i] == 'http://' ) $new[$i]['url'] = '';
else $new[$i]['url'] = stripslashes( $urls[$i] );
}
}
//if (!empty($newchoice)) {
// update_post_meta($post_id,'repeat_fields',$newchoice);
//}
if ( !empty( $new ) && $new != $old ) update_post_meta( $post_id, 'repeat_fields', $new );
elseif ( empty($new) && $old ) delete_post_meta( $post_id, 'repeat_fields', $old );
}
Используйте Advanced Custom Fields. Я не люблю использовать плагины, когда могу сделать что-то сам, но ACF стал незаменимым для решения таких кошмаров с кодом.
Ответ или решение
Повторяемые поля внутри повторяемой группы полей: подробное руководство
В этом руководстве мы рассмотрим, как создать повторяемые поля внутри метабокса повторяемых полей в WordPress. Эта задача может показаться сложной на первый взгляд, но с помощью четкого понимания структуры данных и правильного использования функций WordPress, вы сможете успешно реализовать этот функционал.
1. Основная структура метабокса
Перед тем как углубиться в детали, обеспечим начальную работу с метабоксом, который содержит повторяемые поля. Основная задача состоит в том, чтобы создать метабокс с полями, которые могут повторяться, и ввести возможность добавления внутренних повторяемых полей, таких как "Выбор".
add_action('admin_init', 'poll_add_metaboxes', 1);
function poll_add_metaboxes() {
add_meta_box('Dicey', 'Вопросы и Опции', 'poll_metabox', 'quizzes', 'normal', 'default');
}
function poll_metabox() {
global $post;
$repeat_fields = get_post_meta($post->ID, 'repeat_fields', true);
// Вводим опции
$options = poll_potential_results();
wp_nonce_field('poll_metabox_nonce', 'poll_metabox_nonce');
// Делаем JavaScript для добавления и удаления строк
?>
<script type="text/javascript">
jQuery(document).ready(function($) {
$('#add-row').on('click', function() {
var row = $('.empty-row.screen-reader-text').clone(true);
row.removeClass('empty-row screen-reader-text');
row.insertAfter('#repeatable_row');
return false;
});
$('.remove-row').on('click', function() {
$(this).parents('tr').remove();
return false;
});
});
</script>
<table id="repeatable_row" width="100%">
<tbody>
<?php if ($repeat_fields): ?>
<?php foreach ($repeat_fields as $field): ?>
<tr>
<td>
<table>
<tr>
<td colspan="3"><input type="text" class="widefat" name="name[]" value="<?php echo esc_attr($field['name']); ?>" /></td>
</tr>
<tr>
<td ><a id="add-choice" class="button" href="#">Добавить выбор</a></td>
<td><input type="text" class="widefat" name="url[]" value="<?php echo ($field['url'] != '') ? esc_attr($field['url']) : 'http://'; ?>" /></td>
<td>
<select name="select[]">
<?php foreach ($options as $label => $value): ?>
<option value="<?php echo $value; ?>" <?php selected($field['select'], $value); ?>><?php echo $label; ?></option>
<?php endforeach; ?>
</select>
</td>
<td><a class="button remove-row" href="#">Удалить</a></td>
</tr>
</table>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<!-- здесь будет код по умолчанию -->
<?php endif; ?>
<tr class="empty-row screen-reader-text">
<td>
<table>
<tr>
<td colspan="3"><input type="text" class="widefat" name="name[]" /></td>
</tr>
<tr>
<td><a id="add-choice" class="button" href="#">Добавить выбор</a></td>
<td><input type="text" class="widefat" name="url[]" value="http://" /></td>
<td>
<select name="select[]">
<?php foreach ($options as $label => $value): ?>
<option value="<?php echo $value; ?>"><?php echo $label; ?></option>
<?php endforeach; ?>
</select>
</td>
<td><a class="button remove-row" href="#">Удалить</a></td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
<p><a id="add-row" class="button" href="#">Добавить еще</a></p>
<?php
}
2. Сохранение значений повторяемых полей
Сохранение данных—это важная часть. При сохранении нужно учитывать не только значение полей "name", "url" и "select", но и повторяемые поля внутри каждой группы. В этом разделе мы добавим функционал к функции сохранить метабокс.
add_action('save_post', 'poll_metabox_save');
function poll_metabox_save($post_id) {
// Проверка nonce и прав доступа
if (!isset($_POST['poll_metabox_nonce']) || !wp_verify_nonce($_POST['poll_metabox_nonce'], 'poll_metabox_nonce')) return;
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (!current_user_can('edit_post', $post_id)) return;
$old = get_post_meta($post_id, 'repeat_fields', true);
$new = array();
// Получаем данные
$names = $_POST['name'];
$selects = $_POST['select'];
$urls = $_POST['url'];
$count = count($names);
for ($i = 0; $i < $count; $i++) {
if ($names[$i] != '') {
$new[$i]['name'] = stripslashes(strip_tags($names[$i]));
$new[$i]['select'] = in_array($selects[$i], poll_potential_results()) ? $selects[$i] : '';
$new[$i]['url'] = ($urls[$i] == 'http://') ? '' : stripslashes($urls[$i]);
}
}
if (!empty($new) && $new != $old) {
update_post_meta($post_id, 'repeat_fields', $new);
} elseif (empty($new) && $old) {
delete_post_meta($post_id, 'repeat_fields', $old);
}
}
3. Добавление выборов внутри повторяемых полей
Теперь, когда мы настроили основную логику, можно перейти к добавлению выбора внутри каждой группы. Здесь важно использовать динамические массивы, так как количество выборов может меняться. Пример реализации:
$(document).on('click', '#add-choice', function() {
var choiceRow = $(this).closest('tr').clone(true);
// Очистка значений
choiceRow.find('input').val('');
choiceRow.insertAfter($(this).closest('tr'));
});
Заключение
Создание многоуровневых повторяемых полей в WordPress требует тщательного планирования и понимания работы с массивами. Однако, уделив внимание структуре ваших данных и правильной логике сохранения, вы сможете реализовать сложные сценарии с метабоксами без необходимости в сторонних плагинах, таких как ACF.
Не забывайте тестировать каждую часть кода, а также обеспечивать безопасность пользовательских данных. Надеюсь, это руководство поможет вам в создании кастомных метабоксов!