Повторяемое поле внутри повторяемой группы полей

Вопрос или проблема

Углубляясь в Сохранение повторяемых полей метабокса

Я создал метабокс с серией полей, которые можно повторять. Однако в этих полях я хотел бы создать еще одно поле под названием «Выборы» и сделать его повторяемым внутри каждой группы.

Мне удалось настроить дополнительное поле и сделать его повторяемым, но у меня нет представления о том, как сохранить значение нового повторяемого поля. Новое поле, которое я пытался создать, находится в закомментированных частях кода ниже, а также мои попытки сохранить его

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.

Не забывайте тестировать каждую часть кода, а также обеспечивать безопасность пользовательских данных. Надеюсь, это руководство поможет вам в создании кастомных метабоксов!

Оцените материал
Добавить комментарий

Капча загружается...