Custom List Table Page Tutorial- WordPress

wordpress-list-table

Ok, before I go ahead with the article let’s clearly know what it’s about and what we are going to create in this article.

In This Article, we are going to create a List Table Page in WordPress Administrator interface.

What is a List Table Page?

A List Table Page is page which list down records from database in table format and along with it allows us to perform some action on the records e.g. filtering and searching. The page which you see when you click on ‘All Posts’ or ‘All Pages’ are example of List Table.

So we are going to create a List Table Page in WordPress for our own table in database. It’s a very common requirement when creating a plugin or theme. But most of the time we see developers trying to mimic the Markup and CSS of the WordPress List Table Pages to achieve the Native Look & Feel. There is nothing wrong with it either but there is a better way.

We’ll do it The WordPress Way today, the way in which WordPress does itself.

Introduing WP_List_Table Class

This class is used to generate the List Tables that populate WordPress’ various admin screens. We can use it for our page too. By using this class as a base for our functionality we don’t have to worry about managing the HTML & CSS ourselves. WP_List_Table class has already covered this part and we can focus on more crucial part which is Treatment of Data.

We will extend this class and implement/override the functions as per our requirements. If you dont’t mind messing up with the core to have more grip over things, do look at the WordPress classes for List Tables of posts, pages, plugins and comments. You can find the classes in wp-admin/includes/ folder. The one for posts is class-wp-posts-list-table.php. You will see how each of these classes extends WP_List_Table. So we are lining up with WordPress here.

You can read more about it here.

http://codex.wordpress.org/Function_Reference/WP_List_Table

Note

If you visited the link above you must have seen this

sf

Its true WordPress didn’t create this class as an API to be used by Theme and Plugin developers but for their internal use. So chances are there that this class might change anytime, thus breaking your functionality. So testing your plugin with beta/RC phases of WordPress development should be more than enough to avoid any major issues. Nevertheless, developers should use this class at their own risk.

Enough with background, let’s start some work.

1. Create New Table in Database.

Create a table named wp_stores and add id, name, postcode and phone fields. Put some content in it.


CREATE TABLE wp_stores
(
	id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
	postcode VARCHAR(10) NOT NULL,
	name VARCHAR(100) NOT NULL,
	phone VARHCAR(15) NOT NULL
)

table

2. Setup a plugin for testing

The WP_List_Table class is essentially a small framework we can use to prepare our table. This is an object-oriented approach, because we’ll be creating an object that extends WP_List_Table and using that, instead of using WP_List_Table directly.

For the purpose of example we’ll create a new plugin that will have both our new class and will register a new page in admin panel for testing out our class.

Create a new file custom-list-table.php in plugins folder and add the following code to the file.


<?php
/*
Plugin Name: Custom List Table Tutorial
Plugin URI: http://www.codeway.co.in/
Description: Plugin to demonstrates how to create custom List Tables using working built in classes
Version: 1.0
Author: Ankit
Author URI: http://www.codeway.co.in/
License: GPL2
*/

/*************************** LOAD THE BASE CLASS *******************************
 *******************************************************************************
 * The WP_List_Table class isn't automatically available to plugins, so we need
 * to check if it's available and load it if necessary.
 */
if(!class_exists('WP_List_Table')){
    require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}

/************************** CREATE A PACKAGE CLASS *****************************
 *******************************************************************************
 * Create a new list table package that extends the core WP_List_Table class.
 * WP_List_Table contains most of the framework for generating the table, but we
 * need to define and override some methods so that our data can be displayed
 * exactly the way we need it to be. 
 */
class Store_List_Table extends WP_List_Table {

}

// Register a admin page
function custom_add_menu_items(){
    add_menu_page('Stores', 'Stores List', 0, 'custom_store', 'custom_store_list_page');
} add_action('admin_menu', 'custom_add_menu_items');

// Render page
 function custom_store_list_page(){    
   //Prepare Table of elements
    $wp_list_table = new Store_List_Table();
    $wp_list_table->prepare_items();
?>
    <div class="wrap">
         <div id="icon-edit-pages" class="icon32 icon32-posts-page"><br/></div>
         <h2>Stores</h2>

	    <?php 
			//Table of elements              
			$wp_list_table->display(); 
		?>     
    </div>     
<?php }

Code above do following things:

  1. Declare a plugin
  2. Include the WP_List_Table class if now already included
  3. Create our new class that extends the Wp_List_Table class
  4. And finally it register a top level menu so that we can test our class as we keep adding more functions to our class

At this point we have our basic structure ready and as we proceed with the tutorial we’ll be adding more functions to the class. After adding the constructor to the class from next step, You would be able to activate that plugin and see the output by clicking on the left menu that is added by the plugin.

3.Create Constructor in Class

/**
* Set up a constructor that references the parent constructor. We
* use the parent reference to set some default configs.
*/
function __construct() {
   parent::__construct( array(
     'singular'=> 'store', //Singular label
     'plural' => 'stores', //plural label, also this well be one of the table css class
     'ajax' => false //We won't support Ajax for this table
  ));
}

4. Prepare The Table Header and Footer

/**
* Define the columns that are going to be used in the table
* @return array $columns, the array of columns to use with the table
*/
function get_columns() {
  $columns = array(
    'id'  => 'Id',
    'name'     => 'Name',
    'postcode'    => 'Postcode',
    'phone'  => 'Phone'
  );
  return $columns;
}

5. Sortable Columns

Here we can define columns for which we need sorting functionality. we’ll create get_sortable_columns methods in our class:

/**
* 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(
     'name'     => array('name',false),     //true means it's already sorted
     'postcode'    => array('postcode',false),
     'phone'  => array('phone',false)
   );
   return $sortable_columns;
}

6 Prepare data for display

This is where you prepare your data for display. This method will usually be used to query the database, sort and filter the data, and generally get it ready to be displayed.


/**
* Prepare the table with different parameters, pagination, columns and table elements
*/
function prepare_items() {
   global $wpdb, $_wp_column_headers;
   $screen = get_current_screen();
   /* -- Preparing your query -- */
   $query = "SELECT * FROM stores";

   /* -- Ordering parameters -- */
   //Parameters that are going to be used to order the result
   $orderby = !empty($_GET["orderby"]) ? mysql_real_escape_string($_GET["orderby"]) : 'ASC';
   $order = !empty($_GET["order"]) ? mysql_real_escape_string($_GET["order"]) : '';
   if(!empty($orderby) & !empty($order)){ $query.=' ORDER BY '.$orderby.' '.$order; }

   /* -- Pagination parameters -- */
   //Number of elements in your table?
   $totalitems = $wpdb->query($wpdb->prepare($query)); //return the total number of affected rows
   //How many to display per page?
   $perpage = 10;
   //Which page is this?
   $paged = !empty($_GET["paged"]) ? mysql_real_escape_string($_GET["paged"]) : '';
   //Page Number
   if(empty($paged) || !is_numeric($paged) || $paged<=0 ){ $paged=1; }
   //How many pages do we have in total?
   $totalpages = ceil($totalitems/$perpage);
   //adjust the query to take pagination into account
   if(!empty($paged) && !empty($perpage)){
      $offset=($paged-1)*$perpage;
      $query.=' LIMIT '.(int)$offset.','.(int)$perpage;
   }

   /* -- Register the pagination -- */
   $this->set_pagination_args( array(
      "total_items" => $totalitems,
      "total_pages" => $totalpages,
      "per_page" => $perpage,
   ));
   //The pagination links are automatically built according to those parameters

   /* — Register the Columns — */
   $columns = $this->get_columns();
   $hidden = array();
   $sortable = $this->get_sortable_columns();
   $this->_column_headers = array($columns, $hidden, $sortable);

   /* -- Fetch the items -- */
   $this->items = $wpdb->get_results($query);
}

7 Displaying Rows

/**
* Display the rows of records in the table
* @return string, echo the markup of the rows
*/
function display_rows() {

   //Get the records registered in the prepare_items method
   $records = $this->items;

   //Get the columns registered in the get_columns and get_sortable_columns methods
   list( $columns, $hidden ) = $this->get_column_info();

   //Loop for each record
   if(!empty($records)){foreach($records as $rec){
        //Open the line
        echo '<tr id="record_'.$rec->id.'">';
        foreach ( $columns as $column_name => $column_display_name ) {

             //Style attributes for each col
             $class = "class='$column_name column-$column_name'";
             $style = "";
             if ( in_array( $column_name, $hidden ) ) $style = ' style="display:none;"';
             $attributes = $class . $style;

             //Display the cell
             switch ( $column_name ) {
                case "id": echo '<td '.$attributes.'>'.stripslashes($rec->id).'</td>';  break;
                case "postcode": echo '<td '.$attributes.'>'.stripslashes($rec->postcode).'</td>'; break;
                case "name": echo '<td '.$attributes.'>'.stripslashes($rec->name); echo $actionLinks;'</td>'; break;
                case "phone": echo '<td '.$attributes.'>'.$rec->phone.'</td>'; break;
            }
       }

       //Close the line
       echo'</tr>';
   }}
}

Wrapping Up

This article possibly give you quick start on creating Custom List Tables in Wordpess. If you have any difficulty following up this article, do let me know in comments.

There’s also a great plugin available for this http://wordpress.org/plugins/custom-list-table-example/. This plugin don’t do the stuff but it gives you a great start and define the blank functions for you to fill, and comes with great documentation for each function. Hopefully you can use this plugin along with things you learned from this article to create something useful for you.

The following two tabs change content below.

Gagan Walia

Gagan is Senior Web Developer at Logiciel Solutions. She loves playing out with Wordpress and Cakephp.

Latest posts by Gagan Walia (see all)

  • Lakhwinder Singh

    Thanks Gagan,
    This post is very useful for me. That I create a summary screen very quickly.
    I have no need to create html or css for admin custom pages it generate all data in table format.

    Thanks again.