WP_list_table prepare_items()

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

Я создаю настраиваемый WP_list_table с боковой формой, как (форма добавления новой категории), но когда я отправляю эту форму, wp_list_table не обновляется. Когда я обновляю страницу снова, информация появляется. Я использую плагин wp_list_table_example, все такое же, за исключением получения example_data и формы.

 class TT_Example_List_Table extends WP_List_Table {

    function __construct(){
        global $status, $page;

        //Установить параметры по умолчанию
        parent::__construct( array(
            'singular'  => 'movie',     // единственное имя записей
            'plural'    => 'movies',    // множественное имя записей
            'ajax'      => false        // поддерживает ли эта таблица ajax?
        ) );

    }
    function column_default($item, $column_name){
        switch($column_name){
            case 'rating':
            case 'director':
                return $item[$column_name];
            default:
                return print_r($item,true); //Показать весь массив для устранения неполадок
        }
    }

    function column_title($item){

        //Создать действия по строкам
        $actions = array(
            'edit'      => sprintf('<a href="https://wordpress.stackexchange.com/questions/220788/?page=%s&action=%s&movie=%s">Редактировать</a>',$_REQUEST['page'],'edit',$item['ID']),
            'delete'    => sprintf('<a href="https://wordpress.stackexchange.com/questions/220788/?page=%s&action=%s&movie=%s">Удалить</a>',$_REQUEST['page'],'delete',$item['ID']),
        );

        //Вернуть содержимое заголовка
        return sprintf('%1$s <span style="color:silver">(id:%2$s)</span>%3$s',
            /*$1%s*/ $item['title'],
            /*$2%s*/ $item['ID'],
            /*$3%s*/ $this->row_actions($actions)
        );
    }
    function column_cb($item){
        return sprintf(
            '<input type="checkbox" name="%1$s[]" value="%2$s" />',
            /*$1%s*/ $this->_args['singular'],  //Просто переиспользуем единственное название таблицы ("movie")
            /*$2%s*/ $item['ID']                // Значение чекбокса должно быть id записи
        );
    }

    function get_columns(){
        $columns = array(
            'cb'        => '<input type="checkbox" />', //Отображает чекбокс вместо текста
            'title'     => 'Название',
            'rating'    => 'Рейтинг',
        );
        return $columns;
    }

    function get_sortable_columns() {
        $sortable_columns = array(
            'title'     => array('title',false),     //true означает, что он уже отсортирован
            'rating'    => array('rating',false),
            'director'  => array('director',false)
        );
        return $sortable_columns;
    }

    function get_bulk_actions() {
        $actions = array(
            'delete'    => 'Удалить'
        );
        return $actions;
    }
    function process_bulk_action() {

        //Определить, когда триггерится массовое действие...
        if( 'delete'===$this->current_action() ) {
            wp_die('Элементы удалены (или они были бы удалены, если бы у нас были элементы для удаления)!'); 
        }

    }
    function prepare_items() {

          $data = array();
        $example_data = array();
    $terms = get_terms( 'productcat', array('hide_empty' => false));

print_r($terms);
        if ( ! empty( $terms )  ){
     foreach ( $terms as $term ) {

         $data[] = array(
                            'ID'          =>  $term->term_id,
                            'title'       => $term->name
                            );

     }
 }

        $example_data = $data;

        $per_page = 5;

        $columns = $this->get_columns();
        $hidden = array();
        $sortable = $this->get_sortable_columns();
        $this->_column_headers = array($columns, $hidden, $sortable);
        $this->process_bulk_action();
        $data = $example_data;

        function usort_reorder($a,$b){
            $orderby = (!empty($_REQUEST['orderby'])) ? $_REQUEST['orderby'] : 'title'; //Если нет сортировки, по умолчанию сортировка по названию
            $order = (!empty($_REQUEST['order'])) ? $_REQUEST['order'] : 'asc'; //Если нет порядка, по умолчанию по возрастанию
            $result = strcmp($a[$orderby], $b[$orderby]); //Определить порядок сортировки
            return ($order==='asc') ? $result : -$result; //Отправить конечное направление сортировки в usort
        }
        usort($data, 'usort_reorder');

        $current_page = $this->get_pagenum();
        $total_items = count($data);
        $data = array_slice($data,(($current_page-1)*$per_page),$per_page);

        $this->items = $data;

        $this->set_pagination_args( array(
            'total_items' => $total_items,                  //Мы должны рассчитать общее количество элементов
            'per_page'    => $per_page,                     //Мы должны определить, сколько элементов показывать на странице
            'total_pages' => ceil($total_items/$per_page)   //Мы должны рассчитать общее количество страниц
        ) );
    }

}

