9

I used wp_list_table class to create my custom table in the backend. It's working fine.

Now, I want to add filters like in the below image. enter image description here

Here is my existing code to render admin table with my custom information's.

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); //Show the whole array for troubleshooting purposes
        }
    }

    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">Delete</a>',$_REQUEST['page'],'delete',$item['id']),
        );

        //Return the title contents
        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" />', //Render a checkbox instead of text
            'email'=>__('Date'),  
            'date'=>__('Date'),  
            'common'=>__('Common Alert'),           
            'unit_id'=>__('Unique ID')
        );
        return $columns;
    }

   public function get_sortable_columns() {
        $sortable_columns = array(
            'email'   => array('wp_user_id',false),     //true means it's already sorted
            'date'    => array('date',false),
            'common'  => array('common',false)
        );
        return $sortable_columns;
    }

   public function get_bulk_actions() {
        $actions = array(
            'delete'    => '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('Items deleted (or they would be if we had items to delete)!');
        } 
        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; //This is used only if making any database queries
        $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'; //If no sort, default to title
            $order = (!empty($_REQUEST['order'])) ? $_REQUEST['order'] : 'asc'; //If no order, default to asc
            $result = strcmp($a[$orderby], $b[$orderby]); //Determine sort order
            return ($order==='asc') ? $result : -$result; //Send final sort direction to 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,                  //WE have to calculate the total number of items
            'per_page'    => $per_page,                     //WE have to determine how many items to show on a page
            'total_pages' => ceil($total_items/$per_page)   //WE have to calculate the total number of pages
        ) );
    }
}//class

and

echo '<form method="post">';
    $mydownloads = new Kv_subscribers_list(); 
    echo '</pre><div class="wrap"><h2>Subscribers<a href="'."http://".$_SERVER["SERVER_NAME"].$_SERVER['REQUEST_URI'].'&add_new=true" class="add-new-h2">Add New</a></h2>'; 
    $mydownloads->prepare_items(); 
    $mydownloads->display(); 
    echo '</div></form>'; 

Now, I want to make the filters like

All || Published || Trash

I need to create a custom filter like this.

3 Answers 3

17
+25

Code

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='#'>All</a>",'my-plugin-slug'),
        "published" => __("<a href='#'>Published</a>",'my-plugin-slug'),
        "trashed"   => __("<a href='#'>Trashed</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); //Show the whole array for troubleshooting purposes
    }
}

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">Delete</a>',$_REQUEST['page'],'delete',$item['id']),
    );

    //Return the title contents
    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'=>__('Date'),  
        'common'=>__('Common Alert'),           
        'unit_id'=>__('Unique ID')
    );
    return $columns;
}
public function get_sortable_columns() {
    $sortable_columns = array(
        'email'   => array('wp_user_id',false),     //true means it's already sorted
        'date'    => array('date',false),
        'common'  => array('common',false)
    );
    return $sortable_columns;
}
public function get_bulk_actions() {
    $actions = array(
        'delete'    => '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('Items deleted (or they would be if we had items to delete)!');
    } 
    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; //This is used only if making any database queries
    $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'; //If no sort, default to title
        $order = (!empty($_REQUEST['order'])) ? $_REQUEST['order'] : 'asc'; //If no order, default to asc
        $result = strcmp($a[$orderby], $b[$orderby]); //Determine sort order
        return ($order==='asc') ? $result : -$result; //Send final sort direction to 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,                  //WE have to calculate the total number of items
        'per_page'    => $per_page,                     //WE have to determine how many items to show on a page
        'total_pages' => ceil($total_items/$per_page)   //WE have to calculate the total number of pages
    ) );
}
}//class

Admin Page & Rendering Sample

function o_add_menu_items(){
    add_menu_page('Plugin List Table', 'Sub', '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 = __("Subscribers","my_plugin_slug");
    ?>
    <div class="wrap">
        <h1>
            <?php echo esc_html( $title );?>
             <!-- Check edit permissions -->
             <a href="<?php echo admin_url( 'admin.php?page=subscribers&add_new=true' ); ?>" class="page-title-action">
                <?php echo esc_html_x('Add New', 'my-plugin-slug'); ?>
            </a>
            <?php
            ?>
        </h1>
    </div>
    <?php $mydownloads->views(); ?>
    <form method="post">
    <?php 

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

Explanation

We need to override WP_List_Table class method get_views to get status links on the top.By default it is an empty array.

views method of WP_List_Table uses get_views to display list of those links that we return in the get_views as an associative array with separator |.

We can also override views method to have more control , for example if we want to change separator.

Take a look at how other list tables are using that. For instance check WP_Posts_List_Table.

After you have overridden the method then place $mydownloads->views(); .be sure to escape all and internationalize strings.

Using Filter

We can use views_{$this->screen->id} filter once we have added get_views method. Assuming toplevel_page_subscribers as screen 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='#'>Scheduled</a>";
   return $views;
}
1
  • In my opinion the cleanest way is to use extra_tablenav like @metita described it
    – hbit
    Jan 6, 2022 at 20:31
5

Well, I know this is quite late, but since this is the first result in google when searching for WP_List_Table filtering, I must tell you that there's extra_tablenav function available to be overrode in your class extension:

class Kv_subscribers_list extends WP_List_Table {

    function extra_tablenav( $which )
    {
        switch ( $which )
        {
            case 'top':
                // Your html code to output
                break;

            case 'bottom':
                // Your html code to output
                break;
        }
    }
}

If you want to output in both sections just ignore the switch and set your HTML code straight at the beginning of the function.

1

You can use

<?php
class Kv_subscribers_list extends WP_List_Table {

    function extra_tablenav( $which )
    {
        switch ( $which )
        {
            case 'top':
                // Your html code to output
                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( 'All dates' ); ?></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: Month name, 2: 4-digit year. */
                            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');">Filter</a>
                    </div>
                    <?php
                break;
                break;

            case 'bottom':
                // Your html code to output
                break;
        }
    }
}

and for action query, you can add code in

public function prepare_items()

or funtion 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 . '"';
            }
        }

This is example for get form my database
When click Filter button will go to url from data-rc

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.