If the menu type is list_table
, the administration menu callback defines the list table instead of the menu page. The list table callback involves defining and returning an array consisting of strings, arrays or callbacks. You can also use callbacks in the list table definition for dynamic strings or arrays.
The documentation is based on Cars sample dataset.
function saturn_tables_cars_list_table_func($page = "", $item = array(), $page_number = 1) {
/* BASED ON CARS DATA SET */
/* STANDARD LIST TABLE DEFINITIONS */
$add_new_link = admin_url("/admin.php/?page=my-cars-add-edit-car&id=0");
$list_table_definitions['menu_title'] = '<h1 class="wp-heading-inline">View Cars</h1><a href="' . $add_new_link . '" class="page-title-action">Add New</a>';
$list_table_definitions['notices'] = 'saturn_tables_cars_admin_notices';
$list_table_definitions['header'] = '<p>The cars database is a short list of car information.</p>' ;
$list_table_definitions['columns'] = array('cb' => '<input type="checkbox" />', 'make' => "Make", 'model' => "Model", 'mpg' => "MPG", 'cylinders' => "Cylinders", 'weight' => "Weight", 'model_year' => "Model Year", 'country' => "Country");
$list_table_definitions['get_data'] = 'saturn_tables_cars_return_items';
$list_table_definitions['get_data_count'] = 'saturn_tables_cars_return_items_count';
/* LIST TABLE ACTION DEFINITION VALUES */
$list_table_definitions['column_markup'] = call_user_func('saturn_tables_cars_list_table_markup', $page, $item,
$page_number);
$list_table_definitions['link_actions'] = call_user_func('saturn_tables_cars_list_table_actions', $page, $item,
$page_number);
$list_table_definitions['process_link_actions'] = 'saturn_tables_cars_process_link_actions';
$list_table_definitions['checkbox_id'] = 'id' ;
$list_table_definitions['bulk_actions'] = isset($_GET['status']) && ($_GET['status'] == "trash") ? array( 'bulk_delete' => 'Delete' ) : array( 'bulk_trash' => 'Trash' );
$list_table_definitions['process_bulk_actions'] = 'saturn_tables_cars_process_bulk_actions';
/* EXTRA LIST TABLE DEFINITION VALUES */
$list_table_definitions['views'] = call_user_func("saturn_tables_cars_views");
$list_table_definitions['search'] = array('label'=> "Search Make and Model", 'id' => "search_id");
$list_table_definitions['extra_navigation'] = "saturn_tables_cars_make_dropdown";
$list_table_definitions['filter_button'] = array('text' => "Filter By Make");
$list_table_definitions['sortable'] = array( 'make' => array( 'make', true ), 'model' => array( 'model', false ) );
$list_table_definitions['footer'] = '<p>Powered by <a href="https://saturntables.com/" target="_blank" rel="noopener noreferrer">Saturn Tables</a></p>';
return $list_table_definitions;
}
Menu Title (string)
array key: menu_title
The Saturn Tables list table callable menu title array item will override the menu title defined in the menu declaration if set. This allows menu titles to be dynamic or to be removed if desired.
Behavior:
menu_title
not set: Default menu from menu declarationmenu_title
set and blank: No menu title displayedmenu_title
defined: Overrides default menu title
Menu title in sample list table
$add_new_link = admin_url("/admin.php/?page=my-cars-add-edit-car&id=0");
$list_table_definitions['menu_title'] = '<h1 class="wp-heading-inline">View Cars</h1><a href="' . $add_new_link . '" class="page-title-action">Add New</a>';
Notices (callable)
array key: notices
no return value
Standard admin notices are available through a Saturn Tables callable and are hooked to the admin_notices
hook. In general, you need to make use of form or query string variables to manipulate admin notices. Since admin notices in Saturn Tables are called via a hook they are echoed out and not returned programmatically.
For more on admin notices go to https://codex.wordpress.org/Plugin_API/Action_Reference/admin_notices
function saturn_tables_cars_admin_notices() {
if (isset($_GET['delete']) && ($model = $_GET['delete']) ) {
echo '<div class="notice notice-success is-dismissible"><p>' . __( "Model $model has been deleted.", "saturn-tables" ) . '</p></div>';
} elseif (isset($_GET['trash']) && ($model = $_GET['trash'])) {
echo '<div class="notice notice-success is-dismissible"><p>' . __( "Model $model has been placed in the trash.", "saturn-tables" ) . '</p></div>';
} elseif (isset($_GET['bulk']) && ($bulk = $_GET['bulk']) == 'trash') {
$count = $_GET['count'];
echo '<div class="notice notice-success is-dismissible"><p>' . __( "$count item(s) have been placed in the trash.", "saturn-tables" ) . '</p></div>';
} elseif (isset($_GET['bulk']) && ($bulk = $_GET['bulk']) == 'delete') {
$count = $_GET['count'];
echo '<div class="notice notice-success is-dismissible"><p>' . __( "$count item(s) have been deleted.", "saturn-tables" ) . '</p></div>';
}
}
Header (string)
array key: header
The header array item is a HTML string that is displayed between the menu title and the list table. It is displayed within the form so form variables can be embedded, any HTML content will be displayed.
$list_table_definitions['header'] = '<p>The cars database is a short list of car information.</p>';
Columns (array)
array key: columns
The columns array item defines the columns that will be displayed when rendering the list table, Aside from the checkbox definition, column array keys must match the array keys of the items, or rows, returned by the list table query when the get_data
array is formed with the database query.
$list_table_definitions['columns'] = array('cb' => '<input type="checkbox" />', 'make' => "Make", 'model' => "Model", 'mpg' => "MPG", 'cylinders' => "Cylinders", 'weight' => "Weight", 'model_year' => "Model Year", 'country' => "Country");
Get Data (callable)
array key: get_data
returns: array of array
The get_data
array returns the rows of data to be displayed and used in list table processing generally called items in list table construction. The array is returned in rows of associative arrays with the associative keys corresponding to the keys of the columns array. This array of arrays can correspond directly to a $wpdb
result set if the result set is returned in ARRAY_A
format. This array and database query must also account for pagination and any search terms or WHERE
clauses. These parameters can be brought into the callable via query string.
WordPress $wpdb
documentation available at https://codex.wordpress.org/Class_Reference/wpdb
$list_table_definitions['get_data'] = 'saturn_tables_cars_return_items';
function saturn_tables_cars_return_items($per_page, $page_number) {
global $wpdb;
$offset = ($per_page * ($page_number -1));
$orderby_clause = "";
if (isset($_GET['orderby']) && isset($_GET['order'])) {
$orderby = esc_sql($_GET['orderby']);
$order = esc_sql($_GET['order']);
$orderby_clause = "ORDER BY $orderby $order";
}
$where_clause[] = 1;
if (isset($_GET['status'])) {
$status = ($_GET['status'] == "trash") ? 1 : 0;
$where_clause[] = "status = $status";
} else {
$where_clause[] = "status = 0";
}
if (isset($_GET['s'])) {
$search = esc_sql($_GET['s']);
$where_clause[] = "CONCAT_WS(' ', make, model) LIKE '%$search%'";
}
if (isset($_GET['make'])) {
$make = esc_sql($_GET['make']);
$where_clause[] = ($make == "All Makes") ? 1 : "make = '$make'";
}
$where_clause = implode(" AND ", $where_clause);
$query = "SELECT id, make, model, mpg, cylinders, weight, model_year, country FROM saturn_tables_cars WHERE $where_clause $orderby_clause LIMIT $per_page OFFSET $offset";
$items = $wpdb->get_results($query, ARRAY_A);
$wpdb->flush();
return $items;
}
Get Data Count (callable)
array key: get_data_count
returns: integer
The get_data_count
functionality returns the total count of rows returned in the list table for display and pagination. This count should take into account the search terms and WHERE
clauses but ignore pagination, the query is similar to the get_data query without pagination.
WordPress $wpdb
documentation available at https://codex.wordpress.org/Class_Reference/wpdb
$list_table_definitions['get_data_count'] = 'saturn_tables_cars_return_items_count';
function saturn_tables_cars_return_items_count() {
global $wpdb;
$where_clause[] = 1;
if (isset($_GET['status'])) {
$status = ($_GET['status'] == "trash") ? 1 : 0;
$where_clause[] = "status = $status";
}
if (isset($_GET['s'])) {
$search = esc_sql($_GET['s']);
$where_clause[] = "CONCAT_WS(' ', make, model) LIKE '%$search%'";
}
if (isset($_GET['make'])) {
$make = esc_sql($_GET['make']);
$where_clause[] = ($make == "All Makes") ? 1 : "make = '$make'";
}
$where_clause = implode(" AND ", $where_clause);
$query = "SELECT count(*) FROM saturn_tables_cars WHERE $where_clause";
return $wpdb->get_var($query);
}
Column Markup
array key: column_markup
The column_markup definition defines the markup such as applying a bold font weight, font color or links surrounding a data value. Generally it would be a bold link to edit the row itself through an input form or maybe a link on a data value to apply a filter based on the value. The column markup simply applies formatting and HTML to the data based on the column key.
$list_table_definitions['column_markup'] = call_user_func('saturn_tables_cars_list_table_markup', $page, $item, $page_number);
function saturn_tables_cars_list_table_markup($page, $item, $page_number) {
$item_id = (isset($item['id']) && ((int)$item['id'] > 0)) ? $item['id'] : 0;
$make = (isset($item['make'])) ? $item['make'] : "";
return array('make' => sprintf('<strong><a href="?page=%s&id=%d">%s</a></strong>', 'saturn-tables-cars-add-edit-car', $item_id, $make ) );
}
Link Actions (array)
array key: link_actions
array values: array(column key => array(action links…))
The link_actions
definition defines the links that generally appear when hovering over the primary data column. The actions usually consist of links which either open up editing pages or similar, or cause a delete through the process_link_actions
callable. Although actions are defined as an array, since they usually include per rows values and are different in Standard or Trash views a defined callable is usually best. In general an action must link to an appropriate query string with values that will be used in processing via process_link_actions
.
$list_table_definitions['link_actions'] = call_user_func('saturn_tables_cars_list_table_actions', $page, $item, $page_number);
function saturn_tables_cars_list_table_actions ( $page, $item, $page_number) {
$item_id = (isset($item['id']) && ((int)$item['id'] > 0)) ? $item['id'] : 0;
if (isset($_GET['status']) && ($_GET['status'] == "trash")) {
$links = array( 'make' => array('delete' => sprintf( '<a href="?page=%s&delete_id=%d&paged=%d">Delete Permanently</a>', $page, $item_id, $page_number ),
'restore' => sprintf( '<a href="?page=%s&restore_id=%d&paged=%d">Restore</a>', $page, $item_id, $page_number )));
} else {
$links = array( 'make' => array('trash' => sprintf( '<a href="?page=%s&trash_id=%d&paged=%d">Trash</a>', $page, $item_id , $page_number ),
'edit' => sprintf( '<a href="?page=%s&id=%d">Edit</a>', 'saturn-tables-cars-add-edit-car', $item_id ) ) );
}
return $links;
}
Process Link Actions (callable)
array key: process_link_actions
redirects and exits on execution
The process_link_actions
callable executes on list table construction and is designed to use query string values including a test value to invoke execution. If this test value is not set this callable should do nothing. If the test value is set the link action; usually delete, trash or edit, is executed and there is a redirect without this test value causing process_link_actions to then do nothing. On redirect usually some values, such as pagination or view should be specified. The sample code works from the query string so the test value that causes execution must be intentionally removed before redirect or the list table will redirect endlessly on construction. Note that this callable work directly from the links specified in the actions list table definition value.
$list_table_definitions['process_link_actions'] = 'saturn_tables_cars_process_link_actions';
function saturn_table_cars_process_link_actions() { global $wpdb; if ( (isset($_GET['delete_id']) && $delete_id = (int)$_GET['delete_id']) > 0) { $model = $wpdb->get_var("SELECT model FROM saturn_tables_cars WHERE id = $delete_id"); $wpdb->delete( 'saturn_tables_cars', array('id' => $delete_id), array('id' => '%d')); //redirect without delete_id parse_str($_SERVER['QUERY_STRING'], $query_string); unset($query_string['delete_id']); $query_string['delete'] = $model; $query_string['status'] = "trash"; $redirect = admin_url() . "?" . http_build_query($query_string); wp_redirect( $redirect ); exit; } elseif ( isset($_GET['trash_id']) && ($trash_id = (int)$_GET['trash_id']) > 0) { $model = $wpdb->get_var("SELECT model FROM saturn_tables_cars WHERE id = $trash_id"); $wpdb->update( 'saturn_tables_cars', array('status' => 1), array('id' => $trash_id), array('%d'), array('%d') ); //redirect without trash_id parse_str($_SERVER['QUERY_STRING'], $query_string); unset($query_string['trash_id']); $query_string['trash'] = $model; $redirect = admin_url() . "?" . http_build_query($query_string); wp_redirect( $redirect ); exit; } elseif ( isset($_GET['restore_id']) && ($restore_id = (int)$_GET['restore_id']) > 0) { $model = $wpdb->get_var("SELECT model FROM saturn_tables_cars WHERE id = $restore_id"); $wpdb->update( 'saturn_tables_cars', array('status' => 0), array('id' => $restore_id), array('%d'), array('%d') ); //redirect without trash_id parse_str($_SERVER['QUERY_STRING'], $query_string); unset($query_string['restore_id']); $query_string['restore'] = $model; $query_string['status'] = "trash"; $redirect = admin_url() . "?" . http_build_query($query_string); wp_redirect( $redirect ); exit; } }
Checkbox Id (string)
array key: checkbox_id
This value specifies the column key used in get_data
to define the form value for the checkbox if the checkbox cb
is present. Saturn Tables specifically reserves the checkbox cb
. Generally the checkbox_id
value should be the primary key of the table, it should certainly be unique for each row. The checkbox values are generally used in bulk actions.
$list_table_definitions['checkbox_id'] = 'id';
Bulk Actions (array)
array key: bulk_actions array value: array(bulk action key and name => bulk action dropdown value)
The bulk_actions
array populates the bulk actions dropdown with the array key becoming the option value and the array value becoming the corresponding dropdown display value. The list table bulk action dropdown name is action
for the top and action2 for the bottom
, which both should be retrieved from the query string when processing the bulk action.
$list_table_definitions['bulk_actions'] = isset($_GET['status']) && ($_GET['status'] == "trash") ? array( 'bulk_delete' => 'Delete' ) : array( 'bulk_trash' => 'Trash' );
Process Bulk Actions (callable)
array key: process_bulk_actions
redirects and exits on execution
The process_bulk_actions
callable executes on list table construction and is designed to use query string values based on action
and action2
to invoke execution. If action
and action2
are not set to a value used for processing this callable should do nothing. Like link actions bulk actions are commonly used to delete or put things in the trash. The process_bulk_actions
callable should redirect after processing and usually some values, such as pagination or view should be specified on redirect. The bulk action generally uses checkbox array cb[]
during processing and redirects when action
or action2
are set.
function saturn_tables_cars_process_bulk_actions() {
global $wpdb;
if (isset($_GET['action']) && ($_GET['action'] == 'bulk_trash') || (isset($_GET['action2']) && ($_GET['action2'] == 'bulk_trash' ))) {
$trash_ids = esc_sql( $_GET['cb'] );
$count = 0;
foreach ($trash_ids as $id) {
$affected = $wpdb->update( 'saturn_tables_cars', array('status' => 1), array('id' => $id), array('%d'), array('%d') );
$count += $affected;
}
parse_str($_SERVER['QUERY_STRING'], $query_string);
unset($query_string['action'],$query_string['action2']);
$query_string['bulk'] = "trash";
$query_string['count'] = $count;
$redirect = admin_url() . "?" . http_build_query($query_string);
wp_redirect( $redirect );
exit;
} elseif (isset($_GET['action']) && ($_GET['action'] == 'bulk_delete') || (isset($_GET['action2']) && ($_GET['action2'] == 'bulk_delete' ))) {
$delete_ids = esc_sql( $_GET['cb'] );
$count = 0;
foreach ($delete_ids as $id) {
$affected = $wpdb->delete( 'saturn_tables_cars', array('id' => $id), array('id' => '%d'));;
$count += $affected;
}
parse_str($_SERVER['QUERY_STRING'], $query_string);
unset($query_string['action'],$query_string['action2']);
$query_string['bulk'] = "delete";
$query_string['status'] = "trash";
$query_string['count'] = $count;
$redirect = admin_url() . "?" . http_build_query($query_string);
wp_redirect( $redirect );
exit;
}
}
Views (array)
array key: views
The views
definition provides links generally used for different views such as All, Trash or Active. Views generally require some logic, as the active views
should not be a link, but instead should be bold. So in the example dataset views
, like link_actions
, are returned by a callable via call_user_func
. Views
are generally links with query string variables defining how the data should be returned. Note both get_data
and get_data_count
must accommodate the view definition.
function saturn_tables_cars_views() {
if (isset($_GET['status']) && $_GET['status'] == "trash") {
$all = '<a href="' . admin_url("admin.php?page=my-cars-table&status=all") . '">' . __("All") . '</a>';
$trash = '<strong>' . __("Trash") . '</strong>';
} else {
$all = '<strong>' . __("All") . '</strong>';
$trash = '<a href="' . admin_url("admin.php?page=my-cars-table&status=trash") . '">' . __("Trash") . '</a>';
}
return array( "all" => $all, "trash" => $trash);
}
Search (array)
array key: search
The search
definition utilizes the standard search functionality used with List Tables. Simply defining the search
array will cause the search box with query string variable name “s” to appear. The label will define the search button label and the id will define the text input id. The search terms must be accommodated via get_data
and get_data_count
for searching.
$list_table_definitions['search'] = array('label'=> "Search Make and Model", 'id' => "search_id");
Extra Navigation (callable)
array key: extra_navigation
returns: HTML string
The extra_navigation
definition is designed so that a filter can be accommodated, generally dropdowns, but it also could be radio buttons or similar. The extra_navigation
is outputted into the List Table form and the form values must be processed via query string in get_data
and get_data_count
. Typically the extra_navigation is followed by the filter button, however the filter button could be omitted for various reasons, including a Javascript submit.
$list_table_definitions['extra_navigation'] = "saturn_tables_cars_make_dropdown";
function saturn_tables_cars_make_dropdown() { global $wpdb; $makes = $wpdb->get_col( "SELECT DISTINCT make FROM saturn_tables_cars ORDER BY make" ); $output = '<label for="filter-by-make" class="screen-reader-text">Filter by Make</label>'; $output .= '<select name="make" id="filter-by-make">'; $output .= '<option>All Makes</option>'; foreach ($makes as $make) { $selected = (isset($_GET['make']) && ($make == $_GET['make'])) ? " selected" : ""; $output .= "<option$selected>" . esc_html($make) ."</option>"; } $output .= '</select>'; return $output; }
Filter Button (array)
array key: filter_button
The filter_button
definition defines a submit button where the array keys are text, type, name, wrap
and other_attributes
. Note that the default values may be different than the default values of the WordPress function, specifically the type of button is not primary
but is button
. See the WordPress documentation for available values including defaults. The filter_button
will submit the form so it is advisable to check for it in the process_bulk_actions
callable if there are concerns.
WordPress submit_button documentation is here https://codex.wordpress.org/Function_Reference/submit_button
$list_table_definitions['filter_button'] = array('text' => "Filter By Make");
Sortable (array)
array key: sortable
The sortable
definition defines which columns are sortable
, and links the column header to place sort variables in the query string. There are 2 sort variables that are placed in the query string, orderby
which defines the column key to sort on, and order
which specifies descending or ascending (asc
or desc
). The true/false
boolean determines whether the first sort will be ascending or descending, true implies the column is sorted ascending and the next sort should be descending, false sets the first sort to ascending. Once the sort is set with the column header the query string variables need to be processed in get_data
. List Tables fully rely on the items returned in get_data
, note that sorting and paginating do not need to be considering when getting the record count in get_data_count
. Only search terms and WHERE
clauses need to be considered there for limiting the result set.
The implementation of sorting is done in the example here https://saturntables.com/list-tables/get-data/
$list_table_definitions['sortable'] = array( 'make' => array( 'make', true ), 'model' => array( 'model', false ) );
Footer (string)
array key: footer
The footer array item is a HTML string that is displayed below the list table. It is displayed within the form so form variables can be embedded, any HTML content will be displayed.
$list_table_definitions['footer'] = '<p>Powered by <a href="https://saturntables.com/" target="_blank">Saturn Tables</a></p>';