WordPress Admin listing Table and Paging

Almost svery wordpress plugin developer needs to make Admin side listing for any custom table. This table generally store information that is gather from website and/or end users. Listing of table help to view the data in list format. It also allow admin to add, edit and Delete the data. It also allow bulk action for delete.

During my plugin development, I always wonder that how to make admin side listing for custom table which looks same as post and page listing. Also how can I make pagination for the table. I have searched for pagination and found many class to use that you can also found in my previous post. But I want to make it looks like as below:



After Searching for this I come to know that wordpress also providing the class for listing and paging for custom table. Class Name is Wp_List_Table. Wp_List_Table class is used to create admin screens for the wordpress. We need to extends this class and overload its method to use it.

Now the question is how to use this class and create admin side listing for our created custom table.

WordPress is providing one very good example plugin to see how we can create admin side listing for the custom table. You can find the example plugin Here

This example display code using Array of data. Instead of data we can use any database table. For creating your own table listing copy paste data into your file and follow below steps

Step 1: Create a new file under your plugin directory

Step 2: Include WP_List_Table class file into your file as follow:

 require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );

Step 3: Create class for your custom table and extends it to WP_List_Table.

For this you can copy whole class from example plugin and paste it in your plugin file and rename the class name from TT_Example_List_Table to something else which is preferable for your plugin.

Step 4: If you are using database table for fetching data which will always a case in real life,  then delete the example data array.

We will fetch the data from database when it will be needed. Remove the below code:

