Skip to content

Instantly share code, notes, and snippets.

@paulund
Last active March 8, 2024 10:10
Star You must be signed in to star a gist
Save paulund/7659452 to your computer and use it in GitHub Desktop.
An example code of using the WP_List_Table class. With Pagination.
<?php
/*
* Plugin Name: Paulund WP List Table Example
* Description: An example of how to use the WP_List_Table class to display data in your WordPress Admin area
* Plugin URI: http://www.paulund.co.uk
* Author: Paul Underwood
* Author URI: http://www.paulund.co.uk
* Version: 1.0
* License: GPL2
*/
if(is_admin())
{
new Paulund_Wp_List_Table();
}
/**
* Paulund_Wp_List_Table class will create the page to load the table
*/
class Paulund_Wp_List_Table
{
/**
* Constructor will create the menu item
*/
public function __construct()
{
add_action( 'admin_menu', array($this, 'add_menu_example_list_table_page' ));
}
/**
* Menu item will allow us to load the page to display the table
*/
public function add_menu_example_list_table_page()
{
add_menu_page( 'Example List Table', 'Example List Table', 'manage_options', 'example-list-table.php', array($this, 'list_table_page') );
}
/**
* Display the list table page
*
* @return Void
*/
public function list_table_page()
{
$exampleListTable = new Example_List_Table();
$exampleListTable->prepare_items();
?>
<div class="wrap">
<div id="icon-users" class="icon32"></div>
<h2>Example List Table Page</h2>
<?php $exampleListTable->display(); ?>
</div>
<?php
}
}
// WP_List_Table is not loaded automatically so we need to load it in our application
if( ! class_exists( 'WP_List_Table' ) ) {
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}
/**
* Create a new table class that will extend the WP_List_Table
*/
class Example_List_Table extends WP_List_Table
{
/**
* Prepare the items for the table to process
*
* @return Void
*/
public function prepare_items()
{
$columns = $this->get_columns();
$hidden = $this->get_hidden_columns();
$sortable = $this->get_sortable_columns();
$data = $this->table_data();
usort( $data, array( &$this, 'sort_data' ) );
$perPage = 2;
$currentPage = $this->get_pagenum();
$totalItems = count($data);
$this->set_pagination_args( array(
'total_items' => $totalItems,
'per_page' => $perPage
) );
$data = array_slice($data,(($currentPage-1)*$perPage),$perPage);
$this->_column_headers = array($columns, $hidden, $sortable);
$this->items = $data;
}
/**
* Override the parent columns method. Defines the columns to use in your listing table
*
* @return Array
*/
public function get_columns()
{
$columns = array(
'id' => 'ID',
'title' => 'Title',
'description' => 'Description',
'year' => 'Year',
'director' => 'Director',
'rating' => 'Rating'
);
return $columns;
}
/**
* Define which columns are hidden
*
* @return Array
*/
public function get_hidden_columns()
{
return array();
}
/**
* Define the sortable columns
*
* @return Array
*/
public function get_sortable_columns()
{
return array('title' => array('title', false));
}
/**
* Get the table data
*
* @return Array
*/
private function table_data()
{
$data = array();
$data[] = array(
'id' => 1,
'title' => 'The Shawshank Redemption',
'description' => 'Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency.',
'year' => '1994',
'director' => 'Frank Darabont',
'rating' => '9.3'
);
$data[] = array(
'id' => 2,
'title' => 'The Godfather',
'description' => 'The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son.',
'year' => '1972',
'director' => 'Francis Ford Coppola',
'rating' => '9.2'
);
$data[] = array(
'id' => 3,
'title' => 'The Godfather: Part II',
'description' => 'The early life and career of Vito Corleone in 1920s New York is portrayed while his son, Michael, expands and tightens his grip on his crime syndicate stretching from Lake Tahoe, Nevada to pre-revolution 1958 Cuba.',
'year' => '1974',
'director' => 'Francis Ford Coppola',
'rating' => '9.0'
);
$data[] = array(
'id' => 4,
'title' => 'Pulp Fiction',
'description' => 'The lives of two mob hit men, a boxer, a gangster\'s wife, and a pair of diner bandits intertwine in four tales of violence and redemption.',
'year' => '1994',
'director' => 'Quentin Tarantino',
'rating' => '9.0'
);
$data[] = array(
'id' => 5,
'title' => 'The Good, the Bad and the Ugly',
'description' => 'A bounty hunting scam joins two men in an uneasy alliance against a third in a race to find a fortune in gold buried in a remote cemetery.',
'year' => '1966',
'director' => 'Sergio Leone',
'rating' => '9.0'
);
$data[] = array(
'id' => 6,
'title' => 'The Dark Knight',
'description' => 'When Batman, Gordon and Harvey Dent launch an assault on the mob, they let the clown out of the box, the Joker, bent on turning Gotham on itself and bringing any heroes down to his level.',
'year' => '2008',
'director' => 'Christopher Nolan',
'rating' => '9.0'
);
$data[] = array(
'id' => 7,
'title' => '12 Angry Men',
'description' => 'A dissenting juror in a murder trial slowly manages to convince the others that the case is not as obviously clear as it seemed in court.',
'year' => '1957',
'director' => 'Sidney Lumet',
'rating' => '8.9'
);
$data[] = array(
'id' => 8,
'title' => 'Schindler\'s List',
'description' => 'In Poland during World War II, Oskar Schindler gradually becomes concerned for his Jewish workforce after witnessing their persecution by the Nazis.',
'year' => '1993',
'director' => 'Steven Spielberg',
'rating' => '8.9'
);
$data[] = array(
'id' => 9,
'title' => 'The Lord of the Rings: The Return of the King',
'description' => 'Gandalf and Aragorn lead the World of Men against Sauron\'s army to draw his gaze from Frodo and Sam as they approach Mount Doom with the One Ring.',
'year' => '2003',
'director' => 'Peter Jackson',
'rating' => '8.9'
);
$data[] = array(
'id' => 10,
'title' => 'Fight Club',
'description' => 'An insomniac office worker looking for a way to change his life crosses paths with a devil-may-care soap maker and they form an underground fight club that evolves into something much, much more...',
'year' => '1999',
'director' => 'David Fincher',
'rating' => '8.8'
);
return $data;
}
/**
* Define what data to show on each column of the table
*
* @param Array $item Data
* @param String $column_name - Current column name
*
* @return Mixed
*/
public function column_default( $item, $column_name )
{
switch( $column_name ) {
case 'id':
case 'title':
case 'description':
case 'year':
case 'director':
case 'rating':
return $item[ $column_name ];
default:
return print_r( $item, true ) ;
}
}
/**
* Allows you to sort the data by the variables set in the $_GET
*
* @return Mixed
*/
private function sort_data( $a, $b )
{
// Set defaults
$orderby = 'title';
$order = 'asc';
// If orderby is set, use this as the sort column
if(!empty($_GET['orderby']))
{
$orderby = $_GET['orderby'];
}
// If order is set use this as the order
if(!empty($_GET['order']))
{
$order = $_GET['order'];
}
$result = strcmp( $a[$orderby], $b[$orderby] );
if($order === 'asc')
{
return $result;
}
return -$result;
}
}
?>
@kamalahmed
Copy link

