For those looking to implement WP_List_Table
, please note that all guides I found are woefully out of date and will either have write redundant code or actually ask you to do things that no longer work.
Here is a minimal example that works to some degree. It should be easy to understand without a "guide" and will get you started.
Includes:
- quick filters (views)
- search box
- row actions
Missing:
- page size configuration (I actually haven't seen a Wordpress page use this)
- bulk actions
- pulldown filters
class My_List_Table extends WP_List_Table {
function __construct() {
parent::__construct([
'singular' => 'employee',
'plural' => 'employees',
]);
}
function get_columns() {
return [
'name' => __('Name'),
'employer' => __('Employer'),
'rank' => __('Rank'),
'phone' => __('Telephone'),
'joined' => __('Join Date'),
];
}
/* Optional - without it no column is sortable */
public function get_sortable_columns() {
return [
// keys are "column_name" like above
// values are "order" field names as per what your data model needs
'name' => 'name',
'employer' => 'employer',
'rank' => 'rank',
'joined' => 'joined',
];
}
public function prepare_items() {
// support the search box
$search = @$_REQUEST['s'] ? wp_unslash(trim($_REQUEST['s']))) : '';
// get number of records per page setting from option storage
$per_page = $this->get_items_per_page('my_list_table_per_page');
// fill data array with your model items. In my implementation these
// are StdClass instances with various fields, but it can be anything
// we'll see in a minute how.
$this->items = get_model_items([
'offset' => ($this->get_pagenum()-1)*$per_page,
'count' => $per_page,
'orderby' => @$_GET["orderby"] ?: 'id', // default order field, if not specified
'order' => @$_GET["order"] ?: 'ASC', // default order direction
'search' => $search, // pass search field if set
'status' => @$_REQUEST['status'] // pass view filter, if set [see get_views()]
);
$this->set_pagination_args([
"total_items" => get_model_item_count(),
"per_page" => $per_page,
]);
// `get_model_item_count` should be the total number of records after
// filtering (views and search) but before paging. This may be hard/inefficient
// to do with MySQL. If you want to put the results of `COUNT(*)` here,
// no one will blame you.
}
public function column_default($item, $column_name) {
// default column presentation
// Most of my object fields are printable as is, so we have a generic
// method to handle that.
return $item->$column_name;
}
/* Optional, unless you have data that requires special formatting */
public function column_joined($item) {
// The 'joined' field is a DateTime object and can't be implicitly
// converted to string by the built-in logic, so we'll need to do it
return $item->joined->format("Y-m-d");
}
/* Optional - draw quick filters on top of the table */
public function get_views() {
$makelink = function($filter_val, $name) { // DRYing tool for view makers
$filter_name = 'status';
return '<a href="'
. esc_url(add_query_arg($filter_name, $filter_val)) . '" ' .
(@$_REQUEST[$filter_name]==$filter_val ?
'class="current" aria-current="page"' : ''). ">" .
$name . "</a>";
};
return [
'all' => $makelink(false, __('All')),
'green' => $makelink('green', __('Newbs')),
'pros' => $makelink('pro', __('Experts')),
'bofh' => $makelink('veteran', __('Crusty fellows')),
];
}
/* Optional: row actions */
public function handle_row_actions($item, $column_name, $primary) {
$out = parent::handle_row_actions($item, $column_name, $primary);
if ($column_name === $primary)
$out .= $this->row_actions([
'edit' => sprintf('<a href="%s">%s</a>',
add_query_arg('employee_id', $item->id, admin_url('admin.php?page=edit-employee')),
__("Edit")),
'delete' => sprintf('<a href="%s">%s</a>',
add_query_arg('employee_id', $item->id, admin_url('admin.php?page=delete-employee')),
__("Delete")),
]);
return $out;
}
}
Then the admin page function (for add_menu_page
/add_submenu_page
) may look like this:
function drawAdminPage() {
$my_list_table = new My_List_Table();
$my_list_table->prepare_items();
?>
<div class="wrap">
<h1 class="wp-heading-inline"><?php _e('Admin Page Title')?></h1>
<hr class="wp-header-end">
<?php $my_list_table->views() ?>
<form id="employee-filter" method="get">
<input type="hidden" name="page" value="<?php echo $_REQUEST['page']?>">
<?php $my_list_table->search_box(__('Search'), 'employee') ?>
<?php $my_list_table->display(); ?>
</form>
</div>
<?php
}
WP_List_Table
. This question can probably be updated with information on how to use it.