САМОСТОЯТЕЛЬНЫЕ ФИЛЬТРЫ В ТАБЛИЦАХ ПОСТОВ, КОММЕНТАРИЕВ, ПОЛЬЗОВАТЕЛЕЙ И ТАКСОНОМИИ
В этой статье мы обсудим, как добавить дополнительные фильтры для списков постов (таблица постов в административной панели), списка комментариев (таблица комментариев) и списка пользователей (таблица пользователей). Будет представлена теория и примеры.
Вспомните таблицу постов в административной панели — над таблицей находятся два выпадающих списка: по дате и по категориям. Мы говорим о таких фильтрах. Ниже показано, как добавить свои собственные фильтры (выпадающие списки) и обработать запрос, отфильтровывая список постов по выбранным значениям.
Возможности описанных ниже фильтров можно расширить с помощью дополнительных сортируемых колонок в таблице. Фильтры могут "обрезать" список постов, который затем можно сортировать по колонкам.
Содержание
- Все хуки для вставки HTML-фильтров
- Посты (включая вложения)
- Комментарии
- Пользователи
- Таксономии
- Параметр $which
- Примеры
- Фильтр в таблице постов
- Фильтр в таблице комментариев
- Фильтр в таблице пользователей
- Фильтр в таблице терминов таксономии
Все хуки для вставки HTML-фильтров
Фильтрация постов в административной панели. Фильтры в таблице списка постов могут быть добавлены для любого типа постов, комментариев или пользователей. Всё это делается с помощью необходимых хуков. Логика везде одинаковая: мы добавляем HTML-код выпадающего списка — элемент формы <select>
, а затем обрабатываем запрос.
Теперь давайте посмотрим на все возможные хуки.
Посты (включая вложения)
restrict_manage_posts
:
// Добавляет HTML только над таблицей постов в стандартном блоке фильтра.
do_action('restrict_manage_posts', $post_type, $which);
manage_posts_extra_tablenav
:
// Добавляет HTML над или под таблицей постов, после кнопки "Отправить" стандартных фильтров.
do_action('manage_posts_extra_tablenav', $which);
Комментарии
restrict_manage_comments
:
// Добавляет HTML в верхней части таблицы комментариев в стандартном блоке фильтра.
do_action('restrict_manage_comments');
manage_comments_nav
:
// Добавляет HTML над и под таблицей комментариев, после кнопки "Отправить" фильтров.
do_action('manage_comments_nav', $comment_status);
Пользователи
restrict_manage_users
:
// Добавляет HTML над и под таблицей пользователей, в стандартном блоке фильтра.
do_action('restrict_manage_users', $which);
Таксономии
Для таксономий такие фильтры отсутствуют. Ниже показан пример того, как добавить фильтры для них.
Параметр $which
Во всех фильтрах может быть верхняя (top) или нижняя (bottom) позиция, что означает вывод указанного кода в верхней или нижней части таблицы.
Примеры
Фильтр в таблице постов
Предположим, у нас есть тип поста "событие" и таксономия "сезон". Нам нужно добавить фильтр, чтобы в таблице постов оставались только посты из указанного элемента таксономии "сезон".
Для этого мы используем два фильтра: restrict_manage_posts
и pre_get_posts
:
// Фильтр - добавляем выпадающий список
add_action('restrict_manage_posts', 'add_event_table_filters');
// Обработка запроса
add_action('pre_get_posts', 'add_event_table_filters_handler');
function add_event_table_filters($post_type) {
echo '
';
// Для динамического построения select можно использовать wp_dropdown_categories()
}
function add_event_table_filters_handler($query) {
$cs = function_exists('get_current_screen') ? get_current_screen() : null;
// Убедитесь, что находимся на правильной странице в админке
if (!is_admin() || empty($cs->post_type) || $cs->post_type != 'event' || $cs->id != 'edit-event') {
return;
}
// Сезон
if (@$_GET['sel_season'] != -1) {
$selected_id = @$_GET['sel_season'] ?: 20;
$query->set('tax_query', array(['taxonomy' => 'season', 'terms' => $selected_id]));
}
}
Мы получим работающий фильтр:
Фильтр в таблице комментариев
Условия: для комментариев установлен статус, который записывается в мета-поле комментария. Нам нужно сделать возможность фильтровать список по статусу в таблице комментариев. У нас 3 статуса: "вопрос" (Question), "спасибо" (Thank you), "полезно" (Useful).
Задача: отобразить эти статусы в выпадающе�� меню в фильтрах таблицы комментариев и обработать запрос — если статус выбран, изменить запрос, оставив только комментарии с указанным статусом в таблице.
Для этого мы используем два фильтра: restrict_manage_comments
и parse_comment_query
:
// Добавляет HTML фильтр
add_action('restrict_manage_comments', 'add_comment_filter_select');
// Изменение запроса
add_action('parse_comment_query', 'change_comment_request2');
function add_comment_filter_select() {
$cond = @$_GET['condition'];
?>
base != 'edit-comments' || $cs->id != 'edit-comments') {
return;
}
// Выход, если это запрос для получения номера страницы get_page_of_comment()
$qv = $query->query_vars;
if ($qv['fields'] == 'ids' && $qv['count']) {
return;
}
// Изменение запроса
$query->query_vars['meta_query'] = array(
array(
'key' => 'condition',
'value' => sanitize_key($_GET['condition'])
),
);
}
В результате у нас будет такой работающий фильтр:
JavaScript и атрибут onchange
добавлены для удобства. Это сделано, чтобы при выборе значения фильтр применялся сразу, а не после нажатия кнопки фильтра.
Другой хук для изменения запросов комментариев
Также есть возможность использовать хук comments_clauses
для изменения запроса.
// Изменяем запрос
add_filter('comments_clauses', 'change_comment_request', 10, 2);
function change_comment_request($clauses, $query) {
// Не наш запрос
if (empty($_GET['condition']) || !is_admin()) {
return $clauses;
}
// Убедитесь, что мы на странице таблицы комментариев
$cs = get_current_screen();
if ($cs->base != 'edit-comments' || $cs->id != 'edit-comments') {
return $clauses;
}
// Выход, если это запрос для получения номера страницы get_page_of_comment()
$qv = $query->query_vars;
if ($qv['fields'] == 'ids' && $qv['count']) {
return $clauses;
}
// Изменение запроса
global $wpdb;
$clauses['join'] = " LEFT JOIN $wpdb->commentmeta cm ON (cm.comment_id = $wpdb->comments.comment_ID)";
$clauses['where'] .= $wpdb->prepare(
" AND cm.meta_key='condition' AND cm.meta_value = %s",
$_GET['condition']
);
return $clauses;
}
Фильтр в таблице пользователей
Предположим, каждый пользователь на сайте должен быть активирован, и во время регистрации активационный ключ записывается в мета-поле activation_key
. В момент активации это поле удаляется.
Задача: отобразить фильтр в таблице пользователей, чтобы показать только активированных пользователей или, наоборот, только неактивированных. То есть нам нужно отобразить выпадающий список с выбором статуса пользователя (активирован, неактивирован). И нам нужно обработать запрос, отобрав таблицу пользователей в соответствии с запросом.
// Добавляет HTML над и под таблицей пользователей, в стандартном блоке фильтра.
add_action('restrict_manage_users', 'add_users_list_filters');
// Изменение запроса - вариант 1. С версии 4.0
add_action('pre_get_users', 'users_filter_handler');
function add_users_list_filters($which) {
// Только в верхней части
if ($which != 'top') {
return;
}
$activated = @$_GET['u_activated'];
?>
id !== 'users') {
return;
}
global $wpdb;
if (!empty($_GET['u_activated'])) {
$compare = $_GET['u_activated'] == 'yes' ? 'NOT EXISTS' : 'EXISTS';
$uquery->set('meta_query', array(array('key' => 'activation_key', 'compare' => $compare)));
if (empty($_GET['orderby'])) {
$uquery->set('order', 'DESC');
$uquery->set('orderby', 'user_registered');
}
}
}
Мы получим такой работающий фильтр:
Как и в предыдущем примере, я добавил JavaScript, чтобы при изменении значения выборка применялась сразу без лишних действий — нажатия кнопки "фильтр".
Фильтр в таблице терминов таксономии
На версии WP 4.6 такой фильтр для таблицы терминов таксономии не предусмотрен. Более того, я пытался найти обходные пути, но пространства для маневра тоже немного...
Ниже представлен, возможно, единственный способ добавить фильтры в таблицу терминов таксономии:
Это демонстрационный пример, где мы добавим возможность обрезать список терминов в таблице, оставляя только родительские...
$taxonomy = 'category'; // таксономия, для которой все делается
// Вызываем ob_start()
add_action("{$taxonomy}_add_form", function($taxonomy) {
ob_start();
});
// Вызываем ob_get_clean(), где получаем готовый HTML всей таблицы
// через preg_replace мы вставляем нужный HTML в нужное место
// Выводим результат на экран
add_action("after-{$taxonomy}-table", function($taxonomy) {
$html = ob_get_clean();
$__preg_replace_callback = function($match) {
$val = @$_GET['parent_only'];
ob_start();
?>
)~', $__preg_replace_callback, $html);
});
Чтобы копать в этом направлении, вам нужно взглянуть на следующие файлы:
wp-admin/edit-tags.php
wp-admin/includes/class-wp-terms-list-table.php
wp-admin/includes/class-wp-list-table.php
Хук для изменения запроса
// Изменить запрос - вариант 1
// $this->query_vars = apply_filters('get_terms_args', $query, $taxonomies);
add_filter('get_terms_args', 'my_terms_filter_handler');
function my_terms_filter_handler($query) {
// Проверьте, что мы находимся там, где должны быть, иначе...
if (empty($_GET['parent_only']) || !is_admin()) {
return $query;
}
// Убедитесь, что функция get_terms вызывается из класса с таблицей
// Она также вызывается на этой же странице в выпадающем меню при создании термина...
if (!($query['fields'] == 'count' || isset($query['page']))) {
return $query;
}
$query['parent'] = 0; // только родительские
return $query;
}
Другой хук для изменения SQL-запроса: terms_clauses
Этот пример не связан с предыдущим кодом. Этот код демонстрирует, как добавлять параметры запроса с помощью мета-полей для фильтрации терминов.
Предполагается, что могут быть переданы два параметра фильтрации: предмет или класс. Каждый из них соответствует своему мета-полю для терминов. Параметры могут передаваться вместе или отдельно...
// Изменение SQL-запроса
add_filter('terms_clauses', 'subject_section_sortable_orderby', 10, 3);
function subject_section_sortable_orderby($pieces, $taxonomies, $args) {
// Проверьте, что мы находимся там, где должны быть, иначе это катастрофа...
if ((!@$_GET['subject'] && !@$_GET['grade']) || !is_admin()) {
return $pieces;
}
// Убедитесь, что функция get_terms вызывается из класса с таблицей
$backtrace = debug_backtrace(false);
$backtrace = array_pop($backtrace);
if (
(@$backtrace['class'] != 'WP_List_Table') && // для самой таблицы терминов
(@$backtrace['class'] != 'WP_Terms_List_Table') // для подсчета
) {
return $pieces;
}
// Расширение запроса
global $wpdb;
if (@$_GET['subject']) {
$pieces['join'] .= " LEFT JOIN $wpdb->termmeta AS tm ON t.term_id = tm.term_id ";
$pieces['where'] .= " AND tm.meta_key = 'ss_subject' AND tm.meta_value = " . intval($_GET['subject']) . " ";
}
if (@$_GET['grade']) {
$pieces['join'] .= " LEFT JOIN $wpdb->termmeta AS tm2 ON t.term_id = tm2.term_id ";
$pieces['where'] .= " AND tm2.meta_key = 'ss_grade' AND tm2.meta_value = " . intval($_GET['grade']) . " ";
}
return $pieces;
}
Таким образом, вы можете создавать и управлять фильтрами в таблицах постов, комментариев, пользователей и терминов таксономии в WordPress. Это значительно улучшает функциональность админки и помогает лучше организовать информацию.