function tt_add_menu_items(){
    add_menu_page('Пример списка плагина', 'Пример списка', 'activate_plugins', 'tt_list_test', 'tt_render_list_page');
} add_action('admin_menu', 'tt_add_menu_items');

function tt_render_list_page(){

    //Создать экземпляр нашего класса пакета...
    $testListTable = new TT_Example_List_Table();
    //Получить, подготовить, отсортировать и отфильтровать наши данные...
    $testListTable->prepare_items();

    ?>
    <div class="wrap">

        <div id="icon-users" class="icon32"><br/></div>
        <h2>Тест списка</h2>

        <form id="movies-filter" method="GET">

            <!-- Для плагинов, нам также нужно убедиться, что форма возвращается на нашу текущую страницу -->
            <input type="hidden" name="page" value="<?php echo $_REQUEST['page'] ?>" />
            <!-- Теперь мы можем отобразить завершенную таблицу списка -->
            <?php $testListTable->display(); ?>

        </form>
          <form id="insert_term" name="insert_term" method="post" action=""> 

           <div class="form-field  term-name-wrap">
          <label for="term">Термин</label>
         <input type="text" value="" name="term" id="term" size="40" />
         <p>Описание</p>
        </div>

    <label>Описание</label><input type="text" value="" name="termdesc" id="termdesc" />

    <input type="submit" value="Добавить термин" id="submit" name="submit" />
    <input type="hidden" name="action" value="new_term" />

</form> 

         <?php

if( 'POST' == $_SERVER['REQUEST_METHOD']) &&  $_POST['action'] == "new_term") {
if (isset($_POST['term']) && !empty( $_POST['term']) ) {

 $new_term =  $_POST['term'];
 $description = $_POST['desc'];
        wp_insert_term(
          $new_term,
          'productcat',
            array(
         'description'=> $description,
        ));

    } 

}

?>        
    </div>
    <?php
}

Мой вопрос заключается в том, почему при добавлении нового термина через форму wp_list_table не обновляется, это связано с тем, как данные получаются или как они добавляются. Как обновить wp_table_list после отправки нового термина. Любая помощь приветствуется.

Вы обрабатываете новые термины после того, как уже отобразили таблицу списка, поэтому, чтобы отобразить новый термин, как только вы отправите форму, вам нужно обработать его перед отображением таблицы.

Я добавил новую функцию process_form(), которая обрабатывает отправку формы нового термина, так что, когда форма отправляется, она проверяет поле nonce (которое вы всегда должны использовать wp_create_nonce_field()) и добавляет термин.

Кроме того, для заголовков страниц вам больше не нужен div icon32 <div id="icon-users" class="icon32"><br/></div>, вы должны удалить его.

А заголовки страниц должны быть заключены в теги <h1> для админских экранов с версии WordPress 4.3: https://make.wordpress.org/core/2015/07/31/headings-in-admin-screens-change-in-wordpress-4-3/

function tt_render_list_page() {
    //Обработка отправки формы нового термина
    $this->wpse_220820_process_form();
    //Создать экземпляр нашего класса пакета...
    $testListTable = new TT_Example_List_Table();
    //Получить, подготовить, отсортировать и отфильтровать наши данные...
    $testListTable->prepare_items(); ?>
    <div class="wrap">

        <div id="icon-users" class="icon32"><br/></div>
        <h1>Тест списка</h1>

        <form id="movies-filter" method="GET">

            <!-- Для плагинов, нам также нужно убедиться, что форма возвращается на нашу текущую страницу -->
            <input type="hidden" name="page" value="<?php echo $_REQUEST['page'] ?>"/>
            <!-- Теперь мы можем отобразить завершенную таблицу списка -->
            <?php $testListTable->display(); ?>

        </form>
        <form id="insert_term" name="insert_term" method="post" action="">

            <div class="form-field  term-name-wrap">
                <label for="term">Термин</label>
                <input type="text" value="" name="term" id="term" size="40"/>
                <p>Описание</p>
            </div>

            <label>Описание</label><input type="text" value="" name="termdesc" id="termdesc"/>

            <input type="submit" value="Добавить термин" id="submit" name="submit"/>
            <input type="hidden" name="action" value="new_term"/>
            <?php wp_nonce_field( 'wpse_220788_new_term', 'new_term_nonce' ); ?>
        </form>
    </div>
    <?php
}