Hello Paul,
Thank you very much for your awesome gist. It really helped me use WP_List_Table class in my plugin I am creating. Now I can display data from my custom table very easily 👍 You are awesome :)

@CrisHazzard
Copy link

This was super helpful, thank you!

@pcross1986
Copy link

Can anyone help with this? Same thing just working with the usermeta table and needing 2 meta_values belonging to 2 different meta_keys
https://wordpress.org/support/topic/how-to-get-usermeta-meta_key-and-meta_value/

@reeganaga
Copy link

Thanks Paul
It's very helpful for me as a newbie to learn the wordpress
Excelent :)

@ashfaqshuvo007
Copy link

awesome! just what I was looking for as a noob to get started with Wp_list_table ! Cheers!

@mludi
Copy link

mludi commented Mar 27, 2019

Thanks for that Paul :-) Very helpful

@mrseadev
Copy link

thanks you

@HellBz
Copy link

HellBz commented Jun 21, 2019

Thanks Very Mutch

@kibblewhite
Copy link

This worked great for me. I was trying to get mine working together with tabs and tables. Where other tables failed, your code succeeded! Thanks.

@SamuelHadsall
Copy link

SamuelHadsall commented Jul 31, 2020

I'm trying to use this in my custom plugin based on the plugin Boiler plate https://github.com/DevinVinson/WordPress-Plugin-Boilerplate

