Back to Top

Create Admin tables using WP_List_Table CLASS

Updated 14 July 2018

Create Admin tables using WP_List_Table CLASS – In WordPress WP_List_Table Class is used to display data, e.g. users, plugins, comments, or posts.
Each post type that has a dashboard uses the WP_List_Table class to display data.

We uses WP_List_Table class so that we can display  custom post type data at wordpress backend.
In the WordPress dashboard, the tables that displays the posts, pages and user data are all created internally by WordPress using the WP_List_Table class.
They are used on nearly all default admin pages with lists, and most of the developers often integrate them into their plugins

WP_List_Table class access is marked as private. That means it is not intended for use by plugin and theme developers as it is subject to change without warning in any future WordPress release. If you would still like to make use of the class, you should make a copy to use and distribute with your own project, or else use it at your own risk.

Even After this confimation from, the WP_List_Table class has become widely used by plugins and WordPress developers as it provides a reliable, consistent, and semantic way to create custom list tables in WordPress. Till date, no major changes have occurred in this class or are scheduled to occur, so testing your plugin with beta/RC phases of WordPress development should be more than enough to avoid any major issues.

If you are still feeling risk of using this class a common (and safe) workaround is to make a copy the WP_List_Table class ( /wp-admin/includes/class-wp-list-table.php ) to use and distribute in your plugins, instead of using the original core class. This way, if the core class should ever change, your plugins will continue to work as-is.

Let’s get started with WP_List_Table class :-

Searching for an experienced
WordPress Company ?
Find out More
Register admin menu

We need to Register admin menu using admin_menu hook