/**
 * Проверяет $_POST на отправку формы и вставляет ее в таблицу
 */
function wpse_220820_process_form() {
    if ( ! empty( $_POST['action'] ) && $_POST['action'] == "new_term" ) {
        //Проверка Nonce
        if ( ! empty( $_POST['new_term_nonce'] ) && wp_verify_nonce( $_POST['new_term_nonce'], 'wpse_220788_new_term' ) ) {
            if ( isset( $_POST['term'] ) && ! empty( $_POST['term'] ) ) {

                $new_term    = sanitize_text_field( $_POST['term'] );
                $description = sanitize_text_field( $_POST['desc'] );
                wp_insert_term(
                    $new_term,
                    'productcat',
                    array(
                        'description' => $description,
                    )
                );

            }
        }

    }
}

Ответ или решение

Если у вас есть вопрос о том, как обновить таблицу WP_List_Table после добавления новой категории, вам нужно рассмотреть некоторые нюансы и оптимизировать код. Давайте разберёмся с этим подробнее.

Проблема обновления таблицы

Ваша текущая реализация использует метод prepare_items(), который загружает данные из базы данных только один раз, когда вы вызываете его. Поэтому, когда вы добавляете новую категорию через форму, таблица не обновляется автоматически; потребуется обновление страницы для отображения новых данных.

Решение: обработка формы перед отображением таблицы

Чтобы обновить таблицу сразу после добавления нового термина, вам необходимо обработать данные формы перед вызовом prepare_items(). Это поможет вам убедиться, что новые данные включаются в таблицу при следующем рендеринге. Вот как вы можете это сделать:

  1. Обработайте отправку формы: Создайте метод process_form(), который будет обрабатывать отправку данных формы, проверять nonce и добавлять новый термин.

  2. Вызывайте этот метод перед подготовкой данных: Внутри функции tt_render_list_page() сначала вызывайте обработчик формы, а затем prepare_items(), чтобы обновленная таблица отображалась на экране.

Вот изменённый код, который иллюстрирует подход:

function tt_render_list_page() {
    // 1. Обработка отправки формы
    wpse_220820_process_form();

    // 2. Создание экземпляра таблицы
    $testListTable = new TT_Example_List_Table();

    // 3. Подготовка данных таблицы
    $testListTable->prepare_items();

    ?>
    <div class="wrap">
        <h1>List Table Test</h1>

        <form id="movies-filter" method="GET">
            <input type="hidden" name="page" value="<?php echo $_REQUEST['page']; ?>" />
            <?php $testListTable->display(); ?>
        </form>

        <form id="insert_term" name="insert_term" method="post" action="">
            <div class="form-field term-name-wrap">
                <label for="term">Term</label>
                <input type="text" name="term" id="term" size="40" required />
                <p>Description</p>
            </div>

            <label>Description</label>
            <input type="text" name="termdesc" id="termdesc" />
            <input type="submit" value="Add term" id="submit" name="submit" />
            <input type="hidden" name="action" value="new_term" />
            <?php wp_nonce_field('wpse_220788_new_term', 'new_term_nonce'); ?>
        </form>
    </div>
    <?php
}

function wpse_220820_process_form() {
    if (!empty($_POST['action']) && $_POST['action'] == "new_term") {
        // Проверка nonce для безопасности
        if (!empty($_POST['new_term_nonce']) && wp_verify_nonce($_POST['new_term_nonce'], 'wpse_220788_new_term')) {
            if (isset($_POST['term']) && !empty($_POST['term'])) {
                $new_term    = sanitize_text_field($_POST['term']);
                $description = sanitize_text_field($_POST['termdesc']); // Обратите внимание на правильное имя поля
                wp_insert_term(
                    $new_term,
                    'productcat',
                    array('description' => $description)
                );
            }
        }
    }
}

Объяснение изменений

  1. Обработка формы перед отображением таблицы: Метод wpse_220820_process_form() вызывается в начале функции tt_render_list_page() для обработки входящей формы.

  2. Проверка безопасности: Проверка nonce защищает ваш код от потенциальных атак.

  3. Использование sanitize_text_field: Это помогает избежать возможных уязвимостей, связанных с вводом.

Заключение

Следуя вышеуказанным рекомендациям, вы сможете обновлять данные в таблице WP_List_Table сразу после добавления новой категории без необходимости вручную обновлять страницу. Это обеспечит более плавный и интерактивный пользовательский опыт.

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

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