var $example_data = array(
	 'ID' => 1,
	 'title' => '300',
	 'rating' => 'R',
	 'director' => 'Zach Snyder'
	 'ID' => 2,
	 'title' => 'Eyes Wide Shut',
	 'rating' => 'R',
	 'director' => 'Stanley Kubrick'
	 'ID' => 3,
	 'title' => 'Moulin Rouge!',
	 'rating' => 'PG-13',
	 'director' => 'Baz Luhrman'
	 'ID' => 4,
	 'title' => 'Snow White',
	 'rating' => 'G',
	 'director' => 'Walt Disney'
	 'ID' => 5,
	 'title' => 'Super 8',
	 'rating' => 'PG-13',
	 'director' => 'JJ Abrams'
	 'ID' => 6,
	 'title' => 'The Fountain',
	 'rating' => 'PG-13',
	 'director' => 'Darren Aronofsky'
	 'ID' => 7,
	 'title' => 'Watchmen',
	 'rating' => 'R',
	 'director' => 'Zach Snyder'

Step 5: Setting up the naming and some configs for table listing.

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

 //Set parent defaults
 parent::__construct( array(
 'singular' => 'movie', //singular name of the listed records
 'plural' => 'movies', //plural name of the listed records
 'ajax' => false //does this table support ajax?
 ) );


Step 6: Set Default common value display for the every column using.

function column_default($item, $column_name){
 case 'rating':
 case 'director':
 return $item[$column_name];
 return print_r($item,true); //Show the whole array for troubleshooting purposes

This method is called when the parent class can’t find a method  specifically build for a given column. Generally, it’s recommended to include one method for each column you want to render, keeping your package class neat and organized. For example, if the class needs to process a column named ‘title’, it would first see if a method named $this->column_title() exists – if it does, that method will be used. If it doesn’t, this one will be used. Generally, you should try to use custom column methods as much as  possible.

Step 7: If you have any column column which need to be display diffidently from other in the view. We can create this by below syntax

function column_<field name>($item){
//Some Code
return "formated text";

In example below is given

function column_title($item){

 //Build row actions
 $actions = array(
 'edit' => sprintf('<a href="?page=%s&action=%s&movie=%s">Edit</a>',$_REQUEST['page'],'edit',$item['ID']),
 'delete' => sprintf('<a href="?page=%s&action=%s&movie=%s">Delete</a>',$_REQUEST['page'],'delete',$item['ID']),

 //Return the title contents
 return sprintf('%1$s <span style="color:silver">(id:%2$s)</span>%3$s',
 /*$1%s*/ $item['title'],
 /*$2%s*/ $item['ID'],
 /*$3%s*/ $this->row_actions($actions)

step 8: Display Check boxes for the bulk action.

&nbsp;function column_cb($item){
  return sprintf(
'<input type="checkbox" name="%1$s[]" value="%2$s" />',
/*$1%s*/ $this->_args['singular'], //Let's simply repurpose the table's singular label ("movie")
/*$2%s*/ $item['ID'] //The value of the checkbox should be the record's id

step 9: get all column. here we specify which column to get for display.

This method dictates the table’s columns and titles. This should return an array where the key is the column slug (and class) and the value  is the column’s title text. If you need a checkbox for bulk actions, refer to the $columns array below.

function get_columns(){
 $columns = array(
 'cb' => '<input type="checkbox" />', //Render a checkbox instead of text
 'title' => 'Title',
 'rating' => 'Rating',
 'director' => 'Director'
 return $columns;

Step 10: Decide which column to make sortable. This Method is optional.

If you want one or more columns to be sortable (ASC/DESC toggle), you will need to register it here. This should return an array where the key is the column that needs to be sortable, and the value is db column to sort by. Often, the key and value will be the same, but this is not always the case (as the value is a column name from the database, not the list table).
This method merely defines which columns should be sortable and makes them clickable – it does not handle the actual sorting. You still need to detect the ORDERBY and ORDER query string variables within prepare_items() and sort your data accordingly (usually by modifying your query).

function get_sortable_columns() {
 $sortable_columns = array(
 'title' => array('title',true), //true means its already sorted
 'rating' => array('rating',false),
 'director' => array('director',false)
 return $sortable_columns;

Step 11: Set up bulk action for selected check boxes. This method is optional

If you need to include bulk actions in your list table, this is the place to define them. Bulk actions are an associative array in the format ‘slug’=>’Visible Title’

If this method returns an empty value, no bulk action will be rendered. If you specify any bulk actions, the bulk actions box will be rendered with the table automatically on display().

Also note that list tables are not automatically wrapped in <form> elements, so you will need to create those manually in order for bulk actions to function.

function get_bulk_actions() {
 $actions = array(
 'delete' => 'Delete'
 return $actions;

Now we also need to set up what to do when any one of the bulk action has been called. This can done using below method. This method is optional.

function process_bulk_action() {
 //Detect when a bulk action is being triggered...
 if( 'delete'===$this->current_action() ) {
 wp_die('Items deleted (or they would be if we had items to delete)!');

step 12: This is most important step for the listing the table and fetching the database values.

Here find and delete the code

$data = $this->example_data;

Below that there is function

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');

Also delete this code this code is now no more needed as we are sorting through database query. Add The below Code here

global $wpdb;
 $orderby = (!empty($_REQUEST['orderby'])) ? $_REQUEST['orderby'] : 'sent_time'; //If no sort, default to title
 $order = (!empty($_REQUEST['order'])) ? $_REQUEST['order'] : 'asc'; //If no order, default to asc
 $query='select * from <Table_name> order by '. $orderby . ' ' .$order;
 $data = $wpdb->get_results($query, 'ARRAY_A');

Here first we have called global variable which is available in wordpress for the database operation. ‘$wpdb’ . Then set order by and order values and get the data.

Every things else remain as it is in this function no need to change.

step 13: Now we need to create function which will be called when page is going to display. We just need to create object of our newly created class.

//Create an instance of our package class...
 $testListTable = new TT_Example_List_Table();
 //Fetch, prepare, sort, and filter our data...

And Display the data

<!-- Forms are NOT created automatically, so you need to wrap the table in one to use features like bulk actions -->
 <form id="movies-filter" method="get">
 <!-- For plugins, we also need to ensure that the form posts back to our current page -->
 <input type="hidden" name="page" value="<?php echo $_REQUEST['page'] ?>" />
 <!-- Now we can render the completed list table -->
 <?php $testListTable->display() ?>


This will create both listing and pagination for custom table in wordpress. I think this is really easy to use it rather creating table by self and searching for the pagination class and adding them to the code.

This helps developers to create very neat and clean code. Also, This code is fully compatible with wordpress.

Please comment your queries, Suggestion, Like or Dislike post here.


Note: This example which I have used which is already available in wordpress listing table plugin. I have explained using database connection which was missing in the plugin. Hope this will helps every wordpress developers.

Thank you….