Как создать настраиваемые параметры фильтрации в wp_list_table?

13 апр. 2016 г., 16:39:51
Просмотры: 27.5K
Голосов: 9

Я использовал класс wp_list_table для создания своей пользовательской таблицы в панели администратора. Это работает нормально.

Теперь я хочу добавить фильтры, как показано на изображении ниже. Пример фильтров WordPress в административной панели

Вот мой существующий код для отображения административной таблицы с моей пользовательской информацией.

if( ! class_exists( 'WP_List_Table' ) ) {
    require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}

class Kv_subscribers_list extends WP_List_Table {

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

        parent::__construct( array(
            'singular'  => 'notification',  // единственное число
            'plural'    => 'notifications', // множественное число
            'ajax'      => false      
        ) );        
    }

    function column_default($item, $column_name){
        switch($column_name){
            case 'email':
            case 'date':
            case 'common':          
            case 'unit_id':          
                return $item[$column_name];
            default:
                return print_r($item,true); // Показать весь массив для целей отладки
        }
    }

    function column_email($item){       
        $actions = array(
            'email'     => sprintf('<a href="?page=%s&action=%s&email_id=%s">E-mail</a>',$_REQUEST['page'],'email',$item['id']),
            'delete'    => sprintf('<a href="?page=%s&action=%s&delete_id=%s">Удалить</a>',$_REQUEST['page'],'delete',$item['id']),
        );

        // Вернуть содержимое заголовка
        return sprintf('%1$s %2$s',
            /*$1%s*/ $item['email'],          
            /*$2%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'],  
            /*$2%s*/ $item['id']                
        );
    }

    function get_columns(){
        $columns = array(
            'cb'        => '<input type="checkbox" />', // Отобразить чекбокс вместо текста
            'email'=>__('Дата'),  
            'date'=>__('Дата'),  
            'common'=>__('Общее уведомление'),           
            'unit_id'=>__('Уникальный ID')
        );
        return $columns;
    }

   public function get_sortable_columns() {
        $sortable_columns = array(
            'email'   => array('wp_user_id',false),     // true означает, что уже отсортировано
            'date'    => array('date',false),
            'common'  => array('common',false)
        );
        return $sortable_columns;
    }

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

   public function process_bulk_action() {
        global $wpdb; 
        $notifications_tbl = $wpdb->prefix.'newsletter';

        if( 'delete'===$this->current_action() ) {
            foreach($_POST['notification'] as $single_val){
                $wpdb->delete( $notifications_tbl, array( 'id' => (int)$single_val ) );             
            }
            $redirect_url =  get_admin_url( null, 'admin.php?page=subscribers' );
            wp_safe_redirect($redirect_url); 
            wp_die('Элементы удалены (или были бы удалены, если бы у нас были элементы для удаления)!');
        } 
        if( 'email'===$this->current_action() ) {           
                $result_email_ar = implode("-",$_POST['notification']);
            $redirect_url =  get_admin_url( null, 'admin.php?page=kvcodes&ids='.$result_email_ar  );
            wp_safe_redirect($redirect_url);        

            wp_die('  ');
        }       
    }

    function prepare_items() {
        global $wpdb; // Используется только при выполнении запросов к базе данных
        $database_name = $wpdb->prefix.'newsletter' ;
        $per_page = 10;
        $query = "SELECT * FROM $database_name ORDER BY id DESC";

        $columns = $this->get_columns();
        $hidden = array();
        $sortable = $this->get_sortable_columns();

        $this->_column_headers = array($columns, $hidden, $sortable);        

        $this->process_bulk_action();

        $data =  $wpdb->get_results($query, ARRAY_A );

        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)   // Необходимо вычислить общее количество страниц
        ) );
    }
}//class

и

echo '<form method="post">';
    $mydownloads = new Kv_subscribers_list(); 
    echo '</pre><div class="wrap"><h2>Подписчики<a href="'."http://".$_SERVER["SERVER_NAME"].$_SERVER['REQUEST_URI'].'&add_new=true" class="add-new-h2">Добавить новый</a></h2>'; 
    $mydownloads->prepare_items(); 
    $mydownloads->display(); 
    echo '</div></form>'; 

Теперь я хочу создать фильтры вида

Все || Опубликованные || Корзина

Мне нужно создать пользовательский фильтр такого типа.

0
Все ответы на вопрос 3
1
17

Код

class Kv_subscribers_list extends WP_List_Table {

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

    parent::__construct( array(
        'singular'  => 'notification',  
        'plural'    => 'notifications',   
        'ajax'      => false      
    ) );        
}