if ( current_user_can('edit_files') ) {

  add_action( 'admin_menu','register_my_custom_menu_page');
Using load hook

We need to create admin menu, sub-menus and using load-hook and current_screen hook we can add option and set help tab for admin menu we have created

function register_my_custom_menu_page(){

    global $new_menu_page;
   // creating admin menu 

    add_menu_page('Career', 'Career', 'edit_posts','career','custom_list_page', get_template_directory_uri().'/images/custom.png', 8 );

    $hook=add_submenu_page("career","Custom List","Custom List",'edit_posts', "career", "custom_list_page");
   // adding submenu 
   add_submenu_page("career","Custom Detail","Custom Detail",'edit_posts',"custom_detail", "custom_detail_page");

   // creating options like per page data(pagination)
    add_action( "load-".$hook, 'add_options' ); 

   // Creating help tab 

    add_action( 'current_screen','my_admin_add_help_tab');
function my_admin_add_help_tab() {

    $screen = get_current_screen();

    // Add my_help_tab if current screen is My Admin Page

    $screen->add_help_tab( array(

        'id'    => 'my_help_tab',

        'title' => 'Webkul Help Tab',

        'content'   => '<p>' . __( 'Help Topics Added Here.' ) . '</p>',
 ) );
function add_options() {

$option = 'per_page';

$args = array(

'label' => 'Results',

'default' => 10,

'option' => 'results_per_page'


add_screen_option( $option, $args );

check if WP_List_Table class exists

Checking if WP_List_Table already exists

function custom_list_page(){


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

class Link_List_Table extends WP_List_Table {

    * Constructor, we override the parent to pass our own arguments
    * We usually focus on three parameters: singular and plural labels, as well as whether the class supports AJAX.

    function __construct() {

       parent::__construct( array(

            'singular'  => 'singular_name',     //singular name of the listed records

            'plural'    => 'plural_name',    //plural name of the listed records

            'ajax'      => false 

      ) );



    $wp_list_table = new Link_List_Table();  

                 if( isset($_GET['s']) ){


        } else {



} function custom_detail_page(){ // Add some form and store that data in database and then use that data inside custom_list_page() function }

Setup Default Columns for wp admin table
    public function column_default( $item, $column_name )


        switch( $column_name ) {

            case 'first_column_name':

            case 'second_column_name':

            case 'third_column_name':

            case 'fourth_column_name':

                return "<strong>".$item[$column_name]."</strong>";


                return print_r( $item, true ) ;


Setting Sortable Columns

Setting up sortable columns using  get_sortable_columns()


 * Decide which columns to activate the sorting functionality on

 * @return array $sortable, the array of columns that can be sorted by the user


public function get_sortable_columns() {

     $sortable_columns = array(

            'first_column_name'     => array('first_column_name',true),
            'second_column_name' => array('second_column_name',true) ); 

            return $sortable_columns;
Setup the Hidden Columns
public function get_hidden_columns()

        // Setup Hidden columns and return them
        return array();

Setup Actions for particular Column
     * [OPTIONAL] this is example, how to render column with actions,
     * when you hover row "Edit | Delete" links showed
     * @param $item - row (key, value array)
     * @return HTML

   function first_column_name($item) {
   $actions = array(

            'edit'      => sprintf('<a href="?page=custom_detail_page&user=%s">Edit</a>',$item['id']),

            'trash'    => sprintf('<a href="?page=custom_list_page&action=trash&user=%s">Trash</a>',$item['id']),


  return sprintf('%1$s %2$s', $item['first_column_name'], $this->row_actions($actions) );

Setup Bulk Actions and Process Bulk Action for Columns
 function get_bulk_actions()

        $actions = array(

            'trash'    => 'Move To Trash' 

        return $actions;
public function process_bulk_action()

              global $wpdb;
        if ('trash' === $this->current_action()) {

              if (isset($_GET['user'])) {

                  if (is_array($_GET['user'])){

            foreach ($_GET['user'] as $id) {

            if(!empty($id)) { 


              $table_name = $wpdb->prefix . 'table_name';
              $wpdb->query("update $table_name set post_status='trash' WHERE id IN($id)");  





                  if (!empty($_GET['user'])) { 


                      $table_name = $wpdb->prefix . 'table_name';
                      $wpdb->query("update $table_name set post_status='trash' WHERE id =$id");  





Get Data From Database
private function table_data()
      global $wpdb;

       $table_name = $wpdb->prefix . 'table_name';



          $search = trim($search);

          $wk_post = $wpdb->get_results("SELECT column_name_one,column_name_two FROM $table_name WHERE column_name_three LIKE '%$search%' and column_name_four='value'");


            $wk_post=$wpdb->get_results("SELECT column_name_one,column_name_two FROM $table_name WHERE column_name_three='value'");

        $field_name_one = array();

        $field_name_two = array();


        foreach ($wk_post as $wk_posts) {



            $data[] = array(

                    'first_column_name'  => $field_name_one[$i],

                    'second_column_name' =>   $field_name_two[$i]   



        return $data;

Setup The Prepared Data and SORT using usort method
public function prepare_items()  

        global $wpdb;  

            $columns = $this->get_columns();

            $sortable = $this->get_sortable_columns();



            $data = $this->table_data();
            $totalitems = count($data);

            $user = get_current_user_id();

            $screen = get_current_screen();

            $option = $screen->get_option('per_page', 'option'); 

            $perpage = get_user_meta($user, $option, true);

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

            if ( empty ( $per_page) || $per_page < 1 ) {
              $per_page = $screen->get_option( 'per_page', 'default' ); 


            function usort_reorder($a,$b){

            $orderby = (!empty($_REQUEST['orderby'])) ? $_REQUEST['orderby'] : 'column_name_one'; //If no sort, default to title

            $order = (!empty($_REQUEST['order'])) ? $_REQUEST['order'] : 'desc'; //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');

                $totalpages = ceil($totalitems/$perpage); 

                $currentPage = $this->get_pagenum();
                $data = array_slice($data,(($currentPage-1)*$perpage),$perpage);

                $this->set_pagination_args( array(

                "total_items" => $totalitems,

                "total_pages" => $totalpages,

                "per_page" => $perpage,
            ) );
        $this->items =$data;

You can also find a complete guide over this class here WordPress Codex

. . .

Leave a Comment

Your email address will not be published. Required fields are marked*


  • Pk
  • dhanashree
  • Back to Top

    Message Sent!

    If you have more details or questions, you can reply to the received confirmation email.

    Back to Home