List items from table in WordPress using WP_List_Table doesn’t show records

I’m using WP_List_Table to get listing all the items in a table at WP admin side. This is how I’m doing (the code was copied from another source and changed to suite my needs):

if (!class_exists('WP_List_Table')) {
    require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );

    class FT_WP_Table extends WP_List_Table
    {

        private $order;
        private $orderby;
        private $posts_per_page = 25;

        public function __construct()
        {
            parent :: __construct(array(
                'singular' => "ftraveler",
                'plural' => "ftraveler",
                'ajax' => true
            ));

            $this->set_order();
            $this->set_orderby();
            $this->prepare_items();
            $this->display();
        }

        private function get_sql_results()
        {
            global $wpdb;
            $args = array('id', 'firstname', 'lastname', 'foid', 'no_frequent', 'create_time');
            $sql_select = implode(', ', $args);
            $sql_results = $wpdb->get_results("SELECT " . $sql_select . "FROM" . $wpdb->prefix . "ftraveler ORDER BY $this->orderby $this->order ");
            return $sql_results;
        }

        public function set_order()
        {
            $order = 'DESC';
            if (isset($_GET['order']) AND $_GET['order'])
                    $order = $_GET['order'];
            $this->order = esc_sql($order);
        }

        public function set_orderby()
        {
            $orderby = 'create_date';
            if (isset($_GET['orderby']) AND $_GET['orderby'])
                    $orderby = $_GET['orderby'];
            $this->orderby = esc_sql($orderby);
        }

        /**
         * @see WP_List_Table::ajax_user_can()
         */
        public function ajax_user_can()
        {
            return current_user_can('edit_posts');
        }

        /**
         * @see WP_List_Table::no_items()
         */
        public function no_items()
        {
            _e('No frequent traveler found.');
        }

        /**
         * @see WP_List_Table::get_views()
         */
        public function get_views()
        {
            return array();
        }

        /**
         * @see WP_List_Table::get_columns()
         */
        public function get_columns()
        {
            $columns = array(
                'ID' => __('ID'),
                'firstname' => __('Firstname'),
                'lastname' => __('Lastname'),
                'foid' => __('Passport'),
                'no_frequent' => __('Frequent No'),
                'create_time' => __('Created on')
            );
            return $columns;
        }

        /**
         * @see WP_List_Table::get_sortable_columns()
         */
        public function get_sortable_columns()
        {
            $sortable = array(
                'ID' => array('id', true),
                'firstname' => array('firstname', true),
                'lastname' => array('lastname', true),
                'foid' => array('foid', true),
                'no_frequent' => array('no_frequent', true),
                'create_time' => array('create_time', true),
            );
            return $sortable;
        }

        /**
         * Prepare data for display
         * @see WP_List_Table::prepare_items()
         */
        public function prepare_items()
        {
            $columns = $this->get_columns();
            $hidden = array();
            $sortable = $this->get_sortable_columns();
            $this->_column_headers = array(
                $columns,
                $hidden,
                $sortable
            );

            // SQL results
            $posts = $this->get_sql_results();
            empty($posts) AND $posts = array();

            # >>>> Pagination
            $per_page = $this->posts_per_page;
            $current_page = $this->get_pagenum();
            $total_items = count($posts);
            $this->set_pagination_args(array(
                'total_items' => $total_items,
                'per_page' => $per_page,
                'total_pages' => ceil($total_items / $per_page)
            ));
            $last_post = $current_page * $per_page;
            $first_post = $last_post - $per_page + 1;
            $last_post > $total_items AND $last_post = $total_items;

            // Setup the range of keys/indizes that contain 
            // the posts on the currently displayed page(d).
            // Flip keys with values as the range outputs the range in the values.
            $range = array_flip(range($first_post - 1, $last_post - 1, 1));

            // Filter out the posts we're not displaying on the current page.
            $posts_array = array_intersect_key($posts, $range);
            # <<<< Pagination
            // Prepare the data
            $permalink = __('Edit:');
            foreach ($posts_array as $key => $post) {
                $link = get_edit_post_link($post->ID);
                $no_title = __('No title set');
                $title = !$post->post_title ? "<em>{$no_title}</em>" : $post->post_title;
                $posts[$key]->post_title = "<a title='{$permalink} {$title}' href='{$link}'>{$title}</a>";
            }
            $this->items = $posts_array;
        }

        /**
         * A single column
         */
        public function column_default($item, $column_name)
        {
            return $item->$column_name;
        }

        /**
         * Override of table nav to avoid breaking with bulk actions & according nonce field
         */
        public function display_tablenav($which)
        {

            ?>
            <div class="tablenav <?php echo esc_attr($which); ?>">
                <!-- 
                <div class="alignleft actions">
                <?php # $this->bulk_actions( $which );    ?>
                </div>
                -->
                <?php
                $this->extra_tablenav($which);
                $this->pagination($which);

                ?>
                <br class="clear" />
            </div>
            <?php
        }

        /**
         * Disables the views for 'side' context as there's not enough free space in the UI
         * Only displays them on screen/browser refresh. Else we'd have to do this via an AJAX DB update.
         * 
         * @see WP_List_Table::extra_tablenav()
         */
        public function extra_tablenav($which)
        {
            global $wp_meta_boxes;
            $views = $this->get_views();
            if (empty($views)) return;

            $this->views();
        }

    }

}

And this is how I loading the class:

Read More
function frequent_traveler_admin_actions()
{
    add_menu_page('Frequent Traveler', 'Frequent Traveler', 'activate_plugins', 'ftravelerlist', 'ft_list');
}

add_action('admin_menu', 'frequent_traveler_admin_actions');

function ft_list()
{
    $ftList = new FT_WP_Table();
    echo '</pre><div class="wrap"><h2>'. __('Listing Data') .'</h2>';
    $ftList->prepare_items();
    $ftList->display();
    echo '</div>';
}

But I get not output and by output I mean no records since I get the table twice, see the image below for more info:

What did I do wrong?

Related posts

Leave a Reply

1 comment

  1. You don’t need to fire the methods prepare_items() and display(), this is enough:

    function ft_list()
    {
        echo '<div class="wrap"><h2>'. __('Listing Data') .'</h2>';
        $ftList = new FT_WP_Table();
        echo '</div>';
    }
    

    Check that your SQL query is working ok in phpMyAdmin (or similar tool). As I don’t have the same data as you, I’ve tested with:

    $args = array('ID', 'post_title', 'post_author' );
    $sql_select = implode(', ', $args);
    $sql_results = $wpdb->get_results("SELECT " . $sql_select . " FROM " . $wpdb->posts);
    

    And with:

    public function get_columns()
    {
        $columns = array(
            'ID' => __('ID'),
            'post_title' => __('Title'),
            'post_author' => __('Author')
        );
        return $columns;
    }
    
    public function get_sortable_columns()
    {
        $sortable = array(
            'ID' => array('ID', true),
            'post_title' => array('post_title', true),
            'post_author' => array('post_author', true)
        );
        return $sortable;
    

    Result:

    Related answer