I can get my admin page to load but getting errors like:
Notice: Trying to get property 'id' of non-object in C:\Sites\thefactorystl.wp.dnndev.me\wp-admin\includes\class-wp-list-table.php on line 454

Fatal error: Uncaught Error: Call to a member function render_screen_reader_content() on null in C:\Sites\thefactorystl.wp.dnndev.me\wp-admin\includes\class-wp-list-table.php:807 Stack trace: #0 C:\Sites\thefactorystl.wp.dnndev.me\wp-admin\includes\class-wp-list-table.php(1249): WP_List_Table->pagination('top') #1 C:\Sites\thefactorystl.wp.dnndev.me\wp-admin\includes\class-wp-list-table.php(1186): WP_List_Table->display_tablenav('top'

Update: Figured out the issue

@joho1968
Copy link

joho1968 commented Sep 9, 2020

Still not able to get the "Check all" checkboxes to work. No error in browser's console log. Clicking either of the "Select all" checkboxes (top/bottom), only selects the "Check all" checkboxes, nothing else.

@neeniya
Copy link

neeniya commented Sep 18, 2020

I'm trying to use this in my custom plugin based on the plugin Boiler plate https://github.com/DevinVinson/WordPress-Plugin-Boilerplate

I can get my admin page to load but getting errors like:
Notice: Trying to get property 'id' of non-object in C:\Sites\thefactorystl.wp.dnndev.me\wp-admin\includes\class-wp-list-table.php on line 454

Fatal error: Uncaught Error: Call to a member function render_screen_reader_content() on null in C:\Sites\thefactorystl.wp.dnndev.me\wp-admin\includes\class-wp-list-table.php:807 Stack trace: #0 C:\Sites\thefactorystl.wp.dnndev.me\wp-admin\includes\class-wp-list-table.php(1249): WP_List_Table->pagination('top') #1 C:\Sites\thefactorystl.wp.dnndev.me\wp-admin\includes\class-wp-list-table.php(1186): WP_List_Table->display_tablenav('top'

Update: Figured out the issue

@SamuelHadsall I'm getting this exact same issue. Care to share how you solved this one? Thanks!

@gavin310
Copy link

This worked perfectly right out of the box, thanks! One thing that would add to this is adding checkboxes to each column and some bulk editing controls.

@gavin310
Copy link

If anyone is looking for an example that goes into more detail (row checkboxes and hover actions) there's one here: https://github.com/Veraxus/wp-list-table-example/blob/master/includes/class-tt-example-list-table.php

@fungayimakoni
Copy link

Great. I have been using this for many projects thanks. Struggled adding search function though.

@SamuelHadsall
Copy link

Oh Geeze @neeniya, sorry I took some time off and didn't see this come through. Did you figure this out.

@neeniya
Copy link

neeniya commented May 17, 2021

@SamuelHadsall, no worries, I was able to figure it out the same day. If I remember correctly, my issue stemmed from an incorrectly scoped variable.

@mradulovic988
Copy link

Awesome!

@deadcalf
Copy link

does anybody knows if you can use wp_list_table with a form generated with generate_settings_html?
Thanks

@sarojmaharjan561
Copy link

sarojmaharjan561 commented Apr 19, 2022

I'm trying to use this in my custom plugin based on the plugin Boiler plate https://github.com/DevinVinson/WordPress-Plugin-Boilerplate

I can get my admin page to load but getting errors like: Notice: Trying to get property 'id' of non-object in C:\Sites\thefactorystl.wp.dnndev.me\wp-admin\includes\class-wp-list-table.php on line 454

Fatal error: Uncaught Error: Call to a member function render_screen_reader_content() on null in C:\Sites\thefactorystl.wp.dnndev.me\wp-admin\includes\class-wp-list-table.php:807 Stack trace: #0 C:\Sites\thefactorystl.wp.dnndev.me\wp-admin\includes\class-wp-list-table.php(1249): WP_List_Table->pagination('top') #1 C:\Sites\thefactorystl.wp.dnndev.me\wp-admin\includes\class-wp-list-table.php(1186): WP_List_Table->display_tablenav('top'

Update: Figured out the issue
@SamuelHadsall @neeniya
I'm getting this exact same issue. Care to share how you solved this one?