protected function get_views() { 
    $status_links = array(
        "all"       => __("<a href='#'>Все</a>",'my-plugin-slug'),
        "published" => __("<a href='#'>Опубликованные</a>",'my-plugin-slug'),
        "trashed"   => __("<a href='#'>Удаленные</a>",'my-plugin-slug')
    );
    return $status_links;
}

function column_default($item, $column_name){
    switch($column_name){
        case 'email':
        case 'date':
        case 'common':          
        case 'unit_id':          
            return $item[$column_name];
        default:
            return print_r($item,true); //Показать весь массив для целей отладки
    }
}

function column_email($item){       
    $actions = array(
        'email'     => sprintf('<a href="?page=%s&action=%s&email_id=%s">E-mail</a>',$_REQUEST['page'],'email',$item['id']),
        'delete'    => sprintf('<a href="?page=%s&action=%s&delete_id=%s">Удалить</a>',$_REQUEST['page'],'delete',$item['id']),
    );

    //Возвращаем содержимое заголовка
    return sprintf('%1$s %2$s',
        /*$1%s*/ $item['email'],          
        /*$2%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'],  
        /*$2%s*/ $item['id']                
    );
}

function get_columns(){
    $columns = array(
        'cb'        => '<input type="checkbox" />', 
        'email'=>__('Email'),  
        'date'=>__('Дата'),  
        'common'=>__('Общее уведомление'),           
        'unit_id'=>__('Уникальный ID')
    );
    return $columns;
}
public function get_sortable_columns() {
    $sortable_columns = array(
        'email'   => array('wp_user_id',false),     //true означает, что уже отсортировано
        'date'    => array('date',false),
        'common'  => array('common',false)
    );
    return $sortable_columns;
}
public function get_bulk_actions() {
    $actions = array(
        'delete'    => 'Удалить',
        'email'     => 'Email'
    );
    return $actions;
}

public function process_bulk_action() {

    global $wpdb; 
    $notifications_tbl = $wpdb->prefix.'newsletter';

    if( 'delete'===$this->current_action() ) {
        foreach($_POST['notification'] as $single_val){
            $wpdb->delete( $notifications_tbl, array( 'id' =>    (int)$single_val ) );             
        }
        $redirect_url =  get_admin_url( null, 'admin.php?page=subscribers' );
        wp_safe_redirect($redirect_url); 
        wp_die('Элементы удалены (или были бы удалены, если бы они существовали)!');
    } 
    if( 'email'===$this->current_action() ) {           
            $result_email_ar = implode("-",$_POST['notification']);
        $redirect_url =  get_admin_url( null, 'admin.php?page=kvcodes&ids='.$result_email_ar  );
        wp_safe_redirect($redirect_url);        

        wp_die('  ');
    }       
}

function prepare_items() {
    global $wpdb; //Используется только если выполняются запросы к базе данных
    $database_name = $wpdb->prefix.'newsletter' ;
    $per_page = 10;
    $query = "SELECT * FROM $database_name ORDER BY id DESC";

    $columns = $this->get_columns();
    $hidden = array();
    $sortable = $this->get_sortable_columns();

    $this->_column_headers = array($columns, $hidden, $sortable);        

    $this->process_bulk_action();

    $data =  $wpdb->get_results($query, ARRAY_A );

    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)   //Нужно вычислить общее количество страниц
    ) );
}
}//class

Страница админки и пример рендеринга

function o_add_menu_items(){
    add_menu_page('Plugin List Table', 'Подписчики', 'activate_plugins', 'subscribers', 'o_render_list_page');
} 
add_action('admin_menu', 'o_add_menu_items');

function o_render_list_page() {
    $mydownloads = new Kv_subscribers_list();
    $title = __("Подписчики","my_plugin_slug");
    ?>
    <div class="wrap">
        <h1>
            <?php echo esc_html( $title );?>
             <!-- Проверка прав на редактирование -->
             <a href="<?php echo admin_url( 'admin.php?page=subscribers&add_new=true' ); ?>" class="page-title-action">
                <?php echo esc_html_x('Добавить новый', 'my-plugin-slug'); ?>
            </a>
            <?php
            ?>
        </h1>
    </div>
    <?php $mydownloads->views(); ?>
    <form method="post">
    <?php 

        $mydownloads->prepare_items(); 
        $mydownloads->display();
    ?>
    </form>
<?php
}

Объяснение

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

Метод views класса WP_List_Table использует get_views для отображения списка этих ссылок, которые мы возвращаем в get_views в виде ассоциативного массива с разделителем |.

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

Посмотрите, как другие таблицы используют это. Например, проверьте WP_Posts_List_Table.

После переопределения метода разместите $mydownloads->views();. Убедитесь, что все строки экранированы и интернационализированы.

Использование фильтра

Мы можем использовать фильтр views_{$this->screen->id} после добавления метода get_views. Предполагая, что toplevel_page_subscribers - это ID экрана

add_filter('views_toplevel_page_subscribers','my_plugin_slug_status_links',10, 1);

function my_plugin_slug_status_links($views) {
   $views['scheduled'] =  "<a href='#'>Запланированные</a>";
   return $views;
}
16 апр. 2016 г. 11:39:18
Комментарии

На мой взгляд, самый аккуратный способ - использовать extra_tablenav, как описал @metita

hbit hbit
6 янв. 2022 г. 22:31:32
0

Хоть это и довольно поздно, но так как это первый результат в Google по запросу "фильтрация WP_List_Table", я должен сказать вам, что в вашем классе-наследнике можно переопределить функцию extra_tablenav:

class Kv_subscribers_list extends WP_List_Table {

    function extra_tablenav( $which )
    {
        switch ( $which )
        {
            case 'top':
                // Ваш HTML-код для вывода
                break;

            case 'bottom':
                // Ваш HTML-код для вывода
                break;
        }
    }
}

Если вам нужно выводить код в обоих разделах, просто проигнорируйте switch и поместите ваш HTML-код в начало функции.

15 июл. 2020 г. 17:37:49
0

Вы можете использовать

<?php
class Kv_subscribers_list extends WP_List_Table {

    function extra_tablenav( $which )
    {
        switch ( $which )
        {
            case 'top':
                // Ваш HTML-код для вывода
                global $wpdb, $wp_locale;

                    $extra_checks = "AND status != 'auto-draft'";
                    if ( ! isset( $_GET['status'] ) || 'trash' !== $_GET['status'] ) {
                        $extra_checks .= " AND status != 'trash'";
                    } elseif ( isset( $_GET['status'] ) ) {
                        $extra_checks = $wpdb->prepare( ' AND status = %s', $_GET['status'] );
                    }

                    $sql = "
                    SELECT DISTINCT YEAR( create_date ) AS year, MONTH( create_date ) AS month
                    FROM ".$wpdb->prefix."audio_record
                    WHERE 1 = 1
                    $extra_checks
                    ORDER BY create_date DESC";
        
                    $months = $wpdb->get_results(
                        $wpdb->prepare(
                            $sql
                        )
                    );
                    $month_count = count( $months );

                    if ( ! $month_count || ( 1 == $month_count && 0 == $months[0]->month ) ) {
                        return;
                    }
                    $m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;

                    $wp_query = add_query_arg();
                    $wp_query = remove_query_arg('m');
                    $link = esc_url_raw($wp_query);
                    ?>
                    <div class="alignleft actions">
                    <select name="m" id="filter-by-date">
                        <option<?php selected( $m, 0 ); ?> value="0" data-rc="<?php _e($link); ?>"><?php _e( 'Все даты' ); ?></option>
                    <?php

                    foreach ( $months as $arc_row ) {
                        if ( 0 == $arc_row->year ) {
                            continue;
                        }

                        $month = zeroise( $arc_row->month, 2 );
                        $year  = $arc_row->year;

                        $wp_query = add_query_arg('m', $arc_row->year . $month);
                        $link = esc_url_raw($wp_query);

                        printf(
                            "<option %s value='%s' data-rc='%s'>%s</option>\n",
                            selected( $m, $year . $month, false ),
                            esc_attr( $arc_row->year . $month ),
                            esc_attr( $link),
                            /* translators: 1: Название месяца, 2: 4-значный год. */
                            sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month ), $year )
                        );
                    }
                    ?>
                    </select>
                    <a href="javascript:void(0)" class="button" onclick="window.location.href = jQuery('#filter-by-date option:selected').data('rc');">Фильтр</a>
                    </div>
                    <?php
                break;
                break;

            case 'bottom':
                // Ваш HTML-код для вывода
                break;
        }
    }
}

а для действия запроса, вы можете добавить код в

public function prepare_items()

или функцию get_customers
$this->items = self::get_customers($per_page, $current_page);

<?php
        //public static function get_customers($per_page = 20, $page_number = 1) 


        if (!empty($_REQUEST['m'])) {
            $search = $_REQUEST['m'];
            $year = substr($search,0,4);
            $month = substr($search,4,5);

            if(!empty($year)){
                $sql .= ' And YEAR(create_date)="' . $year . '"';
            }
            if(!empty($month)){
                $sql .= ' And MONTH(create_date)="' . $month . '"';
            }
        }

Это пример получения данных из моей базы данных
При нажатии кнопки "Фильтр" произойдет переход по URL из data-rc

Изображение с примером интерфейса

4 сент. 2021 г. 14:07:08