САМОСТОЯТЕЛЬНЫЕ ФИЛЬТРЫ В ТАБЛИЦАХ ПОСТОВ, КОММЕНТАРИЕВ, ПОЛЬЗОВАТЕЛЕЙ И ТАКСОНОМИИ

САМОСТОЯТЕЛЬНЫЕ ФИЛЬТРЫ В ТАБЛИЦАХ ПОСТОВ, КОММЕНТАРИЕВ, ПОЛЬЗОВАТЕЛЕЙ И ТАКСОНОМИИ

В этой статье мы обсудим, как добавить дополнительные фильтры для списков постов (таблица постов в административной панели), списка комментариев (таблица комментариев) и списка пользователей (таблица пользователей). Будет представлена теория и примеры.

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

Возможности описанных ниже фильтров можно расширить с помощью дополнительных сортируемых колонок в таблице. Фильтры могут "обрезать" список постов, который затем можно сортировать по колонкам.

Содержание

  • Все хуки для вставки 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. Это значительно улучшает функциональность админки и помогает лучше организовать информацию.

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *