构建复杂 WordPress 后台数据列表:WP_List_Table
深度解析与实践
大家好,今天我们来深入探讨如何利用 WordPress 的 WP_List_Table
类来构建复杂的后台数据列表,并实现高级筛选和分页功能。WP_List_Table
是一个强大的工具,可以帮助我们轻松地在 WordPress 后台创建自定义的数据展示界面,提供用户友好的交互体验。
1. WP_List_Table
类概述
WP_List_Table
类位于 wp-admin/includes/class-wp-list-table.php
文件中。它是一个抽象类,我们需要继承它并实现其中的一些方法,才能创建我们自己的列表。该类提供了以下核心功能:
- 数据展示: 将数据以表格的形式展示在后台。
- 分页: 自动处理分页逻辑,方便用户浏览大量数据。
- 排序: 允许用户根据不同的列对数据进行排序。
- 批量操作: 支持用户对选中的数据进行批量操作。
- 列管理: 允许用户自定义显示的列。
- 搜索: 提供搜索功能,方便用户查找数据。
2. 创建自定义列表类
首先,我们需要创建一个自定义类,继承 WP_List_Table
。例如,我们创建一个 My_Custom_List_Table
类来展示一些自定义数据,比如用户提交的反馈信息。
if ( ! class_exists( 'WP_List_Table' ) ) {
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}
class My_Custom_List_Table extends WP_List_Table {
public function __construct() {
parent::__construct( [
'singular' => 'feedback', // 单数形式,用于 URL 参数
'plural' => 'feedbacks', // 复数形式,用于 URL 参数
'ajax' => false // 是否启用 AJAX 分页和排序
] );
}
// ... 其他方法将在后面实现
}
在构造函数中,我们调用了父类的构造函数,并传入了一个数组作为参数。这个数组定义了一些基本属性,例如单数和复数形式的名称,以及是否启用 AJAX。
3. 定义列
接下来,我们需要定义要在表格中显示的列。我们需要实现 get_columns()
方法,该方法返回一个关联数组,键是列的 ID,值是列的标题。
public function get_columns() {
$columns = [
'cb' => '<input type="checkbox" />', // 用于批量操作的复选框
'id' => 'ID',
'name' => '姓名',
'email' => '邮箱',
'message' => '留言',
'date' => '日期'
];
return $columns;
}
cb
列是用于批量操作的复选框列,它是必须的。
4. 定义可排序的列
如果我们希望用户能够根据某些列对数据进行排序,我们需要实现 get_sortable_columns()
方法。该方法返回一个关联数组,键是列的 ID,值是一个数组,包含列的 ID 和一个布尔值,表示是否默认升序排序。
public function get_sortable_columns() {
$sortable_columns = [
'id' => [ 'id', true ], // ID 列可排序,默认升序
'name' => [ 'name', false ], // 姓名列可排序,默认降序
'email' => [ 'email', false ], // 邮箱列可排序,默认降序
'date' => [ 'date', true ] // 日期列可排序,默认升序
];
return $sortable_columns;
}
5. 准备数据
在展示数据之前,我们需要从数据库或其他来源获取数据,并将其格式化为 WP_List_Table
类可以使用的格式。我们需要实现 prepare_items()
方法。
public function prepare_items() {
global $wpdb;
$per_page = 20; // 每页显示的数据条数
$columns = $this->get_columns();
$hidden = [];
$sortable = $this->get_sortable_columns();
$this->_column_headers = [ $columns, $hidden, $sortable ];
$current_page = $this->get_pagenum();
// 获取排序参数
$orderby = isset( $_GET['orderby'] ) ? $_GET['orderby'] : 'date';
$order = isset( $_GET['order'] ) ? $_GET['order'] : 'desc';
// 构建 SQL 查询
$table_name = $wpdb->prefix . 'my_custom_table'; // 替换为你的表名
$sql = "SELECT * FROM $table_name";
// 处理排序
if ( ! empty( $orderby ) ) {
$sql .= ' ORDER BY ' . esc_sql( $orderby );
$sql .= ! empty( $order ) ? ' ' . esc_sql( $order ) : ' ASC';
}
// 计算总数据条数
$total_items = $wpdb->query( $sql );
// 处理分页
$sql .= " LIMIT " . ( ( $current_page - 1 ) * $per_page ) . " , " . $per_page;
// 获取数据
$data = $wpdb->get_results( $sql, ARRAY_A ); // ARRAY_A 返回关联数组
$this->items = $data;
// 配置分页
$this->set_pagination_args( [
'total_items' => $total_items, // 总数据条数
'per_page' => $per_page, // 每页显示的数据条数
'total_pages' => ceil( $total_items / $per_page ) // 总页数
] );
}
在这个方法中,我们首先定义了每页显示的数据条数。然后,我们获取了列的定义、隐藏列和可排序的列。接下来,我们构建了 SQL 查询,从数据库中获取数据。我们还处理了排序和分页逻辑。最后,我们将获取到的数据赋值给 $this->items
属性,并配置了分页参数。
6. 展示数据
现在,我们需要实现 column_default()
方法,该方法用于展示默认列的数据。对于 cb
列,我们需要实现 column_cb()
方法。
public function column_default( $item, $column_name ) {
switch ( $column_name ) {
case 'id':
return $item['id'];
case 'name':
return $item['name'];
case 'email':
return $item['email'];
case 'message':
return substr( $item['message'], 0, 50 ) . '...'; // 截取部分内容
case 'date':
return date( 'Y-m-d H:i:s', strtotime( $item['date'] ) );
default:
return print_r( $item, true ); // 用于调试,显示原始数据
}
}
public function column_cb( $item ) {
return sprintf(
'<input type="checkbox" name="bulk-delete[]" value="%s" />', $item['id']
);
}
在 column_default()
方法中,我们根据列的 ID,从数据中获取相应的值,并将其展示出来。在 column_cb()
方法中,我们生成了用于批量操作的复选框。
7. 批量操作
为了实现批量操作,我们需要实现 get_bulk_actions()
方法,该方法返回一个关联数组,键是操作的 ID,值是操作的标题。
public function get_bulk_actions() {
$actions = [
'delete' => '删除'
];
return $actions;
}
然后,我们需要在 prepare_items()
方法中处理批量操作的逻辑。
public function prepare_items() {
global $wpdb;
// ... 前面的代码省略
$this->process_bulk_action(); // 处理批量操作
// ... 后面的代码省略
}
private function process_bulk_action() {
if ( 'delete' === $this->current_action() ) {
$ids = isset( $_POST['bulk-delete'] ) ? $_POST['bulk-delete'] : [];
if ( ! empty( $ids ) ) {
$ids = array_map( 'absint', $ids ); // 转换为整数
$ids_string = implode( ',', $ids );
global $wpdb;
$table_name = $wpdb->prefix . 'my_custom_table'; // 替换为你的表名
$wpdb->query(
"DELETE FROM $table_name WHERE id IN ($ids_string)"
);
echo '<div class="updated"><p>已删除 ' . count( $ids ) . ' 条数据。</p></div>';
}
}
}
在 process_bulk_action()
方法中,我们首先判断当前的操作是否是删除操作。如果是,我们获取选中的数据的 ID,然后从数据库中删除这些数据。
8. 添加搜索功能
为了添加搜索功能,我们需要重写 prepare_items
方法,在 SQL 查询中加入 WHERE
子句。
public function prepare_items() {
global $wpdb;
$per_page = 20; // 每页显示的数据条数
$columns = $this->get_columns();
$hidden = [];
$sortable = $this->get_sortable_columns();
$this->_column_headers = [ $columns, $hidden, $sortable ];
$this->process_bulk_action(); // 处理批量操作
$current_page = $this->get_pagenum();
// 获取排序参数
$orderby = isset( $_GET['orderby'] ) ? $_GET['orderby'] : 'date';
$order = isset( $_GET['order'] ) ? $_GET['order'] : 'desc';
// 获取搜索词
$search_term = isset( $_REQUEST['s'] ) ? $_REQUEST['s'] : '';
// 构建 SQL 查询
$table_name = $wpdb->prefix . 'my_custom_table'; // 替换为你的表名
$sql = "SELECT * FROM $table_name";
// 处理搜索
if ( ! empty( $search_term ) ) {
$search_term = esc_sql( $search_term );
$sql .= " WHERE name LIKE '%$search_term%' OR email LIKE '%$search_term%' OR message LIKE '%$search_term%'"; // 可以根据需要添加更多的搜索字段
}
// 处理排序
if ( ! empty( $orderby ) ) {
$sql .= ' ORDER BY ' . esc_sql( $orderby );
$sql .= ! empty( $order ) ? ' ' . esc_sql( $order ) : ' ASC';
}
// 计算总数据条数
$total_items = $wpdb->query( $sql );
// 处理分页
$sql .= " LIMIT " . ( ( $current_page - 1 ) * $per_page ) . " , " . $per_page;
// 获取数据
$data = $wpdb->get_results( $sql, ARRAY_A ); // ARRAY_A 返回关联数组
$this->items = $data;
// 配置分页
$this->set_pagination_args( [
'total_items' => $total_items, // 总数据条数
'per_page' => $per_page, // 每页显示的数据条数
'total_pages' => ceil( $total_items / $per_page ) // 总页数
] );
}
public function search_box( $text, $input_id ) {
if ( empty( $_REQUEST['s'] ) && ! $this->has_items() ) {
return;
}
?>
<form id="feedback-filter" method="get">
<input type="hidden" name="page" value="<?php echo $_REQUEST['page'] ?>" />
<?php $this->search_box_input( $input_id ); ?>
<?php submit_button( $text, 'button', false, false, array('id' => 'search-submit') ); ?>
</form>
<?php
}
private function search_box_input( $input_id ) {
if ( ! empty( $_REQUEST['orderby'] ) ) {
echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';
}
if ( ! empty( $_REQUEST['order'] ) ) {
echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
}
if ( ! empty( $_REQUEST['post_status'] ) ) {
echo '<input type="hidden" name="post_status" value="' . esc_attr( $_REQUEST['post_status'] ) . '" />';
}
?>
<label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( '搜索反馈:' ); ?></label>
<input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>" />
<?php
}
我们从 $_REQUEST['s']
中获取搜索词,并将其添加到 SQL 查询的 WHERE
子句中。我们还添加了一个搜索框,方便用户输入搜索词。
9. 添加高级筛选
高级筛选允许用户根据更复杂的条件筛选数据。我们可以通过添加自定义的表单元素来实现高级筛选。
public function extra_tablenav( $which ) {
if ( $which == "top" ) {
// 在表格上方添加自定义筛选表单
?>
<div class="alignleft actions">
<select name="filter_status">
<option value="">所有状态</option>
<option value="pending" <?php selected( isset( $_GET['filter_status'] ) ? $_GET['filter_status'] : '', 'pending' ); ?>>待处理</option>
<option value="approved" <?php selected( isset( $_GET['filter_status'] ) ? $_GET['filter_status'] : '', 'approved' ); ?>>已批准</option>
<option value="rejected" <?php selected( isset( $_GET['filter_status'] ) ? $_GET['filter_status'] : '', 'rejected' ); ?>>已拒绝</option>
</select>
<?php
submit_button( '筛选', 'button', 'filter_action', false, array( 'id' => 'filter-submit' ) );
?>
</div>
<?php
}
if ( $which == "bottom" ) {
// 在表格下方添加其他内容(可选)
}
}
public function prepare_items() {
global $wpdb;
// ... 前面的代码省略
// 获取筛选参数
$filter_status = isset( $_GET['filter_status'] ) ? $_GET['filter_status'] : '';
// 构建 SQL 查询
$table_name = $wpdb->prefix . 'my_custom_table'; // 替换为你的表名
$sql = "SELECT * FROM $table_name";
// 处理筛选
if ( ! empty( $filter_status ) ) {
$filter_status = esc_sql( $filter_status );
$sql .= " WHERE status = '$filter_status'";
}
// ... 后面的代码省略
}
我们使用 extra_tablenav()
方法在表格上方添加了一个自定义的筛选表单,包含一个状态选择框。然后,我们在 prepare_items()
方法中获取筛选参数,并将其添加到 SQL 查询的 WHERE
子句中。
10. 在后台页面中使用列表类
最后,我们需要在后台页面中使用我们创建的列表类。
function my_custom_admin_page() {
?>
<div class="wrap">
<h1>用户反馈</h1>
<?php
$my_list_table = new My_Custom_List_Table();
$my_list_table->prepare_items();
// 添加搜索框
?>
<form method="post">
<input type="hidden" name="page" value="<?php echo $_REQUEST['page'] ?>" />
<?php
$my_list_table->search_box( '搜索', 'feedbacksearch' );
?>
</form>
<?php
$my_list_table->display();
?>
</div>
<?php
}
function my_custom_admin_menu() {
add_menu_page(
'用户反馈',
'用户反馈',
'manage_options',
'my-custom-admin-page',
'my_custom_admin_page'
);
}
add_action( 'admin_menu', 'my_custom_admin_menu' );
我们创建了一个后台页面,并在该页面中实例化了 My_Custom_List_Table
类。然后,我们调用 prepare_items()
方法准备数据,最后调用 display()
方法展示列表。
总结: 构建强大的后台数据列表
通过继承 WP_List_Table
类,定义列、排序、批量操作、搜索和高级筛选,我们可以轻松构建强大的后台数据列表,为用户提供便捷的数据管理界面。
最后要说的话
WP_List_Table
类功能强大,用法灵活,需要根据具体需求进行调整和扩展。希望这篇文章能够帮助你更好地理解和使用 WP_List_Table
类,构建出更加优秀的 WordPress 后台界面。