@SamuelHadsall
Copy link

@sarojmaharjan561 here is my class that I used

// WP_List_Table is not loaded automatically so we need to load it in our application
if (!class_exists('WP_List_Table')) {
    require_once(ABSPATH . 'wp-admin/includes/screen.php');
    require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
}

class Show_Event_History extends WP_List_Table
{

    public function prepare_items()
    {
        $columns = $this->get_columns();
        $hidden = $this->get_hidden_columns();
        $sortable = $this->get_sortable_columns();

        $data = $this->table_data();
        usort($data, array($this, 'sort_data'));

        $perPage = 5;
        $currentPage = $this->get_pagenum();
        $totalItems = count($data);

        $this->set_pagination_args(array(
            'total_items' => $totalItems,
            'per_page'    => $perPage
        ));

        $data = array_slice($data, (($currentPage - 1) * $perPage), $perPage);

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

    /**
     * Override the parent columns method. Defines the columns to use in your listing table
     *
     * @return Array
     */
    public function get_columns()
    {
        $columns = array(
            'event_date' => 'Event Date',
            'artist' => 'Artist',
            'shows_event' => 'Show/Event Name',
            'tour_name' => 'Tour Name',
            'date_modified'  => 'Date Modified'
        );

        return $columns;
    }

    /**
     * Define which columns are hidden
     *
     * @return Array
     */
    public function get_hidden_columns()
    {
        return array();
    }

    /**
     * Define the sortable columns
     *
     * @return Array
     */
    public function get_sortable_columns()
    {
        return array('event_date' => array('event_date', false));
    }

    /**
     * Get the table data
     *
     * @return Array
     */
    private function table_data()
    {

        $data = array();

        $today = current_time('Ymd');

        //do the query of Vehicle Info for all the vehicles available
        $args = array(
            'numberposts'    => -1,
            'post_type'        => 'event',
            'meta_query' => array(
                array(
                    'key' => 'show_info_date_of_event',
                    'value' => $today,
                    'type' => 'DATE',
                    'compare' => '<',
                )
            ),
            'orderby'            => 'meta_value',
            'order'                => 'ASC'
        );

        // Do your stuff, e.g.
        $the_query = new \WP_Query($args);

        if ($the_query->have_posts()) {

            while ($the_query->have_posts()) {
                $the_query->the_post();

                $id = get_the_ID();

                $artist_fields = get_field('artist_info', $id);
                $fieldsGroup = get_field('show_info', $id);
                $name = get_the_title();
                $tourName = $artist_fields['tour_name'] ? $artist_fields['tour_name'] : 'N/A';
                $artist_name = $artist_fields['artist_name']['label'];

                $data[] = array(
                    'event_date' => date('F j, Y', strtotime($fieldsGroup['date_of_event'])),
                    'artist' => $artist_name,
                    'shows_event' => '<a href="' . get_edit_post_link($id) . '">' . $name . '</a>',
                    'tour_name' =>  $tourName,
                    'date_modified' => get_the_modified_date('F j, Y', $id)
                );
            }
        }

        return $data;
    }

    /**
     * Define what data to show on each column of the table
     *
     * @param  Array $item        Data
     * @param  String $column_name - Current column name
     *
     * @return Mixed
     */
    public function column_default($item, $column_name)
    {
        switch ($column_name) {
            case 'event_date':
            case 'artist':
            case 'shows_event':
            case 'tour_name':
            case 'date_modified':
                return $item[$column_name];

            default:
                $item;
        }
    }

    /**
     * Allows you to sort the data by the variables set in the $_GET
     *
     * @return Mixed
     */
    private function sort_data($a, $b)
    {
        // Set defaults
        $orderby = 'event_date';
        $order = 'asc';

        // If orderby is set, use this as the sort column
        if (!empty($_GET['orderby'])) {
            $orderby = $_GET['orderby'];
        }

        // If order is set use this as the order
        if (!empty($_GET['order'])) {
            $order = $_GET['order'];
        }


        $result = strcmp($a[$orderby], $b[$orderby]);

        if ($order === 'asc') {
            return $result;
        }

        return -$result;
    }
}

@segunolamidegitup
Copy link

Thanks. Helpful to me.

@jorgitobg
Copy link

@sarojmaharjan561 here is my class that I used

// WP_List_Table is not loaded automatically so we need to load it in our application
if (!class_exists('WP_List_Table')) {
    require_once(ABSPATH . 'wp-admin/includes/screen.php');
    require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
}

class Show_Event_History extends WP_List_Table
{

    public function prepare_items()
    {
        $columns = $this->get_columns();
        $hidden = $this->get_hidden_columns();
        $sortable = $this->get_sortable_columns();

        $data = $this->table_data();
        usort($data, array($this, 'sort_data'));

        $perPage = 5;
        $currentPage = $this->get_pagenum();
        $totalItems = count($data);

        $this->set_pagination_args(array(
            'total_items' => $totalItems,
            'per_page'    => $perPage
        ));

        $data = array_slice($data, (($currentPage - 1) * $perPage), $perPage);

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

    /**
     * Override the parent columns method. Defines the columns to use in your listing table
     *
     * @return Array
     */
    public function get_columns()
    {
        $columns = array(
            'event_date' => 'Event Date',
            'artist' => 'Artist',
            'shows_event' => 'Show/Event Name',
            'tour_name' => 'Tour Name',
            'date_modified'  => 'Date Modified'
        );

        return $columns;
    }

    /**
     * Define which columns are hidden
     *
     * @return Array
     */
    public function get_hidden_columns()
    {
        return array();
    }

    /**
     * Define the sortable columns
     *
     * @return Array
     */
    public function get_sortable_columns()
    {
        return array('event_date' => array('event_date', false));
    }

    /**
     * Get the table data
     *
     * @return Array
     */
    private function table_data()
    {

        $data = array();

        $today = current_time('Ymd');

        //do the query of Vehicle Info for all the vehicles available
        $args = array(
            'numberposts'    => -1,
            'post_type'        => 'event',
            'meta_query' => array(
                array(
                    'key' => 'show_info_date_of_event',
                    'value' => $today,
                    'type' => 'DATE',
                    'compare' => '<',
                )
            ),
            'orderby'            => 'meta_value',
            'order'                => 'ASC'
        );

        // Do your stuff, e.g.
        $the_query = new \WP_Query($args);

        if ($the_query->have_posts()) {

            while ($the_query->have_posts()) {
                $the_query->the_post();

                $id = get_the_ID();

                $artist_fields = get_field('artist_info', $id);
                $fieldsGroup = get_field('show_info', $id);
                $name = get_the_title();
                $tourName = $artist_fields['tour_name'] ? $artist_fields['tour_name'] : 'N/A';
                $artist_name = $artist_fields['artist_name']['label'];

                $data[] = array(
                    'event_date' => date('F j, Y', strtotime($fieldsGroup['date_of_event'])),
                    'artist' => $artist_name,
                    'shows_event' => '<a href="' . get_edit_post_link($id) . '">' . $name . '</a>',
                    'tour_name' =>  $tourName,
                    'date_modified' => get_the_modified_date('F j, Y', $id)
                );
            }
        }

        return $data;
    }

    /**
     * Define what data to show on each column of the table
     *
     * @param  Array $item        Data
     * @param  String $column_name - Current column name
     *
     * @return Mixed
     */
    public function column_default($item, $column_name)
    {
        switch ($column_name) {
            case 'event_date':
            case 'artist':
            case 'shows_event':
            case 'tour_name':
            case 'date_modified':
                return $item[$column_name];

            default:
                $item;
        }
    }

    /**
     * Allows you to sort the data by the variables set in the $_GET
     *
     * @return Mixed
     */
    private function sort_data($a, $b)
    {
        // Set defaults
        $orderby = 'event_date';
        $order = 'asc';

        // If orderby is set, use this as the sort column
        if (!empty($_GET['orderby'])) {
            $orderby = $_GET['orderby'];
        }

        // If order is set use this as the order
        if (!empty($_GET['order'])) {
            $order = $_GET['order'];
        }


        $result = strcmp($a[$orderby], $b[$orderby]);

        if ($order === 'asc') {
            return $result;
        }

        return -$result;
    }
}

Thanks for your reply! could be possible to get the complete boilerplate you were working? or maybe some help on how to integrate this class?

@djcowan
Copy link

djcowan commented Mar 8, 2024

Glad is my heart, comforted is my soul; for whenever I seek–the glens, the dales, the valleys and the very mountains echo back the name Paul Lund

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment