Published on

WordPress admin native table

Authors

WordPress admin native table

Let’s do it,

We will make a simple plugin which will display product name and URL. Before the following tutorial, I simply recommended going through class-wp-list-table.php file so you can understand easily because we are going to extends Wp_List_Table class which is in that file.

Starting with creating simple file id-generator-via-url.php.

id-generator-via-url.php
<?php
/**
* Plugin Name: ID Generator
* Author : Jignesh Sanghani
* Description: You can add a new link to the admin, it will go, find the links add the ID.
* Text Domain: sp
*/

now our plugin is ready to list in WordPress plugin list. we will register activation hook, so when plugin is activate it'll create table for use to store URL and name

id-generator-via-url.php
function pluginprefix_function_to_run(){

    global $wpdb;

    $charset_collate = $wpdb->get_charset_collate();
    $table_name = $wpdb->prefix.'sb_id_generator';

    $sql = "CREATE TABLE $table_name (
       id mediumint(9) NOT NULL AUTO_INCREMENT,
       name text NOT NULL,
       url text  NOT NULL,
       time datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
       PRIMARY KEY  (id)
   
   ) $charset_collate;";

   require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );

   if($wpdb->get_var("SHOW TABLES LIKE '$table_name'") != $table_name)
       dbDelta( $sql );

}

register_activation_hook( __FILE__, 'pluginprefix_function_to_run' );

now create inc folder and inside that folder create Url_Name_List.php

Url_Name_List.php
class Url_Name_List 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.
     */
    public function __construct() {
        parent::__construct( [
            'singular' => __( 'ID Generator', 'sp' ), //singular name of the listed records
            'plural'   => __( 'ID Generators', 'sp' ), //plural name of the listed records
            'ajax'     => false //should this table support ajax?
        ] );
    }

}

Some time we need to add extra action or functionality we can add here to add any html in header and footer of the table

public  function extra_tablenav( $which ) {
    /**
     * $which will return either 'top' or 'bottom'
     */
    switch ($which) {
        case "top":
            echo '<a class="button button-primary" style="float: left" href="'.admin_url('/').'admin.php?page=add-url-name">Add URL</a>';
        break;
        case "bottom":
            echo '<a class="button button-primary" style="float: left" href="'.admin_url('/').'admin.php?page=add-url-name">Add URL</a>';
        break;
    }
}

extra_tablenav($which) will call two times. you can understand, why it's call two times? because it has one parameter which returns either "top" or "bottom".

This function exists in the parent WP_List_Table class in WordPress, but it doesn’t return anything, so if you don’t override it, nothing bad will happen; the table just won’t have any markup before or after it nothing else.

Now, we will prepare for 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 = [
       'cb'      => '<input type="checkbox" />',
       'id'    => __( 'ID', 'sp' ),
       'url'    => __( 'Url', 'sp' ),
       'name' => __( 'Name', 'sp' ),
   ];

   return $columns;

}

in get_columns() function will build array in the form of 'column_name=>column_title',

'column_name': using this you can access this column data any where in this class

'column_title': will just display header and footer title

Unlike the extra_tablenav() method, the get_columns() is a parent method that must be overridden in order to work. This makes sense because if you don’t declare any columns, the table will break

To specify the columns to which to add sorting functionality, we’ll add the get_sortable() columns method to 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(
       'id' => array('ID', true), //test for true and false
       'name' => array( 'Name', true ),
       'url' => array( 'Url', true )
   );

   return $sortable_columns;

}

here array will form like: column_name => databse_table_cloumn_name

column_name: as we discussed already in the above function, we can access this column data anywhere in this class

databse_table_cloumn_name: which your column of the database table

The code we have just written specifies that we would like to add sorting functionality to out table columns (ID, Name, and Url). If you don’t want the user to be able to sort any columns or if you just don’t want to implement this method, WordPress will just assume that no columns are sortable.

At this point, our class is ready to handle quite a few things. Let’s look now at how to display the data. To make the list table display your data, you’ll need to prepare your items and assign them to the table. This is handled by the prepare_items method:

/**
 * Handles data query and filter, sorting, and pagination.
 */
function prepare_items() {

    global $wpdb;
    /**
     * First, lets decide how many records per page to show
     * if not specify then will take default as 5 row
     */
    $per_page = $this->get_items_per_page('url_per_page', 5);
    $columns = $this->get_columns();
    $hidden = array();

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

    $data = $this->get_name_url();

    function usort_reorder($a,$b){

        $orderby = (!empty($_REQUEST['orderby'])) ? strtolower($_REQUEST['orderby']) : 'id';
        $order = (!empty($_REQUEST['order'])) ? $_REQUEST['order'] : 'asc'; 
        $result = strcmp($a[$orderby], $b[$orderby]); 
        return ($order==='asc') ? $result : -$result;

    }

    usort($data, 'usort_reorder');

    $current_page = $this->get_pagenum();
    $total_items = count($data);

    $data = array_slice($data,(($current_page-1)*$per_page),$per_page);
    /**
     * REQUIRED. We also have to register our pagination options & calculations.
     */
    $this->set_pagination_args( array(
        'total_items' => $total_items,
        'per_page'  => $per_page,
     ) );
    $this->items = $data;

}

As you can see prepare_items() function is bit complex. this is the most important function as well as to display data into the table with a filter.

let's understand each line so we can manipulate this function easily

Preparing the query: The first thing to do is specify the general query that will return the data. Here, it’s a generic SELECT on the links table.

In our function you can see $data = $this->get_name_url(); this line, which called get_name_url method of current class which is not inherit from Wp_List_Table. this is define by us/me.

Code for this function is below

/**
 * Retrieve  data from table
 * @param int $per_page
 * @param int $page_number
 * @return mixed
 */
public static function get_name_url( $per_page = 5, $page_number = 1 ) {
    global $wpdb;
    $sql = "SELECT * FROM {$wpdb->prefix}sb_id_generator";

    if ( ! empty( $_REQUEST['orderby'] ) ) {
        $sql .= ' ORDER BY ' . esc_sql( $_REQUEST['orderby'] );
        $sql .= ! empty( $_REQUEST['order'] ) ? ' ' . esc_sql( $_REQUEST['order'] ) : ' ASC';
    }
   
    $sql .= " LIMIT $per_page";
    $sql .= ' OFFSET ' . ( $page_number - 1 ) * $per_page;

    $result = $wpdb->get_results( $sql, 'ARRAY_A' );

    return $result;
}

Ordering: The second section is for the ordering parameters because we have specified that our table can be sorted by certain fields. In this section, we are getting the field (if any) by which to order our record ($_GET['order']) and the order itself ($_GET['orderby']). We then adjust our query to take those into account by appending an ORDER BY clause.

Pagination: The third section deals with pagination. We specify how many items are in our database table and how many to show per page. We then get the current page number ($_GET['paged']) and then adapt the SQL query to get the correct results based on those pagination parameters.

Registration: This part of the function takes all of the parameters we have prepared and assigns them to our table.

Ready to go: Our list table is now set with all of the information it needs to display our data. It knows what query to execute to get the records from the database; it knows how many records will be returned, and all the pagination parameters are ready. This is an essential method of your list table class. If you don’t implement it properly, WordPress won’t be able to retrieve your data. If the method is missing in your class, WordPress will return an error telling you that the prepare_items method must be overridden.

let's assign data to the columns

/**
 * Render a column when no column specific method exists.
 * @param array $item
 * @param string $column_name
 * @return mixed
 */
public function column_default( $item, $column_name ) {
    switch ( $column_name ) {
  case 'id':   return $item['id'];
        case 'name':  return $item['name'];
        case 'url':   return $item['url'];
        default:      return print_r( $item, true ); //Show the whole array for troubleshooting purposes
    }
}

in the coulmuns_default() has two parameters:

$item: which has filtered array of data

$coulumn_name: which return column name of the table

all basic things are ready, now prepare for display table, crate other class in the same Url_Name_List.php file

Url_Name_List.php
class URL_Plugin {

    static $instance;
    public $customers_obj;
    public function __construct() {
        add_filter( 'set-screen-option', [ __CLASS__, 'set_screen' ], 10, 3 );
        add_action( 'admin_menu', [ $this, 'plugin_menu' ] );
   }

   public static function set_screen( $status, $option, $value ) {
       return $value;
   }
   
   public function plugin_menu() {
       $hook = add_menu_page(
           'ID Generator',
           'ID Generator',
           'manage_options',
           'sb-id-generator',
           [ $this, 'plugin_settings_page' ]
       );
       add_action( "load-$hook", [ $this, 'screen_option' ] );
   
   }
   /**
    * Screen options
    */
   public function screen_option() {
       $option = 'per_page';
       $args = [
           'label' => 'URL',
           'default' => 5,
           'option' => 'url_per_page'
       ];
       add_screen_option( $option, $args );
       $this->customers_obj = new Url_Name_List();
   }
   public function plugin_settings_page() {
       ?>
       <div class="wrap">
           <div id="poststuff">
               <div id="post-body" class="metabox-holder">
                   <div id="post-body-content">
                       <div class="meta-box-sortables ui-sortable">
                           <form method="post">
                               <?php
                               // assign data which we foramted in Url_Name_List class method
                               $this->customers_obj->prepare_items();
                               // this will give nice searching mechanisum
                               $this->customers_obj->search_box('Search', 'search');
                               // whenever you called this method table will display
                               $this->customers_obj->display();
                               ?>
                           </form>
                       </div>
                   </div>
               </div>
               <br class="clear">
           </div>
       </div>
   <?php
   }
       /** Singleton instance */
   public static function get_instance() {
       if ( ! isset( self::$instance ) ) {
           self::$instance = new self();
       }
       return self::$instance;
   }
}

in the above class you can see we create a class URL_Plugin, which will simply arrange code nicely. this class has a constructor and two other methods, which are

Constructor: use to add the setting in screen options menu which is top-right in WordPress dashboard and add menu page in admin dashboard

plugin_setting_page: this is responsible for getting data and displaying table

get_instance: will create and invoke its own class constructor to perform add menu page and initiation of Url_Name_List

almost all the thing which is necessary is done for Url_Name_List.php file extra functionality we will see later now it's time to do magic

back to id-generator-via-url.php file add below code

All things are ready to go

id-generator-via-url.php
/**
 * Plugin require file
 */
if(!class_exists('WP_List_Table')){
   require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}

require_once('includes/Url_Name_List.php');

URL_Plugin::get_instance();