Класс WP_List_Table
в WordPress используется для отображения списка данных, например, пользователей, плагинов, комментариев или постов. Этот класс содержит почти все методы отображения, сортировки, разбиения на страницы и поиска информации. А что может быть очевиднее, чем его использование для создания собственных плагинов?
В этой статье мы постараемся разобрать по шагам создание таблицы, полностью подстроенной под ваши нужды. Здесь аренда выделенного сервера
- Предварительная работа
- Основы
- Сортировка
- Действия
- Массовые действия
- Разбиение на страницы
- Поиск
- Настройки экрана
- Стили таблиц
- Другие настройки
Предварительная работа
Для пробы, мы создадим небольшой плагин, добавляющий пункт меню:
1 2 3 4 5 6 7 8 9 10 |
<?php /* Plugin Name: My List Table Example */ ?> <div class="wrap"> <div id="icon-users" class="icon32"></div> <h2>My List Table Test/h2> </div> <?php |
Основы
Для начала, мы создадим таблицу, имеющую только базовые функции. В первую очередь нам нужно убедиться, что необходимый класс включён, поскольку WP_List_Table
не загружается автоматически:
1 2 3 |
if( ! class_exists( 'WP_List_Table' ) ) { require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' ); } |
Чтобы создать свою таблицу, вам нужно получить класс из WP_List_Table
:
1 2 3 4 |
class My_List_Table extends WP_List_Table { } $myListTable = new My__List_Table(); |
Далее создаём пример данных. Обычно эти данные читаются из базы данных:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var $example_data = array( array('ID' => 1,'booktitle' => 'Quarter Share', 'author' => 'Nathan Lowell', 'isbn' => '978-0982514542'), array('ID' => 2, 'booktitle' => '7th Son: Descent','author' => 'J. C. Hutchins', 'isbn' => '0312384378'), array('ID' => 3, 'booktitle' => 'Shadowmagic', 'author' => 'John Lenahan', 'isbn' => '978-1905548927'), array('ID' => 4, 'booktitle' => 'The Crown Conspiracy', 'author' => 'Michael J. Sullivan', 'isbn' => '978-0979621130'), array('ID' => 5, 'booktitle' => 'Max Quick: The Pocket and the Pendant', 'author' => 'Mark Jeffrey', 'isbn' => '978-0061988929'), array('ID' => 6, 'booktitle' => 'Jack Wakes Up: A Novel', 'author' => 'Seth Harwood', 'isbn' => '978-0307454355') ); |
Прежде чем мы сможем отобразить данные в таблице, мы должны определить некоторые методы и переменные:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function get_columns(){ $columns = array( 'booktitle' => 'Title', 'author' => 'Author', 'isbn' => 'ISBN' ); return $columns; } function prepare_items() { $columns = $this->get_columns(); $hidden = array(); $sortable = array(); $this->_column_headers = array($columns, $hidden, $sortable); $this->items = $this->example_data;; } |
Метод get_columns()
необходим для маркировки столбцов внизу и вверху таблицы. Ключи в массиве должны быть теми же, что и в массиве данных, иначе соответствующие столбцы не будут отображены.
prepare_items
определяет два массива, управляющие работой таблицы:
$hidden
определяет скрытые столбцы (см. Опции экрана),$sortable
определяет, может ли таблица быть отсортирована по этому столбцу.
Наконец, метод назначает данные из примера на переменную представления данных класса — items
.
Прежде чем отобразить каждый столбец, WordPress ищет методы типа column_{key_name}
, например, function column_booktitle
. Такой метод должен быть указан для каждого столбца. Но чтобы не создавать эти методы для всех столбцов в отдельности, можно использовать column_default
. Эта функция обработает все столбцы, для которых не определён специальный метод:
1 2 3 4 5 6 7 8 9 10 |
function column_default( $item, $column_name ) { switch( $column_name ) { case 'booktitle': case 'author': case 'isbn': return $item[ $column_name ]; default: return print_r( $item, true ) ; //Мы отображаем целый массив во избежание проблем } } |
В нашем примере метод возвратит заголовок для каждого столбца, а если столбец не найден, будет отображено содержимое массива $item
.
Это основные компоненты, необходимые для того, чтобы определить пользовательский класс таблицы. Теперь всё, что вам нужно — это добавить страницу администрирования, создать экземпляр нашего класса, подготовить элементы и вызвать display()
, чтобы отобразить таблицу:
1 2 3 4 5 6 7 8 9 10 11 12 |
function my_add_menu_items(){ add_menu_page( 'My Plugin List Table', 'My List Table Example', 'activate_plugins', 'my_list_test', 'my_render_list_page' ); } add_action( 'admin_menu', 'my_add_menu_items' ); function my_render_list_page(){ $myListTable = new My_Example_List_Table(); echo '<div class="wrap"><h2>My List Table Test</h2>'; $myListTable->prepare_items(); $myListTable->display(); echo '</div>'; } |
Это минимальная возможная версия WP_List_Table:
Сортировка
В данный момент элементы представлены в таком порядке, в котором они определены в коде, т.к. класс WP_List_Table
не содержит код для сортировки. Он содержит только небольшой код для маркировки сортируемых столбцов. В разделе «Основы» уже была строка $sortable = array();
, которая теперь будет изменена на:
1 |
$sortable = $this->get_sortable_columns(); |
Также нам нужен метод:
1 2 3 4 5 6 7 8 |
function get_sortable_columns() { $sortable_columns = array( 'booktitle' => array('booktitle',false), 'author' => array('author',false), 'isbn' => array('isbn',false) ); return $sortable_columns; } |
Таким образом заголовки столбцов, о которых мы говорили выше, заменены на ссылки и теперь, когда вы проводите над ними мышью, рядом появляются маленькие треугольники. Второй параметр в массиве значений $sortable_columns
отвечает за порядок сортировки столбца. Если значение true
, столбец будет сортироваться в порядке возрастания, если значение false
, столбец сортируется в порядке убывания, или не упорядочивается. Это необходимо для маленького треугольника около названия столбца, который указывает порядок сортировки, чтобы строки отображались в правильном направлении:
Если вы щёлкаете на заголовок столбца, страница будет перезагружена, а $_GET
будет содержать что-то вроде этого:
1 2 3 4 |
array 'page' => string 'my_list_test' (length=12) 'orderby' => string 'booktitle' (length=5) 'order' => string 'asc' (length=3) |
С этой информацией вы можете написать метод для сортировки наших данных из примера:
1 2 3 4 5 6 7 8 9 10 |
function usort_reorder( $a, $b ) { // Если не отсортировано, по умолчанию title $orderby = ( ! empty( $_GET['orderby'] ) ) ? $_GET['orderby'] : 'booktitle'; // Если не отсортировано, по умолчанию asc $order = ( ! empty($_GET['order'] ) ) ? $_GET['order'] : 'asc'; // Определяем порядок сортировки $result = strcmp( $a[$orderby], $b[$orderby] ); // Отправляем конечный порядок сортировки usort return ( $order === 'asc' ) ? $result : -$result; } |
Теперь, чтобы реально сортировать данные, мы должны расширить prepare_items()
:
1 2 3 4 5 |
function prepare_items() { [..] usort( $this->example_data, array( &$this, 'usort_reorder' ) ); $this->items = $this->example_data; } |
Если вы извлекаете информацию из базы данных (что наиболее вероятно), конечно же, лучше всего использовать непосредственно SQL ORDERBY
.
Действия
Если вы хотите не только отображать элементы, но и управлять ими, вам нужно определить некоторые действия:
1 2 3 4 5 6 7 8 |
function column_booktitle($item) { $actions = array( 'edit' => sprintf('<a href="?page=%s&action=%s&book=%s">Edit</a>',$_REQUEST['page'],'edit',$item['ID']), 'delete' => sprintf('<a href="?page=%s&action=%s&book=%s">Delete</a>',$_REQUEST['page'],'delete',$item['ID']), ); return sprintf('%1$s %2$s', $item['booktitle'], $this->row_actions($actions) ); } |
Эти действия появятся, если пользователь проведет курсор мыши над таблицей:
Если вы щёлкните на одну из ссылок действий, форма возвратит, к примеру, следующие данные в $_GET
:
1 2 3 4 |
array 'page' => string 'my_list_test' (length=12) 'action' => string 'delete' (length=6) 'book' => string '2' (length=1) |
Массовые действия (Bulk actions)
Bulk action осуществляются посредством переписывания метода get_bulk_actions()
и возврата связанного массива:
1 2 3 4 5 6 |
function get_bulk_actions() { $actions = array( 'delete' => 'Delete' ); return $actions; } |
Этот код просто помещает выпадающее меню и кнопку «применить» вверху и внизу таблицы:
Флажки для строк должны быть определены отдельно. Как упоминалось выше, есть метод column_{column}
для отображения столбца. cb
-столбец – особый случай:
1 2 3 4 5 |
function column_cb($item) { return sprintf( '<input type="checkbox" name="book[]" value="%s" />', $item['ID'] ); } |
В данный момент этот метод не будет обрабатываться, потому что мы должны указать классу новый столбец, расширив метод get_columns()
:
1 2 3 4 5 |
function get_columns() { $columns = array( 'cb' => '<input type="checkbox" />', [..] } |
Это также добавит в область заголовка флажок «выбрать всё»:
Если вы не хотите отображать в заголовке переключатель, просто установите значение на пустую строку. Однако вам всё ещё нужно определить пару ключ/значение, иначе никакие переключатели не будут отображаться вообще:
Если нажата кнопка «Применить», форма возвратит различные переменные: action
и action2
, содержащие выбранные действия или -1
, если пользователь не выбрал никаких действий, а если были установлены какие-то флажки, будут возвращены отмеченные строки, в нашем случае books
, к примеру:
1 2 3 4 5 6 |
'action' => string 'delete' (length=6) 'book' => array 0 => string '2' (length=1) 1 => string '6' (length=1) 'action2' => string '-1' (length=2) |
action
содержит выбор из верхнего выпадающего меню, action2
— из нижнего, а book
— id
выделенных строк, если таковые имеются. Можно использовать метод current_action()
, чтобы обратиться к action/action2
:
1 |
$action = $this->current_action(); |
Будет возвращено action
, если в меню установлен выбор, в противном случае action2
. Если ничего не установлено, метод возвратит FALSE
.
Разбиение на страницы
Прежде всего: WordPress не разбивает ваши данные на страницы ни в каком случае. Он только содержит метод для отображения навигационной панели в верхней правой и нижней правой частях таблицы:
Вы должны указать методу, сколько элементов у вас всего, сколько элементов нужно отобразить на странице, и самое главное, данные, которые должны быть отображены на странице:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function prepare_items() { [...] $per_page = 5; $current_page = $this->get_pagenum(); $total_items = count($this->example_data); // необходимо только потому, что у нас пример данных $this->found_data = array_slice($this->example_data,(($current_page-1)*$per_page),$per_page); $this->set_pagination_args( array( 'total_items' => $total_items, //Мы должны вычислить общее количество элементов 'per_page' => $per_page //Мы должны определить, сколько элементов отображается на странице ) ); $this->items = $this->found_data; } |
Как указано в комментариях, array_slice
необходим только потому, что мы используем данные из примера. Если вы извлекаете данные из базы данных, вам нужно только загрузить необходимые данные, используя SQL LIMIT
.
Поиск
Если у вас большое количество данных, поисковая строка упростит доступ к определённым элементам:
1 |
$myListTable->search_box('search', 'search_id'); |
Текст кнопки search
определён первым параметром, id
поля ввода — вторым. Результат будет следующим:
1 2 3 4 5 6 |
<p class="search-box"> <label class="screen-reader-text" for="search_id-search-input"> search:</label> <input id="search_id-search-input" type="text" name="s" value="" /> <input id="search-submit" class="button" type="submit" name="" value="search" /> </p> |
Метод поместит поисковую строку и кнопку поиска в правую сторону и правильно задаст их стиль. Элемент <form>
не был сгенерирован. Вы должны добавить его вручную, в нашем случае так:
1 2 3 4 |
<form method="post"> <input type="hidden" name="page" value="my_list_test" /> <?php $this->search_box('search', 'search_id'); ?> </form> |
(Скрытый элемент необходим, чтобы загрузилась правильная страница)
Чтобы отреагировать на команду поиска, вам нужно проверить содержимое $_POST['s']
и отфильтровать свои данные, перед тем, как отобразить страницу.
Настройки экрана
Все основные внутренние страницы, содержащие WP_List_Table
предоставляют раздел «Screen Options» («Настройки экрана»), где пользователь сможет выбрать, какие столбцы будут показаны, и какое количество строк будет отображаться.
Чтобы добавить опции в свой плагин, вы должны изменить текущий код. Первое, что нужно сделать — это убедиться, что настройки экрана отображены только на текущей странице:
1 2 3 4 5 6 7 8 9 10 11 12 |
$hook = add_menu_page('My Plugin List Table', 'My List Table Example', 'activate_plugins', 'my_list_test', 'my_render_list_page'); add_action( "load-$hook", 'add_options' ); function add_options() { $option = 'per_page'; $args = array( 'label' => 'Books', 'default' => 10, 'option' => 'books_per_page' ); add_screen_option( $option, $args ); } |
Этот код только отображает поле опций и кнопку применения, сохранение и загрузку данных нужно настраивать отдельно. WordPress предоставляет фильтр под названием set-screen-option
, который позаботится об этом:
1 2 3 4 |
add_filter('set-screen-option', 'test_table_set_option', 10, 3); function test_table_set_option($status, $option, $value) { return $value; } |
Настройки сохранены в таблице usermeta
в базе данных, так у каждого пользователя есть свои настройки. Чтобы найти настройки и установить отображение таблицы в соответствии с ними, метод prepare_items
должен быть изменён:
1 2 3 4 5 6 7 8 |
function prepare_items() { [..] //paging $per_page = $this->get_items_per_page('books_per_page', 5); $current_page = $this->get_pagenum(); [...] |
Вместо того, чтобы просто установить число, мы загружаем значение, определённое пользователем. Если пользователь не изменил значение, в базе данных такая опция не сохранится, и будет использовано значение по умолчанию.
Добавление переключателей для скрытия/отображения столбцов доступно в WordPress автоматически. Вам просто нужно убедиться, что экземпляр вашего произвольного класса создан раньше, чем отображена панель настроек экрана, так чтобы родительский класс мог найти имена столбцов. Поэтому соответствующий класс перемещаем в метод add_options()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function add_options() { global $myListTable; $option = 'per_page'; $args = array( 'label' => 'Books', 'default' => 10, 'option' => 'books_per_page' ); add_screen_option( $option, $args ); $myListTable = new My_Example_List_Table; } |
Выбор пользователя автоматически сохраняется с помощью Ajax функций. Однако вы должны сами позаботиться о том, чтобы столбцы были скрыты, если страница была первоначально загружена. Метод get_column_info()
возвращает все, скрытые и сортируемые таблицы. В методе prepare_items()
вместо
1 2 3 4 |
$columns = $this->get_columns(); $hidden = array(); $sortable = $this->get_sortable_columns(); $this->_column_headers = array($columns, $hidden, $sortable); |
теперь
1 |
$this->_column_headers = $this->get_column_info(); |
и столбцы установлены согласно опциям экрана.
Следует избегать использование некоторых строк, таких как следующие ключевые имена, т.к. они обрабатываются WordPress отдельно:
1 |
$special = array('_title', 'cb', 'comment', 'media', 'name', 'title', 'username', 'blogname'); |
Так ваша таблица всё ещё будет работать, но вы не сможете показать/скрыть столбцы.
Стили таблицы
Сейчас у таблицы стандартные стили WordPress. Чтобы это исправить, вам нужно адаптировать классы CSS, которые были автоматически применены к каждому столбцу. Название класса состоит из строки «column-» и ключевого имени массива $columns
, например «column-isbn» или «column-author». В качестве примера мы переопределим ширину столбцов (для простоты, стили прописаны непосредственно в HTML разделе head
):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
function _construct() { [...] add_action( 'admin_head', array( &$this, 'admin_header' ) ); [...] } function admin_header() { $page = ( isset($_GET['page'] ) ) ? esc_attr( $_GET['page'] ) : false; if( 'my_list_test' != $page ) return; echo '<style type="text/css">'; echo '.wp-list-table .column-id { width: 5%; }'; echo '.wp-list-table .column-booktitle { width: 40%; }'; echo '.wp-list-table .column-author { width: 35%; }'; echo '.wp-list-table .column-isbn { width: 20%; }'; echo '</style>'; } |
Другие настройки
Если в списке нет никаких элементов, отображается стандартное сообщение «No items found.». Если вы хотите изменить это сообщение, вы можете переписать метод no_items()
:
1 2 3 |
function no_items() { _e( 'No books found, dude.' ); } |
а как сделать чтобы выводилось имя книги как ссылка и по клику на неё можно было ее изменить?
То что нужно спасибо за материал.
Где конструктор класса? Где описание его параметров? Это я только начала читать!!!
Примеры не скачиваются