Ví dụ về cách sử dụng WP_List_Table

Cập nhật lần cuối vào

WP_List_Table là class cho phép bạn tạo bất kỳ một bảng quản lý các thành phần nào trong admin. Như bạn thấy danh sách Posts, Pages hoặc Users trong WordPress đều kế thừa từ class WP_List_Table. Nếu trong giao diện hoặc plugin của bạn có các dữ liệu theo kiểu danh sách, và bạn muốn tạo trang quản lý danh sách này trong phần options thì bài viết này có thể sẽ giúp ích được cho bạn.

Tạo class kế thừa WP_List_Table

Để hiển thị bất kỳ danh sách nào thì bạn tạo 1 class kế thừa WP_List_Table.

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

class HPDL_API_Key_List_Table extends WP_List_Table {

	public $delete_posts;
	public $date_format;
	public $time_format;

	function __construct() {
		global $status, $page;
		$this->date_format = get_option( 'date_format' );
		$this->time_format = get_option( 'time_format' );
		parent::__construct( array(
			'singular' => __( 'api_key', 'hocwp-pdl' ),
			'plural'   => __( 'api_keys', 'hocwp-pdl' ),
			'ajax'     => false
		) );
		add_action( 'admin_head', array( &$this, 'admin_header' ) );
	}

	function admin_header() {
		global $plugin_page;
		if ( 'hocwp_pdl' != $plugin_page ) {
			return;
		}
	}

	function no_items() {
		_e( 'No API Key found, dude.', 'hocwp-pdl' );
	}

	function column_default( $item, $column_name ) {
		switch ( $column_name ) {
			case 'id':
				return $item->ID;
			case 'date':
				$date = date( "$this->date_format $this->time_format", strtotime( $item->post_date ) );

				return $date;
			case 'domain':
			case 'key':
				return get_post_meta( $item->ID, $column_name, true );
			default:
				return print_r( $item, true );
		}
	}

	function get_sortable_columns() {
		$sortable_columns = array(
			'id'     => array( 'id', false ),
			'domain' => array( 'domain', false ),
			'key'    => array( 'key', false ),
			'date'   => array( 'date', false )
		);

		return $sortable_columns;
	}

	function get_columns() {
		$columns = array(
			'cb'     => '<input type="checkbox" />',
			'id'     => __( 'ID', 'hocwp-pdl' ),
			'domain' => __( 'Domain', 'hocwp-pdl' ),
			'key'    => __( 'Key', 'hocwp-pdl' ),
			'date'   => __( 'Date', 'hocwp-pdl' )
		);

		return $columns;
	}

	function column_id( $item ) {
		global $plugin_page;
		$tab     = 'api_keys';
		$edit    = admin_url( 'post.php?post=' . $item->ID . '&action=edit' );
		$actions = array(
			'edit'   => sprintf( '<a href="%s">Edit</a>', $edit ),
			'delete' => sprintf( '<a href="?page=%s&action=%s&api_key=%s&tab=%s">Delete</a>', $plugin_page, 'delete', $item->ID, $tab ),
		);

		return sprintf( '%1$s %2$s', $item->ID, $this->row_actions( $actions ) );
	}

	function get_bulk_actions() {
		$actions = array(
			'delete' => __( 'Delete', 'hocwp-pdl' )
		);

		return $actions;
	}

	function column_cb( $item ) {
		return sprintf(
			'<input type="checkbox" name="api_keys[]" value="%s" />', $item->ID
		);
	}

	function prepare_items() {
		$columns               = $this->get_columns();
		$hidden                = array();
		$sortable              = $this->get_sortable_columns();
		$this->_column_headers = array( $columns, $hidden, $sortable );
		$per_page              = get_option( 'posts_per_page' );
		if ( ! is_numeric( $per_page ) ) {
			$per_page = 10;
		}
		$current_page = $this->get_pagenum();
		$by           = ( ! empty( $_GET['orderby'] ) ) ? $_GET['orderby'] : 'ID';
		if ( 'id' == $by ) {
			$orderby = 'ID';
		} elseif ( 'date' == $by ) {
			$orderby = 'date';
		} else {
			$orderby = 'meta_value';
		}
		$order = ( ! empty( $_GET['order'] ) ) ? $_GET['order'] : 'asc';
		$args  = array(
			'post_type'      => 'hpdl_api_key',
			'posts_per_page' => $per_page,
			'paged'          => $current_page,
			'orderby'        => $orderby,
			'order'          => $order
		);
		$s     = isset( $_POST['s'] ) ? $_POST['s'] : '';
		if ( ! empty( $s ) ) {
			$args['meta_query'] = array(
				'relation' => 'or',
				array(
					'key'     => 'domain',
					'value'   => $s,
					'compare' => 'like'
				),
				array(
					'key'     => 'key',
					'value'   => $s,
					'compare' => 'like'
				)
			);
		}
		switch ( $by ) {
			case 'key':
			case 'domain':
				$args['meta_key'] = $by;
				break;
		}
		$query = new WP_Query( $args );
		if ( ! $query->have_posts() && is_numeric( $s ) ) {
			$args['post__in'] = array( $s );
			unset( $args['meta_query'] );
			$query = new WP_Query( $args );
		}
		$total_items = $query->found_posts;
		$items       = $query->posts;
		$this->set_pagination_args( array(
			'total_items' => $total_items,
			'per_page'    => $per_page
		) );
		$this->found_data = $items;
		$this->items      = $items;
	}

	public function process_bulk_action() {
		if ( isset( $_POST['_wpnonce'] ) && ! empty( $_POST['_wpnonce'] ) ) {
			$nonce  = filter_input( INPUT_POST, '_wpnonce', FILTER_SANITIZE_STRING );
			$action = 'bulk-' . $this->_args['plural'];
			if ( ! wp_verify_nonce( $nonce, $action ) ) {
				wp_die( 'Nope! Security check failed!', 'hocwp-pdl' );
			}
		}
		$action = $this->current_action();

		switch ( $action ) {
			case 'delete':
				$api_key = isset( $_GET['api_key'] ) ? $_GET['api_key'] : '';
				$key     = get_post( $api_key );
				if ( $key instanceof WP_Post && 'hpdl_api_key' == $key->post_type ) {
					$deleted = wp_delete_post( $key->ID, true );
					if ( false != $deleted ) {
						?>
						<div class="notice notice-success is-dismissible">
							<p>
								<strong><?php _e( 'Info:', 'hocwp-pdl' ); ?></strong>&nbsp;<?php printf( __( '%s API Key has been deleted.', 'hocwp-pdl' ), 1 ); ?>
							</p>
						</div>
						<?php
					}
				} else {
					$api_keys = isset( $_POST['api_keys'] ) ? $_POST['api_keys'] : '';
					if ( is_array( $api_keys ) ) {
						$count = 0;
						foreach ( $api_keys as $api_key ) {
							$key = get_post( $api_key );
							if ( $key instanceof WP_Post && 'hpdl_api_key' == $key->post_type ) {
								$deleted = wp_delete_post( $key->ID, true );
								if ( false != $deleted ) {
									$count ++;
								}
							}
						}
						?>
						<div class="notice notice-success is-dismissible">
							<p>
								<strong><?php _e( 'Info:', 'hocwp-pdl' ); ?></strong>&nbsp;<?php printf( __( '%s API Key deleted.', 'hocwp-pdl' ), $count ); ?>
							</p>
						</div>
						<?php
					}
				}
				break;
		}
	}
}

Đoạn code bên trên mình tạo 1 custom post type là hpdl_api_key. Sau đó, mình muốn hiển thị danh sách các API Key trên trang options thay vì quản lý như post bình thường. Đoạn code tạo custom post type mình có như sau:

$labels = array(
	'name'               => _x( 'API Keys', 'post type general name', 'hocwp-pdl' ),
	'singular_name'      => _x( 'API Key', 'post type singular name', 'hocwp-pdl' ),
	'menu_name'          => _x( 'API Keys', 'admin menu', 'hocwp-pdl' ),
	'name_admin_bar'     => _x( 'API Key', 'add new on admin bar', 'hocwp-pdl' ),
	'add_new'            => _x( 'Add New', 'api key', 'hocwp-pdl' ),
	'add_new_item'       => __( 'Add New API Key', 'hocwp-pdl' ),
	'new_item'           => __( 'New API Key', 'hocwp-pdl' ),
	'edit_item'          => __( 'Edit API Key', 'hocwp-pdl' ),
	'view_item'          => __( 'View API Key', 'hocwp-pdl' ),
	'all_items'          => __( 'All API Keys', 'hocwp-pdl' ),
	'search_items'       => __( 'Search API Keys', 'hocwp-pdl' ),
	'parent_item_colon'  => __( 'Parent API Keys:', 'hocwp-pdl' ),
	'not_found'          => __( 'No API Key found.', 'hocwp-pdl' ),
	'not_found_in_trash' => __( 'No API Key found in Trash.', 'hocwp-pdl' )
);
$args   = array(
	'labels'              => $labels,
	'show_in_nav_menus'   => false,
	'show_in_menu'        => true,
	'show_in_admin_bar'   => false,
	'show_ui'             => true,
	'capabilities'        => array(
		'edit_post'          => 'manage_options',
		'read_post'          => 'manage_options',
		'delete_post'        => 'manage_options',
		'edit_posts'         => 'manage_options',
		'edit_others_posts'  => 'manage_options',
		'publish_posts'      => 'manage_options',
		'read_private_posts' => 'manage_options',
		'create_posts'       => 'manage_options',
		'delete_posts'       => 'manage_options'
	),
	'supports'            => array( 'revisions' ),
	'rewrite'             => false,
	'exclude_from_search' => true,
	'publicly_queryable'  => false
);
register_post_type( 'hpdl_api_key', $args );

Chú ý là bạn phải để đoạn code trên vào trong action init của WordPress nhé.

Hiển thị danh sách trong list table

Để hiển thị danh sách này thì mình tạo 1 action admin_notices như bên dưới:

function hocwp_pdl_admin_notices_action() {
	global $pagenow, $plugin_page;
	if ( 'hocwp_pdl' == $plugin_page ) {
		global $hocwp_pdl;
		$hocwp_pdl->list_api_keys_table->process_bulk_action();
	}
}

add_action( 'admin_notices', 'hocwp_pdl_admin_notices_action' );

Bạn thay hocwp_pdl thành slug trang option mà bạn đang viết. Cuối cùng là trong hàm callback hiển thị HTML của trang option bạn để như sau:

<div style="padding-top: 20px;">
	<a href="<?php echo admin_url( 'edit.php?post_type=hpdl_api_key' ); ?>"
	   class="page-title-action button-primary" style="display: none"><?php _e( 'View Full Lists', 'hocwp-pdl' ); ?></a>
	<a href="<?php echo admin_url( 'post-new.php?post_type=hpdl_api_key' ); ?>"
	   class="page-title-action"><?php _e( 'Add New', 'hocwp-pdl' ); ?></a>
	<?php
	global $hocwp_pdl, $plugin_page;
	$hocwp_pdl->list_api_keys_table->prepare_items();
	?>
	<form method="post">
		<input type="hidden" name="page" value="<?php echo $plugin_page; ?>">
		<?php
		$hocwp_pdl->list_api_keys_table->search_box( __( 'Search Key', 'hocwp-pdl' ), 'search_id' );
		$hocwp_pdl->list_api_keys_table->display();
		?>
	</form>
</div>

Như vậy là bạn đã có thể hiển thị danh sách bất kỳ theo kiểu quản lý danh sách bài viết hoặc tài khoản. Bài viết chỉ mang tính chất tham khảo, các bạn không nên sao chép mà chỉ nên áp dụng có chọn lọc. Chúc bạn thành công.

Theo dõi
Thông báo của
guest

13 Comments
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất
Phản hồi nội tuyến
Xem tất cả bình luận
khám mắt
6 năm trước

Bài biết rất hữu ích, cảm ơn bạn nhé

Tỷ Giá Ngoại Tệ
6 năm trước

Cảm ơn Cường vì đã chia sẻ,

chevrolet VN
6 năm trước

mình đã tìm cách giải quyết vấn đề này từ lâu mà chưa được giờ thì đã làm được rồi.

Vũ WordPress
6 năm trước

Cảm ơn Cường đã chia sẻ nhé.

Nguyễn Bá Đức
6 năm trước

đang cần cảm ơn nhé

sĩ
5 năm trước

Cho mình hỏi. Mình đã tạo 1 bảng bằng WP_List_Table trong backend. Có thể show cái bảng đó ra ngoài frontend không?

sĩ
5 năm trước

Mình không phải dân code. Nên rất mong chờ thử nghiệm và hướng dẫn từ bạn. Cảm ơn vì những chia sẻ của bạn.

Truyện Hot
5 năm trước

Hì, mình sử dụng cách này và custompost để tạo ra các danh mục truyện trên web mình như truyện tranh riêng, truyện chữ riêng, các truyện tính phí riêng, do các truyện đều tự động cập nhật nên phải phân ra như vậy để đỡ mắc công nhiều chỗ,

sĩ
5 năm trước
Trả lời  Truyện Hot

Chào bạn. Bạn có thể hướng dẫn mình hiển thị 1 bảng đã tạo bằng WP_List_Table trong backend ra ngoài frontend không?

Truyện Hot
5 năm trước
Trả lời 

bạn muốn hiển thị danh sách đơn thuần hay theo chuyên mục – bài mới

sĩ
5 năm trước
Trả lời  Truyện Hot

Danh sách mình lấy thông tin từ file json. Mình có tạo một submenu để hiển thị trong backend. Và giờ mình muốn hiển thị trang này ra ngoài frontend.